{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.13.0"
    },
    "blog_metadata": {
      "topic": "How Guided Copilot in VS Code Could Change the Azure App Build Loop",
      "slug": "how-guided-copilot-in-vs-code-could-change-the-azure-app-bui",
      "generated_by": "LinkedIn Post Generator + Azure OpenAI",
      "generated_at": "2026-09-22T21:50:27.305Z"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# How Guided Copilot in VS Code Could Change the Azure App Build Loop\n",
        "\n",
        "This notebook turns the blog post into a hands-on validation workflow for Azure app build readiness. It focuses on the practical claim behind the post: the biggest value is not faster autocomplete, but a more repeatable first mile with standard repo shape, approved IaC entry points, test setup, and deployment guardrails."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "%pip install --quiet pyyaml"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from pathlib import Path\n",
        "import sys\n",
        "import json\n",
        "import shutil\n",
        "import tempfile\n",
        "from textwrap import dedent"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 1: Lightweight repo validation for Azure app build readiness\n",
        "\n",
        "The blog argues that platform guidance should appear early, before teams drift into inconsistent repo layouts and deployment paths. This example validates a minimal repo contract: required folders and files, a test configuration, and at least one approved IaC entry point."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from pathlib import Path\n",
        "import tempfile\n",
        "import shutil\n",
        "\n",
        "\n",
        "def validate_repo(root: Path):\n",
        "    required = [\"src/\", \"tests/\", \"README.md\", \".github/workflows/ci.yml\"]\n",
        "    approved_iac = {\"infra/main.bicep\", \"infra/main.tf\", \"azure.yaml\"}\n",
        "\n",
        "    missing = [p for p in required if not (root / p).exists()]\n",
        "    iac_found = [p for p in approved_iac if (root / p).exists()]\n",
        "    pytest_ok = (root / \"pytest.ini\").exists() or (root / \"pyproject.toml\").exists()\n",
        "\n",
        "    if missing:\n",
        "        return False, f\"Missing required files: {', '.join(missing)}\"\n",
        "    if not pytest_ok:\n",
        "        return False, \"Missing test configuration: pytest.ini or pyproject.toml\"\n",
        "    if not iac_found:\n",
        "        return False, \"No approved IaC entry point found\"\n",
        "\n",
        "    return True, f\"Validation passed. IaC entry point: {iac_found[0]}\"\n",
        "\n",
        "\n",
        "workspace = Path(tempfile.mkdtemp(prefix=\"azure_build_loop_\"))\n",
        "\n",
        "# Create a compliant sample repo\n",
        "(workspace / \"src\").mkdir(parents=True, exist_ok=True)\n",
        "(workspace / \"tests\").mkdir(parents=True, exist_ok=True)\n",
        "(workspace / \".github/workflows\").mkdir(parents=True, exist_ok=True)\n",
        "(workspace / \"infra\").mkdir(parents=True, exist_ok=True)\n",
        "(workspace / \"README.md\").write_text(\"# Sample Azure App\\n\")\n",
        "(workspace / \".github/workflows/ci.yml\").write_text(\"name: ci\\n\")\n",
        "(workspace / \"pyproject.toml\").write_text(\"[tool.pytest.ini_options]\\naddopts='-q'\\n\")\n",
        "(workspace / \"infra/main.bicep\").write_text(\"// bicep placeholder\\n\")\n",
        "\n",
        "ok, message = validate_repo(workspace)\n",
        "print(\"Sample repo:\", workspace)\n",
        "print(message)\n",
        "\n",
        "# Create a failing sample to show the guardrail behavior\n",
        "broken = Path(tempfile.mkdtemp(prefix=\"azure_build_loop_broken_\"))\n",
        "(broken / \"src\").mkdir(parents=True, exist_ok=True)\n",
        "\n",
        "ok2, message2 = validate_repo(broken)\n",
        "print(\"\\nBroken repo:\", broken)\n",
        "print(message2)\n",
        "\n",
        "# Cleanup note\n",
        "print(\"\\nTemporary folders were created for demonstration and can be removed later if desired.\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 2: Guided policy check to block unapproved deployment paths\n",
        "\n",
        "The post emphasizes that guidance should accelerate teams toward approved delivery paths, not arbitrary deployment choices. This example simulates a policy check that allows only specific IaC templates and blocks anything outside the approved set."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from pathlib import Path\n",
        "import tempfile\n",
        "\n",
        "\n",
        "def check_deployment_path(root: Path, requested: str = \"infra/main.bicep\"):\n",
        "    allowed = {\"infra/main.bicep\", \"infra/main.tf\"}\n",
        "    requested_path = root / requested\n",
        "\n",
        "    if not requested_path.exists():\n",
        "        return False, f\"Requested template not found: {requested_path.as_posix()}\"\n",
        "    if requested not in allowed:\n",
        "        return False, f\"Blocked by policy: use one of {sorted(allowed)}\"\n",
        "\n",
        "    return True, f\"Approved deployment path: {requested}\"\n",
        "\n",
        "\n",
        "policy_root = Path(tempfile.mkdtemp(prefix=\"azure_policy_check_\"))\n",
        "(policy_root / \"infra\").mkdir(parents=True, exist_ok=True)\n",
        "(policy_root / \"infra/main.bicep\").write_text(\"// approved bicep\\n\")\n",
        "(policy_root / \"infra/experimental.json\").write_text(\"{}\\n\")\n",
        "\n",
        "for candidate in [\"infra/main.bicep\", \"infra/experimental.json\", \"infra/main.tf\"]:\n",
        "    ok, result = check_deployment_path(policy_root, candidate)\n",
        "    print(f\"{candidate}: {result}\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 3: Deployment preflight translated from PowerShell into Python\n",
        "\n",
        "The original post includes a PowerShell preflight that validates environment inputs and the approved workflow before deployment. Because this notebook uses Python as the primary language, the same logic is implemented here in Python so you can validate the control flow without requiring PowerShell."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Required variables\n",
        "\n",
        "If you later connect this preflight to a real Azure deployment, you will typically need:\n",
        "\n",
        "- `AZURE_SUBSCRIPTION_ID`\n",
        "- `AZURE_TENANT_ID`\n",
        "- `AZURE_CLIENT_ID`\n",
        "- `AZURE_CLIENT_SECRET` or federated identity configuration\n",
        "- A valid Azure CLI login context\n",
        "\n",
        "This notebook does not perform a live deployment; it only validates the preflight logic."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from pathlib import Path\n",
        "import tempfile\n",
        "\n",
        "\n",
        "def deployment_preflight(root: Path, environment: str, location: str, template: str = \"infra/main.bicep\"):\n",
        "    allowed_environments = {\"dev\", \"test\", \"prod\"}\n",
        "    template_path = root / template\n",
        "\n",
        "    if environment not in allowed_environments:\n",
        "        raise ValueError(f\"Invalid environment: {environment}\")\n",
        "    if not template_path.exists():\n",
        "        raise FileNotFoundError(f\"Template not found: {template}\")\n",
        "    if template not in {\"infra/main.bicep\", \"infra/main.tf\"}:\n",
        "        raise ValueError(\"Unapproved IaC entry point\")\n",
        "\n",
        "    command_preview = [\n",
        "        \"az deployment sub create\",\n",
        "        f\"--location {location}\",\n",
        "        f\"--template-file {template}\",\n",
        "        f\"--parameters environment={environment}\",\n",
        "    ]\n",
        "    return \"Preflight passed for {} in {}\\n{}\".format(environment, location, \" \".join(command_preview))\n",
        "\n",
        "\n",
        "preflight_root = Path(tempfile.mkdtemp(prefix=\"azure_preflight_\"))\n",
        "(preflight_root / \"infra\").mkdir(parents=True, exist_ok=True)\n",
        "(preflight_root / \"infra/main.bicep\").write_text(\"// approved bicep\\n\")\n",
        "\n",
        "print(deployment_preflight(preflight_root, environment=\"dev\", location=\"eastus\"))\n",
        "\n",
        "for env_name in [\"sandbox\"]:\n",
        "    try:\n",
        "        print(deployment_preflight(preflight_root, environment=env_name, location=\"eastus\"))\n",
        "    except Exception as exc:\n",
        "        print(f\"Expected failure for environment '{env_name}': {exc}\")\n",
        "\n",
        "try:\n",
        "    print(deployment_preflight(preflight_root, environment=\"test\", location=\"eastus\", template=\"infra/custom.yaml\"))\n",
        "except Exception as exc:\n",
        "    print(f\"Expected failure for template policy: {exc}\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Example 4: Build loop flow representation in Python\n",
        "\n",
        "The blog includes a Mermaid diagram showing how Guided Copilot could generate validation and preflight steps, then route developers toward fixes or approved deployment. This Python example models the same flow as executable logic so the path can be tested in a notebook."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "def build_loop_flow(repo_validation_passed: bool, preflight_passed: bool):\n",
        "    steps = [\"Developer asks Guided Copilot in VS Code\", \"Generate validation + preflight steps\"]\n",
        "\n",
        "    steps.append(\"Run repo validation script\")\n",
        "    if not repo_validation_passed:\n",
        "        steps.append(\"Copilot suggests fixes\")\n",
        "        return steps\n",
        "\n",
        "    steps.append(\"Run deployment preflight\")\n",
        "    if not preflight_passed:\n",
        "        steps.append(\"Copilot suggests fixes\")\n",
        "        return steps\n",
        "\n",
        "    steps.append(\"Invoke approved IaC deployment\")\n",
        "    steps.append(\"Azure app build loop shortens\")\n",
        "    return steps\n",
        "\n",
        "\n",
        "scenarios = {\n",
        "    \"all_green\": (True, True),\n",
        "    \"repo_fails\": (False, False),\n",
        "    \"preflight_fails\": (True, False),\n",
        "}\n",
        "\n",
        "for name, (repo_ok, preflight_ok) in scenarios.items():\n",
        "    print(f\"Scenario: {name}\")\n",
        "    for i, step in enumerate(build_loop_flow(repo_ok, preflight_ok), start=1):\n",
        "        print(f\"  {i}. {step}\")\n",
        "    print()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Summary\n",
        "\n",
        "The core idea from the blog is that Guided Copilot matters most when it reduces first-mile chaos: standard repo shape, test setup, approved IaC, and safer deployment defaults. The examples in this notebook show how lightweight validation and policy checks can turn platform standards into something developers experience directly in the build loop instead of discovering later in review.\n",
        "\n",
        "## Next Steps\n",
        "\n",
        "1. Standardize 1-2 Azure app archetypes for your team.\n",
        "2. Add repo validation checks for README, CI workflow, tests, and approved IaC entry points.\n",
        "3. Enforce deployment-path policy before pipeline execution.\n",
        "4. Measure time-to-first-deployment as a platform outcome.\n",
        "5. Decide which guidance sources, templates, review paths, and exception processes are allowed in your environment."
      ]
    }
  ]
}