カスタム パイプライン タスク拡張機能を追加する
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
Azure DevOps でカスタム ビルドまたはリリース タスク用の拡張機能を組織にインストールする方法について説明します。 詳細については、「Azure Pipelines とは」を参照してください。
Note
この記事では、エージェント ベースの拡張機能のエージェント タスクについて説明します。 サーバー タスクとサーバー ベースの拡張機能の詳細については、 Server Task GitHub のドキュメントを参照してください。
前提条件
Azure DevOps の拡張機能を作成するには、次のソフトウェアとツールが必要です。
ソフトウェア/ツール | 情報 |
---|---|
Azure DevOps 組織 | 組織の作成。 |
テキスト エディター | 多くの手順では、IntelliSense とデバッグのサポートを提供する Visual Studio Code を使用します。 最新バージョンをダウンロード します。 |
Node.js | 最新バージョンをダウンロード します。 |
npmjs.com 4.0.2 以降 | TypeScript コンパイラ。 最新バージョンをダウンロード します。 |
tfx-cli | Azure DevOps 用の Cross-platform CLI を使用して拡張機能をパッケージ化します。 npm i -g tfx-cli を実行して、Node.jsのコンポーネントであるnpm を使用します。 |
Azure DevOps 拡張機能 SDK | azure-devops-extension-sdk パッケージをインストールします。 |
プロジェクトの home ディレクトリ |
ビルドまたはリリース タスク拡張機能の home ディレクトリは、この記事の手順を完了した後の次の例のようになります。 |
|--- README.md
|--- images
|--- extension-icon.png
|--- buildandreleasetask // where your task scripts are placed
|--- vss-extension.json // extension's manifest
重要
開発用マシンは、 最新バージョンの Node を実行して、記述されたコードがエージェントの運用環境と最新のプレビュー以外のバージョンの azure-pipelines-task-lib
と互換性があることを確認する必要があります。 次のコマンドに従って、task.json ファイルを更新します。
"execution": {
"Node20_1": {
"target": "index.js"
}
}
1. カスタム タスクを作成する
buildandreleasetask
フォルダー内で、この手順のすべての部分を実行します。
Note
このチュートリアルの例では、PowerShell で Windows を使用します。 すべてのプラットフォームで汎用にしましたが、環境変数を取得するための構文は異なります。 Mac または Linux を使用している場合は、 $env:<var>=<val>
のインスタンスを export <var>=<val>
に置き換えます。
タスク スキャフォールディングの作成
タスクのフォルダー構造を作成し、必要なライブラリと依存関係をインストールします。
PowerShell コマンド ウィンドウを開き、
buildandreleasetask
フォルダーに移動して、次のコマンドを実行します。npm init --yes
npm init
は、package.json
ファイルを作成します。 既定のすべてのnpm init
オプションを受け入れるために、--yes
パラメーターを追加しました。ヒント
タスク フォルダーにノード モジュールが含まれると想定されているため、エージェントは必要なモジュールを自動的にインストールしません。 これを軽減するには、
node_modules
をbuildandreleasetask
にコピーします。 タスクが大きくなると、VSIX ファイルのサイズ制限 (50 MB) を超えるのは簡単です。 ノード フォルダーをコピーする前に、npm install --production
またはnpm prune --production
を実行するか、スクリプトを記述してすべてをビルドしてパックすることができます。ライブラリに
azure-pipelines-task-lib
を追加します。npm install azure-pipelines-task-lib --save
外部の依存関係に対して TypeScript 型指定がインストールされていることを確認します。
npm install @types/node --save-dev npm install @types/q --save-dev
.gitignore
ファイルを作成し、node_modulesを追加します。 ビルド プロセスでは、毎回node_modulesがビルドされ、チェックインする必要がないように、npm install
とtypings install
を実行する必要があります。echo node_modules > .gitignore
開発依存関係として Mocha をインストールします。
npm install mocha --save-dev -g npm install sync-request --save-dev npm install @types/mocha --save-dev
TypeScript バージョン 2.3.4 または 4.6.3 を選択します。
npm install typescript@4.6.3 -g --save-dev
Note
開発環境で npm を使用して TypeScript がグローバルにインストールされていることを確認し、
tsc
コマンドを使用できるようにします。 この手順を省略すると、TypeScript バージョン 2.3.4 が既定で使用されます。tsc
コマンドを使用できるようにするには、パッケージをグローバルにインストールする必要があります。コンパイラ オプション
tsconfig.json
作成します。 このファイルにより、TypeScript ファイルが JavaScript ファイルにコンパイルされます。tsc --init --target es2022
タスクを作成する
スキャフォールディングが完了したので、カスタム タスクを作成できます。
buildandreleasetask
フォルダーにtask.json
ファイルを作成します。task.json
ファイルはビルド/リリース タスクを記述し、ビルド/リリース システムが構成オプションをユーザーにレンダリングし、ビルド/リリース時に実行するスクリプトを把握するために使用します。次のコードをコピーし、
{{placeholders}}
をタスクの情報に置き換えます。 最も重要なプレースホルダーはtaskguid
であり、一意である必要があります。{ "$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" } } }
次のコードを参照として使用して、
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();
buildandreleasetask
フォルダーから「tsc」と入力して、index.ts
からindex.js
ファイルをコンパイルします。
task.json コンポーネント
task.json
ファイルのコンポーネントの一部については、次の説明を参照してください。
プロパティ | 説明 |
---|---|
id |
タスクの一意の GUID。 |
name |
スペースのない名前。 |
friendlyName |
わかりやすい名前 (スペースを使用できます)。 |
description |
タスクの内容の詳細な説明。 |
author |
ビルドタスクまたはリリース タスクを開発するエンティティを説明する短い文字列 (例: "Microsoft Corporation")。 |
instanceNameFormat |
ビルド/リリース ステップの一覧内でのタスクの表示方法。 変数の値は、 $(variablename)を使用して使用できます。 |
groups |
UI でのタスク プロパティの論理的なグループ化について説明します。 |
inputs |
ビルドまたはリリース タスクの実行時に使用する入力。 このタスクでは、 amplestring という名前の入力が必要です。 |
execution |
スクリプトを含む、このタスクの実行オプション。 |
restrictions |
GitHub Codespaces コマンドに関するタスクに適用される制限タスクが呼び出され、変数タスクを設定できます。 新しいタスクには制限モードを指定することをお勧めします。 |
タスクを実行する
PowerShell から node index.js
を使用してタスクを実行します。
次の例では、入力が指定されていないためにタスクが失敗します (samplestring
は必須の入力です)。
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
修正として、 samplestring
入力を設定し、タスクをもう一度実行できます。
$env:INPUT_SAMPLESTRING="Human"
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]Agent.ProxyUrl=undefined
##vso[task.debug]Agent.CAInfo=undefined
##vso[task.debug]Agent.ClientCert=undefined
##vso[task.debug]Agent.SkipCertValidation=undefined
##vso[task.debug]samplestring=Human
Hello Human
今回は、 samplestring
が指定され、"Hello Human!" が正しく出力されたため、タスクは成功しました。
ヒント
さまざまなタスク ランナーの詳細と、task.jsonに最新のノード バージョンを含める方法については、Azure Pipelines タスク作成者向けの Node ランナー更新ガイダンスを参照してください。
2. タスク スクリプトを単体テストする
単体テストを実行して、呼び出す外部ツールではなく、タスク スクリプトをすばやくテストします。 成功パスと失敗パスの両方のすべての側面をテストします。
テスト ツールをインストールします。 この手順では、 Mocha をテスト ドライバーとして使用します。
npm install mocha --save-dev -g npm install sync-request --save-dev npm install @types/mocha --save-dev
次の内容の
_suite.ts
ファイルを含むtests
フォルダーを作成します。import * 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() { }); after(() => { }); it('should succeed with simple inputs', function(done: Mocha.Done) { // Add success test here }); it('it should fail if tool returns 1', function(done: Mocha.Done) { // Add failure test here }); });
ヒント
テスト フォルダーは buildandreleasetask フォルダーに配置する必要があります。 同期要求エラーが発生した場合は、コマンド
npm i --save-dev sync-request
を使用して buildandreleasetask フォルダーに 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); 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.run(); //current, old function. 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); tmr.setInput('samplestring', 'bad'); tmr.run();
エラー テストでは、ツールが不適切または不完全な入力を取得すると、役に立つ出力で予期された方法で失敗することを検証します。
タスク モック ランナーを実行するには、次のコードを
_suite.ts
ファイルに追加します。it('it should fail if tool returns 1', function(done: Mocha.Done) { this.timeout(1000); let tp = path.join(__dirname, 'failure.js'); let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); tr.run(); 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(); });
テストを実行します。
tsc mocha tests/_suite.js
両方のテストに合格する必要があります。 より詳細な出力 (ビルド コンソールに表示される内容) でテストを実行する場合は、環境変数
TASK_TEST_TRACE=1
設定します。$env:TASK_TEST_TRACE=1
3. 拡張マニフェスト ファイルを作成する
拡張機能マニフェストには、拡張機能に関するすべての情報が含まれています。 これには、タスク フォルダーやイメージ フォルダーなど、ファイルへのリンクが含まれています。 extension-icon.pngを使用してイメージ フォルダーを作成していることを確認します。 次の例は、ビルドまたはリリース タスクを含む拡張機能マニフェストです。
次の.jsonコードをコピーし、home
ディレクトリにvss-extension.json
ファイルとして保存します。
buildandreleasetask フォルダーにこのファイルを作成しないでください。
{
"manifestVersion": 1,
"id": "build-release-task",
"name": "Fabrikam Build and Release Tools",
"version": "0.0.1",
"publisher": "fabrikam",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"description": "Tools for building/releasing with Fabrikam. Includes one build/release task.",
"categories": [
"Azure Pipelines"
],
"icons": {
"default": "images/extension-icon.png"
},
"files": [
{
"path": "buildandreleasetask"
}
],
"contributions": [
{
"id": "custom-build-release-task",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "buildandreleasetask"
}
}
]
}
Note
publisherを発行元名に変更します。 詳細については、「 パブリッシャーの作成」を参照してください。
貢献
プロパティ | 説明 |
---|---|
id |
コントリビューションの識別子。 拡張機能内で一意である必要があります。 ビルド タスクまたはリリース タスクの名前と一致する必要はありません。 通常、ビルドまたはリリース タスク名はコントリビューションの ID にあります。 |
type |
コントリビューションの種類。 ms.vss-distributed-task.taskにする必要があります。 |
targets |
この投稿の "対象" である投稿。 ms.vss-distributed-task.tasksにする必要があります。 |
properties.name |
タスクの名前。 この名前は、対応する自己完結型ビルドまたはリリース パイプライン タスクのフォルダー名と一致する必要があります。 |
ファイル
プロパティ | 説明 |
---|---|
path |
home ディレクトリを基準としたファイルまたはフォルダーのパス。 |
Note
拡張マニフェスト ファイルのプロパティや実行内容など、拡張マニフェスト ファイルの詳細については、 extension マニフェスト リファレンスを参照してください。
4. 拡張機能をパッケージ化する
すべてのファイルをパッケージ化して、拡張機能を Visual Studio Marketplace に取り込みます。 すべての拡張機能は、VSIX 2.0 と互換性のある .vsix ファイルとしてパッケージ化されています。 Microsoft では、拡張機能をパッケージ化するためのクロスプラットフォーム コマンド ライン インターフェイス (CLI) を提供しています。
tfx-cliを取得したら、拡張機能のホーム ディレクトリに移動し、次のコマンドを実行します。
tfx extension create --manifest-globs vss-extension.json
Note
拡張機能または統合のバージョンは、更新ごとにインクリメントする必要があります。
既存の拡張機能を更新する場合は、マニフェストのバージョンを更新するか、 --rev-version
コマンド ライン スイッチを渡します。 これにより、拡張機能の patch バージョン番号がインクリメントされ、新しいバージョンがマニフェストに保存されます。
更新を行うには、タスクのバージョンと拡張機能のバージョンの両方を変更する必要があります。 tfx extension create --manifest-globs vss-extension.json --rev-version
は、タスクのバージョンではなく、拡張機能のバージョンのみを更新します。 詳細については、GitHub の Build タスクを参照してください。
パッケージ化された拡張機能が .vsix ファイルに含まれると、Marketplace に拡張機能を発行する準備が整います。
5. 拡張機能を公開する
拡張機能を発行するには、最初にパブリッシャーを作成し、拡張機能をアップロードして最後に共有。
発行元を作成する
Microsoft の拡張機能を含むすべての拡張機能は、発行元によって提供されていると識別されます。 既存のパブリッシャーのメンバーでない場合は、作成します。
- Visual Studio Marketplace 発行ポータルにサインインします。
- 既存のパブリッシャーのメンバーでない場合は、パブリッシャーの作成を求められます。 発行元の作成を求めるメッセージが表示されない場合は、ページの下部まで下にスクロールし、関連サイト [拡張機能の公開] を選択。
- 発行元の識別子を指定します (例:
mycompany-myteam
)。- この識別子は、拡張機能のマニフェスト ファイルの
publisher
属性の値として使用されます。
- この識別子は、拡張機能のマニフェスト ファイルの
- 発行元の表示名を指定します (例:
My Team
)。
- 発行元の識別子を指定します (例:
- Marketplace パブリッシャー契約を確認し作成を選択します。
発行元が定義されています。 今後のリリースでは、発行元の拡張機能を表示および管理するためのアクセス許可を付与できます。 ユーザー間で資格情報のセットを共有する必要なく、共通の発行元の下で拡張機能を公開する方が簡単で安全です。
拡張機能をアップロードする
新しい拡張機能のアップロード ボタンを見つけて、パッケージ化された .vsix ファイルに移動し、アップロードを選択します。
また、
tfx extension create
ではなく、tfx extension publish
コマンドを使用してコマンド ライン インターフェイス (CLI) を使用して拡張機能をアップロードし、1 つの手順で拡張機能をパッケージ化して発行することもできます。 必要に応じて、--share-with
を使用して、公開後に 1 つ以上のアカウントと拡張機能を共有できます。tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
個人用アクセス トークン (PAT) を作成します。
- [Marketplace (発行)]スコープを選択します。 このスコープにより、トークンは Marketplace に拡張機能を発行することのみに制限されます。
拡張機能を共有する
拡張機能をアップロードすると、Marketplace に表示されますが、誰も表示できません。 インストールしてテストできるように、組織と共有します。
拡張機能を右選択し、 Share を選択し、組織の情報を入力します。 拡張機能にアクセスする他のアカウントと共有することもできます。
重要
公開されている拡張機能を共有するには、発行元を確認する必要があります。 詳細については、「 Package/Publish/Install」を参照してください。
拡張機能が Marketplace で共有されたので、それを使用するすべてのユーザーがインストールする必要があります。
6.拡張機能を Marketplace に発行するビルドおよびリリース パイプラインを作成する
Marketplace でのカスタム タスクの維持に役立つビルドおよびリリース パイプラインを Azure DevOps に作成します。
前提条件
ソフトウェア/ツール
情報
Azure DevOps プロジェクト
Azure DevOps 拡張機能タスク拡張機能
組織内の Azure DevOps 拡張機能タスク 無料でインストールします。
パイプライン ライブラリ変数グループ
パイプラインで使用される変数を保持するパイプライン ライブラリ変数グループを作成します。 詳細については、「 変数グループの追加と使用を参照してください。 変数グループは、Azure DevOps ライブラリ タブまたは CLI から作成できます。 パイプライン内のこのグループ内で 変数を使用します。 また、変数グループで次の変数を宣言します。
publisherId
: Marketplace パブリッシャーの IDextensionId
: vss-extension.json ファイルで宣言されている拡張機能の IDextensionName
: vss-extension.json ファイルで宣言されている拡張機能の名前artifactName
: VSIX ファイル用に作成される成果物の名前
サービス接続
新しい Marketplace サービス接続を作成し、すべてのパイプラインにアクセス許可を付与します。
YAML パイプライン
次の例を使用して、YAML を使用して新しいパイプラインを作成します。 詳細については、「 最初のパイプラインの作成 および YAML スキーマを参照してください。
trigger:
- main
pool:
vmImage: "ubuntu-latest"
variables:
- group: variable-group # Rename to whatever you named your variable group in the prerequisite stage of step 6
stages:
- stage: Run_and_publish_unit_tests
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "v0.x"
- task: Npm@1
inputs:
command: 'install'
workingDir: '/TaskDirectory' # Update to the name of the directory of your task
- task: Bash@3
displayName: Compile Javascript
inputs:
targetType: "inline"
script: |
cd TaskDirectory # Update to the name of the directory of your task
tsc
- task: Npm@1
inputs:
command: 'custom'
workingDir: '/TestsDirectory' # Update to the name of the directory of your task's tests
customCommand: 'testScript' # See the definition in the explanation section below - it may be called test
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/ResultsFile.xml'
- stage: Package_extension_and_publish_build_artifacts
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "0.x"
- task: Npm@1
inputs:
command: 'install'
workingDir: '/TaskDirectory' # Update to the name of the directory of your task
- task: Bash@3
displayName: Compile Javascript
inputs:
targetType: "inline"
script: |
cd TaskDirectory # Update to the name of the directory of your task
tsc
- task: QueryAzureDevOpsExtensionVersion@4
name: QueryVersion
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'ServiceConnection' # Change to whatever you named the service connection
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
versionAction: 'Patch'
- task: PackageAzureDevOpsExtension@4
inputs:
rootFolder: '$(System.DefaultWorkingDirectory)'
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
extensionName: '$(ExtensionName)'
extensionVersion: '$(QueryVersion.Extension.Version)'
updateTasksVersion: true
updateTasksVersionType: 'patch'
extensionVisibility: 'private' # Change to public if you're publishing to the marketplace
extensionPricing: 'free'
- task: CopyFiles@2
displayName: "Copy Files to: $(Build.ArtifactStagingDirectory)"
inputs:
Contents: "**/*.vsix"
TargetFolder: "$(Build.ArtifactStagingDirectory)"
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: '$(ArtifactName)'
publishLocation: 'Container'
- stage: Download_build_artifacts_and_publish_the_extension
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "v0.x"
- task: DownloadBuildArtifacts@0
inputs:
buildType: "current"
downloadType: "single"
artifactName: "$(ArtifactName)"
downloadPath: "$(System.DefaultWorkingDirectory)"
- task: PublishAzureDevOpsExtension@4
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'ServiceConnection' # Change to whatever you named the service connection
fileType: 'vsix'
vsixFile: '$(PublisherID).$(ExtensionName)/$(PublisherID)..vsix'
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
extensionName: '$(ExtensionName)'
updateTasksVersion: false
extensionVisibility: 'private' # Change to public if you're publishing to the marketplace
extensionPricing: 'free'
詳細については、「パイプラインをトリガーするイベントの指定」を参照してください。
Note
各ジョブは新しいユーザー エージェントを使用し、依存関係をインストールする必要があります。
パイプライン ステージ
次のセクションは、パイプライン ステージのしくみを理解するのに役立ちます。
ステージ 1: 単体テストを実行して発行する
このステージでは、単体テストを実行し、テスト結果を Azure DevOps に発行します。
単体テストを実行するには、次の例のように、package.json ファイルにカスタム スクリプトを追加します。
"scripts": {
"testScript": "mocha ./TestFile --reporter xunit --reporter-option output=ResultsFile.xml"
},
"Use Node CLI for Azure DevOps (tfx-cli)" を追加して、tfx-cli をビルド エージェントにインストールします。
"install" コマンドを使用して "npm" タスクを追加し、package.json ファイルを含むフォルダーをターゲットにします。
"Bash" タスクを追加して、TypeScript を JavaScript にコンパイルします。
"custom" コマンドを使用して "npm" タスクを追加し、単体テストを含むフォルダーをターゲットにして、コマンドとして
testScript
入力します。 次の入力を使用します。- コマンド: カスタム
- package.jsonを含む作業フォルダー: /TestsDirectory
- コマンドと引数:
testScript
[テスト結果の発行] タスクを追加します。 Mocha XUnit レポーターを使用している場合は、結果の形式が "XUnit" ではなく "JUnit" であることを確認します。検索フォルダーをルート ディレクトリに設定します。 次の入力を使用します。
- テスト結果の形式: JUnit
- テスト結果ファイル: **/ResultsFile.xml
- 検索フォルダー:
$(System.DefaultWorkingDirectory)
テスト結果が発行されると、[テスト] タブの出力は次の例のようになります。
ステージ 2: 拡張機能をパッケージ化し、ビルド成果物を発行する
"Use Node CLI for Azure DevOps (tfx-cli)" を追加して、tfx-cli をビルド エージェントにインストールします。
"install" コマンドを使用して "npm" タスクを追加し、package.json ファイルを含むフォルダーをターゲットにします。
"Bash" タスクを追加して、TypeScript を JavaScript にコンパイルします。
"拡張機能のバージョンのクエリ" タスクを追加して、既存の拡張機能のバージョンに対してクエリを実行します。 次の入力を使用します。
- 接続: 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)
- 拡張機能の可視性: 拡張機能がまだ開発中の場合は、値を private に設定します。 拡張機能をパブリックにリリースするには、値を public に設定します。
発行されたファイルをコピーする "ファイルのコピー" タスクを追加します。 次の入力を使用します。
- 内容: 成果物として発行するためにコピーされるすべてのファイル
- ターゲット フォルダー: ファイルのコピー先フォルダー
- 例: $(Build.ArtifactStagingDirectory)
"ビルド成果物の発行" を追加して、他のジョブまたはパイプラインで使用するために成果物を発行します。 次の入力を使用します。
- 発行するパス: 発行されるファイルを含むフォルダーへのパス
- 例: $(Build.ArtifactStagingDirectory)
- 成果物名: 成果物に指定された名前
- 成果物の発行場所: 今後のジョブで成果物を使用するには、[Azure Pipelines] を選択します
- 発行するパス: 発行されるファイルを含むフォルダーへのパス
ステージ 3: ビルド成果物をダウンロードして拡張機能を発行する
"Use Node CLI for Azure DevOps (tfx-cli)" を追加して、tfx-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 ファイル内の拡張機能の名前
- 拡張機能の可視性: プライベートまたはパブリック
省略可能: 拡張機能をインストールしてテストする
いくつかの手順で共有されている拡張機能をインストールします。
- 組織のコントロール パネル (
https://dev.azure.com/{organization}/_admin
) から、プロジェクト コレクションの管理ページに移動します。 - Extensions タブで、[自分と共有されている拡張機能] グループで拡張機能を見つけて、拡張機能のリンクを選択します。
- 拡張機能をインストールします。
[ Extensions タブが表示されない場合は、プロジェクトの管理ページではなく、コントロール パネル (プロジェクト コレクション レベルの管理ページ https://dev.azure.com/{organization}/_admin
) にいることを確認してください。
[ Extensions ] タブが表示されない場合、拡張機能は組織で有効になりません。 Visual Studio パートナー プログラムに参加することで、拡張機能機能に早期にアクセスできます。
Azure DevOps 拡張機能をパッケージ化して Visual Studio Marketplace に発行するには、 Azure DevOps 拡張機能タスクをダウンロードできます。
よく寄せられる質問
Azure DevOps の拡張機能にカスタム ビルドタスクまたはリリース タスクを追加する方法については、よく寄せられる質問 (FAQ) を参照してください。
Q: タスクの Azure Pipelines コマンドの使用を制限するにはどうすればよいですか?
タスクによって設定される Azure Pipelines コマンドの使用と変数を制限できます。 このアクションは、タスクが実行されるカスタム スクリプトの変数/vso コマンドへの無制限のアクセスを防ぐのに役立ちます。 新しいタスク用に設定することをお勧めします。 適用するには、task.json ファイルに次のステートメントを追加する必要がある場合があります。
"restrictions": {
"commands": {
"mode": "restricted"
},
"settableVariables": {
"allowed": ["variable1", "test*"]
}
}
restricted
値が mode
に指定されている場合は、タスクによってのみ次のコマンドを実行できます。
logdetail
logissue
complete
setprogress
setsecret
setvariable
debug
settaskvariable
prependpath
publish
settableVariables
制限を使用すると、変数の許可リストを渡すことができます。変数は、setvariable
またはprependpath
コマンドによって設定されます。 また、基本的な正規表現も使用できます。 たとえば、許可リストが ['abc', 'test*']
、 abc
、 test
、または test1
を任意の値を持つ変数として設定した場合、またはパスを前に置くと成功しますが、変数プロキシを設定しようとすると警告が表示されます。 空のリストは、タスクによって変数が変更されていないことを意味します。
settableVariables
キーまたはcommands
キーを省略した場合、関連する制限は適用されません。
この制限機能は、 2.182.1 エージェント バージョンから入手できます。
Q: キャンセルシグナルはタスクによってどのように処理されますか?
A: パイプライン エージェントは、関連する子プロセスに SIGINT
および SIGTERM
シグナルを送信します。 task ライブラリには、処理する明示的な手段はありません。 詳細については、「 Agent ジョブの取り消し」を参照してください。
Q: プロジェクト コレクションからタスクを削除するにはどうすればよいですか?
A: タスクの自動削除はサポートされていません。 自動削除は安全ではなく、そのようなタスクを既に使用している既存のパイプラインを中断します。 ただし、タスクは非推奨としてマークできます。 これを行うには、タスクのバージョンを し タスクを非推奨として マークします。
Q: カスタム タスクを最新のノードにアップグレードするにはどうすればよいですか?
A: 最新の Node バージョンにアップグレードすることをお勧めします。 例については、「 ノード 20 へのタスクのアップグレード」を参照してください。
Microsoft ホステッド エージェントとさまざまな Azure DevOps Server バージョンのライフサイクルが異なるため、タスクの実行場所に応じて、異なる Node ランナー バージョンがインストールされる場合があります。 ノード ランナーのバージョンが異なるエージェントで同じタスクを実行できるようにするには、 task.json ファイルに複数の実行セクションを含めることができます。 次の例では、Node 20 ランナーを含む Azure Pipeline エージェントが既定で選択し、ノード 10 の実装にフォールバックしません。
"execution": {
"Node10": {
"target": "bash.js",
"argumentFormat": ""
},
"Node20_1": {
"target": "bash.js",
"argumentFormat": ""
}
タスクをアップグレードするには:
さまざまな Node ランナー バージョンでタスクをテストし、コードが期待どおりに動作することを確認します。
タスクの実行セクションで、
Node
またはNode10
からNode16
またはNode20
に更新します。以前のバージョンのサーバーをサポートするには、
Node
/Node10
ターゲットのままにする必要があります。 以前のバージョンの Azure DevOps Server には、最新の Node ランナー バージョンが含まれていない可能性があります。ターゲットで定義されているエントリ ポイントを共有するか、使用されている Node バージョンに合わせてターゲットを最適化することができます。
"execution": { "Node10": { "target": "bash10.js", "argumentFormat": "" }, "Node16": { "target": "bash16.js", "argumentFormat": "" }, "Node20_1": { "target": "bash20.js", "argumentFormat": "" }
重要
カスタム タスクに Node 20 ランナーのサポートを追加しないと、 pipelines-agent-*
リリース フィードからインストールされたエージェントでタスクが失敗。