Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e2c17fc
Add Linux tarball support for Homebrew Cask
naga-nandyala Aug 10, 2026
2681931
Refactor standalone tarball release tooling
naga-nandyala Aug 10, 2026
9c8c318
Refactor standalone release pipeline for Linux Cask
naga-nandyala Aug 11, 2026
7e8ab3a
Rename standalone validation pipeline
naga-nandyala Aug 11, 2026
c140a9f
Bootstrap Linuxbrew for standalone tests
naga-nandyala Aug 11, 2026
d26b777
Trust temporary Homebrew Cask tap
naga-nandyala Aug 11, 2026
7c3ebc5
Stabilize Linux tarball smoke test cleanup
naga-nandyala Aug 11, 2026
d504e9a
Disable PR trigger for standalone validation
naga-nandyala Aug 11, 2026
cc3d6b9
Use fork repositories for standalone release
naga-nandyala Aug 11, 2026
84bd263
Use variable group for ESRP Apple key code
naga-nandyala Aug 11, 2026
c5091c4
Parallelize standalone platform validation
naga-nandyala Aug 12, 2026
5577290
Parameterize standalone release target branch
naga-nandyala Aug 12, 2026
62d9b8f
Add standalone publish recovery pipeline
naga-nandyala Aug 12, 2026
224aeb8
Format standalone Cask checksums
naga-nandyala Aug 12, 2026
2a73b3f
Restore Azure standalone release targets
naga-nandyala Aug 12, 2026
abf6a98
Target standalone releases at main
naga-nandyala Aug 12, 2026
3dec1ea
Use Azure recovery pipeline for standalone publishing
naga-nandyala Aug 12, 2026
1ee773c
Publish standalone recovery releases with PAT
naga-nandyala Aug 12, 2026
981f450
Temporarily test PAT publishing in azclips
naga-nandyala Aug 12, 2026
362d229
Revert "Temporarily test PAT publishing in azclips"
naga-nandyala Aug 12, 2026
fbac798
Remove standalone publish recovery pipeline
naga-nandyala Aug 19, 2026
0e5a8ef
Remove deprecated Cask verified parameter
naga-nandyala Aug 19, 2026
4feaa88
Use PAT for standalone GitHub releases
naga-nandyala Aug 19, 2026
ec16af8
Load ESRP signing codes in production pipeline
naga-nandyala Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# Azure CLI - macOS Release Pipeline (Build → Sign → Test → Publish)
# Azure CLI - macOS and Linux Standalone Validation Pipeline
#
# Purpose: Complete end-to-end macOS release pipeline
# Purpose: Manually validate macOS and Linux standalone tarballs and the Homebrew Cask.
# This is an ad hoc testing pipeline, not the production release pipeline.
# Architecture: Chains 4 job templates in sequence
#
# Pipeline Flow:
# 1. macos-build-jobs.yml → Build unsigned tarballs (ARM64 + Intel)
# 2. macos-sign-notarize-jobs.yml → Sign and notarize via ESRP
# 3. macos-test-jobs.yml → Test cask (local file://) + offline install
# 4. macos-publish-jobs.yml → GitHub release + Homebrew cask update
# 3. cask-generation-and-tests.yml → Test cask (local file://) + offline install
# 4. publish-jobs.yml → GitHub release + Homebrew cask update
#
# Output Artifacts:
# - cli-build-unsigned-arm64, cli-build-unsigned-x86_64 (intermediate)
# - cli-signed-notarized-arm64, cli-signed-notarized-x86_64 (final)
# - macos-cli-signed-notarized-arm64, macos-cli-signed-notarized-x86_64 (final)
# - linux-cli-final-arm64, linux-cli-final-x86_64 (final)

trigger: none
pr: none

parameters:
# Build parameters
Expand Down Expand Up @@ -49,11 +51,6 @@ parameters:
type: string
default: 'Azure/homebrew-azure-cli'

- name: GitHubServiceConnection
displayName: 'GitHub Service Connection'
type: string
default: 'Azure'

- name: ESRPServiceConnection
displayName: 'ESRP Service Connection'
type: string
Expand All @@ -76,6 +73,8 @@ variables:
- template: templates/variables.yml
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- group: 'AME ESRP Variable Group'
- group: 'esrp-signing-codes'
- group: 'get-github-pat-token'

- name: GitHubRepo
value: ${{ parameters.GitHubRepo }}
Expand All @@ -100,10 +99,10 @@ variables:
- name: skipNugetSecurityAnalysis
value: true

name: macos-release-$(Build.BuildId)
name: standalone-release-$(Build.BuildId)

# ============================================================================
# JOBS: End-to-end macOS release flow
# JOBS: End-to-end standalone release flow
# ============================================================================
jobs:
# ============================================================================
Expand All @@ -115,6 +114,12 @@ jobs:
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}

- template: templates/linux/linux-build-jobs.yml
parameters:
PythonVersion: ${{ parameters.PythonVersion }}
LinuxArm64Pool: ${{ variables.ubuntu_arm64_pool }}
LinuxX64Pool: ${{ variables.ubuntu_pool }}

# Jobs included:
# - BuildMacOSCli (matrix: ARM64 + Intel)
# - VerifyMacOSCli (matrix: ARM64 + Intel)
Expand All @@ -140,46 +145,58 @@ jobs:
# - SignBinaries (matrix: ARM64 + Intel)
# - CreateNotarizeBundle (matrix: ARM64 + Intel)
# - Notarize (matrix: ARM64 + Intel)
# - CreateFinalTarball (matrix: ARM64 + Intel)
# - CreateMacOSFinalTarball (matrix: ARM64 + Intel)
# Artifacts: cli-signed-notarized-arm64, cli-signed-notarized-x86_64

# ============================================================================
# PHASE 3a: TEST (local file:// cask + offline install)
# ============================================================================
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- template: templates/macos/macos-cask-generation-and-tests.yml
- template: templates/standalone/cask-generation-and-tests.yml
parameters:
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}
LinuxArm64Pool: ${{ variables.ubuntu_arm64_pool }}
LinuxX64Pool: ${{ variables.ubuntu_pool }}
PythonVersion: ${{ parameters.PythonVersion }}
GitHubRepo: $(GitHubRepo)
Debug: ${{ parameters.Debug }}
dependsOn:
- CreateFinalTarball
CaskDependsOn:
- CreateMacOSFinalTarball
- BuildLinuxCli
MacosDependsOn:
- CreateMacOSFinalTarball
LinuxDependsOn:
- BuildLinuxCli

# Jobs included:
# - TestTempTapCask (matrix: ARM64 + Intel) - tests cask with local file:// URLs
# - TestOfflineInstall (matrix: ARM64 + Intel) - tests direct tarball install
# - TestMacOSTempTapCask (matrix: ARM64 + Intel) - tests the macOS cask
# - TestLinuxTempTapCask (matrix: ARM64 + x86_64) - tests the Linux cask
# - TestMacOSOfflineInstall (matrix: ARM64 + Intel) - tests macOS tarballs
# - TestLinuxOfflineInstall (matrix: ARM64 + x86_64) - tests Linux tarballs

# ============================================================================
# PHASE 3b: PUBLISH (GitHub + Homebrew tap)
# ============================================================================
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- template: templates/macos/macos-publish-jobs.yml
- template: templates/standalone/publish-jobs.yml
parameters:
PublishToGitHub: ${{ parameters.PublishToGitHub }}
UpdateHomebrew: ${{ parameters.UpdateHomebrew }}
TestAfterPublish: false
GitHubRepo: $(GitHubRepo)
GitHubServiceConnection: ${{ parameters.GitHubServiceConnection }}
HomebrewTapRepo: ${{ parameters.HomebrewTapRepo }}
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}
LinuxArm64Pool: ${{ variables.ubuntu_arm64_pool }}
LinuxX64Pool: ${{ variables.ubuntu_pool }}
PythonVersion: ${{ parameters.PythonVersion }}
Debug: ${{ parameters.Debug }}
dependsOn:
- TestTempTapCask
- TestOfflineInstall
- TestMacOSTempTapCask
- TestLinuxTempTapCask
- TestMacOSOfflineInstall
- TestLinuxOfflineInstall

# Jobs included:
# - CreateGitHubRelease (conditional)
Expand Down
95 changes: 95 additions & 0 deletions .azure-pipelines/templates/linux/linux-build-jobs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Linux tarball build jobs for the Homebrew Cask release.

parameters:
- name: PythonVersion
type: string
default: '3.14'
- name: LinuxArm64Pool
type: string
default: 'pool-ubuntu-latest-arm64'
- name: LinuxX64Pool
type: string
default: 'pool-ubuntu-2204'
- name: condition
type: string
default: 'succeeded()'
- name: dependsOn
type: object
default: []

jobs:
- job: BuildLinuxCli
displayName: 'Linux | Build and verify CLI'
condition: ${{ parameters.condition }}
dependsOn: ${{ parameters.dependsOn }}
strategy:
matrix:
ARM64:
Architecture: 'arm64'
PoolName: ${{ parameters.LinuxArm64Pool }}
X64:
Architecture: 'x86_64'
PoolName: ${{ parameters.LinuxX64Pool }}
pool:
name: $(PoolName)
timeoutInMinutes: 60

steps:
- checkout: self
fetchDepth: 1

- template: setup-homebrew.yml

- bash: |
set -euo pipefail

brew install python@${{ parameters.PythonVersion }}
PYTHON_PATH="$(brew --prefix python@${{ parameters.PythonVersion }})/libexec/bin/python"
"$PYTHON_PATH" --version
echo "##vso[task.setvariable variable=PythonPath]$PYTHON_PATH"
displayName: 'Install Homebrew Python'

- bash: |
set -euo pipefail

ARCH="$(Architecture)"
OUTPUT_DIR="$(Build.ArtifactStagingDirectory)/cli-build"
"$(PythonPath)" scripts/release/standalone/build_binary_tar_gz.py \
--platform-tag "linux-$ARCH" \
--output-dir "$OUTPUT_DIR"

SOURCE_TARBALL=$(find "$OUTPUT_DIR" -name "azure-cli-*-linux-$ARCH-nopython.tar.gz" -print -quit)
VERSION=$(basename "$SOURCE_TARBALL" | sed -E "s/^azure-cli-(.*)-linux-$ARCH-nopython\.tar\.gz$/\1/")
RELEASE_TARBALL="$OUTPUT_DIR/azure-cli-$VERSION-linux-$ARCH.tar.gz"
cp "$SOURCE_TARBALL" "$RELEASE_TARBALL"
sha256sum "$RELEASE_TARBALL" > "$RELEASE_TARBALL.sha256"
rm "$SOURCE_TARBALL" "$SOURCE_TARBALL.sha256"

echo "Release tarball: $RELEASE_TARBALL"
cat "$RELEASE_TARBALL.sha256"
displayName: 'Build release tarball'
env:
PYTHON_MAJOR_MINOR: ${{ parameters.PythonVersion }}

- bash: |
set -euo pipefail

ARCH="$(Architecture)"
TARBALL=$(find "$(Build.ArtifactStagingDirectory)/cli-build" -name "azure-cli-*-linux-$ARCH.tar.gz" -print -quit)
EXTRACT_DIR=$(mktemp -d)
trap 'rm -rf "$EXTRACT_DIR" || true' EXIT

tar -xzf "$TARBALL" -C "$EXTRACT_DIR"
export AZ_PYTHON="$(PythonPath)"
export AZURE_CORE_COLLECT_TELEMETRY=False
"$EXTRACT_DIR/bin/az" version
displayName: 'Smoke test release tarball'

- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
displayName: 'Generate SBOM'
inputs:
BuildDropPath: $(Build.ArtifactStagingDirectory)/cli-build

- publish: $(Build.ArtifactStagingDirectory)/cli-build
artifact: 'linux-cli-final-$(Architecture)'
displayName: 'Publish Linux CLI ($(Architecture))'
14 changes: 14 additions & 0 deletions .azure-pipelines/templates/linux/setup-homebrew.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
parameters: []

steps:
- bash: |
set -euo pipefail

if ! command -v brew >/dev/null 2>&1; then
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
echo "##vso[task.prependpath]/home/linuxbrew/.linuxbrew/bin"
brew --version
displayName: 'Install Linuxbrew'
2 changes: 1 addition & 1 deletion .azure-pipelines/templates/macos/macos-build-jobs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
echo "Architecture: $ARCH"
$PYTHON --version

$PYTHON scripts/release/macos/build_binary_tar_gz.py \
$PYTHON scripts/release/standalone/build_binary_tar_gz.py \
--platform-tag macos-$ARCH \
--output-dir dist/binary_tar_gz

Expand Down
6 changes: 3 additions & 3 deletions .azure-pipelines/templates/macos/macos-sign-notarize-jobs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ jobs:
inlineOperation: |
[
{
"KeyCode": "CP-401337-Apple",
"KeyCode": "$(ESRPAppleKeyCode)",
"OperationCode": "MacAppDeveloperSign",
"ToolName": "sign",
"ToolVersion": "1.0",
Expand Down Expand Up @@ -454,7 +454,7 @@ jobs:
inlineOperation: |
[
{
"KeyCode": "CP-401337-Apple",
"KeyCode": "$(ESRPAppleKeyCode)",
"OperationCode": "MacAppNotarize",
"ToolName": "sign",
"ToolVersion": "1.0",
Expand All @@ -475,7 +475,7 @@ jobs:
# ============================================================================
# JOB: CREATE FINAL TARBALL (Both Architectures via Matrix)
# ============================================================================
- job: CreateFinalTarball
- job: CreateMacOSFinalTarball
displayName: 'macOS | Create Final Tarball'
dependsOn:
- DownloadAnalyze
Expand Down
Loading
Loading