Skip to content

Instantly share code, notes, and snippets.

@justinyoo
Last active June 6, 2020 18:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinyoo/baf3ecf3240df3037be0f84fe43b5425 to your computer and use it in GitHub Desktop.
Save justinyoo/baf3ecf3240df3037be0f84fe43b5425 to your computer and use it in GitHub Desktop.
Building Azure DevOps Extension on Azure DevOps
import * as path from 'path';
import * as tl from 'azure-pipelines-task-lib/task';
async function run() {
}
run();
Param(
[string] [Parameter(Mandatory=$true)] $SourceDirectory
)
cd $SourceDirectory
Get-ChildItem *.ts -File -Recurse | Where-Object {
$_.FullName -notlike "*node_modules*"
} | ForEach-Object {
tsc $_.FullName
}
{
"id": "{{ GUID }}",
"name": "deploy",
"friendlyName": "Deploy Website",
"description": "Deploy website to Netlify",
"helpMarkDown": "This deployes website to Netlify",
"author": "{{ Author Name }}",
"preview": false,
"showEnvironmentVariables": false,
"runsOn": [
"Agent",
"MachineGroup",
"Server"
],
"category": "Azure Pipelines",
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"instanceNameFormat": "Deploy to Netlify",
"inputs": [
{
"type": "string",
"name": "authToken",
"label": "Authentication Token",
"defaultValue": "",
"required": true,
"helpMarkDown": "The authentication token to login to Netlify"
},
{
"type": "string",
"name": "siteId",
"label": "Site ID",
"defaultValue": "",
"required": true,
"helpMarkDown": "The site ID to deploy to"
},
{
"type": "filePath",
"name": "sourceDirectory",
"label": "Source Directory",
"defaultValue": "$(System.DefaultWorkingDirectory)",
"required": true,
"helpMarkDown": "The source directory to deploy"
},
{
"type": "boolean",
"name": "isValidationOnly",
"label": "Validation Only (No Production Deployment)",
"defaultValue": false,
"required": true,
"helpMarkDown": "Value indicating whether to only validate deployment or not"
},
{
"type": "string",
"name": "message",
"label": "Deployment Message",
"defaultValue": "",
"required": false,
"helpMarkDown": "The short message to include in the deployment log"
},
{
"type": "filePath",
"name": "functionsDirectory",
"label": "Functions Directory",
"defaultValue": "",
"required": false,
"helpMarkDown": "The functions directory to deploy"
}
],
"execution": {
"Node": {
"target": "index.js"
}
}
}
tl.setResourcePath(path.join(__dirname, 'task.json'));
try {
const authToken: string = tl.getInput('authToken', true);
const siteId: string = tl.getInput('siteId', true);
const sourceDirectory: string = tl.getPathInput('sourceDirectory', true, true);
const isValidationOnly: boolean = tl.getBoolInput('isValidationOnly', true);
const message: string = tl.getInput('message', false);
const functionsDirectory: string = tl.getPathInput('functionsDirectory', false, true);
const args: Array<string> = new Array<string>();
args.push('deploy')
args.push('--auth=' + authToken);
args.push('--site=' + siteId);
args.push('--dir=' + sourceDirectory);
if (!isValidationOnly) {
args.push('--prod');
}
if (message) {
args.push('--message=' + message);
}
if (functionsDirectory) {
args.push('--functions=' + functionsDirectory);
}
args.push('--json');
await tl.exec('netlify', args);
}
catch (err) {
tl.setResult(tl.TaskResult.Failed, err.message);
}
{
"id": "{{ GUID }}",
"name": "install",
"friendlyName": "Install Netlify CLI",
"description": "Install Netlify CLI",
"helpMarkDown": "This installs the netlify-cli",
"author": "{{ Author Name }}",
"preview": false,
"showEnvironmentVariables": false,
"runsOn": [
"Agent",
"MachineGroup",
"Server"
],
"category": "Azure Pipelines",
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"instanceNameFormat": "Install Netlify CLI",
"inputs": [
{
"type": "string",
"name": "version",
"label": "Version",
"defaultValue": "",
"required": false,
"helpMarkDown": "The version of Netlify CLI. If omitted, the latest version of netlify-cli is installed. Visit the [npm package](https://www.npmjs.com/package/netlify) to get an appropriate version."
}
],
"execution": {
"Node": {
"target": "index.js"
}
}
}
tl.setResourcePath(path.join(__dirname, 'task.json'));
try {
const version: string = tl.getInput('version', false);
const args: Array<string> = new Array<string>();
args.push('install');
args.push('-g');
if (version) {
args.push('netlify-cli@' + version);
}
else {
args.push('netlify-cli');
}
await tl.exec('npm', args);
}
catch (err) {
tl.setResult(tl.TaskResult.Failed, err.message);
}
# netlify-build.yaml
name: $(Version).$(rev:r)
...
stages:
# Build Pipeline
- stage: Build
jobs:
- job: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
demands: npm
workspace:
clean: all
steps:
# Calls the template
- template: templates/npm-build-steps.yaml
parameters:
extensionName: $(ExtensionName)
# pipelines/netlify-build.yaml
name: $(Version).$(rev:r)
variables:
- group: Common Netlify
trigger:
branches:
include:
- dev
- feature/*
- hotfix/*
paths:
include:
- 'Netlify/*'
exclude:
- 'pipelines/*'
- 'scripts/*'
- '.editorconfig'
- '.gitignore'
- 'README.md'
stages:
# Build Pipeline
- stage: Build
jobs:
- job: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
demands: npm
workspace:
clean: all
steps:
- task: Npm@1
displayName: 'Install npm Packages'
inputs:
command: install
workingDir: '$(Build.SourcesDirectory)/$(ExtensionName)/src'
verbose: false
- task: PowerShell@2
displayName: 'Compile TypeScript Files'
inputs:
targetType: filePath
filePath: '$(Build.SourcesDirectory)/scripts/Compile-TypeScripts.ps1'
arguments: '-SourceDirectory $(Build.SourcesDirectory)/$(ExtensionName)/src'
netlify deploy --auth=*** --site=*** --dir=*** --prod --functions=*** --json
# pipelines/netlify-pr.yaml
pr:
branches:
include:
- dev
paths:
include:
- 'Netlify/*'
exclude:
- 'pipelines/*'
- 'scripts/*'
- '.editorconfig'
- '.gitignore'
- 'README.md'
# pipelines/netlify-release.yaml
name: $(Version).$(rev:r)
...
stages:
# Build Pipeline
- stage: Build
jobs:
- job: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
demands: npm
workspace:
clean: all
variables:
- group: Common Marketplace
- group: PROD Marketplace
steps:
# Calls the template
- template: templates/npm-build-steps.yaml
parameters:
extensionName: $(ExtensionName)
# Continue existing tasks
- task: ms-devlabs.vsts-developer-tools-build-tasks.tfx-installer-build-task.TfxInstaller@1
displayName: 'Install tfx-cli'
inputs:
version: v0.7.x
autoUpdate: true
...
# pipelines/netlify-release.yaml
name: $(Version).$(rev:r)
variables:
- group: Common Netlify
trigger:
branches:
include:
- release/netlify
paths:
include:
- 'Netlify/*'
exclude:
- 'pipelines/*'
- 'scripts/*'
- '.editorconfig'
- '.gitignore'
- 'README.md'
stages:
# Build Pipeline
- stage: Build
jobs:
- job: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
demands: npm
workspace:
clean: all
variables:
- group: Common Marketplace
- group: PROD Marketplace
steps:
- task: Npm@1
displayName: 'Install npm Packages'
inputs:
command: install
workingDir: '$(Build.SourcesDirectory)/$(ExtensionName)/src'
verbose: false
- task: PowerShell@2
displayName: 'Compile TypeScript Files'
inputs:
targetType: filePath
filePath: '$(Build.SourcesDirectory)/scripts/Compile-TypeScripts.ps1'
arguments: '-SourceDirectory $(Build.SourcesDirectory)/$(ExtensionName)/src'
- task: ms-devlabs.vsts-developer-tools-build-tasks.tfx-installer-build-task.TfxInstaller@1
displayName: 'Install tfx-cli'
inputs:
version: v0.7.x
autoUpdate: true
- task: ms-devlabs.vsts-developer-tools-build-tasks.package-extension-build-task.PackageVSTSExtension@1
displayName: 'Package Extension'
inputs:
rootFolder: '$(Build.SourcesDirectory)/$(ExtensionName)'
patternManifest: '$(ManifestFileName)'
outputPath: '$(Build.ArtifactStagingDirectory)'
outputVariable: 'Extension.OutputPath'
publisherId: '$(PublisherId)'
extensionId: '$(ExtensionId)'
extensionName: '$(ExtensionName)'
extensionVersion: '$(Version)'
updateTasksVersion: false
updateTasksId: false
extensionVisibility: private
extensionPricing: free
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact'
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)
artifactName: drop
publishLocation: 'Container'
# Release Pipeline to DEV
- stage: DEV
jobs:
- deployment: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
variables:
- group: Common Marketplace
- group: DEV Marketplace
environment: netlify-dev
strategy:
runOnce:
deploy:
steps:
- task: TfxInstaller@1
#- task: ms-devlabs.vsts-developer-tools-build-tasks.tfx-installer-build-task.TfxInstaller@1
displayName: 'Install tfx-cli'
inputs:
version: "v0.7.x"
autoUpdate: true
- task: PublishExtension@1
#- task: ms-devlabs.vsts-developer-tools-build-tasks.publish-extension-build-task.PublishExtension@1
displayName: 'Publish Extension'
inputs:
connectedServiceName: aliencube.marketplace.visualstudio.com
fileType: vsix
vsixFile: '$(Pipeline.Workspace)/drop/$(PublisherId.Prod).$(ExtensionId)-$(Version).vsix'
publisherId: $(PublisherId)
updateTasksVersion: false
updateTasksId: false
extensionVisibility: $(Visibility)
extensionPricing: $(Pricing)
outputVariable: Extension.OutputPath
shareWith: $(Organisation)
# Release Pipeline to PROD
- stage: PROD
jobs:
- deployment: HostedVs2017
displayName: Hosted VS2017
pool:
name: Hosted VS2017
variables:
- group: Common Marketplace
- group: PROD Marketplace
environment: netlify-prod
strategy:
runOnce:
deploy:
steps:
- task: TfxInstaller@1
#- task: ms-devlabs.vsts-developer-tools-build-tasks.tfx-installer-build-task.TfxInstaller@1
displayName: 'Install tfx-cli'
inputs:
version: "v0.7.x"
autoUpdate: true
- task: PublishExtension@1
#- task: ms-devlabs.vsts-developer-tools-build-tasks.publish-extension-build-task.PublishExtension@1
displayName: 'Publish Extension'
inputs:
connectedServiceName: aliencube.marketplace.visualstudio.com
fileType: vsix
vsixFile: '$(Pipeline.Workspace)/drop/$(PublisherId.Prod).$(ExtensionId)-$(Version).vsix'
publisherId: $(PublisherId)
updateTasksVersion: false
updateTasksId: false
extensionVisibility: $(Visibility)
extensionPricing: $(Pricing)
outputVariable: Extension.OutputPath
node install/index.js
# templates/npm-build-steps.yaml
parameters:
extensionName: ""
steps:
- task: Npm@1
displayName: 'Install npm Packages'
inputs:
command: install
workingDir: '$(Build.SourcesDirectory)/${{ parameters.extensionName }}/src'
verbose: false
- task: PowerShell@2
displayName: 'Compile TypeScript Files'
inputs:
targetType: filePath
filePath: '$(Build.SourcesDirectory)/scripts/Compile-TypeScripts.ps1'
arguments: '-SourceDirectory $(Build.SourcesDirectory)/${{ parameters.extensionName }}/src'
npm install -g netlify-cli@[version]
npm install azure-pipelines-task-lib --save
npm install @types/node --save-dev
npm install @types/q --save-dev
npm install -g tfx-cli
npm install -g typescript
# PowerShell
$env:INPUT_VERSION = "2.11.23"
# bash
export INPUT_VERSION="2.11.23"
tfx extension create --manifest-globs vss-extension.json
{
"manifestVersion": 1,
"id": "{{ Extension ID }}",
"version": "{{ Extension Version }}",
"name": "{{ Extenson Name }}",
"publisher": "{{ Publisher ID }}",
"description": "{{ Description }}",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"categories": [
"Azure Pipelines"
],
"tags": [
"netlify"
],
"galleryFlags": [
"Free",
"Public"
],
"icons": {
"default": "icon.png"
},
"content": {
"details": {
"path": "README.md"
}
},
"files": [
{
"path": "images",
"addressable": true
},
{
"path": "src/install",
"packagePath": "install"
},
{
"path": "src/deploy",
"packagePath": "deploy"
},
{
"path": "src/node_modules",
"packagePath": "install/node_modules"
},
{
"path": "src/node_modules",
"packagePath": "deploy/node_modules"
}
],
"links": {
"overview": {
"uri": "https://github.com/aliencube/AzureDevOps.Extensions/blob/master/README.md"
},
"license": {
"uri": "https://github.com/aliencube/AzureDevOps.Extensions/blob/master/LICENSE"
},
"repository": {
"uri": "https://github.com/aliencube/AzureDevOps.Extensions"
},
"issues": {
"uri": "https://github.com/aliencube/AzureDevOps.Extensions/issues"
}
},
"repository": {
"type": "git",
"uri": "https://github.com/aliencube/AzureDevOps.Extensions"
},
"badges": [
{
"href": "https://dev.azure.com/aliencube/AzureDevOps.Extensions/_build/latest?definitionId=-1",
"uri": "https://dev.azure.com/aliencube/AzureDevOps.Extensions/_apis/build/status/%5Bnetlify%5D%20dev%2C%20feature%2C%20hotfix",
"description": "Build Status"
}
],
"contributions": [
{
"id": "install-task",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "install"
}
},
{
"id": "deploy-task",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "deploy"
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment