Содержание

Azure DevOps

Tasks / Задачи - https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/?view=azure-pipelines
Expressions / Выражения - https://docs.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops

Переменные

https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables

Обновить переменную pipeline releases через api

  1. Добавить переменную в pipline (пример для переменной v1030)
  2. Добавить разрешений на редактирование pipeline: Pipeline → Releases → Name-Pipeline → More actions → Security → Users: Name-Project Build Service (company) → Edit release pipeline: Allow
  3. Разрешить скриптам доступ к токену OAuth: Name-Pipeline → Edit → Tasks: Name-Task → Deployment group job|Agent job → Additional options → Allow scripts to access the OAuth token: Enable
  4. Создать задачу, примрер на powershell inline:
    $url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0"
    Write-Host "URL: $url"
    $pipeline = Invoke-RestMethod -Uri $url -Headers @{
        Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
    }
    Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
     
    # Update an existing variable named v1030 to its new value 1035
    $pipeline.variables.v1030.value = "1035"
     
    ####****************** update the modified object **************************
    $json = @($pipeline) | ConvertTo-Json -Depth 99
     
     
    $updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
     
    write-host "==========================================================" 
    Write-host "The value of Varialbe 'v1030' is updated to" $updatedef.variables.v1030.value
    write-host "=========================================================="
  5. Переменная доступна как: «$(v1030)» или «$env:v1030»

Создать переменную между task

Job 1, powershell:

Write-Host "##vso[task.setvariable variable=testvar;]testvalue"

Job 2, powershell:

Write-Host "Using testvar: $($env:testvar) = $(testvar)"

https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash
https://medium.com/microsoftazure/how-to-pass-variables-in-azure-pipelines-yaml-tasks-5c81c5d31763

Версия pipeline

Установить build версию в YAML:

version: $[format('{0:yyMM}.{0:dd}.{1}.{2}', pipeline.startTime, variables['system.pullRequest.pullRequestId'], counter(format('{0:yyyyMMdd}-{1}', pipeline.startTime, variables['Build.SourceBranchName']), 1))]

Пример присвоения: 2108.07.2424.1

Обновить build версию:

echo "##vso[build.updatebuildnumber]$version"
Write-Host "##vso[build.updatebuildnumber]$version"

Обновить release версию:

echo "##vso[release.updatereleasename]$version"
Write-Host "##vso[release.updatereleasename]$version"

https://docs.microsoft.com/ga-ie/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash

Логирование

Команды ведения журнала - https://learn.microsoft.com/ru-ru/azure/devops/pipelines/scripts/logging-commands

Tag

Добавить tag на commit из pipeline:

  1. Добавить persistCredentials: true в checkout:
    steps:
    - checkout: self
      fetchDepth: 1
      clean: true
      persistCredentials: true
  2. Добавить задачу для установки tag:
    - script: |
        git tag $(tag)
        git push --tags
      workingDirectory: $(Build.SourcesDirectory)
      displayName: 'git tag $(tag)'
  3. Добавить пользователя Project Collection Build Service в Contributors:
    1. %PROJECT% → Settings → Permissions → Contributors → Members → Add
  4. Отключить опцию Limit job authorization scope to current project for non-release pipelines:
    1. %PROJECT% → Settings → Pipelines: Settings → General

Tag Pipeline

Добавить тэг migrations на pipeline

Write-Host "##vso[build.addbuildtag]migrations"

https://piotr.gg/dev-ops/add-tag-to-you-build-in-azure-devops.html

submodules

Для доступа pipeline к репозиториям в других проектах, в проекте с этим pipeline:

  1. Отключить опцию Limit job authorization scope to current project for non-release pipelines и Protect access to repositories in YAML pipelines:
    1. %PROJECT% → Settings → Pipelines: Settings → General

https://github.com/microsoftdocs/azure-devops-docs/issues/11939

Версия build

Пример добавления префикса к версии сборки в зависимости от ветки:

name: $(version)

variables:
  ${{ if contains(variables['Build.SourceBranch'],'/pull/') }}:
    version: $[format('{0}.{1}',variables['system.pullRequest.pullRequestId'],counter(variables['system.pullRequest.pullRequestId'], 0))]
  ${{ if in(variables['Build.SourceBranchName'], 'main','master') }}:
    version: $[format('{0}.{1:yyMM}.{1:dd}.{2}', variables['majorVersion'], pipeline.startTime, counter(format('{0:yyyyMMdd}-{1}', pipeline.startTime, variables['Build.SourceBranchName']), 1))]
  ${{ if and(not(contains(variables['Build.SourceBranch'], '/pull/')),notIn(variables['Build.SourceBranchName'], 'main','master')) }}:
    version: $[format('{0}.{1:yyMM}.{1:dd}.{2}-{3}', variables['majorVersion'], pipeline.startTime, counter(format('{0:yyyyMMdd}-{1}', pipeline.startTime, variables['Build.SourceBranchName']), 1), variables['Build.SourceBranchName'])]

Checkout

Checkout без --tags (в конце обязательно поставить job «git unset»):

azure-pipelines.yml

azure-pipelines.yml

steps:
- checkout: none
- script: |
    git version
    git lfs version
    git init
    git clean -fdx
    git reset --hard HEAD
    git remote add origin $(BUILD.REPOSITORY.URI)
    git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" fetch --force --prune --progress --no-recurse-submodules --depth=1 origin +$(BUILD.SOURCEVERSION):refs/remotes/origin/$(BUILD.SOURCEVERSION)
    git checkout --progress --force refs/remotes/origin/$(BUILD.SOURCEVERSION) || exit 1
    echo submodules
    git submodule sync
    git -c http.$(System.CollectionUri).extraheader="AUTHORIZATION: bearer $(System.AccessToken)" submodule update --init --force --depth=1 || exit 1
    echo persistCredentials
    git config "http.$(BUILD.REPOSITORY.URI).extraheader" "AUTHORIZATION: bearer $(System.AccessToken)" || exit 1
  workingDirectory: $(Build.SourcesDirectory)
  displayName: 'git checkout'
 
...jobs...
  
- script: |
    git config --unset-all "http.$(BUILD.REPOSITORY.URI).extraheader"
  displayName: 'git unset'
  condition: always()


https://github.com/microsoft/azure-pipelines-agent/blob/master/docs/design/percentEncoding.md

Извлечение внешнего репозитория

checkout.yaml

checkout.yaml

resources:
  repositories:
  - repository: OtherGit
    endpoint: "GIT_SERVICE_CONNECTIONS"
    name: PROJECT/REPOSITORY
    type: git
    ref: $(Build.SourceBranchName)
    fetchDepth: 1
    clean: true

steps:
- checkout: OtherGit
  submodules: true


Аутентификация через токен

Кодировать токен в base64 (добавить префикс pat:):

TOKEN64=$(echo -n "pat:${TOKEN}" | base64)

Клонировать репозиторий с помощью токена:

git -c http.extraheader="AUTHORIZATION: basic ${TOKEN64}" clone https://dev.azure.com/ORGNAME/PROJECT/_git/REPOSITORY

https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#alternative-to-using-the-checkout-submodules-option

Agent

start.sh

start.sh

#!/bin/bash
set -e
 
if [ -z "$AZP_URL" ]; then
  echo 1>&2 "error: missing AZP_URL environment variable"
  exit 1
fi
 
if [ -z "$AZP_TOKEN_FILE" ]; then
  if [ -z "$AZP_TOKEN" ]; then
    echo 1>&2 "error: missing AZP_TOKEN environment variable"
    exit 1
  fi
 
  AZP_TOKEN_FILE=/azp/.token
  echo -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fi
 
unset AZP_TOKEN
 
if [ -n "$AZP_WORK" ]; then
  mkdir -p "$AZP_WORK"
fi
 
export AGENT_ALLOW_RUNASROOT="1"
 
cleanup() {
  if [ -e config.sh ]; then
    print_header "Cleanup. Removing Azure Pipelines agent..."
 
    # If the agent has some running jobs, the configuration removal process will fail.
    # So, give it some time to finish the job.
    while true; do
      ./config.sh remove --unattended --auth PAT --token $(cat "$AZP_TOKEN_FILE") && break
 
      echo "Retrying in 30 seconds..."
      sleep 30
    done
  fi
}
 
print_header() {
  lightcyan='\033[1;36m'
  nocolor='\033[0m'
  echo -e "${lightcyan}$1${nocolor}"
}
 
# Let the agent ignore the token env variables
export VSO_AGENT_IGNORE=AZP_TOKEN,AZP_TOKEN_FILE
 
source ./env.sh
 
print_header "1. Configuring Azure Pipelines agent..."
 
./config.sh --unattended \
  --agent "${AZP_AGENT_NAME:-$(hostname)}" \
  --url "$AZP_URL" \
  --auth PAT \
  --token $(cat "$AZP_TOKEN_FILE") \
  --pool "${AZP_POOL:-Default}" \
  --work "${AZP_WORK:-_work}" \
  --replace \
  --acceptTeeEula & wait $!
 
print_header "2. Running Azure Pipelines agent..."
 
trap 'cleanup; exit 0' EXIT
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM
 
# To be aware of TERM and INT signals call run.sh
# Running it with the --once flag at the end will shut down the agent after the build is executed
./run.sh "$@"

Dockerfile

Dockerfile

FROM ubuntu:20.04
 
# To make it easier for build and release pipelines to run apt-get,
# configure apt to not require confirmation (assume the -y argument by default)
ENV DEBIAN_FRONTEND=noninteractive
RUN echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes
 
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    jq \
    git \
    iputils-ping \
    libcurl4 \
    libicu66 \
    libunwind8 \
    netcat \
    libssl1.0 \
  && rm -rf /var/lib/apt/lists/*
 
RUN curl -LsS https://aka.ms/InstallAzureCLIDeb | bash \
  && rm -rf /var/lib/apt/lists/*
 
ARG TARGETARCH=amd64
ARG AGENT_VERSION=2.191.1
 
WORKDIR /azp
RUN if [ "$TARGETARCH" = "amd64" ]; then \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz; \
    else \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-${TARGETARCH}-${AGENT_VERSION}.tar.gz; \
    fi; \
    curl -LsS "$AZP_AGENTPACKAGE_URL" | tar -xz
 
COPY ./start.sh .
RUN chmod +x start.sh
 
#adding default programs
#azcopy
RUN curl -o /tmp/azcopy.tgz https://aka.ms/downloadazcopy-v10-linux --location --max-redirs 10; \
  tar -xzvf /tmp/azcopy.tgz -C /tmp; \
  mv /tmp/azcopy*/azcopy /usr/bin/; \
  rm -rf /tmp/azcopy*
#dotnet sdk
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN  curl -o /tmp/packages-microsoft-prod.deb https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb; \
  dpkg -i /tmp/packages-microsoft-prod.deb; \
  rm /tmp/packages-microsoft-prod.deb; \
  apt-get update; \
  apt-get install -y --no-install-recommends dotnet-sdk-5.0
 
ENTRYPOINT [ "./start.sh" ]

Azure DevOps → Organization Settings → Agent pools → Add pool
Azure DevOps → User settings → Personal Access Tokens → New Token → Agent Pools: Read & Manage

docker build -t azureagent .
docker run -e AZP_URL=https://organization.visualstudio.com -e AZP_AGENT_NAME=dockeragent -e AZP_POOL=Docker -e AZP_TOKEN=secret-token --rm -d azureagent

https://docs.microsoft.com/Ru-Ru/Azure/Devops/pipelines/agents/docker?view=azure-devops

Ошибки

TLS1.2

https://github.com/microsoft/azure-devops-tls12 - скрипт для «смягчения» последствий перехода на TLS 1.2
https://stackoverflow.com/questions/70929356/azure-pipelines-local-agent-failing-to-connect-with-ssl-error
https://devblogs.microsoft.com/visualstudio/azure-devops-requires-tls-1-2-on-all-connections-including-visual-studio/

fatal: Cannot prompt because terminal prompts have been disabled.

Решение: Включить передачу токена в checkout pipeline: persistCredentials

https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/steps-checkout
Checkout