Create azure-devops.html
· 1 year ago
0159984349e48e1f4c5cb5e2bd9182c589425325
Parent:
3fadb28f9
1 file changed +768 −0
- azure-devops.html +768 −0
Diff
--- /dev/null +++ b/azure-devops.html @@ -0,0 +1,768 @@ + + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond</title> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🚀</text></svg>"> + + <!-- SEO & Metadata --> + <meta name="description" content="A comprehensive, opinionated cheatsheet for the entire Azure DevOps ecosystem. Covers Azure Boards, Repos, Pipelines, Test Plans, Artifacts, Terraform for IaC, and SonarQube for code quality."> + <meta name="keywords" content="DevOps, Azure DevOps, Cheatsheet, Azure Boards, Azure Repos, Azure Pipelines, Azure Test Plans, Azure Artifacts, Terraform, SonarQube, CI/CD, Agile, Git, IaC, Security, YAML"> + <link rel="canonical" href="https://cheatsheets.davidveksler.com/azure-devops.html"> + + <!-- Open Graph / Facebook --> + <meta property="og:type" content="website"> + <meta property="og:url" content="https://cheatsheets.davidveksler.com/azure-devops.html"> + <meta property="og:title" content="The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond"> + <meta property="og:description" content="A battle-hardened guide to the full Azure DevOps suite, including Boards for planning, Repos for code, Pipelines for CI/CD, Test Plans, and Artifacts for package management."> + <meta property="og:image" content="https://cheatsheets.davidveksler.com/images/azure-devops.png"> + <meta property="og:image:alt" content="A visual diagram of the full DevOps lifecycle, highlighting components like Boards, Repos, and Pipelines."> + + <!-- Twitter --> + <meta name="twitter:card" content="summary_large_image"> + <meta name="twitter:url" content="https://cheatsheets.davidveksler.com/azure-devops.html"> + <meta name="twitter:title" content="The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond"> + <meta name="twitter:description" content="An opinionated cheatsheet for mastering the Azure DevOps ecosystem, from agile planning with Boards to CI/CD with Pipelines."> + <meta name="twitter:image" content="https://cheatsheets.davidveksler.com/images/azure-devops.png"> + <meta name="twitter:creator" content="@heroiclife"> + + <!-- JSON-LD Structured Data --> + <script type="application/ld+json"> + { + "@context": "https://schema.org", + "@type": "TechArticle", + "headline": "The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond", + "description": "A comprehensive, opinionated cheatsheet for the entire Azure DevOps ecosystem. Covers Azure Boards, Repos, Pipelines, Test Plans, Artifacts, Terraform for IaC, and SonarQube for code quality.", + "image": "https://cheatsheets.davidveksler.com/images/azure-devops.png", + "author": { + "@type": "Person", + "name": "David Veksler (AI Generated)" + }, + "publisher": { + "@type": "Organization", + "name": "David Veksler Cheatsheets", + "logo": { + "@type": "ImageObject", + "url": "https://cheatsheets.davidveksler.com/images/logo-placeholder.png" + } + }, + "datePublished": "2024-06-15", + "dateModified": "2024-06-15", + "keywords": "DevOps, CI/CD, Azure DevOps, Azure Boards, Azure Repos, Azure Pipelines, Azure Test Plans, Azure Artifacts, Terraform, SonarQube, IaC, Git, Automation, Security" + } + </script> + + <!-- Bootstrap CSS --> + <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> + <!-- Bootstrap Icons --> + <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" rel="stylesheet"> + + <style> + :root { + --bs-body-bg: #1a1d21; + --bs-body-color: #e9ecef; + --bs-primary: #0d6efd; /* Azure Blue */ + --card-bg: #212529; + --card-border-color: #495057; + --card-shadow-color: rgba(0, 0, 0, 0.4); + --text-color-main: #f8f9fa; + --text-color-secondary: #adb5bd; + --text-color-highlight: #78C1F3; /* Light Blue Highlight */ + --schema-bg-color: rgba(33, 37, 41, 0.7); + --schema-border-color: #343a40; + --blueprint-grid-color: rgba(108, 117, 125, 0.1); + + /* DevOps Category Colors */ + --devops-color-plan: #2E7D32; /* Planning Green */ + --devops-color-scm: #F05032; /* Git Orange */ + --devops-color-ci: #F7B601; /* SonarQube Yellow */ + --devops-color-testing: #FF6F00; /* Testing Amber */ + --devops-color-artifacts: #6A1B9A; /* Artifacts Purple */ + --devops-color-cd: #0078D4; /* Azure Blue */ + --devops-color-iac: #7B42BC; /* Terraform Purple */ + --devops-color-security: #D73A49; /* Security Red */ + --devops-color-monitoring: #28A745;/* Monitoring Green */ + + --db-category-color: var(--bs-primary); /* Default */ + } + + body { + background-color: var(--bs-body-bg); + background-image: + linear-gradient(var(--blueprint-grid-color) 1px, transparent 1px), + linear-gradient(to right, var(--blueprint-grid-color) 1px, transparent 1px); + background-size: 50px 50px; + font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif; + } + + .page-header { + background: linear-gradient(135deg, rgba(13, 110, 253, 0.1), rgba(0, 0, 0, 0.2)); + padding: 3rem 1.5rem; + text-align: center; + border-bottom: 1px solid var(--schema-border-color); + margin-bottom: 2rem; + } + .page-header h1 { font-weight: 300; font-size: 2.8rem; } + .page-header .lead { max-width: 800px; margin: auto; font-style: italic; color: var(--text-color-secondary); } + + #filter-controls { + background-color: rgba(26, 29, 33, 0.85); + backdrop-filter: blur(8px); + padding: 1rem; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); + margin-bottom: 2rem; position: sticky; top: 10px; z-index: 1020; + } + #search-box { + background-color: #2c3136; border-color: var(--card-border-color); color: var(--bs-body-color); + } + #search-box::placeholder { color: #6c757d; } + #search-box:focus { + background-color: #2c3136; color: var(--bs-body-color); border-color: var(--bs-primary); + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + } + + .schema-container { + background-color: var(--schema-bg-color); border: 1px solid var(--schema-border-color); + border-radius: 8px; padding: 1.5rem; margin-bottom: 2.5rem; box-shadow: 0 8px 30px rgba(0,0,0,0.2); + } + + .section-title { + color: var(--db-category-color); margin: -2.7rem 0 1.5rem 0; font-weight: 600; + text-transform: uppercase; letter-spacing: .08em; font-size: 1.1rem; border-bottom: none; + padding: 0.4rem 1rem; background-color: var(--bs-body-bg); display: inline-block; + position: relative; left: 1rem; + } + + .info-card { + background: var(--card-bg); border: 1px solid var(--card-border-color); border-radius: 6px; + box-shadow: 0 4px 12px var(--card-shadow-color); height: 100%; display: flex; flex-direction: column; + transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + } + .info-card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px var(--card-shadow-color); } + + .info-card h5 { + color: #fff; background-color: var(--db-category-color); font-size: 1rem; text-align: center; + margin: 0; padding: 0.7rem 0.5rem; font-weight: 600; display: flex; justify-content: center; + align-items: center; gap: .5rem; border-bottom: 1px solid var(--card-border-color); + border-radius: 5px 5px 0 0; + } + .info-card h5 .bi { font-size: 1.2em; opacity: 0.9; } + + .card-content-wrapper { padding: 1rem; flex-grow: 1; display: flex; flex-direction: column; } + .info-card p.summary { font-size: .9rem; color: var(--text-color-secondary); margin-bottom: 1rem; flex-grow: 1; line-height: 1.6; } + + .details-toggle { + font-size: 0.8rem; margin-top: auto; align-self: flex-start; color: var(--text-color-secondary); + border-color: var(--text-color-secondary); transition: all 0.2s ease; + } + .details-toggle:hover { color: #fff; background-color: var(--db-category-color); border-color: var(--db-category-color); } + .details-toggle .bi { transition: transform 0.2s ease-in-out; } + .details-toggle[aria-expanded="true"] .bi { transform: rotate(180deg); } + + .collapse-content { + font-size: 0.9rem; border-top: 1px solid var(--card-border-color); padding: 1rem; background-color: #1a1d21; + } + .collapse-content h6 { font-weight: 700; color: var(--text-color-highlight); margin-top: 0.8rem; margin-bottom: 0.5rem; font-size: 0.95rem; } + .collapse-content ul { padding-left: 1.2rem; } + .collapse-content code { + font-size: 0.85rem; color: #e83e8c; background-color: rgba(255, 255, 255, 0.05); + padding: 0.2em 0.4em; border-radius: 3px; + } + .collapse-content .callout { + border-left: 4px solid var(--db-category-color); padding: 0.8rem 1rem; margin: 1rem 0; + background-color: rgba(255,255,255,0.03); border-radius: 0 4px 4px 0; + } + + .term { font-weight: 600; color: var(--text-color-highlight); background-color: rgba(120, 193, 243, 0.1); padding: 0.1em 0.35em; border-radius: 3px; cursor: help; } + + /* Category Color Styling */ + .section-plan, .card-plan { --db-category-color: var(--devops-color-plan); } + .section-scm, .card-scm { --db-category-color: var(--devops-color-scm); } + .section-ci, .card-ci { --db-category-color: var(--devops-color-ci); } + .section-testing, .card-testing { --db-category-color: var(--devops-color-testing); } + .section-artifacts, .card-artifacts { --db-category-color: var(--devops-color-artifacts); } + .section-cd, .card-cd { --db-category-color: var(--devops-color-cd); } + .section-iac, .card-iac { --db-category-color: var(--devops-color-iac); } + .section-security, .card-security { --db-category-color: var(--devops-color-security); } + .section-monitoring, .card-monitoring { --db-category-color: var(--devops-color-monitoring); } + + footer { border-top: 1px solid var(--schema-border-color); padding-top: 2rem; margin-top: 2rem; color: var(--text-color-secondary); font-size: 0.9em; } + footer a { color: var(--text-color-secondary); text-decoration: none; } + footer a:hover { color: #fff; text-decoration: underline; } + </style> +</head> +<body class="bg-dark text-light"> + + <header class="page-header"> + <h1><i class="bi bi-bezier"></i> The Complete Azure DevOps Cheatsheet</h1> + <p class="lead">A brutally honest, battle-hardened guide to the entire Azure DevOps suite. From planning with Boards, coding with Repos, building and releasing with Pipelines, to testing, artifacts, and beyond.</p> + </header> + + <div class="container"> + <div id="filter-controls"> + <input type="search" id="search-box" class="form-control mb-3" placeholder="Search topics, tools, or keywords (e.g., Boards, YAML, SAST)..."> + <div id="category-filters" class="btn-toolbar" role="toolbar" aria-label="Category Filters"></div> + <div class="alert alert-warning mt-3" id="no-results" style="display: none;">No items match your criteria.</div> + </div> + </div> + + <main class="container" id="main-container"> + + <!-- 1. Agile Planning (Azure Boards) --> + <div class="schema-container section-plan" data-section-id="section-plan" data-section-name="Plan"> + <h2 class="section-title">Agile Planning & Work Management</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-plan" id="card-plan-boards"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-kanban"></i> Azure Boards</h5> + <div class="card-content-wrapper"> + <p class="summary">If you don't plan your work, you plan to fail. Azure Boards is the central hub for work item tracking, backlogs, and sprint planning. It's where all work should originate.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePlanBoards" aria-expanded="false" aria-controls="collapsePlanBoards">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapsePlanBoards"> + <h6>Core Components:</h6> + <ul> + <li><strong>Work Items:</strong> The fundamental units of work (e.g., User Story, Bug, Task).</li> + <li><strong>Backlogs:</strong> A prioritized list of work items. You'll have product backlogs (all work) and sprint backlogs (work for the current iteration).</li> + <li><strong>Boards:</strong> Kanban-style visualization of your workflow. Customize columns to match your team's process.</li> + <li><strong>Sprints/Iterations:</strong> Time-boxed periods where a team commits to a set of work.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-plan" id="card-plan-linking"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-link-45deg"></i> Best Practice: Traceability</h5> + <div class="card-content-wrapper"> + <p class="summary">Your mantra: "If it's not in Boards, it doesn't exist." Every commit, branch, and pull request must be linked to a work item. This provides end-to-end traceability from idea to deployment.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePlanLinking" aria-expanded="false" aria-controls="collapsePlanLinking">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapsePlanLinking"> + <h6>Why It's Non-Negotiable:</h6> + <ul> + <li><strong>Context:</strong> Understand *why* a change was made, directly from the code.</li> + <li><strong>Auditing:</strong> Easily track all changes related to a specific feature or bug fix.</li> + <li><strong>Automation:</strong> Use branch policies to enforce work item linking on all pull requests.</li> + <li><strong>Reporting:</strong> Generate accurate reports on team velocity, cycle time, and project status.</li> + </ul> + <div class="callout callout-danger"><strong>Critical Rule:</strong> Configure your `main` branch policy to "Check for linked work items." This is the simplest and most effective process improvement you can make.</div> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 2. Source Control Management (SCM) --> + <div class="schema-container section-scm" data-section-id="section-scm" data-section-name="Code"> + <h2 class="section-title">Source Control Management</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-scm" id="card-scm-azure-repos"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-git"></i> Azure Repos</h5> + <div class="card-content-wrapper"> + <p class="summary">The foundation of your pipeline. It's Git. Don't overthink it. If your code is in TFVC, your top priority is migrating. No excuses.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseScmAzureRepos" aria-expanded="false" aria-controls="collapseScmAzureRepos">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseScmAzureRepos"> + <h6>Core Principle:</h6> + <p>This is your single source of truth. All changes—code, configuration, pipelines, infrastructure—must live here. Protect it accordingly.</p> + <h6>Tooling:</h6> + <ul> + <li><strong>Azure Repos:</strong> It's a perfectly functional Git host that integrates tightly with the rest of Azure DevOps.</li> + <li><strong>Git:</strong> The undisputed standard for version control. Anything else is a historical artifact and technical debt.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-scm" id="card-scm-branch-policies"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-sign-turn-right"></i> Best Practice: Branch Policies</h5> + <div class="card-content-wrapper"> + <p class="summary">Policies are non-negotiable. Protect your `main` branch like it's the last bastion of sanity. Automate your Pull Requests to enforce quality gates from the very start.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseScmBranchPolicies" aria-expanded="false" aria-controls="collapseScmBranchPolicies">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseScmBranchPolicies"> + <h6>Mandatory Policies for `main`:</h6> + <ul> + <li><strong>Require a minimum number of reviewers:</strong> No developer merges their own code without a second pair of eyes.</li> + <li><strong>Check for linked work items:</strong> Every change must be traceable to a requirement or bug.</li> + <li><strong>Check for comment resolution:</strong> Ensure all review feedback is addressed.</li> + <li><strong>Enforce Build Validation:</strong> Link your CI pipeline here. If the PR doesn't build and pass tests, it's blocked. This is your first quality gate.</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 3. Continuous Integration (CI) --> + <div class="schema-container section-ci" data-section-id="section-ci" data-section-name="Build"> + <h2 class="section-title">Continuous Integration</h2> + <div class="row g-4"> + <div class="col-lg-4"> + <div class="info-card card-ci" id="card-ci-pipelines"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-filetype-yml"></i> Azure Pipelines (YAML ONLY)</h5> + <div class="card-content-wrapper"> + <p class="summary">Your pipeline is code. Treat it like code. Do NOT use the "classic" UI editor. It creates a click-ops nightmare that is impossible to version, review, or scale.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiPipelines" aria-expanded="false" aria-controls="collapseCiPipelines">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseCiPipelines"> + <h6>Core Principle:</h6> + <p>Define your build pipeline as an `azure-pipelines.yml` file, committed to the root of your repository. This ensures your pipeline is versioned alongside your code.</p> + <h6>Best Practices:</h6> + <ul> + <li><strong>Use Templates:</strong> For common, reusable steps, create pipeline templates. This standardizes your process and makes maintenance trivial.</li> + <li><strong>Use Variable Groups:</strong> For shared variables and secrets. Link them to Azure Key Vault.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-4"> + <div class="info-card card-ci" id="card-ci-sonarqube"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-search-heart"></i> SonarQube Integration</h5> + <div class="card-content-wrapper"> + <p class="summary"><span class="term" data-bs-toggle="tooltip" title="A tool for continuous inspection of code quality.">SonarQube</span> is your automated code reviewer. Integrate it into CI and fail the build if the quality gate is not met.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiSonarqube" aria-expanded="false" aria-controls="collapseCiSonarqube">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseCiSonarqube"> + <h6>Typical CI Pipeline Steps with SonarQube:</h6> + <ol> + <li><strong>Prepare Analysis:</strong> Connects to your SonarQube server.</li> + <li><strong>Run Build & Tests:</strong> Compile code and generate code coverage reports.</li> + <li><strong>Run Code Analysis:</strong> Sonar scanner analyzes code and coverage reports.</li> + <li><strong>Publish Quality Gate Result:</strong> Polls SonarQube and checks the Quality Gate status.</li> + </ol> + <div class="callout callout-danger"> + <strong>Critical Rule:</strong> Configure the "Publish Quality Gate Result" task to fail the build if the gate fails. + </div> + </div> + </div> + </div> + </div> + <div class="col-lg-4"> + <div class="info-card card-ci" id="card-ci-stages"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-boxes"></i> CI Key Stages</h5> + <div class="card-content-wrapper"> + <p class="summary">The moment code is merged, it must be built, tested, and packaged. The goal is to catch errors early and often, before they reach production.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiStages" aria-expanded="false" aria-controls="collapseCiStages">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseCiStages"> + <h6>Mandatory Stages:</h6> + <ul> + <li><strong>Build:</strong> Compile the code. If it doesn't build, it's broken.</li> + <li><strong>Test:</strong> Run unit and integration tests.</li> + <li><strong>Scan:</strong> Perform security and quality scans (e.g., SonarQube, SAST, SCA).</li> + <li><strong>Package:</strong> Create a deployable artifact (e.g., a <span class="term" data-bs-toggle="tooltip" title="A standardized unit of software that packages up code and all its dependencies.">Docker image</span>).</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 4. Quality Assurance (Azure Test Plans) --> + <div class="schema-container section-testing" data-section-id="section-testing" data-section-name="Test"> + <h2 class="section-title">Quality Assurance & Test Management</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-testing" id="card-test-plans"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-clipboard2-check"></i> Azure Test Plans</h5> + <div class="card-content-wrapper"> + <p class="summary">Automated tests are essential but don't cover everything. Use Azure Test Plans for manual, exploratory, and user acceptance testing (UAT) to ensure comprehensive quality.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTestPlans" aria-expanded="false" aria-controls="collapseTestPlans">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseTestPlans"> + <h6>Key Features:</h6> + <ul> + <li><strong>Test Plans & Suites:</strong> Group test cases into logical suites. Requirement-based suites automatically link test cases to user stories in Boards.</li> + <li><strong>Test Case Management:</strong> Define detailed, step-by-step manual test cases with expected results.</li> + <li><strong>Web-based Test Runner:</strong> Execute tests directly in the browser, marking steps as pass/fail and capturing screenshots or recordings.</li> + <li><strong>Exploratory Testing:</strong> Capture rich data (notes, screenshots, HAR files) during unscripted testing sessions.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-testing" id="card-test-integration"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-arrows-angle-contract"></i> End-to-End Traceability</h5> + <div class="card-content-wrapper"> + <p class="summary">Linking test results back to requirements is critical for quality reporting. Test Plans creates a full audit trail, showing which tests validate which features and what their latest outcomes are.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTestIntegration" aria-expanded="false" aria-controls="collapseTestIntegration">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseTestIntegration"> + <h6>How It Connects:</h6> + <ul> + <li>Failing a manual test step can automatically create a bug in Azure Boards, pre-populated with repro steps and system info.</li> + <li>Test results from automated CI/CD pipeline runs can be published to Test Plans, providing a single view of both manual and automated test quality.</li> + <li>Stakeholders can view the "Test" tab on a work item to see all associated test cases and their results, providing confidence before deployment.</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 5. Package Management (Azure Artifacts) --> + <div class="schema-container section-artifacts" data-section-id="section-artifacts" data-section-name="Artifacts"> + <h2 class="section-title">Package Management</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-artifacts" id="card-artifacts-overview"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-box-seam"></i> Azure Artifacts</h5> + <div class="card-content-wrapper"> + <p class="summary">Manage your dependencies. Azure Artifacts provides private, secure feeds for hosting packages like NuGet, npm, Maven, Python, and Universal Packages. Stop relying solely on public registries.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArtifactsOverview" aria-expanded="false" aria-controls="collapseArtifactsOverview">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseArtifactsOverview"> + <h6>Why Use It?</h6> + <ul> + <li><strong>Reliability:</strong> Cache upstream packages. If a public registry goes down or a package is unpublished, your builds won't break.</li> + <li><strong>Security:</strong> Control what packages your organization uses. Share private packages securely across teams.</li> + <li><strong>Integration:</strong> Seamlessly integrated with Azure Pipelines for publishing and restoring packages.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-artifacts" id="card-artifacts-feeds"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-diagram-3"></i> Feeds and Views</h5> + <div class="card-content-wrapper"> + <p class="summary">Don't just dump packages into a single feed. Use views (`@local`, `@prerelease`, `@release`) to promote packages through different quality rings, just like you do with your code.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArtifactsFeeds" aria-expanded="false" aria-controls="collapseArtifactsFeeds">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseArtifactsFeeds"> + <h6>Release Flow with Views:</h6> + <ol> + <li>CI build publishes a new package version to the `@local` view.</li> + <li>Automated tests run against the `@local` view.</li> + <li>If tests pass, the pipeline promotes the package to the `@prerelease` view for broader integration testing.</li> + <li>After validation, a release pipeline promotes the package to the `@release` view, making it available for production use.</li> + </ol> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 6. Infrastructure as Code (IaC) --> + <div class="schema-container section-iac" data-section-id="section-iac" data-section-name="IaC"> + <h2 class="section-title">Infrastructure as Code</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-iac" id="card-iac-terraform"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-filetype-tf"></i> Terraform</h5> + <div class="card-content-wrapper"> + <p class="summary">Your infrastructure must be defined as code. Manual configuration in the Azure Portal is a recipe for disaster. <span class="term" data-bs-toggle="tooltip" title="An open-source IaC tool by HashiCorp.">Terraform</span> is the industry standard.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseIacTerraform" aria-expanded="false" aria-controls="collapseIacTerraform">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseIacTerraform"> + <h6>Why Terraform?</h6> + <p>While Microsoft pushes Bicep/ARM, Terraform is cloud-agnostic and its `plan` command is a lifesaver for preventing accidental changes.</p> + <h6>The Holy Trinity of Terraform Commands in a Pipeline:</h6> + <ul> + <li><code>terraform init</code>: Initializes the backend and providers.</li> + <li><code>terraform plan</code>: Shows exactly what will change. This step must create a plan artifact that requires manual approval.</li> + <li><code>terraform apply</code>: Executes the approved plan.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-iac" id="card-iac-state"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-database-lock"></i> Terraform Remote State</h5> + <div class="card-content-wrapper"> + <p class="summary">The biggest mistake teams make with Terraform is storing the `terraform.tfstate` file locally. Always use a remote backend like an Azure Storage Account.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseIacState" aria-expanded="false" aria-controls="collapseIacState">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseIacState"> + <h6>Why Remote State is Critical:</h6> + <ul> + <li><strong>Collaboration:</strong> Allows multiple team members to work on the same infrastructure.</li> + <li><strong>State Locking:</strong> Prevents concurrent runs from corrupting the state file.</li> + <li><strong>Security:</strong> The state file can contain secrets. Storing it in a secured storage account is essential.</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 7. Continuous Delivery/Deployment (CD) --> + <div class="schema-container section-cd" data-section-id="section-cd" data-section-name="Release"> + <h2 class="section-title">Continuous Delivery/Deployment</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-cd" id="card-cd-releases"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-rocket-takeoff"></i> Azure Pipelines (Releases)</h5> + <div class="card-content-wrapper"> + <p class="summary">Automating your release is the whole point. Release Pipelines offer better visualization of your environments and crucial manual approval gates for production.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCdReleases" aria-expanded="false" aria-controls="collapseCdReleases">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseCdReleases"> + <h6>Release Pipeline Structure:</h6> + <ul> + <li><strong>Artifacts:</strong> Triggered by a new build artifact (e.g., Docker image, Terraform plan).</li> + <li><strong>Stages:</strong> Create a stage for each environment (e.g., Dev, QA, Prod).</li> + <li><strong>Approval Gates:</strong> Use automated gates (smoke tests) and manual gates (human approval) to control promotion between stages.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-cd" id="card-cd-concepts"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-lightbulb"></i> Key Deployment Concepts</h5> + <div class="card-content-wrapper"> + <p class="summary">Differentiate between Continuous Delivery (manual deploy to prod) and Continuous Deployment (automatic to prod). Use deployment strategies to limit blast radius.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCdConcepts" aria-expanded="false" aria-controls="collapseCdConcepts">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseCdConcepts"> + <ul> + <li><strong>Immutable Infrastructure:</strong> Don't modify running servers. Replace them with fresh ones built from your artifacts.</li> + <li><strong>Blue/Green or Canary Deployments:</strong> Deploy to a subset of users (Canary) or a parallel environment (Blue/Green) before a full rollout.</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 8. Security --> + <div class="schema-container section-security" data-section-id="section-security" data-section-name="Security"> + <h2 class="section-title">Security</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-security" id="card-security-practices"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-shield-check"></i> Key Security Practices (Shift Left)</h5> + <div class="card-content-wrapper"> + <p class="summary">Security is not a separate step; it's a part of every step. Embed automated security checks into your pipeline to catch vulnerabilities early.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityPractices" aria-expanded="false" aria-controls="collapseSecurityPractices">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseSecurityPractices"> + <h6>Pipeline Integration Points:</h6> + <ul> + <li><strong><span class="term" data-bs-toggle="tooltip" title="Static Application Security Testing">SAST</span>:</strong> Analyze source code. SonarQube has SAST capabilities.</li> + <li><strong><span class="term" data-bs-toggle="tooltip" title="Software Composition Analysis">SCA</span>:</strong> Scan open-source dependencies for known vulnerabilities.</li> + <li><strong>Container Scanning:</strong> Scan your Docker images for vulnerabilities.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-security" id="card-security-keyvault"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-key"></i> Secret Management: Azure Key Vault</h5> + <div class="card-content-wrapper"> + <p class="summary">Don't put secrets in your code, variable groups, or YAML files. This is amateur hour. Use Azure Key Vault.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityKeyvault" aria-expanded="false" aria-controls="collapseSecurityKeyvault">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseSecurityKeyvault"> + <h6>The Only Acceptable Way:</h6> + <p>Store all secrets in Azure Key Vault. In your Pipeline, use a Variable Group linked to the Key Vault. Secrets will be fetched at runtime and masked in logs.</p> + <div class="callout callout-danger"> + <strong>Critical Rule:</strong> Developers should not have direct access to production secrets. The pipeline is the only entity that should fetch and use them in production. + </div> + </div> + </div> + </div> + </div> + </div> + </div> + + <!-- 9. Monitoring & Observability --> + <div class="schema-container section-monitoring" data-section-id="section-monitoring" data-section-name="Monitor"> + <h2 class="section-title">Monitoring & Observability</h2> + <div class="row g-4"> + <div class="col-lg-6"> + <div class="info-card card-monitoring" id="card-monitoring-pillars"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-kanban"></i> The Three Pillars</h5> + <div class="card-content-wrapper"> + <p class="summary">If you're not monitoring your application in production, you're flying blind. Observability is understanding your system's state from the outside.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseMonitoringPillars" aria-expanded="false" aria-controls="collapseMonitoringPillars">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseMonitoringPillars"> + <ul> + <li><strong>Logging:</strong> Records of discrete events. Use structured logging.</li> + <li><strong>Metrics:</strong> Aggregated, time-series data on key performance indicators (e.g., CPU, latency).</li> + <li><strong>Tracing:</strong> Track a single request as it moves through your distributed system.</li> + </ul> + </div> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="info-card card-monitoring" id="card-monitoring-tools"> + <div class="card-body d-flex flex-column"> + <h5><i class="bi bi-tools"></i> Azure Tooling</h5> + <div class="card-content-wrapper"> + <p class="summary">Use the integrated Azure tools. They're not always best-in-class, but their deep integration simplifies your life immensely.</p> + <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseMonitoringTools" aria-expanded="false" aria-controls="collapseMonitoringTools">Details <i class="bi bi-chevron-down"></i></button> + </div> + <div class="collapse collapse-content" id="collapseMonitoringTools"> + <h6>Recommended Azure Stack:</h6> + <ul> + <li><strong>Azure Monitor:</strong> The umbrella service for metrics and basic logging.</li> + <li><strong>Application Insights:</strong> The APM solution. Instrument your code with its SDK to get rich logging, dependency tracking, and distributed tracing.</li> + <li><strong>Log Analytics Workspace:</strong> The destination for all your logs. Use Kusto Query Language (KQL) to query everything.</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </div> + + </main> + + <footer class="container text-center py-4"> + <p class="mb-1">© <span id="currentYear"></span> David Veksler Cheatsheets</p> + <p class="mb-2" style="font-size: 0.8em;">Last Updated: <span id="lastUpdatedDate">June 15, 2024</span></p> + <div> + <a href="https://learn.microsoft.com/en-us/azure/devops/" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-box"></i> Azure DevOps Docs</a> + <a href="https://www.terraform.io/docs" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-file-earmark-code"></i> Terraform Docs</a> + <a href="https://docs.sonarqube.org/latest/" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-search"></i> SonarQube Docs</a> + </div> + </footer> + + <!-- Bootstrap JS --> + <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script> + + <script> + document.addEventListener('DOMContentLoaded', () => { + // Initialize Bootstrap Tooltips + const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); + tooltipTriggerList.map(function (tooltipTriggerEl) { + return new bootstrap.Tooltip(tooltipTriggerEl); + }); + + document.getElementById('currentYear').textContent = new Date().getFullYear(); + + const searchBox = document.getElementById('search-box'); + const categoryFiltersContainer = document.getElementById('category-filters'); + const noResultsDiv = document.getElementById('no-results'); + const allSchemaContainers = Array.from(document.querySelectorAll('.schema-container')); + let activeFilter = 'all'; + + function initializeFilters() { + const allButton = document.createElement('button'); + allButton.type = 'button'; + allButton.className = 'btn btn-primary filter-btn active'; + allButton.textContent = 'All'; + allButton.dataset.filter = 'all'; + categoryFiltersContainer.appendChild(allButton); + + const btnGroup = document.createElement('div'); + btnGroup.className = 'btn-group flex-wrap ms-2'; + btnGroup.setAttribute('role', 'group'); + + const sectionColors = {}; + allSchemaContainers.forEach(section => { + const sectionId = section.dataset.sectionId; + const sectionName = section.dataset.sectionName || 'Unnamed'; + const computedColor = getComputedStyle(section).getPropertyValue('--db-category-color').trim(); + sectionColors[sectionId] = computedColor; + + const button = document.createElement('button'); + button.type = 'button'; + button.className = 'btn btn-outline-secondary filter-btn'; + button.textContent = sectionName; + button.dataset.filter = sectionId; + button.style.setProperty('--bs-btn-border-color', computedColor); + button.style.setProperty('--bs-btn-hover-border-color', computedColor); + button.style.setProperty('--bs-btn-color', computedColor); + button.style.setProperty('--bs-btn-hover-color', '#fff'); + button.style.setProperty('--bs-btn-hover-bg', computedColor); + button.style.setProperty('--bs-btn-active-bg', computedColor); + button.style.setProperty('--bs-btn-active-border-color', computedColor); + btnGroup.appendChild(button); + }); + categoryFiltersContainer.appendChild(btnGroup); + + categoryFiltersContainer.addEventListener('click', (event) => { + if (event.target.classList.contains('filter-btn')) { + document.querySelectorAll('#category-filters .filter-btn.active').forEach(btn => btn.classList.remove('active')); + event.target.classList.add('active'); + activeFilter = event.target.dataset.filter; + applyFiltersAndSearch(); + } + }); + searchBox.addEventListener('input', applyFiltersAndSearch); + } + + function applyFiltersAndSearch() { + const searchTerm = searchBox.value.toLowerCase().trim(); + let itemsFound = 0; + + allSchemaContainers.forEach(section => { + const sectionId = section.dataset.sectionId; + let sectionHasVisibleCards = false; + const cardsInSection = Array.from(section.querySelectorAll('.info-card')); + + cardsInSection.forEach(card => { + const cardTextContent = card.textContent.toLowerCase(); + const matchesSearch = searchTerm === '' || cardTextContent.includes(searchTerm); + const matchesFilter = activeFilter === 'all' || sectionId === activeFilter; + + const cardColumn = card.closest('.col-lg-4, .col-lg-6'); + if (matchesSearch && matchesFilter) { + if(cardColumn) cardColumn.style.display = ''; + sectionHasVisibleCards = true; + itemsFound++; + } else { + if(cardColumn) cardColumn.style.display = 'none'; + } + }); + + section.style.display = sectionHasVisibleCards ? '' : 'none'; + }); + noResultsDiv.style.display = itemsFound === 0 ? 'block' : 'none'; + } + + const collapseElements = document.querySelectorAll('.collapse'); + collapseElements.forEach(collapseEl => { + const button = document.querySelector(`.details-toggle[data-bs-target="#${collapseEl.id}"]`); + if(button) { + const iconEl = button.querySelector('.bi'); + collapseEl.addEventListener('show.bs.collapse', () => iconEl.classList.replace('bi-chevron-down', 'bi-chevron-up')); + collapseEl.addEventListener('hide.bs.collapse', () => iconEl.classList.replace('bi-chevron-up', 'bi-chevron-down')); + } + }); + + initializeFilters(); + }); + </script> +</body> +</html>