Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022 | Azure DevOps Server 2020
이 가이드에서는 사용자 지정 빌드 또는 릴리스 작업을 Azure DevOps 확장으로 만들고, 테스트하고, 게시하는 방법에 대해 설명합니다. 사용자 지정 파이프라인 작업을 사용하면 간단한 유틸리티에서 외부 시스템과의 복잡한 통합에 이르기까지 팀의 워크플로에 맞게 조정된 특수 기능으로 Azure DevOps를 확장할 수 있습니다.
다음 작업을 수행하는 방법을 알아봅니다.
- 개발 환경 및 프로젝트 구조 설정
- TypeScript 및 Azure Pipelines 작업 라이브러리를 사용하여 작업 논리 만들기
- 모의 프레임워크를 사용하여 포괄적인 단위 테스트 구현
- 배포를 위해 확장 패키지
- Visual Studio Marketplace에 게시
- 확장 유지 관리를 위해 자동화된 CI/CD 파이프라인 설정
Azure Pipelines에 대한 자세한 내용은 Azure Pipelines란?
참고
이 문서에서는 에이전트 기반 확장의 에이전트 작업을 다룹니다. 서버 작업 및 서버 기반 확장에 대한 자세한 내용은 서버 작업 작성을 참조하세요.
필수 조건
시작하기 전에 다음 요구 사항이 있는지 확인합니다.
| 구성 요소 | 요구 사항 | 설명 |
|---|---|---|
| Azure DevOps 조직 | 필수 | 조직 만들기 (없는 경우) |
| 텍스트 편집기 | 권장 | IntelliSense용 Visual Studio Code 및 디버깅 지원 |
| Node.js | 필수 | 최신 버전 설치(Node.js 20 이상 권장) |
| TypeScript 컴파일러 | 필수 | 최신 버전 설치(버전 4.6.3 이상) |
| Azure DevOps CLI(tfx-cli) | 필수 | 패키지를 사용하여 npm i -g tfx-cli 확장 설치 |
| Azure DevOps 확장 SDK | 필수 | azure-devops-extension-sdk 패키지 설치 |
| 테스트 프레임워크 | 필수 | 단위 테스트를 위한 모카(설치 중에 설치) |
프로젝트 구조
home 프로젝트에 대한 디렉터리를 만듭니다. 이 자습서를 완료하면 확장에 다음과 같은 구조가 있어야 합니다.
|--- README.md
|--- images
|--- extension-icon.png
|--- buildandreleasetask // Task scripts location
|--- task.json // Task definition
|--- index.ts // Main task logic
|--- package.json // Node.js dependencies
|--- tests/ // Unit tests
|--- _suite.ts
|--- success.ts
|--- failure.ts
|--- vss-extension.json // Extension manifest
중요함
개발 컴퓨터는 프로덕션 환경과의 호환성을 보장하기 위해 최신 버전의 Node.js 실행해야 합니다. 노드 20을 사용하도록 파일을 업데이트합니다 task.json .
"execution": {
"Node20_1": {
"target": "index.js"
}
}
1. 사용자 지정 작업 만들기
이 섹션에서는 사용자 지정 작업의 기본 구조 및 구현을 만드는 방법에 대해 설명합니다. 이 단계의 모든 파일은 프로젝트 디렉터리 내의 buildandreleasetaskhome 폴더 내에 만들어야 합니다.
참고
이 연습에서는 PowerShell과 함께 Windows를 사용합니다. 단계는 모든 플랫폼에서 작동하지만 환경 변수 구문은 다릅니다. Mac 또는 Linux에서 $env:<var>=<val>export <var>=<val>.
작업 스캐폴딩 설정
기본 프로젝트 구조를 만들고 필요한 종속성을 설치합니다.
Node.js 프로젝트를 초기화하려면 PowerShell을 열고 폴더로 이동하여 다음을 실행합니다
buildandreleasetask.npm init --yes파일이
package.json기본 설정으로 만들어집니다. 플래그는--yes모든 기본 옵션을 자동으로 허용합니다.팁
Azure Pipelines 에이전트는 작업 폴더에 노드 모듈이 포함될 것으로 예상합니다. 폴더에 복사
node_modules합니다buildandreleasetask. VSIX 파일 크기(50MB 제한)를 관리하려면 패키징 전에 실행npm install --production하거나npm prune --production패키징하기 전에 고려합니다.Azure Pipelines 작업 라이브러리를 설치합니다.
npm install azure-pipelines-task-lib --saveTypeScript 형식 정의를 설치합니다.
npm install @types/node --save-dev npm install @types/q --save-dev버전 제어 제외 설정
echo node_modules > .gitignore빌드 프로세스를 실행하여 매번 node_modules 다시 빌드
npm install해야 합니다.테스트 종속성 설치:
npm install mocha --save-dev -g npm install sync-request --save-dev npm install @types/mocha --save-devTypeScript 컴파일러 설치:
npm install typescript@4.6.3 -g --save-dev참고
TypeScript를 전역적으로 설치하여 명령을 사용할 수 있는지 확인
tsc합니다. 이 값이 없으면 TypeScript 2.3.4가 기본적으로 사용됩니다.TypeScript 컴파일 구성:
tsc --init --target es2022이 파일은
tsconfig.jsonES2022 대상 설정을 사용하여 만들어집니다.
작업 논리 구현
스캐폴딩이 완료되면 기능 및 메타데이터를 정의하는 핵심 작업 파일을 만듭니다.
작업 정의 파일을 만듭니다. 폴더에 만듭니
task.json다buildandreleasetask. 이 파일은 입력, 실행 설정 및 UI 프레젠테이션을 정의하는 Azure Pipelines 시스템에 대한 작업을 설명합니다.{ "$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json", "id": "{{taskguid}}", "name": "{{taskname}}", "friendlyName": "{{taskfriendlyname}}", "description": "{{taskdescription}}", "helpMarkDown": "", "category": "Utility", "author": "{{taskauthor}}", "version": { "Major": 0, "Minor": 1, "Patch": 0 }, "instanceNameFormat": "Echo $(samplestring)", "inputs": [ { "name": "samplestring", "type": "string", "label": "Sample String", "defaultValue": "", "required": true, "helpMarkDown": "A sample string" } ], "execution": { "Node20_1": { "target": "index.js" } } }참고
작업의 실제 정보로 대체
{{placeholders}}합니다.taskguid는 고유해야 합니다. PowerShell을 사용하여 생성:(New-Guid).Guid작업 논리를 구현하려면 작업의 주요 기능을 사용하여 만듭니
index.ts다.import tl = require('azure-pipelines-task-lib/task'); async function run() { try { const inputString: string | undefined = tl.getInput('samplestring', true); if (inputString == 'bad') { tl.setResult(tl.TaskResult.Failed, 'Bad input was given'); return; } console.log('Hello', inputString); } catch (err: any) { tl.setResult(tl.TaskResult.Failed, err.message); } } run();TypeScript를 JavaScript로 컴파일:
tsc파일은
index.jsTypeScript 원본에서 만들어집니다.
task.json 구성 요소 이해
파일이 task.json 작업 정의의 핵심입니다. 주요 속성은 다음과 같습니다.
| 속성 | 설명 | 예시 |
|---|---|---|
id |
작업에 대한 고유 GUID 식별자 | 다음을 사용하여 생성됨 (New-Guid).Guid |
name |
공백이 없는 작업 이름(내부적으로 사용) | MyCustomTask |
friendlyName |
UI에 표시된 표시 이름 | My Custom Task |
description |
작업 기능에 대한 자세한 설명 | Performs custom operations on files |
author |
게시자 또는 작성자 이름 | My Company |
instanceNameFormat |
파이프라인 단계에서 태스크가 표시되는 방식 | Process $(inputFile) |
inputs |
입력 매개 변수 배열 | 다음 입력 형식을 참조하세요. |
execution |
실행 환경 사양 |
Node20_1, PowerShell3 등 |
restrictions |
명령 및 변수에 대한 보안 제한 사항 | 새 작업에 권장 |
보안 제한 사항
프로덕션 작업의 경우 보안 제한을 추가하여 명령 사용 및 변수 액세스를 제한합니다.
"restrictions": {
"commands": {
"mode": "restricted"
},
"settableVariables": {
"allowed": ["variable1", "test*"]
}
}
제한된 모드 는 다음 명령만 허용합니다.
-
logdetail,logissue, ,complete,setprogress -
setsecret,setvariable, ,debug,settaskvariable -
prependpath,publish
변수 허용 목록 컨트롤을 통해 또는 setvariable을 통해 prependpath 설정할 수 있는 변수입니다. 기본 정규식 패턴을 지원합니다.
참고
이 기능을 사용하려면 에이전트 버전 2.182.1 이상이 필요합니다.
입력 형식 및 예제
작업 매개 변수에 대한 일반적인 입력 형식:
"inputs": [
{
"name": "stringInput",
"type": "string",
"label": "Text Input",
"defaultValue": "",
"required": true,
"helpMarkDown": "Enter a text value"
},
{
"name": "boolInput",
"type": "boolean",
"label": "Enable Feature",
"defaultValue": "false",
"required": false
},
{
"name": "picklistInput",
"type": "pickList",
"label": "Select Option",
"options": {
"option1": "First Option",
"option2": "Second Option"
},
"defaultValue": "option1"
},
{
"name": "fileInput",
"type": "filePath",
"label": "Input File",
"required": true,
"helpMarkDown": "Path to the input file"
}
]
로컬로 작업 테스트
패키징하기 전에 작업을 테스트하여 올바르게 작동하는지 확인합니다.
입력이 누락된 테스트(실패해야 합니다).
node index.js예상 출력:
##vso[task.debug]agent.workFolder=undefined ##vso[task.debug]loading inputs and endpoints ##vso[task.debug]loaded 0 ##vso[task.debug]task result: Failed ##vso[task.issue type=error;]Input required: samplestring ##vso[task.complete result=Failed;]Input required: samplestring유효한 입력으로 테스트(성공해야 합니다).
$env:INPUT_SAMPLESTRING="World" node index.js예상 출력:
##vso[task.debug]agent.workFolder=undefined ##vso[task.debug]loading inputs and endpoints ##vso[task.debug]loading INPUT_SAMPLESTRING ##vso[task.debug]loaded 1 ##vso[task.debug]samplestring=World Hello World테스트 오류 처리:
$env:INPUT_SAMPLESTRING="bad" node index.js이 작업은 코드에서 오류 처리 경로를 트리거해야 합니다.
팁
작업 실행기 및 Node.js 버전에 대한 자세한 내용은 Node Runner 업데이트 지침을 참조하세요.
자세한 내용은 빌드/릴리스 작업 참조를 참조하세요.
2. 포괄적인 단위 테스트 구현
작업을 철저히 테스트하면 안정성이 보장되고 프로덕션 파이프라인에 배포하기 전에 문제를 catch할 수 있습니다.
테스트 종속성 설치
필요한 테스트 도구를 설치합니다.
npm install mocha --save-dev -g
npm install sync-request --save-dev
npm install @types/mocha --save-dev
테스트 만들기
tests파일을 포함하는 작업 디렉터리에 폴더를 만듭니다._suite.tsimport * as path from 'path'; import * as assert from 'assert'; import * as ttm from 'azure-pipelines-task-lib/mock-test'; describe('Sample task tests', function () { before( function() { // Setup before tests }); after(() => { // Cleanup after tests }); it('should succeed with simple inputs', function(done: Mocha.Done) { // Success test implementation }); it('should fail if tool returns 1', function(done: Mocha.Done) { // Failure test implementation }); });팁
테스트 폴더는 작업 폴더(예:
buildandreleasetask)에 있어야 합니다. 동기화 요청 오류가 발생하면 작업 폴더npm i --save-dev sync-request에 설치합니다.테스트 디렉터리에 만들어
success.ts성공적인 작업 실행을 시뮬레이션합니다.import ma = require('azure-pipelines-task-lib/mock-answer'); import tmrm = require('azure-pipelines-task-lib/mock-run'); import path = require('path'); let taskPath = path.join(__dirname, '..', 'index.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); // Set valid input for success scenario tmr.setInput('samplestring', 'human'); tmr.run();성공 테스트를 파일에 추가합니다
_suite.ts.it('should succeed with simple inputs', function(done: Mocha.Done) { this.timeout(1000); let tp: string = path.join(__dirname, 'success.js'); let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); tr.runAsync().then(() => { console.log(tr.succeeded); assert.equal(tr.succeeded, true, 'should have succeeded'); assert.equal(tr.warningIssues.length, 0, "should have no warnings"); assert.equal(tr.errorIssues.length, 0, "should have no errors"); console.log(tr.stdout); assert.equal(tr.stdout.indexOf('Hello human') >= 0, true, "should display Hello human"); done(); }).catch((error) => { done(error); // Ensure the test case fails if there's an error }); });테스트 디렉터리에서 오류 처리를 테스트하기 위해 만듭니
failure.ts다.import ma = require('azure-pipelines-task-lib/mock-answer'); import tmrm = require('azure-pipelines-task-lib/mock-run'); import path = require('path'); let taskPath = path.join(__dirname, '..', 'index.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); // Set invalid input to trigger failure tmr.setInput('samplestring', 'bad'); tmr.run();실패 테스트를 파일에 추가합니다
_suite.ts.it('should fail if tool returns 1', function(done: Mocha.Done) { this.timeout(1000); const tp = path.join(__dirname, 'failure.js'); const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); tr.runAsync().then(() => { console.log(tr.succeeded); assert.equal(tr.succeeded, false, 'should have failed'); assert.equal(tr.warningIssues.length, 0, 'should have no warnings'); assert.equal(tr.errorIssues.length, 1, 'should have 1 error issue'); assert.equal(tr.errorIssues[0], 'Bad input was given', 'error issue output'); assert.equal(tr.stdout.indexOf('Hello bad'), -1, 'Should not display Hello bad'); done(); }); });
테스트 실행
테스트 도구 모음을 실행합니다.
# Compile TypeScript
tsc
# Run tests
mocha tests/_suite.js
두 테스트 모두 통과해야 합니다. 자세한 출력(빌드 콘솔 출력과 유사)의 경우 추적 환경 변수를 설정합니다.
$env:TASK_TEST_TRACE=1
mocha tests/_suite.js
테스트 검사 모범 사례
- 모든 입력 조합 테스트: 유효한 입력, 잘못된 입력, 누락된 필수 입력
- 테스트 오류 시나리오: 네트워크 오류, 파일 시스템 오류, 권한 문제
- 모의 외부 종속성: 단위 테스트에서 외부 서비스에 의존하지 마세요.
- 출력 유효성 검사: 콘솔 출력, 작업 결과 및 생성된 아티팩트 확인
- 성능 테스트: 대용량 파일을 처리하는 작업에 대한 테스트를 추가하는 것이 좋습니다.
보안 모범 사례
- 입력 유효성 검사: 항상 입력 유효성 검사 및 삭제
-
비밀 처리: 중요한 데이터에 사용
setSecret - 명령 제한: 프로덕션 작업에 대한 명령 제한 구현
- 최소 권한: 필요한 권한만 요청
- 일반 업데이트: 종속성 및 Node.js 버전을 최신 상태로 유지
작업을 로컬로 테스트하고 포괄적인 단위 테스트를 구현한 후 Azure DevOps용 확장으로 패키지합니다.
패키징 도구 설치
플랫폼 간 명령줄 인터페이스(tfx-cli)를 설치합니다.
npm install -g tfx-cli
확장 매니페스트 만들기
확장 매니페스트(vss-extension.json)에는 작업 폴더 및 이미지에 대한 참조를 포함하여 확장에 대한 모든 정보가 포함됩니다.
파일을 사용하여 이미지 폴더
extension-icon.png만들기확장의 루트 디렉터리에서 만듭니
vss-extension.json다(작업 폴더에 없음).{ "manifestVersion": 1, "id": "my-custom-tasks", "name": "My Custom Tasks", "version": "1.0.0", "publisher": "your-publisher-id", "targets": [ { "id": "Microsoft.VisualStudio.Services" } ], "description": "Custom build and release tasks for Azure DevOps", "categories": [ "Azure Pipelines" ], "icons": { "default": "images/extension-icon.png" }, "files": [ { "path": "MyCustomTask" } ], "contributions": [ { "id": "my-custom-task", "type": "ms.vss-distributed-task.task", "targets": [ "ms.vss-distributed-task.tasks" ], "properties": { "name": "MyCustomTask" } } ] }
키 매니페스트 속성
| 속성 | 설명 |
|---|---|
publisher |
Marketplace 게시자 식별자 |
contributions.id |
확장 내의 고유 식별자 |
contributions.properties.name |
작업 폴더 이름과 일치해야 합니다. |
files.path |
매니페스트를 기준으로 작업 폴더의 경로 |
참고
게시자 값을 게시자 이름으로 변경합니다. 게시자를 만드는 방법에 대한 자세한 내용은 게시자 만들기를 참조하세요.
확장을 패키징합니다.
확장자를 .vsix 파일로 패키지합니다.
tfx extension create --manifest-globs vss-extension.json
버전 관리
-
확장 버전: 각 업데이트에
vss-extension.json대한 버전 증가 -
작업 버전: 각 작업 업데이트에
task.json대한 버전 증가 -
자동 증가: 패치 버전을 자동으로 증분하는 데 사용
--rev-version
tfx extension create --manifest-globs vss-extension.json --rev-version
중요함
Azure DevOps에서 변경 내용을 적용하려면 작업 버전과 확장 버전을 모두 업데이트해야 합니다.
버전 관리 전략
작업 업데이트에 대한 의미 체계 버전 관리 원칙을 따릅니다.
- 주 버전: 입력/출력의 주요 변경 내용
- 부 버전: 새로운 기능, 이전 버전과 호환
- 패치 버전: 버그 수정만
업데이트 프로세스:
-
task.json버전 업데이트 -
vss-extension.json버전 업데이트 - 테스트 조직에서 철저히 테스트
- 문제 게시 및 모니터링
Visual Studio Marketplace에 게시
1. 게시자 만들기
- Visual Studio Marketplace 게시 포털에 로그인
- 메시지가 표시되면 새 게시자를 만듭니다.
-
게시자 식별자: 확장 매니페스트에 사용됨(예:
mycompany-myteam) -
표시 이름: 마켓플레이스에 표시된 공용 이름(예:
My Team)
-
게시자 식별자: 확장 매니페스트에 사용됨(예:
- Marketplace 게시자 계약 검토 및 동의
2. 확장 업로드
웹 인터페이스 메서드:
- 새 확장 업로드 선택
- 패키지된
.vsix파일 선택 - 업로드를 선택합니다.
명령줄 메서드:
tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization
3. 확장 공유
- 마켓플레이스에서 확장을 마우스 오른쪽 단추로 클릭합니다.
- 공유 선택
- 조직 이름 입력
- 필요에 따라 더 많은 조직 추가
중요함
퍼블리셔는 공개적으로 확장을 공유하도록 확인해야 합니다. 자세한 내용은 패키지/게시/설치를 참조 하세요.
4. 조직에 설치
공유한 후 Azure DevOps 조직에 확장을 설치합니다.
- 조직 설정>확장으로 이동
- 확장 찾아보기
- 무료 가져오기를 선택하고 설치
3. 확장 패키지 및 게시
확장 확인
설치 후 작업이 올바르게 작동하는지 확인합니다.
- 파이프라인을 만들거나 편집합니다.
- 사용자 지정 작업을 추가합니다.
- 파이프라인 편집기에서 작업 추가 선택
- 이름으로 사용자 지정 작업 검색
- 파이프라인에 추가
- 작업 매개 변수 구성:
- 필수 입력 설정
- 옵션 설정 구성
- 파이프라인을 실행하여 기능 테스트
- 실행 모니터링:
- 작업 로그에서 적절한 실행 확인
- 예상 출력 확인
- 오류 또는 경고가 없는지 확인
4. CI/CD를 사용하여 확장 게시 자동화
사용자 지정 작업을 효과적으로 유지하려면 테스트, 패키징 및 게시를 처리하는 자동화된 빌드 및 릴리스 파이프라인을 만듭니다.
자동화를 위한 필수 구성 요소
- Azure DevOps 확장 작업: 무료로 확장 설치
-
변수 그룹: 다음 변수를 사용하여 파이프라인 라이브러리 변수 그룹을 만듭니다.
-
publisherId: Marketplace 게시자 ID -
extensionId: vss-extension.json 확장 ID -
extensionName: vss-extension.json 확장명 -
artifactName: VSIX 아티팩트 이름
-
- 서비스 연결: 파이프라인 액세스 권한을 사용하여 Marketplace 서비스 연결 만들기
CI/CD 파이프라인 완료
테스트, 패키징 및 게시를 위한 포괄적인 단계를 포함하는 YAML 파이프라인을 만듭니다.
trigger:
- main
pool:
vmImage: "ubuntu-latest"
variables:
- group: extension-variables # Your variable group name
stages:
- stage: Test_and_validate
displayName: 'Run Tests and Validate Code'
jobs:
- job: RunTests
displayName: 'Execute unit tests'
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: Npm@1
displayName: 'Install task dependencies'
inputs:
command: 'install'
workingDir: '/MyCustomTask' # Update to your task directory
- task: Bash@3
displayName: 'Compile TypeScript'
inputs:
targetType: "inline"
script: |
cd MyCustomTask # Update to your task directory
tsc
- task: Npm@1
displayName: 'Run unit tests'
inputs:
command: 'custom'
workingDir: '/MyCustomTask' # Update to your task directory
customCommand: 'test' # Ensure this script exists in package.json
- task: PublishTestResults@2
displayName: 'Publish test results'
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/test-results.xml'
searchFolder: '$(System.DefaultWorkingDirectory)'
- stage: Package_extension
displayName: 'Package Extension'
dependsOn: Test_and_validate
condition: succeeded()
jobs:
- job: PackageExtension
displayName: 'Create VSIX package'
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: Npm@1
displayName: 'Install dependencies'
inputs:
command: 'install'
workingDir: '/MyCustomTask'
- task: Bash@3
displayName: 'Compile TypeScript'
inputs:
targetType: "inline"
script: |
cd MyCustomTask
tsc
- task: QueryAzureDevOpsExtensionVersion@4
name: QueryVersion
displayName: 'Query current extension version'
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'marketplace-connection'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
versionAction: 'Patch'
- task: PackageAzureDevOpsExtension@4
displayName: 'Package extension'
inputs:
rootFolder: '$(System.DefaultWorkingDirectory)'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
extensionName: '$(extensionName)'
extensionVersion: '$(QueryVersion.Extension.Version)'
updateTasksVersion: true
updateTasksVersionType: 'patch'
extensionVisibility: 'private'
extensionPricing: 'free'
- task: PublishBuildArtifacts@1
displayName: 'Publish VSIX artifact'
inputs:
PathtoPublish: '$(System.DefaultWorkingDirectory)/*.vsix'
ArtifactName: '$(artifactName)'
publishLocation: 'Container'
- stage: Publish_to_marketplace
displayName: 'Publish to Marketplace'
dependsOn: Package_extension
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: PublishExtension
displayName: 'Deploy to marketplace'
environment: 'marketplace-production'
strategy:
runOnce:
deploy:
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: PublishAzureDevOpsExtension@4
displayName: 'Publish to marketplace'
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'marketplace-connection'
fileType: 'vsix'
vsixFile: '$(Pipeline.Workspace)/$(artifactName)/*.vsix'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
extensionName: '$(extensionName)'
updateTasksVersion: false
extensionVisibility: 'private'
extensionPricing: 'free'
테스트를 위한 package.json 구성
테스트 스크립트를 다음 사항에 추가합니다 package.json.
{
"scripts": {
"test": "mocha tests/_suite.js --reporter xunit --reporter-option output=test-results.xml",
"test-verbose": "cross-env TASK_TEST_TRACE=1 npm test"
}
}
파이프라인 단계 분석
1단계: 테스트 및 유효성 검사
- 목적: 코드 품질 및 기능 확인
- 작업: 종속성 설치, TypeScript 컴파일, 단위 테스트 실행, 결과 게시
- 유효성 검사: 계속하려면 모든 테스트가 통과해야 합니다.
2단계: 패키지 확장
- 목적: 배포 가능한 VSIX 패키지 만들기
- 작업: 현재 버전 쿼리, 증분 버전, 패키지 확장, 아티팩트 게시
- 버전 관리: 자동으로 버전 증분 처리
3단계: 마켓플레이스에 게시
- 목적: Visual Studio Marketplace에 배포
- 조건: 성공적인 패키징 후 주 분기에서만 실행
- 환경: 승인 게이트에 배포 환경 사용
CI/CD에 대한 모범 사례
- 분기 보호: 주/릴리스 분기에서만 게시
- 환경 게이트: 프로덕션 릴리스에 배포 환경 사용
- 버전 관리: 충돌을 방지하기 위해 버전 증분 자동화
- 테스트 검사: 패키징하기 전에 포괄적인 테스트 검사 확인
- 보안: 하드 코딩된 자격 증명 대신 서비스 연결 사용
- 모니터링: 실패한 배포에 대한 경고 설정
클래식 빌드 파이프라인의 경우 다음 단계에 따라 확장 패키징 및 게시를 설정합니다.
TypeScript를
BashJavaScript로 컴파일하는 작업을 추가합니다.기존 버전을 쿼리하려면 다음 입력을 사용하여 쿼리 확장 버전 작업을 추가합니다.
- 연결: Visual Studio Marketplace
- Visual Studio Marketplace(서비스 연결): 서비스 연결
- 게시자 ID: Visual Studio Marketplace 게시자의 ID
- 확장 ID:
vss-extension.json파일에 있는 확장 프로그램의 ID - 버전 늘리기: 패치
- 출력 변수:
Task.Extension.Version
매니페스트 Json을 기반으로 확장을 패키지하려면 다음 입력을 사용하여 패키지 확장 태스크를 추가합니다.
- 루트 매니페스트 폴더: 매니페스트 파일이 포함된 루트 디렉터리를 가리킵니다. 예를 들어
$(System.DefaultWorkingDirectory)루트 디렉터리입니다. - 매니페스트 파일:
vss-extension.json - 게시자 ID: Visual Studio Marketplace 게시자의 ID
- 확장 ID:
vss-extension.json파일에 있는 확장 프로그램의 ID - 확장 이름: 사용자 확장명의
vss-extension.json파일 - 확장 버전:
$(Task.Extension.Version) - 작업 버전 무시: 체크됨 (true)
- 재정의 유형: 패치 버전만 교체(1.0.r)
- 확장 표시 유형: 확장이 아직 개발 중인 경우 값을 프라이빗으로 설정합니다. 확장을 공용으로 해제하려면 값을 public으로 설정합니다.
- 루트 매니페스트 폴더: 매니페스트 파일이 포함된 루트 디렉터리를 가리킵니다. 예를 들어
게시된 파일에 복사하려면 다음 입력을 사용하여 파일 복사 작업을 추가합니다.
- 내용: 아티팩트로 게시하기 위해 복사할 모든 파일
- 대상 폴더: 파일이 복사되는 폴더
- 예:
$(Build.ArtifactStagingDirectory)
- 예:
빌드 아티팩트 게시 옵션을 추가하여 다른 작업이나 파이프라인에서 아티팩트를 사용할 수 있도록 게시하십시오. 다음 입력을 사용합니다.
- 게시할 경로: 게시 중인 파일이 포함된 폴더의 경로입니다.
- 예:
$(Build.ArtifactStagingDirectory)
- 예:
- 아티팩트 이름: 아티팩트에 지정된 이름
- 아티팩트 게시 위치: Azure Pipelines를 선택하여 향후 작업에서 아티팩트 사용
- 게시할 경로: 게시 중인 파일이 포함된 폴더의 경로입니다.
3단계: 빌드 아티팩트 다운로드 및 확장 게시
빌드 에이전트에 tfx-cli를 설치하려면 Azure DevOps(tfx-cli)에 노드 CLI를 사용합니다.
아티팩트를 새 작업에 다운로드하려면 다음 입력을 사용하여 빌드 아티팩트 다운로드 작업을 추가합니다.
- 생성된 아티팩트 다운로드: 동일한 파이프라인에서 새 작업에서 아티팩트를 다운로드하는 경우 현재 빌드를 선택합니다. 새 파이프라인에서 다운로드하는 경우 특정 빌드를 선택합니다.
- 다운로드 유형: 게시된 모든 파일을 다운로드하려면 특정 아티팩트를 선택하세요.
- 아티팩트 이름: 게시된 아티팩트의 이름
- 대상 디렉터리: 파일을 다운로드해야 하는 폴더
게시 확장 작업을 수행하려면 다음 입력을 사용하세요.
- 연결: Visual Studio Marketplace
- Visual Studio Marketplace 연결: ServiceConnection
- 입력 파일 형식: VSIX 파일
- VSIX 파일:
/Publisher.*.vsix - 게시자 ID: Visual Studio Marketplace 게시자의 ID
- 확장 ID:
vss-extension.json파일에 있는 확장 프로그램의 ID - 확장 이름: 사용자 확장명의
vss-extension.json파일 - 확장 표시 유형: 프라이빗 또는 퍼블릭
선택 사항: 확장 설치 및 테스트
확장을 게시한 후에는 Azure DevOps 조직에 설치해야 합니다.
조직에 확장 설치
몇 가지 단계로 공유 확장을 설치합니다.
조직 설정으로 이동하여 확장을 선택합니다.
내 확장 공유 섹션에서 확장을 찾습니다.
- 확장 링크 선택
- 무료 가져오기 또는 설치 선택
설치된 확장 목록에 확장이 표시되는지 확인합니다.
- 파이프라인 작업 라이브러리에서 사용할 수 있음 확인
참고
확장 탭이 표시되지 않으면 프로젝트 수준이 아닌 조직 관리 수준(https://dev.azure.com/{organization}/_admin)에 있는지 확인합니다.
엔드투엔드 테스트
설치 후 포괄적인 테스트를 수행합니다.
테스트 파이프라인 만들기:
- 새 파이프라인에 사용자 지정 작업 추가
- 모든 입력 매개 변수 구성
- 다양한 입력 조합으로 테스트
기능 유효성 검사:
- 파이프라인 실행 및 실행 모니터링
- 작업 출력 및 로그 확인
- 잘못된 입력으로 오류 처리 확인
테스트 성능:
- 큰 입력 파일로 테스트(해당하는 경우)
- 리소스 사용량 모니터링
- 시간 제한 동작 유효성 검사
자주 묻는 질문
Q: 작업 취소는 어떻게 처리합니까?
A: 파이프라인 에이전트가 SIGINTSIGTERM 작업 프로세스에 보내고 신호를 보냅니다.
작업 라이브러리는 명시적 취소 처리를 제공하지 않지만 태스크는 신호 처리기를 구현할 수 있습니다. 자세한 내용은 에이전트 작업 취소를 참조하세요.
Q: 조직에서 작업을 제거하려면 어떻게 해야 하나요?
A: 자동 삭제는 기존 파이프라인을 중단하기 때문에 지원되지 않습니다. 대신에:
- 작업 사용 중단: 더 이상 사용되지 않는 작업으로 표시
- 버전 관리: 작업 버전 범프
- 통신: 사용 중단 타임라인에 대해 사용자에게 알립니다.
Q: 작업을 최신 Node.js 버전으로 업그레이드하려면 어떻게 해야 하나요?
A: 성능 및 보안을 향상시키려 면 최신 노드 버전 으로 업그레이드합니다. 마이그레이션 지침은 작업을 노드 20으로 업그레이드를 참조하세요.
다음에서 여러 실행 섹션을 포함하여 여러 노드 버전을 지원합니다.task.json
"execution": {
"Node20_1": {
"target": "index.js"
},
"Node10": {
"target": "index.js"
}
}
노드 20이 있는 에이전트는 기본 버전을 사용하는 반면 이전 에이전트는 노드 10으로 대체됩니다.
작업을 업그레이드하려면 다음을 수행합니다.
코드가 예상대로 작동하는지 확인하려면 다양한 노드 실행기 버전에서 작업을 테스트합니다.
작업의 실행 섹션에서
Node또는Node10을Node16또는Node20로 업데이트합니다.이전 서버 버전을 지원하려면 대상을
Node/Node10그대로 두어야 합니다. 이전 Azure DevOps Server 버전에는 최신 노드 실행기 버전이 포함되지 않을 수 있습니다.대상에 정의된 진입점을 공유하거나 대상을 노드 버전에 맞게 최적화하도록 선택할 수 있습니다.
"execution": { "Node10": { "target": "bash10.js", "argumentFormat": "" }, "Node16": { "target": "bash16.js", "argumentFormat": "" }, "Node20_1": { "target": "bash20.js", "argumentFormat": "" } }
중요함
사용자 지정 작업에 Node 20 Runner에 대한 지원을 추가하지 않으면 pipelines-agent-*릴리스 피드설치된 에이전트에서 실패합니다.