--- name: azure-devops-pipeline description: Generates Azure DevOps pipeline YAML using EKS-Pool with nonprod auto-deploy and prod manual approval gate. Always load this skill first, then load the type-specific skill before generating any YAML. --- ## What I do Guide the generation of a complete `azure-pipelines.yml` file for a self-hosted EKS-Pool Azure DevOps agent pool. I define all shared standards. You MUST also load the appropriate type skill before generating YAML: - Lambda deployments → load `azure-pipeline-lambda` - Ansible playbooks → load `azure-pipeline-ansible` - Docker builds → load `azure-pipeline-docker` ## IMPORTANT — do not generate YAML without loading a type skill STOP. Before generating any pipeline YAML, you MUST load the type skill that matches the requested pipeline type: - `azure-pipeline-lambda` for Lambda - `azure-pipeline-ansible` for Ansible - `azure-pipeline-docker` for Docker Generate nothing until that skill is loaded. ## Required inputs — ask the user for these before generating 1. **Service/repo name** — used in display names and tags 2. **Pipeline type** — `lambda` | `ansible` | `docker` 3. **Target tier** — `nonprod` | `prod` 4. **Trigger branch** — branch that triggers auto-deploy (default: `main`) 5. **Secret sources** — which are in use: `ADO variable groups` | `AWS SSM/Secrets Manager` | `Vault/OpenBao` (can be multiple) 6. **ADO variable group name(s)** — if ADO variable groups selected ## Pipeline skeleton — always use this structure ```yaml trigger: branches: include: - pool: EKS-Pool stages: - stage: Lint displayName: "Lint" jobs: - job: Lint pool: EKS-Pool timeoutInMinutes: 30 continueOnError: false steps: [] # type skill fills this in - stage: SecurityScan displayName: "Security Scan" dependsOn: Lint condition: succeeded() jobs: - job: SecurityScan pool: EKS-Pool timeoutInMinutes: 30 continueOnError: false steps: [] # type skill fills this in - stage: Build displayName: "Build" dependsOn: SecurityScan condition: succeeded() jobs: - job: Build pool: EKS-Pool timeoutInMinutes: 30 continueOnError: false steps: [] # type skill fills this in - stage: DeployNonprod displayName: "Deploy — Nonprod" dependsOn: Build condition: succeeded() jobs: - deployment: DeployNonprod displayName: "Deploy to Nonprod" pool: EKS-Pool timeoutInMinutes: 30 environment: nonprod strategy: runOnce: deploy: steps: [] # type skill fills this in - stage: DeployProd displayName: "Deploy — Prod" dependsOn: DeployNonprod condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/')) jobs: - deployment: DeployProd displayName: "Deploy to Prod" pool: EKS-Pool timeoutInMinutes: 30 environment: prod # manual approval gate configured in ADO environment settings strategy: runOnce: deploy: steps: [] # type skill fills this in + git tag step below ``` ## Prod tier pipelines When `target tier` is `prod`, omit `DeployNonprod` entirely. The pipeline contains only `Lint` → `SecurityScan` → `Build` → `DeployProd` with the manual approval gate. When `target tier` is `nonprod`, omit `DeployProd` entirely. ## Git tagging on prod deploy Add this as the final step inside `DeployProd`'s steps (prod tier only): ```yaml - script: | git config user.email "azdo-pipeline@$(System.TeamProject)" git config user.name "Azure DevOps Pipeline" git remote set-url origin "https://x-token:$(System.AccessToken)@$(echo $BUILD_REPOSITORY_URI | sed 's|https://||')" git tag $(Build.BuildNumber) $(Build.SourceVersion) git push origin $(Build.BuildNumber) displayName: "Tag commit with build number" env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) BUILD_REPOSITORY_URI: $(Build.Repository.Uri) ``` ## Secret handling patterns Emit the correct block(s) based on declared secret sources: ### ADO variable groups ```yaml variables: - group: ``` Reference values as `$(VAR_NAME)` throughout the pipeline. ### AWS SSM Parameter Store ```yaml - script: | VALUE=$(aws ssm get-parameter \ --name "/myapp/mykey" \ --with-decryption \ --query "Parameter.Value" \ --output text) echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE" displayName: "Fetch secret from SSM" ``` ### AWS Secrets Manager ```yaml - script: | VALUE=$(aws secretsmanager get-secret-value \ --secret-id "myapp/mykey" \ --query "SecretString" \ --output text) echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE" displayName: "Fetch secret from Secrets Manager" ``` ### Vault / OpenBao ```yaml - script: | VALUE=$(vault kv get -field=mykey secret/myapp/mykey) echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE" displayName: "Fetch secret from Vault" env: VAULT_ADDR: $(VAULT_ADDR) VAULT_TOKEN: $(VAULT_TOKEN) ``` ## Hard rules — always follow these - `pool: EKS-Pool` on every job — no exceptions - `timeoutInMinutes: 30` on every job - `continueOnError: false` at **job level** on every job (not step level). Step-level `continueOnError` may be omitted. - No secrets hardcoded in YAML — all via variable groups or runtime fetch - Every stage and job has a `displayName:` set - `pool: EKS-Pool` must appear at job level, not stage level, to ensure it applies correctly