├── templates
├── ant.properties.json
├── gcc.properties.json
├── go.properties.json
├── html.properties.json
├── php.properties.json
├── ruby.properties.json
├── android.properties.json
├── empty.properties.json
├── gradle.properties.json
├── maven.properties.json
├── node.js.properties.json
├── xcode.properties.json
├── .net-desktop.properties.json
├── asp.net.properties.json
├── node.js-with-vue.properties.json
├── python-django.properties.json
├── xamarin.ios.properties.json
├── asp.net-core.properties.json
├── jekyll-container.properties.json
├── node.js-with-grunt.properties.json
├── node.js-with-gulp.properties.json
├── node.js-with-react.properties.json
├── python-package.properties.json
├── xamarin.android.properties.json
├── node.js-with-angular.properties.json
├── node.js-with-webpack.properties.json
├── asp.net-core-.net-framework.properties.json
├── universal-windows-platform.properties.json
├── docker-build.properties.json
├── docker-container-to-acr.properties.json
├── docker-container-to-aks.properties.json
├── docker-container-webapp.properties.json
├── resources
│ ├── k8s
│ │ ├── service.yml
│ │ └── deployment.yml
│ └── arm
│ │ ├── acr.json
│ │ ├── aks.json
│ │ └── webapp-on-containers.json
├── docker-container-functionapp.properties.json
├── gcc.yml
├── icons
│ └── svg
│ │ ├── universalwindowsplatform.svg
│ │ ├── vue.svg
│ │ ├── empty.svg
│ │ ├── angular.svg
│ │ ├── webpack.svg
│ │ ├── django.svg
│ │ ├── xamarin.svg
│ │ ├── functionapp.svg
│ │ ├── aks.svg
│ │ ├── cxx.svg
│ │ ├── html.svg
│ │ ├── azurecontainerregistry.svg
│ │ ├── gradle.svg
│ │ ├── dotnet.svg
│ │ ├── golang.svg
│ │ ├── xcode.svg
│ │ ├── android.svg
│ │ ├── ant.svg
│ │ ├── react.svg
│ │ ├── python.svg
│ │ ├── php.svg
│ │ ├── aspdotnet.svg
│ │ └── dotnetcore.svg
├── html.yml
├── asp.net-core.yml
├── node.js.yml
├── node.js-with-vue.yml
├── empty.yml
├── node.js-with-react.yml
├── ant.yml
├── android.yml
├── node.js-with-grunt.yml
├── node.js-with-gulp.yml
├── ruby.yml
├── node.js-with-angular.yml
├── docker-build.yml
├── node.js-with-webpack.yml
├── maven.yml
├── xcode.yml
├── docker-container.properties.json
├── gradle.yml
├── jekyll-container.yml
├── xamarin.android.yml
├── php-webapp-to-linux-on-azure.properties.json
├── python-to-linux-webapp-on-azure.properties.json
├── maven-webapp-to-linux-on-azure.properties.json
├── .net-desktop.yml
├── node.js-react-webapp-to-linux-on-azure.properties.json
├── node.js-express-webapp-to-linux-on-azure.properties.json
├── php.yml
├── node.js-functionapp-to-linux-on-azure.properties.json
├── universal-windows-platform.yml
├── python-package.yml
├── asp.net.yml
├── python-functionapp-to-linux-on-azure.properties.json
├── asp.net-core-functionapp-to-windows-on-azure.properties.json
├── xamarin.ios.yml
├── powershell-functionapp-to-windows-on-azure.properties.json
├── asp.net-core-.net-framework.yml
├── go.yml
├── docker-container.yml
├── deploy-to-existing-kubernetes-cluster.properties.json
├── python-django.yml
├── maven-webapp-to-linux-on-azure.yml
├── powershell-functionapp-to-windows-on-azure.yml
├── node.js-react-webapp-to-linux-on-azure.yml
├── asp.net-core-functionapp-to-windows-on-azure.yml
├── node.js-express-webapp-to-linux-on-azure.yml
├── node.js-functionapp-to-linux-on-azure.yml
├── python-functionapp-to-linux-on-azure.yml
├── php-webapp-to-linux-on-azure.yml
├── python-to-linux-webapp-on-azure.yml
├── docker-container-to-acr.yml
├── docker-container-webapp.yml
├── docker-container-functionapp.yml
├── deploy-to-existing-kubernetes-cluster.yml
└── docker-container-to-aks.yml
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── config.yml
│ └── yaml-issues.md
└── workflows
│ ├── autoAssignABTT.yml
│ └── stale.yml
├── design
├── images
│ ├── environment.png
│ ├── run-panel-with-params.png
│ ├── jira-traceability-build-1.png
│ ├── jira-traceability-build-2.png
│ ├── jira-traceability-deploy-1.png
│ ├── jira-traceability-deploy-2.png
│ └── pipeline-caching-task-editor.jpg
├── README.md
├── yaml-principles.md
├── variables.md
├── checkout-path.md
├── node10-agent-support.md
├── step-target-restricted-mode.md
├── deprecated
│ ├── container-steps.md
│ └── container-steps-implementation.md
├── deployment.md
├── each-expression.md
├── readonly-variables.md
├── sidecar-containers.md
├── step-target.md
└── deployment-strategies.md
├── .vscode
└── extensions.json
├── LICENSE
├── README.md
└── SECURITY.md
/templates/ant.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "ant"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/gcc.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "cxx"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/go.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "golang"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/html.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "html"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/php.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "php"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/ruby.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "ruby"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/android.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "android"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/empty.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "empty"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/gradle.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "gradle"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/maven.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "maven"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "nodejs"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/xcode.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "xcode"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/.net-desktop.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "dotnet"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/asp.net.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "aspdotnet"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-vue.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "vue"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/python-django.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "django"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/xamarin.ios.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "xamarin"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/asp.net-core.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "dotnetcore"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/jekyll-container.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "jekyll"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-grunt.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "grunt"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-gulp.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "gulp"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-react.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "react"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/python-package.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "python"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/xamarin.android.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "xamarin"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-angular.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "angular"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/node.js-with-webpack.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "webpack"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/asp.net-core-.net-framework.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "dotnetcore"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/universal-windows-platform.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "universalwindowsplatform"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Global rule:
2 | * @microsoft/akvelon-build-task-team @microsoft/azure-pipelines-platform
3 |
--------------------------------------------------------------------------------
/design/images/environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/environment.png
--------------------------------------------------------------------------------
/design/images/run-panel-with-params.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/run-panel-with-params.png
--------------------------------------------------------------------------------
/design/images/jira-traceability-build-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/jira-traceability-build-1.png
--------------------------------------------------------------------------------
/design/images/jira-traceability-build-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/jira-traceability-build-2.png
--------------------------------------------------------------------------------
/design/images/jira-traceability-deploy-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/jira-traceability-deploy-1.png
--------------------------------------------------------------------------------
/design/images/jira-traceability-deploy-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/jira-traceability-deploy-2.png
--------------------------------------------------------------------------------
/design/images/pipeline-caching-task-editor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-pipelines-yaml/HEAD/design/images/pipeline-caching-task-editor.jpg
--------------------------------------------------------------------------------
/templates/docker-build.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "docker",
3 | "parameters": [
4 | {
5 | "name": "dockerfilePath",
6 | "type": "string",
7 | "required": "true",
8 | "displayName": "Dockerfile",
9 | "defaultValue": "**/Dockerfile"
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/templates/docker-container-to-acr.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "docker",
3 | "parameters": [
4 | { "name" : "azureServiceConnectionId", "type": "connectedService:azureRM", "required": "true", "displayName": "Azure subscription" },
5 | { "name" : "repositoryName", "type": "string", "required": "true", "displayName": "Repository name" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/templates/docker-container-to-aks.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "aks",
3 | "parameters": [
4 | { "name" : "azureServiceConnectionId", "type": "connectedService:azureRM", "required": "true", "displayName": "Azure subscription" },
5 | { "name" : "repositoryName", "type": "string", "required": "true", "displayName": "Repository name" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/templates/docker-container-webapp.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "docker",
3 | "parameters": [
4 | { "name" : "azureServiceConnectionId", "type": "connectedService:azureRM", "required": "true", "displayName": "Azure subscription" },
5 | { "name" : "repositoryName", "type": "string", "required": "true", "displayName": "Repository name" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/templates/resources/k8s/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
5 | spec:
6 | type: LoadBalancer
7 | ports:
8 | - port: {{ servicePort }}
9 | selector:
10 | app: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Developer Community
4 | url: https://developercommunity.visualstudio.com/spaces/21/index.html
5 | about: Feature ideas and problem reports go here.
6 | - name: Azure DevOps Support
7 | url: https://azure.microsoft.com/support/devops/
8 | about: Get product support here.
9 |
--------------------------------------------------------------------------------
/templates/docker-container-functionapp.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "functionapp",
3 | "parameters": [
4 | { "name" : "azureServiceConnectionId", "type": "connectedService:azureRM", "required": "true", "displayName": "Azure subscription" },
5 | { "name" : "repositoryName", "type": "string", "required": "true", "displayName": "Repository name" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/templates/gcc.yml:
--------------------------------------------------------------------------------
1 | # C/C++ with GCC
2 | # Build your C/C++ project with GCC using make.
3 | # Add steps that publish test results, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/c-cpp/gcc
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - script: |
14 | make
15 | displayName: 'make'
16 |
--------------------------------------------------------------------------------
/templates/icons/svg/universalwindowsplatform.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/html.yml:
--------------------------------------------------------------------------------
1 | # HTML
2 | # Archive your static HTML project and save it with the build record.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: ArchiveFiles@2
14 | inputs:
15 | rootFolderOrFile: '$(build.sourcesDirectory)'
16 | includeRootFolder: false
17 | - task: PublishBuildArtifacts@1
18 |
--------------------------------------------------------------------------------
/templates/icons/svg/vue.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/templates/icons/svg/empty.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/templates/asp.net-core.yml:
--------------------------------------------------------------------------------
1 | # ASP.NET Core
2 | # Build and test ASP.NET Core projects targeting .NET Core.
3 | # Add steps that run tests, create a NuGet package, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | variables:
13 | buildConfiguration: 'Release'
14 |
15 | steps:
16 | - script: dotnet build --configuration $(buildConfiguration)
17 | displayName: 'dotnet build $(buildConfiguration)'
18 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "ms-azure-devops.azure-pipelines"
8 | ],
9 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
10 | "unwantedRecommendations": [
11 |
12 | ]
13 | }
--------------------------------------------------------------------------------
/templates/icons/svg/angular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/node.js.yml:
--------------------------------------------------------------------------------
1 | # Node.js
2 | # Build a general Node.js project with npm.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | npm run build
21 | displayName: 'npm install and build'
22 |
--------------------------------------------------------------------------------
/templates/node.js-with-vue.yml:
--------------------------------------------------------------------------------
1 | # Node.js with Vue
2 | # Build a Node.js project that uses Vue.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | npm run build
21 | displayName: 'npm install and build'
22 |
--------------------------------------------------------------------------------
/templates/empty.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - script: echo Hello, world!
14 | displayName: 'Run a one-line script'
15 |
16 | - script: |
17 | echo Add other tasks to build, test, and deploy your project.
18 | echo See https://aka.ms/yaml
19 | displayName: 'Run a multi-line script'
20 |
--------------------------------------------------------------------------------
/templates/node.js-with-react.yml:
--------------------------------------------------------------------------------
1 | # Node.js with React
2 | # Build a Node.js project that uses React.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | npm run build
21 | displayName: 'npm install and build'
22 |
--------------------------------------------------------------------------------
/templates/ant.yml:
--------------------------------------------------------------------------------
1 | # Ant
2 | # Build your Java projects and run tests with Apache Ant.
3 | # Add steps that save build artifacts and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/java
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: Ant@1
14 | inputs:
15 | workingDirectory: ''
16 | buildFile: 'build.xml'
17 | javaHomeOption: 'JDKVersion'
18 | jdkVersionOption: '1.8'
19 | jdkArchitectureOption: 'x64'
20 | publishJUnitResults: true
21 | testResultsFiles: '**/TEST-*.xml'
22 |
--------------------------------------------------------------------------------
/templates/android.yml:
--------------------------------------------------------------------------------
1 | # Android
2 | # Build your Android project with Gradle.
3 | # Add steps that test, sign, and distribute the APK, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/android
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'macos-latest'
11 |
12 | steps:
13 | - task: Gradle@2
14 | inputs:
15 | workingDirectory: ''
16 | gradleWrapperFile: 'gradlew'
17 | gradleOptions: '-Xmx3072m'
18 | publishJUnitResults: false
19 | testResultsFiles: '**/TEST-*.xml'
20 | tasks: 'assembleDebug'
21 |
--------------------------------------------------------------------------------
/templates/node.js-with-grunt.yml:
--------------------------------------------------------------------------------
1 | # Node.js with Grunt
2 | # Build a Node.js project using the Grunt task runner.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | grunt --gruntfile Gruntfile.js
21 | displayName: 'npm install and run grunt'
22 |
--------------------------------------------------------------------------------
/templates/node.js-with-gulp.yml:
--------------------------------------------------------------------------------
1 | # Node.js with gulp
2 | # Build a Node.js project using the gulp task runner.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install
20 | gulp default --gulpfile gulpfile.js
21 | displayName: 'npm install and run gulp'
22 |
--------------------------------------------------------------------------------
/templates/ruby.yml:
--------------------------------------------------------------------------------
1 | # Ruby
2 | # Package your Ruby project.
3 | # Add steps that install rails, analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/ruby
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: UseRubyVersion@0
14 | inputs:
15 | versionSpec: '>= 2.5'
16 |
17 | - script: |
18 | gem install bundler
19 | bundle install --retry=3 --jobs=4
20 | displayName: 'bundle install'
21 |
22 | - script: bundle exec rake
23 | displayName: 'bundle exec rake'
24 |
--------------------------------------------------------------------------------
/templates/node.js-with-angular.yml:
--------------------------------------------------------------------------------
1 | # Node.js with Angular
2 | # Build a Node.js project that uses Angular.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install -g @angular/cli
20 | npm install
21 | ng build --prod
22 | displayName: 'npm install and build'
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/yaml-issues.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Talk about YAML
3 | about: 'We can talk about YAML here. We cannot take problem reports or support requests.'
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | This repo is for working in the open on Azure Pipelines YAML features. It's not a great place to make [new feature requests](https://developercommunity.visualstudio.com/spaces/21/index.html), [report problems](https://developercommunity.visualstudio.com/spaces/21/index.html), or [get support](https://azure.microsoft.com/en-us/support/devops/). Issues you open here may sit unreviewed for a very long time.
11 |
--------------------------------------------------------------------------------
/templates/docker-build.yml:
--------------------------------------------------------------------------------
1 | # Docker
2 | # Build a Docker image
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | tag: '$(Build.BuildId)'
13 |
14 | stages:
15 | - stage: Build
16 | displayName: Build image
17 | jobs:
18 | - job: Build
19 | displayName: Build
20 | pool:
21 | {{ pool }}
22 | steps:
23 | - task: Docker@2
24 | displayName: Build an image
25 | inputs:
26 | command: build
27 | dockerfile: '{{ dockerfilePath }}'
28 | tags: |
29 | $(tag)
30 |
--------------------------------------------------------------------------------
/templates/node.js-with-webpack.yml:
--------------------------------------------------------------------------------
1 | # Node.js with webpack
2 | # Build a Node.js project using the webpack CLI.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: NodeTool@0
14 | inputs:
15 | versionSpec: '10.x'
16 | displayName: 'Install Node.js'
17 |
18 | - script: |
19 | npm install -g webpack webpack-cli --save-dev
20 | npm install
21 | npx webpack --config webpack.config.js
22 | displayName: 'npm install, run webpack'
23 |
--------------------------------------------------------------------------------
/templates/maven.yml:
--------------------------------------------------------------------------------
1 | # Maven
2 | # Build your Java project and run tests with Apache Maven.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/java
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: Maven@3
14 | inputs:
15 | mavenPomFile: 'pom.xml'
16 | mavenOptions: '-Xmx3072m'
17 | javaHomeOption: 'JDKVersion'
18 | jdkVersionOption: '1.8'
19 | jdkArchitectureOption: 'x64'
20 | publishJUnitResults: true
21 | testResultsFiles: '**/surefire-reports/TEST-*.xml'
22 | goals: 'package'
23 |
--------------------------------------------------------------------------------
/templates/xcode.yml:
--------------------------------------------------------------------------------
1 | # Xcode
2 | # Build, test, and archive an Xcode workspace on macOS.
3 | # Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/xcode
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'macos-latest'
11 |
12 | steps:
13 | - task: Xcode@5
14 | inputs:
15 | actions: 'build'
16 | scheme: ''
17 | sdk: 'iphoneos'
18 | configuration: 'Release'
19 | xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
20 | xcodeVersion: 'default' # Options: 8, 9, 10, 11, 12, default, specifyPath
21 |
--------------------------------------------------------------------------------
/templates/docker-container.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "docker",
3 | "parameters": [
4 | {
5 | "name": "containerRegistryConnection",
6 | "type": "endpoint:containerRegistry",
7 | "required": "true",
8 | "displayName": "Container Registry"
9 | },
10 | {
11 | "name": "imageRepository",
12 | "type": "string",
13 | "required": "true",
14 | "displayName": "Image Name"
15 | },
16 | {
17 | "name": "dockerfilePath",
18 | "type": "string",
19 | "required": "false",
20 | "displayName": "Dockerfile",
21 | "defaultValue": "**/Dockerfile"
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/templates/gradle.yml:
--------------------------------------------------------------------------------
1 | # Gradle
2 | # Build your Java project and run tests with Gradle using a Gradle wrapper script.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/java
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: Gradle@2
14 | inputs:
15 | workingDirectory: ''
16 | gradleWrapperFile: 'gradlew'
17 | gradleOptions: '-Xmx3072m'
18 | javaHomeOption: 'JDKVersion'
19 | jdkVersionOption: '1.8'
20 | jdkArchitectureOption: 'x64'
21 | publishJUnitResults: true
22 | testResultsFiles: '**/TEST-*.xml'
23 | tasks: 'build'
24 |
--------------------------------------------------------------------------------
/templates/jekyll-container.yml:
--------------------------------------------------------------------------------
1 | # Jekyll site
2 | # Package your Jekyll site using the jekyll/builder Docker container image.
3 | # Add steps that build, test, save build artifacts, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | steps:
13 | - task: Docker@0
14 | displayName: 'Run Jekyll'
15 | inputs:
16 | containerRegistryType: 'Container Registry'
17 | action: 'Run an image'
18 | imageName: 'jekyll/builder:latest'
19 | volumes: |
20 | $(build.sourcesDirectory):/srv/jekyll
21 | $(build.binariesDirectory):/srv/jekyll/_site
22 | containerCommand: 'jekyll build --future'
23 | detached: false
24 |
--------------------------------------------------------------------------------
/templates/xamarin.android.yml:
--------------------------------------------------------------------------------
1 | # Xamarin.Android
2 | # Build a Xamarin.Android project.
3 | # Add steps that test, sign, and distribute an app, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/xamarin
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'macos-latest'
11 |
12 | variables:
13 | buildConfiguration: 'Release'
14 | outputDirectory: '$(build.binariesDirectory)/$(buildConfiguration)'
15 |
16 | steps:
17 | - task: NuGetToolInstaller@1
18 |
19 | - task: NuGetCommand@2
20 | inputs:
21 | restoreSolution: '**/*.sln'
22 |
23 | - task: XamarinAndroid@1
24 | inputs:
25 | projectFile: '**/*droid*.csproj'
26 | outputDirectory: '$(outputDirectory)'
27 | configuration: '$(buildConfiguration)'
28 |
--------------------------------------------------------------------------------
/templates/icons/svg/webpack.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/php-webapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "php",
3 | "parameters": [
4 | {
5 | "name": "azureRmServiceConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true"
8 | },
9 | {
10 | "name": "webAppName",
11 | "type": "dataSourcePicklist",
12 | "required": "true",
13 | "displayName": "Web App name"
14 | }
15 | ],
16 | "dataSourceBindings": [
17 | {
18 | "dataSourceName": "AzureRMWebAppNamesByAppType",
19 | "endpointParameterName": "azureRmServiceConnection",
20 | "parameters": {
21 | "WebAppKind": "webAppLinux"
22 | },
23 | "target": "webAppName"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/.github/workflows/autoAssignABTT.yml:
--------------------------------------------------------------------------------
1 | name: Auto Assign ABTT to Project Board
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | assign_one_project:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | name: Assign to ABTT Project
14 | steps:
15 | - name: "Add triage and area labels"
16 | uses: actions-ecosystem/action-add-labels@v1
17 | with:
18 | github_token: ${{ secrets.GITHUB_TOKEN }}
19 | labels: |
20 | Area: Yaml
21 | triage
22 |
23 | - name: "Assign issues with 'Area: ABTT' label to project board"
24 | uses: actions/add-to-project@v0.4.1
25 | with:
26 | project-url: https://github.com/orgs/microsoft/projects/755
27 | github-token: ${{ secrets.ABTT_TOKEN }}
28 |
--------------------------------------------------------------------------------
/design/README.md:
--------------------------------------------------------------------------------
1 | # Azure Pipelines YAML - Design Docs
2 |
3 | The design docs within this repo are created at different times during the development of Azure Pipelines, to support collaborative contributions to the design process. Designs documents are for,
4 |
5 | * features considered for implementation but never implemented
6 | * already implemented features
7 | * future ideas for features
8 |
9 | The design docs in this repo may not represent the current state of an Azure Pipelines feature.
10 |
11 | For the most upto date information about a feature refer to the [Azure Pipeline Docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops) and specifically the [Azure Pipeline Yaml Reference](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema)
12 |
--------------------------------------------------------------------------------
/templates/python-to-linux-webapp-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "python",
3 | "parameters": [
4 | {
5 | "name": "azureServiceConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true"
8 | },
9 | {
10 | "name": "webAppName",
11 | "type": "dataSourcePicklist",
12 | "required": "true",
13 | "displayName": "Web App name"
14 | }
15 | ],
16 | "dataSourceBindings": [
17 | {
18 | "dataSourceName": "AzureRMWebAppNamesByAppType",
19 | "endpointParameterName": "azureServiceConnection",
20 | "parameters": {
21 | "WebAppKind": "webAppLinux"
22 | },
23 | "target": "webAppName"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/templates/resources/arm/acr.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "registryName": {
6 | "type": "string"
7 | },
8 | "registryLocation": {
9 | "type": "string"
10 | },
11 | "registrySku": {
12 | "defaultValue": "Standard",
13 | "type": "string"
14 | }
15 | },
16 | "resources": [
17 | {
18 | "type": "Microsoft.ContainerRegistry/registries",
19 | "sku": {
20 | "name": "[parameters('registrySku')]"
21 | },
22 | "name": "[parameters('registryName')]",
23 | "apiVersion": "2017-10-01",
24 | "location": "[parameters('registryLocation')]",
25 | "properties": {
26 | "adminUserEnabled": true
27 | }
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/templates/resources/k8s/deployment.yml:
--------------------------------------------------------------------------------
1 | apiVersion : apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
10 | template:
11 | metadata:
12 | labels:
13 | app: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
14 | spec:
15 | containers:
16 | - name: {{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
17 | image: {{ containerRegistryConnection.Authorization.Parameters.loginServer }}/{{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}
18 | ports:
19 | - containerPort: {{ servicePort }}
--------------------------------------------------------------------------------
/templates/icons/svg/django.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/maven-webapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "maven",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "webAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName":"Web App name"
15 | }
16 | ],
17 | "dataSourceBindings": [
18 | {
19 | "dataSourceName": "AzureRMWebAppNamesByAppType",
20 | "endpointParameterName": "azureRmConnection",
21 | "parameters": {
22 | "WebAppKind": "webAppLinux"
23 | },
24 | "target": "webAppName"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/templates/.net-desktop.yml:
--------------------------------------------------------------------------------
1 | # .NET Desktop
2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions.
3 | # Add steps that publish symbols, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | variables:
13 | solution: '**/*.sln'
14 | buildPlatform: 'Any CPU'
15 | buildConfiguration: 'Release'
16 |
17 | steps:
18 | - task: NuGetToolInstaller@1
19 |
20 | - task: NuGetCommand@2
21 | inputs:
22 | restoreSolution: '$(solution)'
23 |
24 | - task: VSBuild@1
25 | inputs:
26 | solution: '$(solution)'
27 | platform: '$(buildPlatform)'
28 | configuration: '$(buildConfiguration)'
29 |
30 | - task: VSTest@2
31 | inputs:
32 | platform: '$(buildPlatform)'
33 | configuration: '$(buildConfiguration)'
34 |
--------------------------------------------------------------------------------
/templates/icons/svg/xamarin.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/templates/node.js-react-webapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "react",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "webAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName": "Web App name"
15 | }
16 | ],
17 | "dataSourceBindings": [
18 | {
19 | "dataSourceName": "AzureRMWebAppNamesByAppType",
20 | "endpointParameterName": "azureRmConnection",
21 | "parameters": {
22 | "WebAppKind": "webAppLinux"
23 | },
24 | "target": "webAppName"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/templates/node.js-express-webapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "nodejs",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "webAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName": "Web App name"
15 | }
16 | ],
17 | "dataSourceBindings": [
18 | {
19 | "dataSourceName": "AzureRMWebAppNamesByAppType",
20 | "endpointParameterName": "azureRmConnection",
21 | "parameters": {
22 | "WebAppKind": "webAppLinux"
23 | },
24 | "target": "webAppName"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/templates/php.yml:
--------------------------------------------------------------------------------
1 | # PHP
2 | # Test and package your PHP project.
3 | # Add steps that run tests, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/php
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | variables:
13 | phpVersion: 7.2
14 |
15 | steps:
16 | - script: |
17 | sudo update-alternatives --set php /usr/bin/php$(phpVersion)
18 | sudo update-alternatives --set phar /usr/bin/phar$(phpVersion)
19 | sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpVersion)
20 | sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpVersion)
21 | sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpVersion)
22 | php -version
23 | displayName: 'Use PHP version $(phpVersion)'
24 |
25 | - script: composer install --no-interaction --prefer-dist
26 | displayName: 'composer install'
27 |
--------------------------------------------------------------------------------
/templates/node.js-functionapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "functionapp",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "functionAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName":"Function App name"
15 | }
16 | ],
17 | "dataSourceBindings": [
18 | {
19 | "dataSourceName": "AzureFunctionAppNamesByAppType",
20 | "endpointParameterName": "azureRmConnection",
21 | "parameters": {
22 | "WebAppKind": "functionAppLinux"
23 | },
24 | "target": "functionAppName"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/templates/icons/svg/functionapp.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/universal-windows-platform.yml:
--------------------------------------------------------------------------------
1 | # Universal Windows Platform
2 | # Build a Universal Windows Platform project using Visual Studio.
3 | # Add steps that test and distribute an app, save build artifacts, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | variables:
13 | solution: '**/*.sln'
14 | buildPlatform: 'x86|x64|ARM'
15 | buildConfiguration: 'Release'
16 | appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\'
17 |
18 | steps:
19 | - task: NuGetToolInstaller@1
20 |
21 | - task: NuGetCommand@2
22 | inputs:
23 | restoreSolution: '$(solution)'
24 |
25 | - task: VSBuild@1
26 | inputs:
27 | platform: 'x86'
28 | solution: '$(solution)'
29 | configuration: '$(buildConfiguration)'
30 | msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
31 |
--------------------------------------------------------------------------------
/templates/python-package.yml:
--------------------------------------------------------------------------------
1 | # Python package
2 | # Create and test a Python package on multiple Python versions.
3 | # Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/python
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 | strategy:
12 | matrix:
13 | Python27:
14 | python.version: '2.7'
15 | Python35:
16 | python.version: '3.5'
17 | Python36:
18 | python.version: '3.6'
19 | Python37:
20 | python.version: '3.7'
21 |
22 | steps:
23 | - task: UsePythonVersion@0
24 | inputs:
25 | versionSpec: '$(python.version)'
26 | displayName: 'Use Python $(python.version)'
27 |
28 | - script: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | displayName: 'Install dependencies'
32 |
33 | - script: |
34 | pip install pytest pytest-azurepipelines
35 | pytest
36 | displayName: 'pytest'
37 |
--------------------------------------------------------------------------------
/templates/asp.net.yml:
--------------------------------------------------------------------------------
1 | # ASP.NET
2 | # Build and test ASP.NET projects.
3 | # Add steps that publish symbols, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | variables:
13 | solution: '**/*.sln'
14 | buildPlatform: 'Any CPU'
15 | buildConfiguration: 'Release'
16 |
17 | steps:
18 | - task: NuGetToolInstaller@1
19 |
20 | - task: NuGetCommand@2
21 | inputs:
22 | restoreSolution: '$(solution)'
23 |
24 | - task: VSBuild@1
25 | inputs:
26 | solution: '$(solution)'
27 | msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
28 | platform: '$(buildPlatform)'
29 | configuration: '$(buildConfiguration)'
30 |
31 | - task: VSTest@2
32 | inputs:
33 | platform: '$(buildPlatform)'
34 | configuration: '$(buildConfiguration)'
35 |
--------------------------------------------------------------------------------
/templates/python-functionapp-to-linux-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "functionapp",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "functionAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName":"Function App name"
15 | },
16 | {
17 | "name": "workingDirectory",
18 | "type": "pickList",
19 | "required": "true",
20 | "displayName": "Working Directory"
21 | }
22 | ],
23 | "dataSourceBindings": [
24 | {
25 | "dataSourceName": "AzureFunctionAppNamesByAppType",
26 | "endpointParameterName": "azureRmConnection",
27 | "parameters": {
28 | "WebAppKind": "functionAppLinux"
29 | },
30 | "target": "functionAppName"
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/templates/asp.net-core-functionapp-to-windows-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "functionapp",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "functionAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName":"Function App name"
15 | },
16 | {
17 | "name": "workingDirectory",
18 | "type": "pickList",
19 | "required": "true",
20 | "displayName": "Working Directory"
21 | }
22 | ],
23 | "dataSourceBindings": [
24 | {
25 | "dataSourceName": "AzureFunctionAppNamesByAppType",
26 | "endpointParameterName": "azureRmConnection",
27 | "parameters": {
28 | "WebAppKind": "functionApp"
29 | },
30 | "target": "functionAppName"
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/templates/xamarin.ios.yml:
--------------------------------------------------------------------------------
1 | # Xamarin.iOS
2 | # Build a Xamarin.iOS project.
3 | # Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/xamarin
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'macos-latest'
11 |
12 | steps:
13 | # To manually select a Xamarin SDK version on the Microsoft-hosted macOS agent,
14 | # configure this task with the *Mono* version that is associated with the
15 | # Xamarin SDK version that you need, and set the "enabled" property to true.
16 | # See https://go.microsoft.com/fwlink/?linkid=871629
17 | - script: sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh 5_12_0
18 | displayName: 'Select the Xamarin SDK version'
19 | enabled: false
20 |
21 | - task: NuGetToolInstaller@1
22 |
23 | - task: NuGetCommand@2
24 | inputs:
25 | restoreSolution: '**/*.sln'
26 |
27 | - task: XamariniOS@2
28 | inputs:
29 | solutionFile: '**/*.sln'
30 | configuration: 'Release'
31 | buildForSimulator: true
32 | packageApp: false
33 |
--------------------------------------------------------------------------------
/templates/powershell-functionapp-to-windows-on-azure.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "functionapp",
3 | "parameters": [
4 | {
5 | "name": "azureRmConnection",
6 | "type": "endpoint:azureRm",
7 | "required": "true",
8 | "displayName": "Azure Connection"
9 | },
10 | {
11 | "name": "functionAppName",
12 | "type": "dataSourcePicklist",
13 | "required": "true",
14 | "displayName":"Function App name"
15 | },
16 | {
17 | "name": "workingDirectory",
18 | "type": "pickList",
19 | "required": "false",
20 | "defaultValue": "$(System.DefaultWorkingDirectory)",
21 | "displayName": "Working Directory"
22 | }
23 | ],
24 | "dataSourceBindings": [
25 | {
26 | "dataSourceName": "AzureFunctionAppNamesByAppType",
27 | "endpointParameterName": "azureRmConnection",
28 | "parameters": {
29 | "WebAppKind": "functionApp"
30 | },
31 | "target": "functionAppName"
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | daysUntilStale: 1
2 |
3 | daysUntilClose: 1
4 |
5 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
6 | onlyLabels: []
7 |
8 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
9 | exemptLabels: []
10 |
11 | # Set to true to ignore issues in a project (defaults to false)
12 | exemptProjects: false
13 |
14 | # Set to true to ignore issues in a milestone (defaults to false)
15 | exemptMilestones: false
16 |
17 | # Set to true to ignore issues with an assignee (defaults to false)
18 | exemptAssignees: false
19 |
20 | # Label to use when marking as stale
21 | staleLabel: dont-fear-the-reaper
22 |
23 | # Comment to post when marking as stale. Set to `false` to disable
24 | markComment: >
25 | In order to consolidate to fewer feedback channels, we've moved suggestions and
26 | issue reporting to [Developer Community](https://developercommunity.visualstudio.com/spaces/21/index.html).
27 | Sorry for any confusion resulting from this move.
28 |
29 | limitPerRun: 30
30 |
31 | # Limit to only `issues` or `pulls`
32 | only: issues
33 |
--------------------------------------------------------------------------------
/templates/asp.net-core-.net-framework.yml:
--------------------------------------------------------------------------------
1 | # ASP.NET Core (.NET Framework)
2 | # Build and test ASP.NET Core projects targeting the full .NET Framework.
3 | # Add steps that publish symbols, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | variables:
13 | solution: '**/*.sln'
14 | buildPlatform: 'Any CPU'
15 | buildConfiguration: 'Release'
16 |
17 | steps:
18 | - task: NuGetToolInstaller@1
19 |
20 | - task: NuGetCommand@2
21 | inputs:
22 | restoreSolution: '$(solution)'
23 |
24 | - task: VSBuild@1
25 | inputs:
26 | solution: '$(solution)'
27 | msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
28 | platform: '$(buildPlatform)'
29 | configuration: '$(buildConfiguration)'
30 |
31 | - task: VSTest@2
32 | inputs:
33 | platform: '$(buildPlatform)'
34 | configuration: '$(buildConfiguration)'
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/templates/go.yml:
--------------------------------------------------------------------------------
1 | # Go
2 | # Build your Go project.
3 | # Add steps that test, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/go
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 |
12 | variables:
13 | GOBIN: '$(GOPATH)/bin' # Go binaries path
14 | GOROOT: '/usr/local/go1.11' # Go installation path
15 | GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path
16 | modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code
17 |
18 | steps:
19 | - script: |
20 | mkdir -p '$(GOBIN)'
21 | mkdir -p '$(GOPATH)/pkg'
22 | mkdir -p '$(modulePath)'
23 | shopt -s extglob
24 | shopt -s dotglob
25 | mv !(gopath) '$(modulePath)'
26 | echo '##vso[task.prependpath]$(GOBIN)'
27 | echo '##vso[task.prependpath]$(GOROOT)/bin'
28 | displayName: 'Set up the Go workspace'
29 |
30 | - script: |
31 | go version
32 | go get -v -t -d ./...
33 | if [ -f Gopkg.toml ]; then
34 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
35 | dep ensure
36 | fi
37 | go build -v .
38 | workingDirectory: '$(modulePath)'
39 | displayName: 'Get dependencies, then build'
40 |
--------------------------------------------------------------------------------
/templates/docker-container.yml:
--------------------------------------------------------------------------------
1 | # Docker
2 | # Build and push an image to Azure Container Registry
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | # Container registry service connection established during pipeline creation
13 | dockerRegistryServiceConnection: '{{ containerRegistryConnection.Id }}'
14 | imageRepository: '{{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}'
15 | containerRegistry: '{{ containerRegistryConnection.Authorization.Parameters.loginServer }}'
16 | dockerfilePath: '{{ dockerfilePath }}'
17 | tag: '$(Build.BuildId)'
18 |
19 | # Agent VM image name
20 | vmImageName: 'ubuntu-latest'
21 |
22 | stages:
23 | - stage: Build
24 | displayName: Build and push stage
25 | jobs:
26 | - job: Build
27 | displayName: Build
28 | pool:
29 | vmImage: $(vmImageName)
30 | steps:
31 | - task: Docker@2
32 | displayName: Build and push an image to container registry
33 | inputs:
34 | command: buildAndPush
35 | repository: $(imageRepository)
36 | dockerfile: $(dockerfilePath)
37 | containerRegistry: $(dockerRegistryServiceConnection)
38 | tags: |
39 | $(tag)
40 |
--------------------------------------------------------------------------------
/templates/icons/svg/aks.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/icons/svg/cxx.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/icons/svg/html.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/deploy-to-existing-kubernetes-cluster.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "iconName": "aks",
3 | "parameters": [
4 | {
5 | "name": "k8sResource",
6 | "type": "environmentResource:kubernetes",
7 | "required": "true",
8 | "displayName": "Kubernetes Resource"
9 | },
10 | {
11 | "name": "containerRegistryConnection",
12 | "type": "endpoint:containerRegistry",
13 | "required": "true",
14 | "displayName": "Container Registry"
15 | },
16 | {
17 | "name": "imageRepository",
18 | "type": "string",
19 | "required": "true",
20 | "displayName": "Image Name"
21 | },
22 | {
23 | "name": "servicePort",
24 | "type": "pickList",
25 | "required": "true",
26 | "displayName": "Service Port"
27 | },
28 | {
29 | "name": "reviewApp",
30 | "type": "boolean",
31 | "displayName": "Enable Review App flow for Pull Requests"
32 | }
33 | ],
34 | "assets": [
35 | {
36 | "type": "file",
37 | "path": "k8s/deployment.yml",
38 | "destinationPath": "manifests/deployment.yml",
39 | "description": "Kubernetes manifest (deployment)"
40 | },
41 | {
42 | "type": "file",
43 | "path": "k8s/service.yml",
44 | "destinationPath": "manifests/service.yml",
45 | "description": "Kubernetes manifest (service)"
46 | }
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/design/yaml-principles.md:
--------------------------------------------------------------------------------
1 | # YAML language principles
2 |
3 | Here are the principles we're using to evaluate YAML suggestions, especially when they affect the base syntax.
4 | These are *very* rough in priority order.
5 |
6 | 1. Make simple things simple, complex things possible.
7 | Consider the new user and how they grow-up / level-up.
8 | Don't forget the deep expert who has to read and write these things day in and day out.
9 | 2. Be opinionated.
10 | Try to do the right thing automatically.
11 | Give a way to bail out if we guess wrong.
12 | 3. Wherever possible, have only one way of doing things.
13 | That way, when customers discover it, they're (by definition) doing it the *right* way.
14 | 4. Follow the principle of least surprise.
15 | If you have to make a decision with no clear "right" answer, consider which way will be less surprising once learned.
16 | That'll be easier to *remember*.
17 | 5. Understand what others chose to do and why.
18 | Our system is different in large and small ways from other CI/CD systems.
19 | This principle *doesn't* mean "just do what \ does".
20 | 6. Our language is terse, moreso for common things.
21 | It's "job", not "jobToRun".
22 | A well-placed adjective can clear up a lot of confusion, though: it's "displayName", not "name".
23 |
24 | ## Notes for internal contributors
25 |
26 | When you want to add new YAML schema to the platform, please write up a functional spec with examples and proposed syntax.
27 | Open a PR into the `design/` directory in this repo.
28 | Send mail to `azpipeyamlreview` with the PR number.
29 | We'll take a look and get back to you with high-quality feedback within 5 business days.
30 | This way we get both public and internal eyes on the proposal before it's implemented.
31 |
--------------------------------------------------------------------------------
/templates/icons/svg/azurecontainerregistry.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/icons/svg/gradle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/python-django.yml:
--------------------------------------------------------------------------------
1 | # Python Django
2 | # Test a Django project on multiple versions of Python.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/python
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | pool:
10 | {{ pool }}
11 | strategy:
12 | matrix:
13 | Python35:
14 | PYTHON_VERSION: '3.5'
15 | Python36:
16 | PYTHON_VERSION: '3.6'
17 | Python37:
18 | PYTHON_VERSION: '3.7'
19 | maxParallel: 3
20 |
21 | steps:
22 | - task: UsePythonVersion@0
23 | inputs:
24 | versionSpec: '$(PYTHON_VERSION)'
25 | architecture: 'x64'
26 |
27 | - task: PythonScript@0
28 | displayName: 'Export project path'
29 | inputs:
30 | scriptSource: 'inline'
31 | script: |
32 | """Search all subdirectories for `manage.py`."""
33 | from glob import iglob
34 | from os import path
35 | # Python >= 3.5
36 | manage_py = next(iglob(path.join('**', 'manage.py'), recursive=True), None)
37 | if not manage_py:
38 | raise SystemExit('Could not find a Django project')
39 | project_location = path.dirname(path.abspath(manage_py))
40 | print('Found Django project in', project_location)
41 | print('##vso[task.setvariable variable=projectRoot]{}'.format(project_location))
42 |
43 | - script: |
44 | python -m pip install --upgrade pip setuptools wheel
45 | pip install -r requirements.txt
46 | pip install unittest-xml-reporting
47 | displayName: 'Install prerequisites'
48 |
49 | - script: |
50 | pushd '$(projectRoot)'
51 | python manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
52 | displayName: 'Run tests'
53 |
54 | - task: PublishTestResults@2
55 | inputs:
56 | testResultsFiles: "**/TEST-*.xml"
57 | testRunTitle: 'Python $(PYTHON_VERSION)'
58 | condition: succeededOrFailed()
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Azure Pipelines YAML
2 |
3 | YAML templates, samples, and community interaction for designing [Azure Pipelines](https://docs.microsoft.com/azure/devops/pipelines/).
4 |
5 | We've consolidated issue and suggestion tracking in [Developer Community](https://developercommunity.visualstudio.com/spaces/21/index.html).
6 | This repo will remain for working in the open on YAML pipelines, so feedback on PRs will be the primary way to use it.
7 | You might also want the [docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops) or to open a [support ticket](https://azure.microsoft.com/support/devops/).
8 |
9 | - [Templates](templates/)
10 | - [Design docs](design/README.md)
11 |
12 | ## Contributing
13 |
14 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
15 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
16 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
17 |
18 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
19 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
20 | provided by the bot. You will only need to do this once across all repos using our CLA.
21 |
22 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
23 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
24 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
25 |
26 | ## Security issues
27 |
28 | Do you think there might be a security issue with Azure Pipelines?
29 | Have you been phished or identified a security vulnerability?
30 | Please don't report it here - let us know by sending an email to secure@microsoft.com.
31 |
--------------------------------------------------------------------------------
/templates/icons/svg/dotnet.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/resources/arm/aks.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "clusterName": {
6 | "type": "string"
7 | },
8 | "clusterLocation": {
9 | "type": "string"
10 | },
11 | "servicePrincipalId": {
12 | "type": "securestring"
13 | },
14 | "servicePrincipalKey": {
15 | "type": "securestring"
16 | },
17 | "agentCount": {
18 | "defaultValue": 1,
19 | "type": "int"
20 | },
21 | "agentVMSize": {
22 | "defaultValue": "Standard_D2_v2",
23 | "type": "string"
24 | },
25 | "registryName": {
26 | "type": "string"
27 | },
28 | "registryLocation": {
29 | "type": "string"
30 | },
31 | "registrySku": {
32 | "defaultValue": "Standard",
33 | "type": "string"
34 | }
35 | },
36 | "variables": {},
37 | "resources": [
38 | {
39 | "type": "Microsoft.ContainerRegistry/registries",
40 | "sku": {
41 | "name": "[parameters('registrySku')]"
42 | },
43 | "name": "[parameters('registryName')]",
44 | "apiVersion": "2017-10-01",
45 | "location": "[parameters('registryLocation')]",
46 | "properties": {
47 | "adminUserEnabled": true
48 | }
49 | },
50 | {
51 | "apiVersion": "2018-03-31",
52 | "type": "Microsoft.ContainerService/managedClusters",
53 | "location": "[parameters('clusterLocation')]",
54 | "name": "[parameters('clusterName')]",
55 | "dependsOn": [],
56 | "properties": {
57 | "dnsPrefix": "[parameters('clusterName')]",
58 | "agentPoolProfiles": [
59 | {
60 | "name": "agentpool",
61 | "count": "[parameters('agentCount')]",
62 | "vmSize": "[parameters('agentVMSize')]"
63 | }
64 | ],
65 | "servicePrincipalProfile": {
66 | "clientId": "[parameters('servicePrincipalId')]",
67 | "secret": "[parameters('servicePrincipalKey')]"
68 | }
69 | }
70 | }
71 | ]
72 | }
--------------------------------------------------------------------------------
/design/variables.md:
--------------------------------------------------------------------------------
1 | # Variables context and condition simplification
2 |
3 | ## Processing within a file
4 |
5 | Changes:
6 | - Add variables to the context, as they are read (completed)
7 | - Add `else` and `elif` (not completed)
8 |
9 | Example jobs template:
10 |
11 | ```yaml
12 | parameters:
13 | jobName: ''
14 | jobs:
15 | - job: ${{ parameters.jobName }}
16 | variables:
17 | public: ${{ eq(variables['System.TeamProject'], 'public') }}
18 | publicOrPR: ${{ or(eq(variables.public, 'true'), eq(variables['Build.Reason'], 'PullRequest')) }}
19 | steps:
20 | - ${{ if eq(variables.public, 'true') }}:
21 | - script: ./setup-internal-tools.sh
22 | - ${{ else }}:
23 | - script: ./setup-tools.sh
24 | - script: build
25 | - script: test
26 | - ${{ if eq(variables.publicOrPR, 'true') }}:
27 | - script: publish-telemetry
28 | ```
29 |
30 | Note, attempts to override system variables will fail.
31 |
32 | Note, although variables are added to the context as the are read, they do not flow downstream across files during template compilation.
33 |
34 | ## Reuse variable definitions
35 |
36 | Allow variables to be imported from a file.
37 |
38 | Variables can be imported wherever they can normally be defined. That is, at the root of the pipeline, on a stage, or on a job.
39 |
40 | For example:
41 |
42 | ```yaml
43 | # my-variables.yml
44 |
45 | parameters:
46 | config: debug
47 | variables:
48 | arch: x64
49 | config: ${{ parameters.config }}
50 | sign: ${{ eq(parameters.config, 'debug') }}
51 | publish: ${{ or(eq(parameters.config, 'release'), startsWith(variables['build.sourceBranch'], 'refs/heads/dogfood/')) }}
52 | ```
53 |
54 | ```yaml
55 | # my-jobs.yml
56 |
57 | parameters:
58 | jobName: ''
59 | jobs:
60 | - job: ${{ parameters.jobName }}
61 | variables:
62 | - template: my-variables.yml # reference variables
63 | parameters:
64 | config: release
65 | steps:
66 | - script: build --config ${{ variables.config }} --arch ${{ variables.arch }}
67 | - ${{ if eq(variables.sign, 'true') }}:
68 | - script: sign
69 | - ${{ if eq(variables.publish, 'true') }}:
70 | - script: publish
71 | ```
72 |
--------------------------------------------------------------------------------
/templates/maven-webapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Maven package Java project Web App to Linux on Azure
2 | # Build your Java project and deploy it to Azure as a Linux web app
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/java
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 |
11 | # Azure Resource Manager connection created during pipeline creation
12 | azureSubscription: '{{ azureRmConnection.Id }}'
13 |
14 | # Web app name
15 | webAppName: '{{ webAppName }}'
16 |
17 | # Environment name
18 | environmentName: '{{ webAppName }}'
19 |
20 | # Agent VM image name
21 | vmImageName: 'ubuntu-latest'
22 |
23 | stages:
24 | - stage: Build
25 | displayName: Build stage
26 | jobs:
27 | - job: MavenPackageAndPublishArtifacts
28 | displayName: Maven Package and Publish Artifacts
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - task: Maven@3
34 | displayName: 'Maven Package'
35 | inputs:
36 | mavenPomFile: 'pom.xml'
37 |
38 | - task: CopyFiles@2
39 | displayName: 'Copy Files to artifact staging directory'
40 | inputs:
41 | SourceFolder: '$(System.DefaultWorkingDirectory)'
42 | Contents: '**/target/*.?(war|jar)'
43 | TargetFolder: $(Build.ArtifactStagingDirectory)
44 |
45 | - upload: $(Build.ArtifactStagingDirectory)
46 | artifact: drop
47 |
48 | - stage: Deploy
49 | displayName: Deploy stage
50 | dependsOn: Build
51 | condition: succeeded()
52 | jobs:
53 | - deployment: DeployLinuxWebApp
54 | displayName: Deploy Linux Web App
55 | environment: $(environmentName)
56 | pool:
57 | vmImage: $(vmImageName)
58 | strategy:
59 | runOnce:
60 | deploy:
61 | steps:
62 | - task: AzureWebApp@1
63 | displayName: 'Azure Web App Deploy: {{ webAppName }}'
64 | inputs:
65 | azureSubscription: $(azureSubscription)
66 | appType: webAppLinux
67 | appName: $(webAppName)
68 | package: '$(Pipeline.Workspace)/drop/**/target/*.?(war|jar)'
69 |
--------------------------------------------------------------------------------
/templates/powershell-functionapp-to-windows-on-azure.yml:
--------------------------------------------------------------------------------
1 | # PowerShell Function App to Windows on Azure
2 | # Build a PowerShell Function App and deploy it to Azure as a Windows function app.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-powershell
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 | # Azure Resource Manager connection created during pipeline creation
11 | azureSubscription: '{{ azureRmConnection.Id }}'
12 |
13 | # Function app name
14 | functionAppName: '{{ functionAppName }}'
15 |
16 | # Agent VM image name
17 | vmImageName: 'windows-2019'
18 |
19 | # Working Directory
20 | workingDirectory: '{{ workingDirectory }}'
21 |
22 | stages:
23 | - stage: Build
24 | displayName: Build stage
25 |
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - powershell: |
34 | if (Test-Path "extensions.csproj") {
35 | dotnet build extensions.csproj --output ./$(workingDirectory)/bin
36 | }
37 | displayName: 'Build extensions'
38 |
39 | - task: ArchiveFiles@2
40 | displayName: 'Archive files'
41 | inputs:
42 | rootFolderOrFile: $(workingDirectory)
43 | includeRootFolder: false
44 | archiveType: zip
45 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
46 | replaceExistingArchive: true
47 |
48 | - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
49 | artifact: drop
50 |
51 | - stage: Deploy
52 | displayName: Deploy stage
53 | dependsOn: Build
54 | condition: succeeded()
55 |
56 | jobs:
57 | - deployment: Deploy
58 | displayName: Deploy
59 | environment: $(functionAppName)
60 | pool:
61 | vmImage: $(vmImageName)
62 |
63 | strategy:
64 | runOnce:
65 | deploy:
66 |
67 | steps:
68 | - task: AzureFunctionApp@1
69 | displayName: 'Azure functions app deploy'
70 | inputs:
71 | azureSubscription: '$(azureSubscription)'
72 | appType: functionApp
73 | appName: $(functionAppName)
74 | package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
--------------------------------------------------------------------------------
/templates/node.js-react-webapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Node.js React Web App to Linux on Azure
2 | # Build a Node.js React app and deploy it to Azure as a Linux web app.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 |
11 | # Azure Resource Manager connection created during pipeline creation
12 | azureSubscription: '{{ azureRmConnection.Id }}'
13 |
14 | # Web app name
15 | webAppName: '{{ webAppName }}'
16 |
17 | # Environment name
18 | environmentName: '{{ webAppName }}'
19 |
20 | # Agent VM image name
21 | vmImageName: 'ubuntu-latest'
22 |
23 | stages:
24 | - stage: Build
25 | displayName: Build stage
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - task: ArchiveFiles@2
34 | displayName: 'Archive files'
35 | inputs:
36 | rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
37 | includeRootFolder: false
38 | archiveType: zip
39 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
40 | replaceExistingArchive: true
41 |
42 | - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
43 | artifact: drop
44 |
45 | - stage: Deploy
46 | displayName: Deploy stage
47 | dependsOn: Build
48 | condition: succeeded()
49 | jobs:
50 | - deployment: Deploy
51 | displayName: Deploy
52 | environment: $(environmentName)
53 | pool:
54 | vmImage: $(vmImageName)
55 | strategy:
56 | runOnce:
57 | deploy:
58 | steps:
59 | - task: AzureRmWebAppDeployment@4
60 | displayName: 'Azure App Service Deploy: {{ webAppName }}'
61 | inputs:
62 | azureSubscription: $(azureSubscription)
63 | appType: webAppLinux
64 | WebAppName: $(webAppName)
65 | packageForLinux: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
66 | RuntimeStack: 'NODE|10.10'
67 | StartupCommand: 'npm run start'
68 | ScriptType: 'Inline Script'
69 | InlineScript: |
70 | npm install
71 | npm run build --if-present
--------------------------------------------------------------------------------
/design/checkout-path.md:
--------------------------------------------------------------------------------
1 | # Control the checkout location of code
2 |
3 | Customers often wish to control the location of checked-out code.
4 | While we're still designing and working on [multiple checkout](multi-checkout.md), we can make progress on controlling the checkout of `self`.
5 |
6 | Scenarios:
7 | - Previous versions of Go were quite particular about directory structure.
8 | This would let users more easily meet the default expectations, rather than play games with environment variables.
9 | - Some infrastructure makes assumptions about directory structure.
10 | For example, Facebook's Jest repo used to assume the code was in a directory called `jest`.
11 | - Containers.
12 | libgit2's CI pipeline maps sources into a particular directory in the container.
13 | Tools installed in the container expect to find the sources there.
14 |
15 | Dependency:
16 | - ~~Introduction of a new `$(Pipeline.Workspace)` variable which always resolves to the workspace for a particular pipeline.~~
17 | _Postponed for now -- Build.SourcesDirectory gives the right loation._ See [the pipeline artifacts spec](pipeline-artifacts.md) for the feature which introduces this variable.
18 |
19 | ## Schema
20 |
21 | ```yaml
22 | steps:
23 | - checkout: self
24 | path: string # where to put the repo; always rooted at $(Pipeline.Workspace)
25 | ```
26 |
27 | `$(Build.SourcesDirectory)` should also point to the actual `self` checkout location. Over time, we'll deprecate the `$(Build.*)` series of variables.
28 |
29 | ### Example
30 |
31 | ```yaml
32 | steps:
33 | - checkout: self
34 | path: PutMyCodeHere # will checkout at $(Pipeline.Workspace)/PutMyCodeHere
35 | - script: ../PutMyCodeHere/build.sh
36 | # default working directory still point to $(Agent.BuildDirectory)/s,
37 | # so the extra ../PutMyCodeHere/ is needed
38 | ```
39 |
40 | ### Relative vs absolute paths
41 |
42 | Relative paths are supported cross-platform.
43 | Consider `path: foo/src`.
44 | That resolves to `$(Pipeline.Workspace)/foo/src`, which correctly resolves on both Windows and Linux.
45 |
46 | Absolute paths are challenging to support cross-platform in a clean way.
47 | They also make it harder to trust running multiple agents on a single host.
48 | Finally, they can lead to hard-to-debug issues with permissions and cleanup.
49 | The agent's work is supposed to be self-contained, so for our initial implementation, we will not support absolute paths.
50 |
--------------------------------------------------------------------------------
/templates/asp.net-core-functionapp-to-windows-on-azure.yml:
--------------------------------------------------------------------------------
1 | # .NET Core Function App to Windows on Azure
2 | # Build a .NET Core function app and deploy it to Azure as a Windows function App.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/en-us/azure/devops/pipelines/languages/dotnet-core
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 | # Azure Resource Manager connection created during pipeline creation
11 | azureSubscription: '{{ azureRmConnection.Id }}'
12 |
13 | # Function app name
14 | functionAppName: '{{ functionAppName }}'
15 |
16 | # Agent VM image name
17 | vmImageName: 'vs2017-win2016'
18 |
19 | # Working Directory
20 | workingDirectory: '{{ workingDirectory }}'
21 |
22 | stages:
23 | - stage: Build
24 | displayName: Build stage
25 |
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - task: DotNetCoreCLI@2
34 | displayName: Build
35 | inputs:
36 | command: 'build'
37 | projects: |
38 | $(workingDirectory)/*.csproj
39 | arguments: --output $(System.DefaultWorkingDirectory)/publish_output --configuration Release
40 |
41 | - task: ArchiveFiles@2
42 | displayName: 'Archive files'
43 | inputs:
44 | rootFolderOrFile: '$(System.DefaultWorkingDirectory)/publish_output'
45 | includeRootFolder: false
46 | archiveType: zip
47 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
48 | replaceExistingArchive: true
49 |
50 | - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
51 | artifact: drop
52 |
53 | - stage: Deploy
54 | displayName: Deploy stage
55 | dependsOn: Build
56 | condition: succeeded()
57 |
58 | jobs:
59 | - deployment: Deploy
60 | displayName: Deploy
61 | environment: 'development'
62 | pool:
63 | vmImage: $(vmImageName)
64 |
65 | strategy:
66 | runOnce:
67 | deploy:
68 |
69 | steps:
70 | - task: AzureFunctionApp@1
71 | displayName: 'Azure functions app deploy'
72 | inputs:
73 | azureSubscription: '$(azureSubscription)'
74 | appType: functionApp
75 | appName: $(functionAppName)
76 | package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
--------------------------------------------------------------------------------
/templates/node.js-express-webapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Node.js Express Web App to Linux on Azure
2 | # Build a Node.js Express app and deploy it to Azure as a Linux web app.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 |
11 | # Azure Resource Manager connection created during pipeline creation
12 | azureSubscription: '{{ azureRmConnection.Id }}'
13 |
14 | # Web app name
15 | webAppName: '{{ webAppName }}'
16 |
17 | # Environment name
18 | environmentName: '{{ webAppName }}'
19 |
20 | # Agent VM image name
21 | vmImageName: 'ubuntu-latest'
22 |
23 | stages:
24 | - stage: Build
25 | displayName: Build stage
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - task: NodeTool@0
34 | inputs:
35 | versionSpec: '16.x'
36 | displayName: 'Install Node.js'
37 |
38 | - script: |
39 | npm install
40 | npm run build --if-present
41 | npm run test --if-present
42 | displayName: 'npm install, build and test'
43 |
44 | - task: ArchiveFiles@2
45 | displayName: 'Archive files'
46 | inputs:
47 | rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
48 | includeRootFolder: false
49 | archiveType: zip
50 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
51 | replaceExistingArchive: true
52 |
53 | - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
54 | artifact: drop
55 |
56 | - stage: Deploy
57 | displayName: Deploy stage
58 | dependsOn: Build
59 | condition: succeeded()
60 | jobs:
61 | - deployment: Deploy
62 | displayName: Deploy
63 | environment: $(environmentName)
64 | pool:
65 | vmImage: $(vmImageName)
66 | strategy:
67 | runOnce:
68 | deploy:
69 | steps:
70 | - task: AzureWebApp@1
71 | displayName: 'Azure Web App Deploy: {{ webAppName }}'
72 | inputs:
73 | azureSubscription: $(azureSubscription)
74 | appType: webAppLinux
75 | appName: $(webAppName)
76 | runtimeStack: 'NODE|16-lts'
77 | package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
78 | startUpCommand: 'npm run start'
79 |
--------------------------------------------------------------------------------
/templates/node.js-functionapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Node.js Function App to Linux on Azure
2 | # Build a Node.js function app and deploy it to Azure as a Linux function app.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 |
11 | # Azure Resource Manager connection created during pipeline creation
12 | azureSubscription: '{{ azureRmConnection.Id }}'
13 |
14 | # Function app name
15 | functionAppName: '{{ functionAppName }}'
16 |
17 | # Environment name
18 | environmentName: '{{ functionAppName }}'
19 |
20 | # Agent VM image name
21 | vmImageName: 'ubuntu-latest'
22 |
23 | stages:
24 | - stage: Build
25 | displayName: Build stage
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - task: NodeTool@0
34 | inputs:
35 | versionSpec: '10.x'
36 | displayName: 'Install Node.js'
37 |
38 | - script: |
39 | if [ -f extensions.csproj ]
40 | then
41 | dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
42 | fi
43 | displayName: 'Build extensions'
44 |
45 | - script: |
46 | npm install
47 | npm run build --if-present
48 | npm run test --if-present
49 | displayName: 'Prepare binaries'
50 |
51 | - task: ArchiveFiles@2
52 | displayName: 'Archive files'
53 | inputs:
54 | rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
55 | includeRootFolder: false
56 | archiveType: zip
57 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
58 | replaceExistingArchive: true
59 |
60 | - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
61 | artifact: drop
62 |
63 | - stage: Deploy
64 | displayName: Deploy stage
65 | dependsOn: Build
66 | condition: succeeded()
67 | jobs:
68 | - deployment: Deploy
69 | displayName: Deploy
70 | environment: $(environmentName)
71 | pool:
72 | vmImage: $(vmImageName)
73 | strategy:
74 | runOnce:
75 | deploy:
76 | steps:
77 | - task: AzureFunctionApp@1
78 | displayName: 'Azure Functions App Deploy: {{ functionAppName }}'
79 | inputs:
80 | azureSubscription: '$(azureSubscription)'
81 | appType: functionAppLinux
82 | appName: $(functionAppName)
83 | package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
--------------------------------------------------------------------------------
/templates/python-functionapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Python Function App to Linux on Azure
2 | # Build a Python function app and deploy it to Azure as a Linux function app.
3 | # Add steps that analyze code, save build artifacts, deploy, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/python
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 | # Azure Resource Manager connection created during pipeline creation
11 | azureSubscription: '{{ azureRmConnection.Id }}'
12 |
13 | # Function app name
14 | functionAppName: '{{ functionAppName }}'
15 |
16 | # Agent VM image name
17 | vmImageName: 'ubuntu-latest'
18 |
19 | # Working Directory
20 | workingDirectory: '{{ workingDirectory }}'
21 |
22 | stages:
23 | - stage: Build
24 | displayName: Build stage
25 |
26 | jobs:
27 | - job: Build
28 | displayName: Build
29 | pool:
30 | vmImage: $(vmImageName)
31 |
32 | steps:
33 | - bash: |
34 | if [ -f extensions.csproj ]
35 | then
36 | dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
37 | fi
38 | workingDirectory: $(workingDirectory)
39 | displayName: 'Build extensions'
40 |
41 | - task: UsePythonVersion@0
42 | displayName: 'Use Python 3.6'
43 | inputs:
44 | versionSpec: 3.6 # Functions V2 supports Python 3.6 as of today
45 |
46 | - bash: |
47 | pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
48 | workingDirectory: $(workingDirectory)
49 | displayName: 'Install application dependencies'
50 |
51 | - task: ArchiveFiles@2
52 | displayName: 'Archive files'
53 | inputs:
54 | rootFolderOrFile: '$(workingDirectory)'
55 | includeRootFolder: false
56 | archiveType: zip
57 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
58 | replaceExistingArchive: true
59 |
60 | - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
61 | artifact: drop
62 |
63 | - stage: Deploy
64 | displayName: Deploy stage
65 | dependsOn: Build
66 | condition: succeeded()
67 |
68 | jobs:
69 | - deployment: Deploy
70 | displayName: Deploy
71 | environment: 'development'
72 | pool:
73 | vmImage: $(vmImageName)
74 |
75 | strategy:
76 | runOnce:
77 | deploy:
78 |
79 | steps:
80 | - task: AzureFunctionApp@1
81 | displayName: 'Azure functions app deploy'
82 | inputs:
83 | azureSubscription: '$(azureSubscription)'
84 | appType: functionAppLinux
85 | appName: $(functionAppName)
86 | package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
--------------------------------------------------------------------------------
/templates/php-webapp-to-linux-on-azure.yml:
--------------------------------------------------------------------------------
1 | # PHP as Linux Web App on Azure
2 | # Build, package and deploy your PHP project to Azure Linux Web App.
3 | # Add steps that run tests and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/php
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 | # Azure Resource Manager connection created during pipeline creation
11 | azureSubscription: '{{ azureRmServiceConnection.Id }}'
12 |
13 | # Web app name
14 | webAppName: '{{ webAppName }}'
15 |
16 | # Agent VM image name
17 | vmImageName: 'ubuntu-latest'
18 |
19 | # Environment name
20 | environmentName: '{{ webAppName }}'
21 |
22 | # Root folder under which your composer.json file is available.
23 | rootFolder: $(System.DefaultWorkingDirectory)
24 |
25 | stages:
26 | - stage: Build
27 | displayName: Build stage
28 | variables:
29 | phpVersion: '7.3'
30 | jobs:
31 | - job: BuildJob
32 | pool:
33 | vmImage: $(vmImageName)
34 | steps:
35 | - script: |
36 | sudo update-alternatives --set php /usr/bin/php$(phpVersion)
37 | sudo update-alternatives --set phar /usr/bin/phar$(phpVersion)
38 | sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpVersion)
39 | sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpVersion)
40 | sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpVersion)
41 | php -version
42 | workingDirectory: $(rootFolder)
43 | displayName: 'Use PHP version $(phpVersion)'
44 |
45 | - script: composer install --no-interaction --prefer-dist
46 | workingDirectory: $(rootFolder)
47 | displayName: 'Composer install'
48 |
49 | - task: ArchiveFiles@2
50 | displayName: 'Archive files'
51 | inputs:
52 | rootFolderOrFile: '$(rootFolder)'
53 | includeRootFolder: false
54 | archiveType: zip
55 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
56 | replaceExistingArchive: true
57 |
58 | - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
59 | displayName: 'Upload package'
60 | artifact: drop
61 |
62 | - stage: Deploy
63 | displayName: 'Deploy Web App'
64 | dependsOn: Build
65 | condition: succeeded()
66 | jobs:
67 | - deployment: DeploymentJob
68 | pool:
69 | vmImage: $(vmImageName)
70 | environment: $(environmentName)
71 | strategy:
72 | runOnce:
73 | deploy:
74 | steps:
75 | - task: AzureWebApp@1
76 | displayName: 'Deploy Azure Web App : {{ webAppName }}'
77 | inputs:
78 | azureSubscription: $(azureSubscription)
79 | appName: $(webAppName)
80 | package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
--------------------------------------------------------------------------------
/templates/python-to-linux-webapp-on-azure.yml:
--------------------------------------------------------------------------------
1 | # Python to Linux Web App on Azure
2 | # Build your Python project and deploy it to Azure as a Linux Web App.
3 | # Change python version to one thats appropriate for your application.
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/python
5 |
6 | trigger:
7 | - {{ branch }}
8 |
9 | variables:
10 | # Azure Resource Manager connection created during pipeline creation
11 | azureServiceConnectionId: '{{ azureServiceConnection.Id }}'
12 |
13 | # Web app name
14 | webAppName: '{{ webAppName }}'
15 |
16 | # Agent VM image name
17 | vmImageName: 'ubuntu-latest'
18 |
19 | # Environment name
20 | environmentName: '{{ webAppName }}'
21 |
22 | # Project root folder. Point to the folder containing manage.py file.
23 | projectRoot: $(System.DefaultWorkingDirectory)
24 |
25 | # Python version: 3.7
26 | pythonVersion: '3.7'
27 |
28 | stages:
29 | - stage: Build
30 | displayName: Build stage
31 | jobs:
32 | - job: BuildJob
33 | pool:
34 | vmImage: $(vmImageName)
35 | steps:
36 | - task: UsePythonVersion@0
37 | inputs:
38 | versionSpec: '$(pythonVersion)'
39 | displayName: 'Use Python $(pythonVersion)'
40 |
41 | - script: |
42 | python -m venv antenv
43 | source antenv/bin/activate
44 | python -m pip install --upgrade pip
45 | pip install setup
46 | pip install -r requirements.txt
47 | workingDirectory: $(projectRoot)
48 | displayName: "Install requirements"
49 |
50 | - task: ArchiveFiles@2
51 | displayName: 'Archive files'
52 | inputs:
53 | rootFolderOrFile: '$(projectRoot)'
54 | includeRootFolder: false
55 | archiveType: zip
56 | archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
57 | replaceExistingArchive: true
58 |
59 | - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
60 | displayName: 'Upload package'
61 | artifact: drop
62 |
63 | - stage: Deploy
64 | displayName: 'Deploy Web App'
65 | dependsOn: Build
66 | condition: succeeded()
67 | jobs:
68 | - deployment: DeploymentJob
69 | pool:
70 | vmImage: $(vmImageName)
71 | environment: $(environmentName)
72 | strategy:
73 | runOnce:
74 | deploy:
75 | steps:
76 |
77 | - task: UsePythonVersion@0
78 | inputs:
79 | versionSpec: '$(pythonVersion)'
80 | displayName: 'Use Python version'
81 |
82 | - task: AzureWebApp@1
83 | displayName: 'Deploy Azure Web App : {{ webAppName }}'
84 | inputs:
85 | azureSubscription: $(azureServiceConnectionId)
86 | appName: $(webAppName)
87 | package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/templates/icons/svg/golang.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/templates/icons/svg/xcode.svg:
--------------------------------------------------------------------------------
1 |
58 |
--------------------------------------------------------------------------------
/design/node10-agent-support.md:
--------------------------------------------------------------------------------
1 | # Azure Pipelines agent Node v10 support
2 |
3 | ## Overview
4 |
5 | Currently, the Azure Pipelines agent supports running JavaScript code via the Node handler. This handler runs version 6 of the node runtime, released in April 2016. As of November 2018, Node v6 is under "maintenance" status.
6 |
7 | Because task developers may desire to use features from a newer Node API, and also consume libraries which may no longer support Node v6, the agent will benefit from supporting more up-to-date Node versions.
8 |
9 | Node v10 is the latest version under LTS status.
10 |
11 | ## Architecture
12 |
13 | The agent will support a new handler: Node10. Node10 will syntactically look the same as the existing Node handler, with the only exception that Node10 will end up invoking the Node runtime, version 10.
14 |
15 | We'll add a minimum agent version demand should the task.json require the Node10 handler.
16 |
17 | **task.json sample**
18 |
19 | ``` json
20 | "execution": {
21 | "Node10": {
22 | "target": "myscript.js",
23 | "argumentFormat": ""
24 | }
25 | },
26 | ```
27 |
28 | Initially, the agent is going to package both v6 and v10 Node runtimes, and leave the current v6 workflow unaltered. A feature flag `AGENT_USE_NODE10` will be introduced to the Node handler to switch between the v6 and v10 backends.
29 |
30 | The Node v10 switching mechanism will be implemented by the existing `NodeHandler.cs` class.
31 |
32 | ## Rolling out feature
33 |
34 | Rolling out Node v10 support will be executed in three phases:
35 |
36 | 1. New versions of the agents (with node v10) will be deployed to Ring 0. Then, we'll monitor pipeline runs from the build canary, with the feature flag off, and look out for any regressions. This phase is basically equivalent to what we already do for every new build release.
37 |
38 | ```
39 | "Node10" -> NodeHandler.cs -> Node v10 runtime
40 |
41 |
42 |
43 | (Feature flag off)
44 | "Node" -> NodeHandler.cs -> Node v6 runtime
45 | ```
46 |
47 | 2. Once we're sure there are no pipeline run regressions, we turn the feature flag on to switch "Node" to the v10 handler in the build canary, and again, look out for any regressions. Simultaneously, we continue deploying the agent to later scale units. Initially with the feature flag off, then turned on.
48 |
49 | ```
50 | "Node10" -> NodeHandler.cs -> Node v10 runtime
51 | ^
52 | /
53 | /
54 | (Feature flag on) /
55 | "Node" -> NodeHandler.cs --- Node v6 runtime
56 | ```
57 |
58 | 3. Once we've turned the feature flag everywhere on hosted, we'll still keep the v6 and v10 runtimes, and the feature flag OFF for the next on-prem release. This is because we don't have control over the tasks that are written against those on-prem environments. After the on-prem release, we'll remove the Node v6 runtime from the agent, in addition to the feature flag.
59 |
60 | ```
61 | "Node10" -> NodeHandler.cs -> Node v10 runtime
62 | ^
63 | /
64 | /
65 | (No feature flag) /
66 | "Node" -> NodeHandler.cs ---
67 | ```
68 |
--------------------------------------------------------------------------------
/templates/docker-container-to-acr.yml:
--------------------------------------------------------------------------------
1 | # Docker image and Azure Container Registry
2 | # Build a Docker image and push it to an Azure Container Registry.
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | # ========================================================================
13 | # Mandatory variables
14 | # ========================================================================
15 |
16 | # Update Azure.ResourceGroupName value with Azure resource group name.
17 | Azure.ResourceGroupName: '{{#toAlphaNumericString repositoryName 50}}{{/toAlphaNumericString}}'
18 |
19 | # Update Azure.ServiceConnectionId value with AzureRm service endpoint.
20 | Azure.ServiceConnectionId: '{{ azureServiceConnectionId }}'
21 |
22 | # Update Azure.Location value with Azure Location.
23 | Azure.Location: 'eastus'
24 |
25 | # Update ACR.Name value with ACR name. Please note ACR names should be all lower-case and alphanumeric only.
26 | ACR.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
27 |
28 | # ========================================================================
29 | # Optional variables
30 | # ========================================================================
31 |
32 | ACR.ImageName: '$(ACR.Name):$(Build.BuildId)'
33 | ACR.FullName: '$(ACR.Name).azurecr.io'
34 | Azure.CreateResources: 'true' # Update Azure.CreateResources to false if you have already created resources like resource group and azure container registry.
35 | System.Debug: 'false'
36 |
37 | jobs:
38 |
39 | - job: CreateResources
40 | displayName: Create required resources
41 | condition: and(succeeded(), eq(variables['Azure.CreateResources'], 'true'))
42 |
43 | pool:
44 | {{ pool }}
45 |
46 | steps:
47 | - task: AzureResourceGroupDeployment@2
48 | displayName: 'Azure Deployment:Create Azure Container Registry'
49 | inputs:
50 | azureSubscription: '$(Azure.ServiceConnectionId)'
51 | resourceGroupName: '$(Azure.ResourceGroupName)'
52 | location: '$(Azure.Location)'
53 | templateLocation: 'URL of the file'
54 | csmFileLink: 'https://raw.githubusercontent.com/Microsoft/azure-pipelines-yaml/master/templates/resources/arm/acr.json'
55 | overrideParameters: '-registryName "$(ACR.Name)" -registryLocation "$(Azure.Location)"'
56 |
57 | - job: BuildImage
58 | displayName: Build
59 | dependsOn: CreateResources
60 | condition: or(succeeded(), ne(variables['Azure.CreateResources'], 'true'))
61 |
62 | pool:
63 | {{ pool }}
64 |
65 | steps:
66 | - task: Docker@1
67 | displayName: 'Build an image'
68 | inputs:
69 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
70 | azureContainerRegistry: '$(ACR.FullName)'
71 | imageName: '$(ACR.ImageName)'
72 | command: build
73 | dockerFile: '**/Dockerfile'
74 |
75 | - task: Docker@1
76 | displayName: 'Push an image'
77 | inputs:
78 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
79 | azureContainerRegistry: '$(ACR.FullName)'
80 | imageName: '$(ACR.ImageName)'
81 | command: push
82 |
--------------------------------------------------------------------------------
/templates/icons/svg/android.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/resources/arm/webapp-on-containers.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "webAppName": {
6 | "type": "string"
7 | },
8 | "hostingPlanName": {
9 | "type": "string"
10 | },
11 | "sku": {
12 | "defaultValue": "S1 Standard",
13 | "type": "string"
14 | },
15 | "registryName": {
16 | "type": "string"
17 | },
18 | "imageName": {
19 | "type": "string"
20 | },
21 | "registryLocation": {
22 | "type": "string"
23 | },
24 | "registrySku": {
25 | "defaultValue": "Standard",
26 | "type": "string"
27 | },
28 | "startupCommand": {
29 | "defaultValue": "",
30 | "type": "string"
31 | }
32 | },
33 | "resources": [
34 | {
35 | "type": "Microsoft.Web/sites",
36 | "name": "[parameters('webAppName')]",
37 | "apiVersion": "2018-02-01",
38 | "location": "[resourceGroup().location]",
39 | "properties": {
40 | "name": "[parameters('webAppName')]",
41 | "siteConfig": {
42 | "appSettings": [
43 | {
44 | "name": "DOCKER_REGISTRY_SERVER_URL",
45 | "value": "[concat('https://', reference(concat('Microsoft.ContainerRegistry/registries/', parameters('registryName'))).loginServer)]"
46 | },
47 | {
48 | "name": "DOCKER_REGISTRY_SERVER_USERNAME",
49 | "value": "[listCredentials(concat('Microsoft.ContainerRegistry/registries/', parameters('registryName')), '2017-10-01').username]"
50 | },
51 | {
52 | "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
53 | "value": "[listCredentials(concat('Microsoft.ContainerRegistry/registries/', parameters('registryName')), '2017-10-01').passwords[0].value]"
54 | }
55 | ],
56 | "appCommandLine": "[parameters('startupCommand')]",
57 | "linuxFxVersion": "[concat('DOCKER|', reference(concat('Microsoft.ContainerRegistry/registries/', parameters('registryName'))).loginServer, '/', parameters('imageName'))]"
58 | },
59 | "serverFarmId": "[concat('/subscriptions/', subscription().subscriptionId,'/resourcegroups/', resourceGroup().name, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
60 | },
61 | "dependsOn": [
62 | "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
63 | "[concat('Microsoft.ContainerRegistry/registries/', parameters('registryName'))]"
64 | ]
65 | },
66 | {
67 | "type": "Microsoft.ContainerRegistry/registries",
68 | "sku": {
69 | "name": "[parameters('registrySku')]"
70 | },
71 | "name": "[parameters('registryName')]",
72 | "apiVersion": "2017-10-01",
73 | "location": "[parameters('registryLocation')]",
74 | "properties": {
75 | "adminUserEnabled": true
76 | }
77 | },
78 | {
79 | "type": "Microsoft.Web/serverfarms",
80 | "sku": {
81 | "tier": "[first(skip(split(parameters('sku'), ' '), 1))]",
82 | "name": "[first(split(parameters('sku'), ' '))]"
83 | },
84 | "kind": "linux",
85 | "name": "[parameters('hostingPlanName')]",
86 | "apiVersion": "2018-02-01",
87 | "location": "[resourceGroup().location]",
88 | "properties": {
89 | "name": "[parameters('hostingPlanName')]"
90 | }
91 | }
92 | ]
93 | }
--------------------------------------------------------------------------------
/templates/icons/svg/ant.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/design/step-target-restricted-mode.md:
--------------------------------------------------------------------------------
1 | # Step target command "restricted mode"
2 |
3 | With the introduction of [step targets](step-target.md), the code running inside a given step can be mostly isolated from the agent host.
4 | Agent logging commands remain a vector for untrusted user code to make permanent changes to its environment.
5 | For instance, `task.setVariable` can alter system variables for the duration of the job.
6 | `artifact.upload` can exfiltrate bits off the machine or poison otherwise-trusted artifacts.
7 |
8 | This spec proposes an extension to step targets allowing them to be placed in "command restricted mode".
9 | In command restricted mode, only a small, approved subset of logging commands are processed.
10 | These are necessary for communicating the status or outcome of a step.
11 | All other commands are excluded.
12 |
13 | ## What gets isolated?
14 |
15 | By default, all commands are denied.
16 | In order to be allowed, a command should meet all of these criteria:
17 | - Command is necessary to update the agent about the current step's progress or state
18 | - There is no safer way to perform the action
19 | - After reasonable threat modeling, we can't see a way for untrusted code to exploit the command
20 |
21 | ## Syntax
22 |
23 | The `target` property of a step will be expanded to allow either a simple string or a mapping.
24 | If it's a string, the string is the target of the step (either `host` or a container resource name) and safe mode is off (as if `commands: any` were specified).
25 | If it's a mapping, the following keys are supported:
26 |
27 | ```yaml
28 | - script: ...
29 | target:
30 | container: string (container name or the word `host`)
31 | commands: enum (one of "restricted" or "any", with "any" the default)
32 | ```
33 |
34 | ## Example
35 |
36 | ```yaml
37 | resources:
38 | containers:
39 | - container: somecontainer
40 | image: azcr.io/secureazurecontainer:latest
41 |
42 | - script: echo running this step on host
43 | - script: echo running this step in container
44 | target:
45 | container: somecontainer
46 | - script: echo running this step in container, in restricted mode
47 | target:
48 | container: somecontainer
49 | commands: restricted
50 | ```
51 |
52 | ## Which commands are allowed?
53 |
54 | As of October 2019, the following commands exist.
55 | Commands allowed in restricted mode are marked with ✅:
56 |
57 | | Area | Command | Allowed? | Notes
58 | |------|---------|----------|------
59 | | `artifact` | `associate`
60 | | `artifact` | `upload`
61 | | `build` | `uploadlog`
62 | | `build` | `uploadsummary`
63 | | `build` | `updatebuildnumber`
64 | | `build` | `addbuildtag`
65 | | `codecoverage` | `publish`
66 | | `codecoverage` | `enable`
67 | | `plugininternal` | `updaterepositorypath`
68 | | `release` | `updatereleasename` | | not needed since `release` plugin isn't loaded for YAML
69 | | `task` | `addattachment`
70 | | `task` | `complete` | ✅
71 | | `task` | `debug` | ✅
72 | | `task` | `logdetail` | ✅
73 | | `task` | `logissue` | ✅
74 | | `task` | `prependpath` | ✅
75 | | `task` | `setprogress` | ✅
76 | | `task` | `setsecret` | ✅
77 | | `task` | `setvariable` | ✅ | requires future "readonly variables" feature to be secure
78 | | `task` | `settaskvariable` | ✅ | investigating whether this is truly needed
79 | | `task` | `setendpoint`
80 | | `task` | `uploadfile`
81 | | `task` | `uploadsummary`
82 | | `telemetry` | `publish` | ✅
83 | | `results` | `publish`
84 |
85 | Many of the "publish" commands are probably allowable, but they apply to the job rather than the particular step.
86 | Therefore, given the principles above, they're disallowed in restricted mode.
87 | A follow-up script running outside of safe mode can do any sanitization required and then call the relevant command.
88 |
--------------------------------------------------------------------------------
/design/deprecated/container-steps.md:
--------------------------------------------------------------------------------
1 | # Container steps
2 |
3 | Status: **ON HOLD, NOT IMPLEMENTING RIGHT NOW**
4 |
5 | An emerging pattern is running discrete steps of a job in different containers.
6 | Each one carries along a persistent, read/write volume as its workspace.
7 |
8 | An example straight from a customer:
9 | - microsoft/dotnet => build C# code
10 | - yarn => build and bundle JS
11 | - aws/sdk => push static files to S3
12 | - gcloud/sdk => download database files from private buckets, update some GCP stuff
13 | - docker => build and push image for this app
14 | - kubectl => deploy this new image on Kubernetes
15 | - our custom container => do checks and send email/Slack
16 |
17 | Containers steps can be seen as an alternative to tasks.
18 | Instead of writing to our custom task.json system and packaging dependencies into a VSIX, you write to Docker's system and package dependencies in an image.
19 |
20 | ## Solving the file permissions problem
21 | When containers write files to volumes, they're written with the UID of the container user.
22 | This means you either have to be root or running as that UID on the host to access the files.
23 | This will break things like uploading artifacts unless we run that in a container as root.
24 | We'll need agent work to move those operations out to a plugin, which we can then run in a container as root.
25 |
26 | ## Other considerations
27 | - We don't (and can't easily) support Alpine Linux containers at the job level.
28 | There are too many runtime dependencies that it doesn't support.
29 | But, `docker run`ning into an arbitrary container doesn't require any of that infrastructure.
30 | So we'd have a great story for using teeny containers and not feel bad about having some extra requirements on full-job containers.
31 | - Need to support custom workspace mapping, environment variables, and custom UIDs.
32 | - Need to support mapping in the Docker daemon so that `docker` CLI will work as expected.
33 | - Need to support the job running as a container when a container step is used.
34 |
35 | ## Later
36 | - Arbitrary volume mappings
37 | - Boolean to de-privilege the container so it can't call out to the host Docker daemon
38 | - Build and run from a Dockerfile in the repo.
39 | The .NET CLI team would use this; talk to @livarcocc as needed.
40 | Consider these scenarios:
41 | - I have have a tool that I want to define as part of a container but don't want to push it to a registry.
42 | - My deployment tooling is packaged as a container and whenever I run that tooling I want the version of that tooling from the branch.
43 |
44 | ## Challenges
45 | - This will be tricky to support on-premises.
46 | Containers in general rely on access to a Docker registry, and those tend to be cloud-hosted.
47 | Many Azure DevOps Server instances won't have internet connectivity.
48 |
49 | ## YAML syntax
50 |
51 | This is loosely based on `docker` command line syntax.
52 |
53 | ```yaml
54 | resources:
55 | containers:
56 | - image: microsoft/dotnet:latest
57 | name: dotnet
58 | - image: facebook/yarn:latest
59 | name: yarn
60 |
61 | steps:
62 | - run: dotnet
63 | env:
64 | DOTNET_CLI_TELEMETRY_OPTOUT: true # add an environment variable
65 | cmd: build # override the default CMD/ENTRYPOINT in the container
66 | - run: yarn
67 | workspace: /my/custom/workspace # override the default workspace mapping
68 | uid: 1001 # overrides the default user ID that we create
69 | ```
70 |
71 | If your container image is from DockerHub, you can skip the forward-declaration and use the image name directly.
72 |
73 | ```yaml
74 | - run: microsoft/dotnet:latest
75 | env:
76 | DOTNET_CLI_TELEMETRY_OPTOUT: true # add an environment variable
77 | - run: facebook/yarn:latest
78 | ```
79 |
80 | If you need a custom Docker registry, you have to go with forward-declarations in the `resources` section.
81 |
--------------------------------------------------------------------------------
/design/deployment.md:
--------------------------------------------------------------------------------
1 | # A deployment job
2 |
3 | A "deployment" job is a collection of steps to be run sequentially against the environment.
4 | We recommend specifying deployment steps in a deployment job.
5 |
6 | ## Scenarios
7 |
8 | - Run a set of steps against an environment. Record deployment history and status of the deployments.
9 | - Perform safe deployments. In other words, define how your application is rolled-out.
10 |
11 |
12 | ### Schema
13 |
14 | ```yaml
15 | jobs:
16 | - deployment: string # name of the deployment job, A-Z, a-z, 0-9, and underscore
17 | displayName: string # friendly name to display in the UI
18 | dependsOn: string | [ string ]
19 | environment: string # target environment name and optionally a resource-name to record the deployment history; format: .
20 | condition: string
21 | continueOnError: boolean # 'true' if future jobs should run even if this job fails; defaults to 'false'
22 | pool: pool # see pool schema
23 | timeoutInMinutes: number # how long to run the job before automatically cancelling
24 | cancelTimeoutInMinutes: number # how much time to give 'run always even if cancelled tasks' before killing them
25 | variables: { string: string } | [ variable | variableReference ]
26 | strategy:
27 | runOnce: # default runOnce strategy, useful for running the steps sequentially once against the environment.
28 | deploy:
29 | displayName: string # friendly name to display in the UI
30 | steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
31 | ```
32 |
33 | Following properties are on hold
34 | ```yaml
35 | container: jobContainer
36 | services: jobServices
37 | workspace: jobWorkSpace.
38 | ```
39 |
40 | ### Example
41 |
42 | ```YAML
43 | jobs:
44 | # track deployments on the environment
45 | - deployment: DeployWeb
46 | displayName: deploy Web App
47 | pool:
48 | vmImage: 'Ubuntu-16.04'
49 | # creates an environment if it doesn't exist
50 | environment: 'smarthotel-dev'
51 | strategy:
52 | # default deployment strategy, more coming...
53 | runOnce:
54 | deploy:
55 | steps:
56 | - script: echo my first deployment
57 | ```
58 |
59 | In the above example, with each run of this job, deployment history is recorded against the "smarthotel-dev" environment.
60 |
61 | > Note:
62 | > - Currently only Kubernetes resources are supported within an environment, with support for VMs and other resources on the roadmap.
63 | > - It is also possible to create an environment with empty resources and use that as namespace to record deployment history as shown in the example above.
64 |
65 | The following example snippet demonstrates how a pipeline can refer an environment and a resource within the same to be used as the target for a deployment job,
66 |
67 | ```YAML
68 | jobs:
69 | - deployment: DeployWeb
70 | displayName: deploy Web App
71 | pool:
72 | vmImage: 'Ubuntu-16.04'
73 | # records deployment against bookings resource - Kubernetes namespace
74 | environment: 'smarthotel-dev.bookings'
75 | strategy:
76 | runOnce:
77 | deploy:
78 | steps:
79 | # No need to explicitly pass the connection details
80 | - task: KubernetesManifest@0
81 | displayName: Deploy to Kubernetes cluster
82 | inputs:
83 | action: deploy
84 | namespace: $(k8sNamespace)
85 | manifests: |
86 | $(System.ArtifactsDirectory)/manifests/*
87 | imagePullSecrets: |
88 | $(imagePullSecret)
89 | containers: |
90 | $(containerRegistry)/$(imageRepository):$(tag)
91 | ```
92 |
93 | The above approach has the following benefits -
94 | - Records deployment history on a specific resource within the environment as opposed to recording the history on all resources within the environment.
95 | - Steps in the deployment job **automatically inherit** the connection details of the resource (in this case, a kubernetes namespace: *smarthotel-dev.bookings*) as the deployment job is linked to the environment.
96 | This is particularly useful in the cases where the same connection detail is to be set for multiple steps of the job.
97 |
--------------------------------------------------------------------------------
/templates/icons/svg/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/icons/svg/python.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/docker-container-webapp.yml:
--------------------------------------------------------------------------------
1 | # Docker image, Azure Container Registry, and Azure Web App
2 | # Build a Docker image, push it to an Azure Container Registry, and deploy it to an Azure Web App.
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | # ========================================================================
13 | # Mandatory variables
14 | # ========================================================================
15 |
16 | # Update Azure.ResourceGroupName value with Azure resource group name.
17 | Azure.ResourceGroupName: '{{#toAlphaNumericString repositoryName 50}}{{/toAlphaNumericString}}'
18 |
19 | # Update Azure.ServiceConnectionId value with AzureRm service endpoint.
20 | Azure.ServiceConnectionId: '{{ azureServiceConnectionId }}'
21 |
22 | # Update Azure.Location value with Azure Location.
23 | Azure.Location: 'eastus'
24 |
25 | # Update ACR.Name value with ACR name. Please note ACR names should be all lower-case and alphanumeric only.
26 | ACR.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
27 |
28 | # Update Web.Name value with a name that identifies your new Web app. Valid characters are a-z, 0-9, and -.
29 | WebApp.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
30 |
31 | # Update ServicePlan.Name value with a name of the app service plan.
32 | ServicePlan.Name: '{{#toAlphaNumericString repositoryName 45}}{{/toAlphaNumericString}}-plan'
33 |
34 | # ========================================================================
35 | # Optional variables
36 | # ========================================================================
37 |
38 | ACR.ImageName: '$(ACR.Name):$(Build.BuildId)'
39 | ACR.FullName: '$(ACR.Name).azurecr.io'
40 | Azure.CreateResources: 'true' # Update Azure.CreateResources to false if you have already created resources like resource group and azure container registry.
41 | System.Debug: 'false'
42 |
43 | jobs:
44 |
45 | - job: CreateResources
46 | displayName: Create resources
47 | condition: and(succeeded(), eq(variables['Azure.CreateResources'], 'true'))
48 |
49 | pool:
50 | {{ pool }}
51 |
52 | steps:
53 | - task: AzureResourceGroupDeployment@2
54 | displayName: 'Azure Deployment:Create Azure Container Registry, Azure WebApp Service'
55 | inputs:
56 | azureSubscription: '$(Azure.ServiceConnectionId)'
57 | resourceGroupName: '$(Azure.ResourceGroupName)'
58 | location: '$(Azure.Location)'
59 | templateLocation: 'URL of the file'
60 | csmFileLink: 'https://raw.githubusercontent.com/Microsoft/azure-pipelines-yaml/master/templates/resources/arm/webapp-on-containers.json'
61 | overrideParameters: '-registryName "$(ACR.Name)" -registryLocation "$(Azure.Location)" -imageName "$(ACR.ImageName)" -webAppName "$(WebApp.Name)" -hostingPlanName "$(ServicePlan.Name)"'
62 |
63 | - job: BuildImage
64 | displayName: Build
65 | dependsOn: CreateResources
66 | condition: or(succeeded(), ne(variables['Azure.CreateResources'], 'true'))
67 |
68 | pool:
69 | {{ pool }}
70 |
71 | steps:
72 | - task: Docker@1
73 | displayName: 'Build an image'
74 | inputs:
75 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
76 | azureContainerRegistry: '$(ACR.FullName)'
77 | imageName: '$(ACR.ImageName)'
78 | command: build
79 | dockerFile: '**/Dockerfile'
80 |
81 | - task: Docker@1
82 | displayName: 'Push an image'
83 | inputs:
84 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
85 | azureContainerRegistry: '$(ACR.FullName)'
86 | imageName: '$(ACR.ImageName)'
87 | command: push
88 |
89 | - job: DeployApp
90 | displayName: Deploy
91 | dependsOn: BuildImage
92 | condition: succeeded()
93 |
94 | pool:
95 | {{ pool }}
96 |
97 | steps:
98 | - task: AzureWebAppContainer@1
99 | displayName: 'Azure Web App on Container Deploy: $(WebApp.Name)'
100 | inputs:
101 | azureSubscription: '$(Azure.ServiceConnectionId)'
102 | appName: $(WebApp.Name)
103 | imageName: '$(ACR.FullName)/$(ACR.ImageName)'
104 |
--------------------------------------------------------------------------------
/templates/docker-container-functionapp.yml:
--------------------------------------------------------------------------------
1 | # Docker image, Azure Container Registry, and Azure Functions app
2 | # Build a Docker image, push it to an Azure Container Registry, and deploy it to an Azure Functions app.
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | # ========================================================================
13 | # Mandatory variables
14 | # ========================================================================
15 |
16 | # Update Azure.ResourceGroupName value with Azure resource group name.
17 | Azure.ResourceGroupName: '{{#toAlphaNumericString repositoryName 50}}{{/toAlphaNumericString}}'
18 |
19 | # Update Azure.ServiceConnectionId value with AzureRm service endpoint.
20 | Azure.ServiceConnectionId: '{{ azureServiceConnectionId }}'
21 |
22 | # Update Azure.Location value with Azure Location.
23 | Azure.Location: 'eastus'
24 |
25 | # Update ACR.Name value with ACR name. Please note ACR names should be all lower-case and alphanumeric only.
26 | ACR.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
27 |
28 | # Update FunctionApp.Name value with a name that identifies your new function app. Valid characters are a-z, 0-9, and -.
29 | FunctionApp.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
30 |
31 | # Update StorageAccount.Name value with Storage account name. Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only.
32 | StorageAccount.Name: '{{#toAlphaNumericString repositoryName 20}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
33 |
34 | # Update ServicePlan.Name value with a name of the app service plan.
35 | ServicePlan.Name: '{{#toAlphaNumericString repositoryName 45}}{{/toAlphaNumericString}}-plan'
36 |
37 | # ========================================================================
38 | # Optional variables
39 | # ========================================================================
40 |
41 | ACR.ImageName: '$(ACR.Name):$(Build.BuildId)'
42 | ACR.FullName: '$(ACR.Name).azurecr.io'
43 | ACR.Sku: 'Standard'
44 | Azure.CreateResources: 'true' # Update Azure.CreateResources to false if you have already created resources like resource group and azure container registry.
45 | System.Debug: 'false'
46 |
47 | jobs:
48 |
49 | - job: CreateResources
50 | displayName: Create resources
51 | condition: and(succeeded(), eq(variables['Azure.CreateResources'], 'true'))
52 |
53 | pool:
54 | {{ pool }}
55 |
56 | steps:
57 | - task: AzureResourceGroupDeployment@2
58 | displayName: 'Azure Deployment:Create Azure Container Registry, Azure WebApp Service'
59 | inputs:
60 | azureSubscription: '$(Azure.ServiceConnectionId)'
61 | resourceGroupName: '$(Azure.ResourceGroupName)'
62 | location: '$(Azure.Location)'
63 | templateLocation: 'URL of the file'
64 | csmFileLink: 'https://raw.githubusercontent.com/Microsoft/azure-pipelines-yaml/master/templates/resources/arm/functionapp.json'
65 | overrideParameters: '-registryName "$(ACR.Name)" -registryLocation "$(Azure.Location)" -functionAppName "$(FunctionApp.Name)" -hostingPlanName "$(ServicePlan.Name)" -storageAccountName "$(StorageAccount.Name)"'
66 |
67 | - job: BuildImage
68 | displayName: Build
69 | dependsOn: CreateResources
70 | condition: or(succeeded(), ne(variables['Azure.CreateResources'], 'true'))
71 |
72 | pool:
73 | {{ pool }}
74 |
75 | steps:
76 | - task: Docker@1
77 | displayName: 'Build an image'
78 | inputs:
79 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
80 | azureContainerRegistry: '$(ACR.FullName)'
81 | imageName: '$(ACR.ImageName)'
82 | command: build
83 | dockerFile: '**/Dockerfile'
84 |
85 | - task: Docker@1
86 | displayName: 'Push an image'
87 | inputs:
88 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
89 | azureContainerRegistry: '$(ACR.FullName)'
90 | imageName: '$(ACR.ImageName)'
91 | command: push
92 |
93 | - job: DeployApp
94 | displayName: Deploy
95 | dependsOn: BuildImage
96 | condition: succeeded()
97 |
98 | pool:
99 | {{ pool }}
100 |
101 | steps:
102 | - task: AzureFunctionAppContainer@1
103 | displayName: 'Azure Function App on Container Deploy: $(FunctionApp.Name)'
104 | inputs:
105 | azureSubscription: '$(Azure.ServiceConnectionId)'
106 | appName: $(FunctionApp.Name)
107 | imageName: '$(ACR.FullName)/$(ACR.ImageName)'
108 |
--------------------------------------------------------------------------------
/design/deprecated/container-steps-implementation.md:
--------------------------------------------------------------------------------
1 | # Container Steps Implementation
2 |
3 | **Important note**
4 | This design doc exists for historical interest and possible future implementation.
5 | Azure Pipelines currently has no plans to build this feature.
6 | For a workload like this, we currently recommend customers use `- script: docker run ` steps.
7 |
8 | ## Overview and Requirements
9 |
10 | - Container steps should be an abstraction of what the actual technology is used
11 | - We're going to start with Docker containers running on the host
12 | - When we enable a Kubernetes pool provider, this would have to work
13 | - One command, and one container per step
14 | - Don't re-use containers between steps
15 | - Container creation is fast, so use that fact in our favor
16 | - Simpler mental model; user avoids needing to worry about cleaning up resources between steps
17 | - Begin support on Linux. As we continue our internal testing, we'll investigate and test support for Windows Containers
18 | - Sane defaults, but let the user override those defaults to enable more advanced scenarios
19 |
20 | ## Inputs
21 |
22 | |Name|Type|Required|Description|
23 | |---|---|---|---|
24 | |image|string|true|The name of the image to run the command (e.g. ubuntu or microsoft/dotnet-samples:latest)|
25 | |cmd|string[]|false|The command that is passed to the entry point (e.g. build or echo Hello World)|
26 | |entrypoint|string|false|The entry point|
27 | |env|string[]|false|A list of key-value pairs in this format: key=value. Each env var goes in its own line.|
28 | |uid|int|false|The UID used to run the command as (unset: default UID)|
29 | |workspace|string|false|The agent workspace path to map (unset: map to a known, consistent location)|
30 |
31 | ## Agent plugin, or TS task?
32 |
33 | - We can implement the container steps feature in two ways:
34 | - As an agent plugin, in C#
35 | - As a task, in TypeScript
36 |
37 | Both have their advantages and disadvantages. The current prototype is currently being written as an agent plugin, but can later be written as a task if we think it would be better over the long term.
38 |
39 | ## Agent plugin architecture
40 |
41 | - Module: Agent.Plugins
42 | - Namespace: Agent.Plugins.RunInContainer
43 |
44 | |Class Name|Description|
45 | |---|---|
46 | |`RunInContainerPlugin`|Agent plugin which calls the appropriate CLI manager to run a command in a container (for now, Docker)|
47 | |`DockerCliManager`|Helper class, which encapsulates the logic to build the command line to run `docker run` with the right image, environment variables, etc.|
48 |
49 | ## Environment variables
50 |
51 | `Docker run` supports passing in environment variables in two ways:
52 | - Using a set of -e flags (e.g. `-e foo=bar -e foo2=bar2`)
53 | - Saving a list of env vars in a file, and reference it with the --env-file flag (e.g. `--env-file env.list`)
54 |
55 | Using the --env-file would be the preferred option as it avoids two problems:
56 | - Having the risk of exposing secrets in log files
57 | - Running into a command line length limit
58 |
59 | ## Workspace mappings and file permissions
60 |
61 | The user that runs inside the agent may not be the same as the user that runs inside the container.
62 | Given this, the agent infrastructure should take special care with file permissions, to ensure that files created by the agent are accessible from the container, and vice versa.
63 |
64 | One option is to ensure that the root workspace folder is accessible by both the agent user and container user. This requires knowing the UID of both the user running in the agent, and the container in advance.
65 |
66 | The other option is to force the UIDs for both the agent and container to be the same. This would imply running a step as a custom UID is not supported.
67 |
68 | ## \#\#[vso… support
69 |
70 | \#\#[vso… variables are a mechanism for steps to output information back to the agent. Because these variables may contain paths, we want to consider the case where the path representing the resource inside the container is different than the path outside the container, in the agent at the host level.
71 |
72 | - **Don't support \#\#[vso… commands inside the container steps at all**
73 | - Easiest to implement, but most restrictive to user scenarios
74 | - **Support \#\#[vso… commands, but do not attempt path translation**
75 | - Medium complexity, user would need to keep in mind that paths are not being translated if workspace was overridden
76 | - **Support \#\#[vso… commands, and perform path translation**
77 | - Most complicated to implement, and also we can fall into the risk of mis-translating vars that look like paths but they're not in reality
78 |
79 | Tentative suggestion: We can start out by not supporting \#\#[vso… variables, and later on see if adding support is beneficial for our customer workflows.
80 |
81 | ## Resources
82 |
83 | `Docker run`: https://docs.docker.com/engine/reference/commandline/run
84 |
--------------------------------------------------------------------------------
/templates/icons/svg/php.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/icons/svg/aspdotnet.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/templates/icons/svg/dotnetcore.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/design/each-expression.md:
--------------------------------------------------------------------------------
1 | # "Each" Template Expression
2 |
3 | ## Scenarios
4 |
5 | ### Scenario: Wrap steps
6 |
7 | For example, consider the following template:
8 |
9 | ```yaml
10 | parameters:
11 | jobs: []
12 |
13 | jobs:
14 | - ${{ each job in parameters.jobs }}: # Each job
15 | - job: ${{ job.job }} # Copy the job properties
16 | displayName: ${{ job.displayName }}
17 | ${{ if job.dependsOn }}:
18 | dependsOn: ${{ job.dependsOn }}
19 | ${{ if job.condition }}:
20 | condition: ${{ job.condition }}
21 | ${{ if job.strategy }}:
22 | strategy: ${{ job.strategy }}
23 | ${{ if job.continueOnError }}:
24 | continueOnError: ${{ job.continueOnError }}
25 | ${{ if job.timeoutInMinutes }}:
26 | timeoutInMinutes: ${{ job.timeoutInMinutes }}
27 | ${{ if job.cancelTimeoutInMinutes }}:
28 | cancelTimeoutInMinutes: ${{ job.cancelTimeoutInMinutes }}
29 | ${{ if job.container }}:
30 | container: ${{ job.container }}
31 | ${{ if job.variables }}:
32 | variables: ${{ job.variables }}
33 | ${{ if job.pool }}:
34 | pool: ${{ job.pool }}
35 | ${{ if job.workspace }}:
36 | workspace: ${{ job.workspace }}
37 | steps: # Inject steps
38 | - task: SetupMyBuildTools@1 # Pre steps
39 | - ${{ job.steps }} # Users steps
40 | - task: PublishMyTelemetry@1 # Post steps
41 | condition: always()
42 | ```
43 |
44 | We can shorten the example above, by leveraging an `each` expression to iterate over the job mapping itself:
45 |
46 | ```yaml
47 | parameters:
48 | jobs: []
49 |
50 | jobs:
51 | - ${{ each job in parameters.jobs }}: # Each job
52 | - ${{ each pair in job }}: # Insert all properties other than "steps"
53 | ${{ if ne(pair.key, 'steps') }}:
54 | ${{ pair.key }}: ${{ pair.value }}
55 | steps: # Wrap the steps
56 | - task: SetupMyBuildTools@1 # Pre steps
57 | - ${{ job.steps }} # Users steps
58 | - task: PublishMyTelemetry@1 # Post steps
59 | condition: always()
60 | ```
61 |
62 | ### Scenario: Wrap jobs
63 |
64 | For example, consider the following template:
65 |
66 | ```yaml
67 | parameters:
68 | jobs: []
69 |
70 | jobs:
71 | - job: CredScan # Cred scan first
72 | pool: MyCredScanPool
73 | steps:
74 | - task: MyCredScanTask@1
75 | - ${{ each job in parameters.jobs }}: # Then each job
76 | - job: ${{ job.job }}
77 | dependsOn: # Inject dependency
78 | - CredScan
79 | - ${{ if job.dependsOn }}:
80 | - ${{ job.dependsOn }}
81 | ${{ if job.displayName }}: # Copy all other job properties
82 | displayName: ${{ job.displayName }}
83 | ${{ if job.condition }}:
84 | condition: ${{ job.condition }}
85 | ${{ if job.strategy }}:
86 | strategy: ${{ job.strategy }}
87 | ${{ if job.continueOnError }}:
88 | continueOnError: ${{ job.continueOnError }}
89 | ${{ if job.timeoutInMinutes }}:
90 | timeoutInMinutes: ${{ job.timeoutInMinutes }}
91 | ${{ if job.cancelTimeoutInMinutes }}:
92 | cancelTimeoutInMinutes: ${{ job.cancelTimeoutInMinutes }}
93 | ${{ if job.container }}:
94 | container: ${{ job.container }}
95 | ${{ if job.variables }}:
96 | variables: ${{ job.variables }}
97 | ${{ if job.pool }}:
98 | pool: ${{ job.pool }}
99 | ${{ if job.workspace }}:
100 | workspace: ${{ job.workspace }}
101 | ${{ if job.steps }}:
102 | steps: ${{ job.steps }}
103 | ```
104 |
105 | We can shorten the example above, by leveraging an `each` expression to iterate over the job mapping itself:
106 |
107 | ```yaml
108 | parameters:
109 | jobs: []
110 |
111 | jobs:
112 | - job: CredScan # Cred scan first
113 | pool: MyCredScanPool
114 | steps:
115 | - task: MyCredScanTask@1
116 | - ${{ each job in parameters.jobs }}: # Then each job
117 | - ${{ each pair in job }}: # Insert all properties other than "dependsOn"
118 | ${{ if ne(pair.key, 'dependsOn') }}:
119 | ${{ pair.key }}: ${{ pair.value }}
120 | dependsOn: # Inject dependency
121 | - CredScan
122 | - ${{if job.dependsOn}}:
123 | - ${{ job.dependsOn }}
124 | ```
125 |
126 | ## Syntax details
127 |
128 | ### Iterative sequence insertion
129 |
130 | Scenarios are listed above.
131 |
132 | Technical syntax example:
133 |
134 | ```yaml
135 | mySequence:
136 | - outer pre
137 | - ${{ each myItem in parameters.myCollection }}:
138 | - nested pre
139 | - ${{ myItem }}
140 | - nested post
141 | - outer post
142 | ```
143 |
144 | ## Iterative mapping insertion
145 |
146 | A real scenario is detailed above. See the shortened example, for the first scenario.
147 |
148 | Technical syntax example:
149 |
150 | ```yaml
151 | parameters:
152 | myCollection:
153 | - key: myKey1
154 | value: my value 1
155 | - key: myKey2
156 | value: my value 2
157 | myMapping:
158 | outer pre: abc
159 | ${{ each myItem in parameters.myCollection }}: # Each key-value pair in the mapping
160 | pre_${{ myItem.key }}: pre ${{ myItem.value }}
161 | ${{ myItem.key }}: ${{ myItem.Value }}
162 | outer post: def
163 | ```
164 |
--------------------------------------------------------------------------------
/design/readonly-variables.md:
--------------------------------------------------------------------------------
1 | # Read-only variables
2 |
3 | Pipeline variables are little bits of data which help tasks/scripts in a pipeline decide what work to perform.
4 | For example, we make the triggering reason available as a variable called `Build.Reason`.
5 | Variables are exposed to tasks/scripts by making them available as environment variables.
6 | Scripts and tasks can also create new variables or update the contents of existing ones.
7 |
8 | ## The problems with variables
9 |
10 | Creating new variables is not a problem.
11 | Mutating existing ones, however, can be problematic:
12 | - A step can accidentally or maliciously clobber another step's variable, changing future steps' behavior
13 | - Similarly, a system variable can have its contents changed, altering behavior
14 | - Because of the mechanism for setting variables ([logging commands](https://docs.microsoft.com/azure/devops/pipelines/scripts/logging-commands)), using a feature like `set -x` can cause a variable to get its intended contents plus a spurious `'` at the end
15 | - Steps can accidentally or maliciously overwrite important shell variables like `TEMP`, altering the agent's behavior
16 |
17 | We can imagine scenarios where a poorly-secured step in a pipeline could allow for an injection attack against another step / job.
18 | It's important to close this gap as much as possible, without wrecking the ability to pass data between steps.
19 |
20 | ## Solution: make variables readonly
21 |
22 | Many of these problems can be fixed, or at least partially mitigated, by marking some variables as readonly.
23 | In fact, we document that this is the case for system-injected pipeline variables, but don't actually enforce it today.
24 |
25 | A readonly variable can be set once, then its contents cannot be changed using `##vso[task.setVariable]`.
26 | Any attempt to do so generates a warning.
27 | (This is to help with troubleshooting, in case there are tasks/scripts relying on the older behavior.)
28 | The warning will be something like:
29 | > `VariableName` is read-only and can't be changed.
30 |
31 | Azure Pipelines itself can still change variables.
32 | For instance, if the build name is changed using the appropriate logging command, then `Build.BuildNumber` may be changed to reflect that.
33 |
34 | All of the following should be readonly:
35 | - All system variables (whether from the server or agent) - this includes `System.`, `Agent.`, `Build.`, and so on
36 | - Output variables (those set using `isOutput=true`)
37 | - Queue-time variables
38 | - Task- and script-created variables with a new setting, `isReadonly=true`
39 | - YAML-described variables created with a new property, `readonly: true`
40 |
41 | ## Example
42 |
43 | This example YAML shows all the kinds of readonly variables.
44 |
45 | ```yaml
46 | variables:
47 | - name: first
48 | value: one
49 | readonly: true # new syntax marking this variable readonly
50 |
51 | steps:
52 | - script: echo "##vso[task.setVariable variable=second;isReadonly=true]two"
53 | displayName: Set a readonly variable from a script/task
54 | - script: echo "##vso[task.setVariable variable=third;isOutput=true]three"
55 | displayName: Output variables are automatically readonly
56 | - script: echo Another readonly variable is $(Build.SourcesDirectory)
57 | displayName: System variables are readonly
58 | # not pictured: queue-time variables that came from the server
59 | # are also readonly
60 | ```
61 |
62 | ## Enforcement
63 |
64 | For variables marked readonly, the agent should refuse to update them.
65 | Additionally, if the server is asked to update these variables by the agent, it should also refuse.
66 |
67 | ## Not covered
68 |
69 | This feature does not address the scenario where a pipeline variable overwrites an important shell environment variable (think `TEMP`/`TMP`, `PATH`, etc.).
70 | This feature only covers which pipeline variables are readonly.
71 | A sufficiently paranoid pipeline author could implement a pattern like the following:
72 |
73 | ```yaml
74 | steps:
75 | - script: echo "##vso[task.setVariable variable=PATH;isReadonly=true]$PATH"
76 | displayName: Preserve the initial value of PATH
77 | ```
78 |
79 | Then all subsequent steps will get the frozen copy of `PATH`.
80 |
81 | A future feature may be needed to address not clobbering existing environment variables.
82 |
83 | ## Safe deployment
84 |
85 | There's not a lot of support or telemetry for detecting how widely our customers depend on current behavior.
86 | Therefore, we need to put this behind a feature flag and roll it out safely.
87 | Ideally this is a server-side feature flag, but if we need an agent-side setting as well, that's acceptable.
88 |
89 | Plan:
90 | - Sprint _X_: When the flag is on, warn in situations where a variable would be overwritten.
91 | Turning off the feature flag turns off this warning (to fix situations where a customer is overwhelmed with warnings).
92 | - Sprint _X+1_: When the flag is on, variables cannot be overwritten.
93 | Turning off the flag turns off the behavior but does _not_ turn off the warning.
94 | - Sprint _X+2_: Remove feature flag.
95 |
96 | ## On-prem considerations
97 |
98 | An older TFS server may be using a newer agent.
99 | The older TFS server knows nothing about readonly variables.
100 | Those variables may remain mutable since the agent is taking its cues from the server.
101 |
--------------------------------------------------------------------------------
/design/sidecar-containers.md:
--------------------------------------------------------------------------------
1 | # "Sidecar" or "multi-container" support
2 |
3 | An emerging pattern is the need for a "sidecar container".
4 | Run your build and tests in a container, and they need the support of one or more other containers to complete.
5 | Concrete scenario: Django is a Python-based web framework.
6 | They support 5 different database backends out of the box.
7 | So, a complete run of their test suite needs to happen against Postgres, MySQL, Microsoft SQL Server, Oracle, and MariaDB.
8 |
9 | This is one of the problems that [Docker Compose](https://docs.docker.com/compose/) exists to solve.
10 | We could let the user specify a Docker Compose file directly, but Docker Compose is too general.
11 | We don't need multiple networks, deployment constraints, replicas, and restart policies.
12 | Instead, we embed a mini-config inspired by Docker Compose v3 but without the overly general parts.
13 |
14 | ## Syntax
15 |
16 | This example assumes we introduce inline container resource definitions.
17 | We would also support our existing, separate-resource syntax.
18 |
19 | ```yaml
20 | jobs:
21 | - job: MyJob
22 | pool:
23 | container:
24 | image: python:latest
25 | name: python-builder
26 |
27 | ## Multi-container support here
28 | services:
29 | redis:
30 | image: redis:alpine
31 | ports:
32 | - "6379"
33 | postgres:
34 | image: postgres:9.4
35 | volumes:
36 | - db-data:/var/lib/postgresql/data
37 | env:
38 | FOO: bar
39 | ## End multi-container
40 |
41 | steps:
42 | - script: ...
43 | displayName: Run tests
44 | ```
45 | We would spin up the sidecar containers and make sure they're networked together with the main `python-builder` container.
46 |
47 | ### Syntax note
48 |
49 | Docker Compose allows a second syntax for environment variables and uses the key `environment`.
50 | For consistency, I elected to stick with what we use everywhere else in Azure Pipelines: `env`.
51 |
52 | ## Requirements
53 |
54 | We support spinning up one or more sidecar containers when the job starts.
55 | The job itself may be in a container as well, or it may be running on the host.
56 | Tasks and scripts must be able to access the network services offered by the sidecar containers.
57 | All the containers that Azure Pipelines knows about will be on a shared Docker network.
58 | Also, we must be able to map in somewhat arbitrary bind mounts.
59 |
60 | ### Networking for container jobs
61 |
62 | A container job can access the other containers by hostname.
63 | Ports specified in the container are automatically exposed.
64 | `redis-cli -h redis ping` should work, assuming there's a container whose resource name is `redis`.
65 |
66 | ### Networking for host jobs
67 |
68 | For a host job, we can't rely on Docker DNS for name resolution.
69 | Customers can specify host:container port maps and then use the host port:
70 | If the portspec is `- "8080:80"`, `curl localhost:8080` should work.
71 |
72 | If multiple agents run on a single host, hard mapping to ports can cause conflicts.
73 | Instead, customers should use ephemeral port maps: `- 6379` which will cause the host to pick a random, unused port number.
74 | We'll provide environment variables which let the host know where to access services.
75 | `redis-cli -h localhost -p $(agent.services.redis.ports.6379) ping` would be expected to work.
76 |
77 | ### Storage
78 |
79 | Of the many volume formats Docker Compose offers, we'll implement three:
80 | - Bind mounts from host: `/opt/data:/var/lib/mysql`
81 | - Randomly-named bind mounts: `/var/lib/mysql` - fewer use cases for this, but no reason to block it
82 | - Named volumes: `datavolume:/var/lib/mysql` - good for sharing data across several containers as well as persisting data on a private agent
83 |
84 | There is no need to implement the "long" syntax.
85 |
86 | ## Industry considerations
87 |
88 | CircleCI has something like this.
89 | ```yaml
90 | version: 2
91 | jobs:
92 | build:
93 | working_directory: ~/mern-starter
94 | # The primary container is an instance of the first image listed. The job's commands run in this container.
95 | docker:
96 | - image: circleci/node:4.8.2-jessie
97 | # The secondary container is an instance of the second listed image which is run in a common network where ports exposed on the primary container are available on localhost.
98 | - image: mongo:3.4.4-jessie
99 | ```
100 |
101 | Drone.io's config file is ["a superset of Docker Compose"](http://docs.drone.io/getting-started/#configuration), so they get this for free.
102 | ```yaml
103 | pipeline:
104 | build:
105 | image: golang
106 | commands:
107 | - go get
108 | - go build
109 | - go test
110 |
111 | services:
112 | postgres:
113 | image: postgres:9.4.5
114 | environment:
115 | - POSTGRES_USER=myapp
116 | ```
117 |
118 | ## Other notes
119 | In the future, we could support Docker Compose files directly.
120 | Starting small allows us to constrain the capabilities and retain flexibility.
121 | For simple scenarios, something inline in the pipeline is preferable.
122 |
123 | The need for multiple containers starts to break into deployment scenarios as well.
124 | While this is a pure build'n'test play, we assume the deployment side will also want to read like a Docker Compose file.
125 | This maintains a common vocabulary and fewer distinct concepts.
126 |
--------------------------------------------------------------------------------
/templates/deploy-to-existing-kubernetes-cluster.yml:
--------------------------------------------------------------------------------
1 | # Deploy to Azure Kubernetes Service
2 | # Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 |
13 | # Container registry service connection established during pipeline creation
14 | dockerRegistryServiceConnection: '{{ containerRegistryConnection.Id }}'
15 | imageRepository: '{{#toAlphaNumericString imageRepository 50}}{{/toAlphaNumericString}}'
16 | containerRegistry: '{{ containerRegistryConnection.Authorization.Parameters.loginServer }}'
17 | dockerfilePath: '**/Dockerfile'
18 | tag: '$(Build.BuildId)'
19 | imagePullSecret: '{{#toAlphaNumericString containerRegistryConnection.Name 50}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}-auth'
20 |
21 | # Agent VM image name
22 | vmImageName: 'ubuntu-latest'
23 |
24 | {{#if reviewApp}}
25 | # Name of the new namespace being created to deploy the PR changes.
26 | k8sNamespaceForPR: 'review-app-$(System.PullRequest.PullRequestId)'
27 | {{/if}}
28 |
29 | stages:
30 | - stage: Build
31 | displayName: Build stage
32 | jobs:
33 | - job: Build
34 | displayName: Build
35 | pool:
36 | vmImage: $(vmImageName)
37 | steps:
38 | - task: Docker@2
39 | displayName: Build and push an image to container registry
40 | inputs:
41 | command: buildAndPush
42 | repository: $(imageRepository)
43 | dockerfile: $(dockerfilePath)
44 | containerRegistry: $(dockerRegistryServiceConnection)
45 | tags: |
46 | $(tag)
47 |
48 | - upload: manifests
49 | artifact: manifests
50 |
51 | - stage: Deploy
52 | displayName: Deploy stage
53 | dependsOn: Build
54 |
55 | jobs:
56 | - deployment: Deploy
57 | {{#if reviewApp}}
58 | condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
59 | {{/if}}
60 | displayName: Deploy
61 | pool:
62 | vmImage: $(vmImageName)
63 | environment: '{{ k8sResource.EnvironmentReference.Name }}.{{ k8sResource.Name }}'
64 | strategy:
65 | runOnce:
66 | deploy:
67 | steps:
68 | - task: KubernetesManifest@0
69 | displayName: Create imagePullSecret
70 | inputs:
71 | action: createSecret
72 | secretName: $(imagePullSecret)
73 | dockerRegistryEndpoint: $(dockerRegistryServiceConnection)
74 |
75 | - task: KubernetesManifest@0
76 | displayName: Deploy to Kubernetes cluster
77 | inputs:
78 | action: deploy
79 | manifests: |
80 | $(Pipeline.Workspace)/manifests/deployment.yml
81 | $(Pipeline.Workspace)/manifests/service.yml
82 | imagePullSecrets: |
83 | $(imagePullSecret)
84 | containers: |
85 | $(containerRegistry)/$(imageRepository):$(tag)
86 |
87 | {{#if reviewApp}}
88 | - deployment: DeployPullRequest
89 | displayName: Deploy Pull request
90 | condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/pull/'))
91 | pool:
92 | vmImage: $(vmImageName)
93 |
94 | environment: '{{ k8sResource.EnvironmentReference.Name }}.$(k8sNamespaceForPR)'
95 | strategy:
96 | runOnce:
97 | deploy:
98 | steps:
99 | - reviewApp: {{ k8sResource.Name }}
100 |
101 | - task: Kubernetes@1
102 | displayName: 'Create a new namespace for the pull request'
103 | inputs:
104 | command: apply
105 | useConfigurationFile: true
106 | inline: '{ "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "$(k8sNamespaceForPR)" }}'
107 |
108 | - task: KubernetesManifest@0
109 | displayName: Create imagePullSecret
110 | inputs:
111 | action: createSecret
112 | secretName: $(imagePullSecret)
113 | namespace: $(k8sNamespaceForPR)
114 | dockerRegistryEndpoint: $(dockerRegistryServiceConnection)
115 |
116 | - task: KubernetesManifest@0
117 | displayName: Deploy to the new namespace in the Kubernetes cluster
118 | inputs:
119 | action: deploy
120 | namespace: $(k8sNamespaceForPR)
121 | manifests: |
122 | $(Pipeline.Workspace)/manifests/deployment.yml
123 | $(Pipeline.Workspace)/manifests/service.yml
124 | imagePullSecrets: |
125 | $(imagePullSecret)
126 | containers: |
127 | $(containerRegistry)/$(imageRepository):$(tag)
128 |
129 | - task: Kubernetes@1
130 | name: get
131 | displayName: 'Get services in the new namespace'
132 | continueOnError: true
133 | inputs:
134 | command: get
135 | namespace: $(k8sNamespaceForPR)
136 | arguments: svc
137 | outputFormat: jsonpath='http://{.items[0].status.loadBalancer.ingress[0].ip}:{.items[0].spec.ports[0].port}'
138 |
139 | # Getting the IP of the deployed service and writing it to a variable for posing comment
140 | - script: |
141 | url="$(get.KubectlOutput)"
142 | message="Your review app has been deployed"
143 | if [ ! -z "$url" -a "$url" != "http://:" ]
144 | then
145 | message="${message} and is available at $url.
[Learn More](https://aka.ms/testwithreviewapps) about how to test and provide feedback for the app."
146 | fi
147 | echo "##vso[task.setvariable variable=GITHUB_COMMENT]$message"
148 | {{/if}}
149 |
--------------------------------------------------------------------------------
/design/step-target.md:
--------------------------------------------------------------------------------
1 | # Step Target
2 |
3 | Today, steps run either on the agent host or, if the step is part of a [container job](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/container-phases?view=azure-devops&tabs=yaml), inside of the container specified on the job.
4 | All steps in a job run in one context; separate steps cannot target different contexts throughout the job.
5 | Additionally, steps cannot target [services containers](./sidecar-containers.md) at all.
6 |
7 | The goal of a step target is to give the pipeline author flexibility in where a given step in the job runs.
8 | This provides additional flexibility for pipeline authors and template authors.
9 |
10 | ## Scenarios
11 |
12 | 1. Some of my steps need to run on the host, while others need to run in a job container for isolation purposes.
13 | (For more on isolation, see the [step target "safe mode"](step-target-safe-mode.md) spec.)
14 | 2. I need to run specific steps inside specific service containers for configuration purposes.
15 |
16 | ## YAML syntax
17 |
18 | **Example:** a container job using [services](./sidecar-containers.md) with one step targeting a service container.
19 |
20 | In the example below we see a single job that defined two service containers as well as a job container.
21 |
22 | * The first step in the job targets the `postgres` service container in order to run some sort of configuration script.
23 | * The second step runs in the `python-builder` container that is specified as part of the `container:` property for the job.
24 | * The third step targets the host machine where the agent is running.
25 |
26 | ```yaml
27 | jobs:
28 | - job: MyJob
29 | container:
30 | image: python:latest
31 | name: python-builder
32 |
33 | ## Multi-container support here
34 | services:
35 | redis:
36 | image: redis:alpine
37 | ports:
38 | - "6379"
39 | postgres:
40 | image: postgres:9.4
41 | volumes:
42 | - db-data:/var/lib/postgresql/data
43 | env:
44 | FOO: bar
45 | ## End multi-container
46 |
47 | steps:
48 | - script: ...
49 | displayName: Configure postrgres
50 | target: postgres # targets a service container
51 | - script: ...
52 | displayName: Run tests
53 | # no target, so targets the default (in this case, job container)
54 | - script: ...
55 | target: host # targets the host - another reserved word like "self"
56 |
57 | ```
58 |
59 | ## A more complicated example
60 |
61 | In this example, we run some steps on the host and others in a container.
62 | The user's template is considered "untrusted" code, so all passed-in steps are rewritten to target the container.
63 | Also, we pre-configure the container so that it has no network access.
64 |
65 | * The `azure-pipelines.yml` pipeline file specifies one job that is derived from a job template. Here we see the consumer of that template passing in an enture job definition including a contaienr and two steps.
66 | * The `jobs-template.yml` loops over all of the parameters in the template and all of the jobs and applies the `job-template.yml` to it.
67 | * In the `job-template.yml` we take all of the parameters and steps from the job and remap them into a job that has a step that targets the host that first removes the network from the job container in order to make sure that when the steps run they do not have access to any external network resources. Then we loop over each step and create new steps from he properties explicilty omitting the `target:` property so they are limited to only targeting the job container.
68 |
69 | ```yaml
70 | ## job-template.yml
71 | parameters:
72 | # Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
73 | cancelTimeoutInMinutes: ''
74 | condition: ''
75 | continueOnError: false
76 | container: ''
77 | dependsOn: ''
78 | displayName: ''
79 | steps: []
80 | pool: ''
81 | strategy: ''
82 | timeoutInMinutes: ''
83 | variables: []
84 | workspace: ''
85 |
86 | - jobs
87 | job: ${{ parameters.name }}
88 | # common jobs parameters
89 | steps:
90 | # remove the docker network from the job container need an easy way to determine the job network and job container
91 | - script: docker network disconnect
92 | target: host # reserved name for the host the worker is running on
93 |
94 | # copy each proerty from each step skipping the target property
95 | - ${{ each step in parameters.steps }}:
96 | ${{ each property in step }}:
97 | ${{ if ne(property.key, 'target') }}:
98 | ${{ property.key }}: ${{ property.value }}
99 |
100 | ## jobs-template.yml
101 | parameters:
102 | jobs: []
103 |
104 | jobs:
105 | - ${{ each job in parameters.jobs }}:
106 | - template: ./job-template.yml
107 | parameters:
108 | # pass along parameters
109 | ${{ each parameter in parameters }}:
110 | ${{ if ne(parameter.key, 'jobs') }}:
111 | ${{ parameter.key }}: ${{ parameter.value }}
112 |
113 | # pass along job properties
114 | ${{ each property in job }}:
115 | ${{ if ne(property.key, 'job') }}:
116 | ${{ property.key }}: ${{ property.value }}
117 |
118 | name: ${{ job.job }}
119 |
120 | ## azure-pipelines.yml
121 |
122 | resources:
123 | containers:
124 | - container: mycontianer
125 | image: org/mycontainer:stable
126 |
127 | jobs:
128 | - template: /templates/jobs-template.yml
129 | parameters:
130 | jobs:
131 | - job: MyBuild
132 | container: mycontainer
133 | steps:
134 | - script: ...
135 | - script: ...
136 | ```
137 |
138 |
139 |
140 | ## Future work
141 |
142 | - Need a standard way to get the name of the job network and the job container (probably pipeline variables)
143 | - Service containers need a way to map the `workspace` like the job container does
144 |
--------------------------------------------------------------------------------
/templates/docker-container-to-aks.yml:
--------------------------------------------------------------------------------
1 | # Docker image, Azure Container Registry, and Azure Kubernetes Service
2 | # Build a Docker image, push it to an Azure Container Registry, and deploy it to Azure Kubernetes Service.
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - {{ branch }}
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | # ========================================================================
13 | # Mandatory variables
14 | # ========================================================================
15 |
16 | # Update Azure.ResourceGroupName value with Azure resource group name.
17 | Azure.ResourceGroupName: '{{#toAlphaNumericString repositoryName 50}}{{/toAlphaNumericString}}'
18 |
19 | # Update Azure.ServiceConnectionId value with AzureRm service endpoint.
20 | Azure.ServiceConnectionId: '{{ azureServiceConnectionId }}'
21 |
22 | # Update Azure.Location value with Azure Location.
23 | Azure.Location: 'eastus'
24 |
25 | # Update ACR.Name value with ACR name. Please note ACR names should be all lower-case and alphanumeric only.
26 | ACR.Name: '{{#toAlphaNumericString repositoryName 46}}{{/toAlphaNumericString}}{{#shortGuid}}{{/shortGuid}}'
27 |
28 | # Update AKS.ClusterName value Azure kubernetes cluster name.
29 | AKS.ClusterName: '{{#toAlphaNumericString repositoryName 32}}{{/toAlphaNumericString}}'
30 |
31 | # Docker Container port
32 | Container.Port: 5000
33 |
34 | # ========================================================================
35 | # Optional variables
36 | # ========================================================================
37 |
38 | ACR.RepositoryName: '$(ACR.Name)'
39 | ACR.ImageName: '$(ACR.Name):$(Build.BuildId)'
40 | ACR.FullName: '$(ACR.Name).azurecr.io'
41 | ACR.Sku: 'Standard'
42 | AKS.KubeDeploymentYaml: '$(System.DefaultWorkingDirectory)/KubeDeployment.yml' # Update AKS.KubeDeploymentYaml if you want to use deployment file from repo instead of generated file.
43 | AKS.DeploymentPort: '$(Container.Port)'
44 | Azure.CreateResources: 'true' # Update Azure.CreateResources to false if you have already created resources like resource group, azure container registry and azure kubernetes cluster.
45 | System.Debug: 'false'
46 |
47 | jobs:
48 |
49 | - job: CreateResources
50 | displayName: Create resources
51 | condition: and(succeeded(), eq(variables['Azure.CreateResources'], 'true'))
52 |
53 | pool:
54 | {{ pool }}
55 |
56 | steps:
57 | - task: AzureResourceGroupDeployment@2
58 | displayName: 'Azure Deployment:Create ACR and AKS'
59 | inputs:
60 | azureSubscription: '$(Azure.ServiceConnectionId)'
61 | resourceGroupName: '$(Azure.ResourceGroupName)'
62 | location: '$(Azure.Location)'
63 | templateLocation: 'URL of the file'
64 | addSpnToEnvironment: true
65 | csmFileLink: 'https://raw.githubusercontent.com/Microsoft/azure-pipelines-yaml/master/templates/resources/arm/aks.json'
66 | overrideParameters: '-registryName "$(ACR.Name)" -registryLocation "$(Azure.Location)" -servicePrincipalId $servicePrincipalId -servicePrincipalKey $servicePrincipalKey -clusterName "$(AKS.ClusterName)" -clusterLocation "$(Azure.Location)"'
67 |
68 | - job: BuildImage
69 | displayName: Build
70 | dependsOn: CreateResources
71 | condition: or(succeeded(), ne(variables['Azure.CreateResources'], 'true'))
72 |
73 | pool:
74 | {{ pool }}
75 |
76 | steps:
77 | - task: Docker@1
78 | displayName: 'Build an image'
79 | inputs:
80 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
81 | azureContainerRegistry: '$(ACR.FullName)'
82 | imageName: '$(ACR.ImageName)'
83 | command: build
84 | dockerFile: '**/Dockerfile'
85 |
86 | - task: Docker@1
87 | displayName: 'Push an image'
88 | inputs:
89 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
90 | azureContainerRegistry: '$(ACR.FullName)'
91 | imageName: '$(ACR.ImageName)'
92 | command: push
93 |
94 | - job: DeployApp
95 | displayName: Deploy
96 | dependsOn: BuildImage
97 | condition: succeeded()
98 |
99 | pool:
100 | {{ pool }}
101 |
102 | steps:
103 | - bash: |
104 | if [ -f $(AKS.KubeDeploymentYaml) ]; then
105 | echo "##vso[task.setvariable variable=AKS.KubeDeploymentYamlExists;]true"
106 | else
107 | echo "##vso[task.setvariable variable=AKS.KubeDeploymentYamlExists;]false"
108 | fi
109 | displayName: 'Check kubernetes deployment yaml exists'
110 |
111 | - bash: |
112 | echo "apiVersion : apps/v1beta1
113 | kind: Deployment
114 | metadata:
115 | name: $(ACR.RepositoryName)
116 | spec:
117 | replicas: 1
118 | template:
119 | metadata:
120 | labels:
121 | app: $(ACR.RepositoryName)
122 | spec:
123 | containers:
124 | - name: $(ACR.RepositoryName)
125 | image: $(ACR.FullName)/$(ACR.ImageName)
126 | ports:
127 | - containerPort: $(AKS.DeploymentPort)
128 | ---
129 | apiVersion: v1
130 | kind: Service
131 | metadata:
132 | name: $(ACR.RepositoryName)
133 | spec:
134 | type: LoadBalancer
135 | ports:
136 | - port: $(AKS.DeploymentPort)
137 | selector:
138 | app: $(ACR.RepositoryName)" > $(AKS.KubeDeploymentYaml)
139 | displayName: 'Generate kubernetes deployment yaml'
140 | condition: and(succeeded(), eq(variables['AKS.KubeDeploymentYamlExists'], 'False'))
141 |
142 | - task: Kubernetes@1
143 | displayName: 'kubectl apply'
144 | inputs:
145 | azureSubscriptionEndpoint: '$(Azure.ServiceConnectionId)'
146 | azureResourceGroup: '$(Azure.ResourceGroupName)'
147 | kubernetesCluster: '$(AKS.ClusterName)'
148 | arguments: '-f $(AKS.KubeDeploymentYaml)'
149 | command: 'apply'
150 |
--------------------------------------------------------------------------------
/design/deployment-strategies.md:
--------------------------------------------------------------------------------
1 | ## Deployment strategies
2 |
3 | One of the key advantages of continuous delivery of application updates is the ability to quickly push updates into production for specific microservices, giving developers the ability to respond rapidly to changing business requirements.
4 |
5 | With Azure DevOps, environments are first-class constructs, handling the underlying orchestration such as **deployment strategies**, verifying health checks, disabling old version and rolling out new version, traceability down artifact versions are key to continuous value delivery.
6 |
7 | This proposal contains a number of interconnected elements. For example, an [environment](environment.md), a [deployment](deployment.md) job, primitive building blocks, and simplified YAML syntax to enable **safe deployments** in the majority of cases. Our approach to building a deployment orchestration language for **safe deployments** will be to get the fundamental building blocks right.
8 |
9 | **runOnce**: default strategy, if not defined.
10 |
11 | ```yaml
12 | jobs:
13 | - deployment:
14 | environment: musicCarnivalProd
15 | pool:
16 | name: musicCarnivalProdPool
17 | strategy:
18 | runOnce:
19 | deploy:
20 | steps:
21 | - script: echo deploy web app...
22 | ```
23 |
24 | When deploying application updates it is important that the technique used to deliver update enables initialization, deploying the update, testing the updated version after routing traffic and in case of failure, run steps to restore to last known good version. We achieve this using fundamental building blocks viz., hooks where you can run your steps during deployment lifecycle. Each of the lifecycle hooks will be resolved into an agent, or a [server](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&tabs=yaml#server-jobs), (*or a container or validation job in future*). The lifecycle job type would be determined by the `pool` attribute. By default the lifecycle jobs will inherit the pool type specified by the `deployment`.
25 |
26 | Following are descriptions of the lifecycle events where you can run a hook during a deployment lifecycle
27 |
28 | **preDeploy** – Use to run tasks before the deploy step is executed.
29 |
30 | **Deploy** – Use to run the deploy tasks. The results of a lifecycle hook event can trigger a rollback.
31 |
32 | **routeTraffic** – Use to run tasks that serves the traffic to the updated version. The results of a lifecycle hook event can trigger a rollback.
33 |
34 | **postRouteTraffic** - Use to run the tasks after the traffic is routed. Typically these tasks monitor the health of the updated version for defined interval. The results of a lifecycle hook event can trigger a rollback.
35 |
36 | **on: Failure or Success** - Use to run the task to peform rollback actions or clean-up. The results of a lifecycle hook event doesn't trigger a rollback.
37 |
38 | Using the lifecycle hooks, we can achieve complex deployment events such as -
39 |
40 | - Canary
41 | - Rolling
42 |
43 | **Canary**: reduce the risk by slowly rolling out the change to a small subset of users.
44 | As you gain more confidence in the new version, you can start releasing it to more servers in your infrastructure
45 | and routing more users to it.
46 |
47 | Consider the following Azure Pipelines pipeline defined in YAML
48 |
49 | ```yaml
50 | jobs:
51 | - deployment:
52 | environment: musicCarnivalProd
53 | pool:
54 | name: musicCarnivalProdPool
55 | strategy:
56 | canary:
57 | increments: [10,20]
58 | preDeploy:
59 | steps:
60 | - script: initialize, cleanup....
61 | deploy:
62 | steps:
63 | - script: echo deploy updates...
64 | routeTraffic:
65 | steps:
66 | - script: echo routing traffic...
67 | postRouteTaffic:
68 | pool: server
69 | steps:
70 | - script: echo monitor application health...
71 | on:
72 | failure:
73 | steps:
74 | - script: echo perform rollback actions.
75 | success:
76 | steps:
77 | - script: echo checks passed, notify...
78 | ```
79 |
80 |
81 | **Rolling**: A rolling deployment replaces instances of the previous version of an application with instances of the new version of the application on a fixed set of machines (rolling set) in each iteration.
82 |
83 | For example, a rolling deployment typically waits for new pods to become ready via a readiness check before scaling down the old components. If a significant issue occurs, the rolling deployment can be aborted.
84 |
85 | ```yaml
86 | jobs:
87 | - deployment:
88 | environment: musicCarnivalProd
89 | pool:
90 | name: musicCarnivalProdPool
91 | strategy:
92 | rolling:
93 | maxParallel: 5
94 | preDeploy:
95 | steps:
96 | - script: echo initialize, cleanup, install certs...
97 | deploy:
98 | steps:
99 | - script: echo deploy web app...
100 | routeTraffic:
101 | steps:
102 | - script: echo swap slots...
103 | postRouteTaffic:
104 | pool: server
105 | steps:
106 | - task: appInsightsAlerts .
107 | on:
108 | failure:
109 | steps:
110 | - script: echo swap slots back..
111 | success:
112 | steps:
113 | - script: echo checks passed...
114 | ```
115 |
116 | #### Variables
117 | During execution, the jobs would have access to pre-defined system variables. For example, $(strategy), $(environment.staging), $(environment.prod), $(action), $(increments) etc.
118 |
119 | ### Virtual Machine deployment (for discussion)
120 |
121 | Azure Pipelimes supports **push** using remote script such as SSH and **pull** deployments using local agents to Virtual Machines. The proposal involves supporting **push** based deployments as first class option using remote PowerShell or SSH to Virtual Machines in the environment.
122 |
123 |
124 |
--------------------------------------------------------------------------------