Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7558667
macos - homebrew cask changes
naga-nandyala Mar 2, 2026
5c5fd9d
updated comments
naga-nandyala Mar 2, 2026
7ce7e47
changed the connection details and test tap
naga-nandyala Mar 3, 2026
be47832
removed hardcoded values
naga-nandyala Mar 3, 2026
972158c
Parameterize ESRPServiceConnection in sign-notarize template
naga-nandyala Mar 3, 2026
46fadd0
Rename temp test tap to azure-cli-pipeline-test to avoid conflict
naga-nandyala Mar 3, 2026
d3c291b
Fix GitHub release target to use main branch of tap repo
naga-nandyala Mar 3, 2026
b95ab9c
Fix cask path to use sharded layout Casks/a/azure-cli.rb
naga-nandyala Mar 3, 2026
bcea968
Add license header to build_binary_tar_gz.py
naga-nandyala Mar 4, 2026
cbb0655
Address Copilot PR review: fix pool casing, README filename, docstring
naga-nandyala Mar 4, 2026
6da387f
Address Copilot PR review round 2: template python version, env var f…
naga-nandyala Mar 4, 2026
40f2d89
Pass PYTHON_MAJOR_MINOR env var to build script from pipeline parameter
naga-nandyala Mar 4, 2026
6a93326
gh copilot review comments w.r.t pythonpath addressed
naga-nandyala Mar 9, 2026
479bbdb
tab completions change
naga-nandyala Mar 10, 2026
9b6007a
AZ_INSTALLER change & az upgrade change
naga-nandyala Mar 12, 2026
65ea275
Legal File Changes
naga-nandyala Mar 12, 2026
56ca496
Legal File Changes
naga-nandyala Mar 12, 2026
ea8ae1c
Fix cask push: reset to origin/main before updating to avoid rebase c…
naga-nandyala Mar 12, 2026
e99faad
Address Copilot review: fix misleading comment and remove unused para…
naga-nandyala Mar 13, 2026
1691b85
Fix ThirdPartyNotices.txt encoding: convert Windows-1252 to UTF-8
naga-nandyala Mar 22, 2026
fc92b44
Gate ESRP variable group and sign/notarize phases to release project
naga-nandyala Mar 23, 2026
7b88017
Sync resourceManagement.yml for squad mapping
azclibot Mar 23, 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
188 changes: 188 additions & 0 deletions .azure-pipelines/macos-standalone-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Azure CLI - macOS Release Pipeline (Build → Sign → Test → Publish)
#
# Purpose: Complete end-to-end macOS 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
#
# Output Artifacts:
# - cli-build-unsigned-arm64, cli-build-unsigned-x86_64 (intermediate)
# - cli-signed-notarized-arm64, cli-signed-notarized-x86_64 (final)

trigger: none

parameters:
# Build parameters
- name: PythonVersion
displayName: 'Python Version (Homebrew)'
type: string
default: '3.13'

# Sign/notarize parameters
- name: BundleId
displayName: 'Bundle ID for notarization'
type: string
default: 'com.microsoft.azure.cli'

# Publish parameters
- name: PublishToGitHub
displayName: 'Publish to GitHub Release'
type: boolean
default: true

- name: GitHubRepo
displayName: 'GitHub Repository (owner/repo)'
type: string
default: 'Azure/homebrew-azure-cli'

- name: UpdateHomebrew
displayName: 'Update Homebrew cask after release'
type: boolean
default: true

- name: HomebrewTapRepo
displayName: 'Homebrew Tap Repository'
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
default: 'ame_esrp_connection'

- name: Debug
displayName: 'Enable debug diagnostics'
type: boolean
default: false

resources:
repositories:
- repository: homebrewtap
type: github
endpoint: 'Azure'
name: Azure/homebrew-azure-cli
ref: main

variables:
- template: templates/variables.yml
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- group: 'AME ESRP Variable Group'

- name: GitHubRepo
value: ${{ parameters.GitHubRepo }}
- name: HomebrewTapRepo
value: ${{ parameters.HomebrewTapRepo }}

# Disable auto-injection tasks
- name: Codeql.Enabled
value: false
- name: Codeql.SkipTaskAutoInjection
value: true
- name: CodeQL.enabled
value: false
- name: runCodesignValidationInjection
value: false
- name: DOTNET_CLI_TELEMETRY_OPTOUT
value: 1
- name: DOTNET_NOLOGO
value: 1
- name: NugetSecurityAnalysisWarningLevel
value: none
- name: skipNugetSecurityAnalysis
value: true

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

# ============================================================================
# JOBS: End-to-end macOS release flow
# ============================================================================
jobs:
# ============================================================================
# PHASE 1: BUILD (unsigned tarballs)
# ============================================================================
- template: templates/macos/macos-build-jobs.yml
parameters:
PythonVersion: ${{ parameters.PythonVersion }}
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}

# Jobs included:
# - BuildMacOSCli (matrix: ARM64 + Intel)
# - VerifyMacOSCli (matrix: ARM64 + Intel)
# Artifacts: cli-build-unsigned-arm64, cli-build-unsigned-x86_64

# ============================================================================
# PHASE 2: SIGN & NOTARIZE (via ESRP)
# ============================================================================
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- template: templates/macos/macos-sign-notarize-jobs.yml
parameters:
BundleId: ${{ parameters.BundleId }}
PythonVersion: ${{ parameters.PythonVersion }}
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}
ESRPServiceConnection: ${{ parameters.ESRPServiceConnection }}
UseCurrentPipelineArtifacts: true
dependsOn:
- VerifyMacOSCli

# Jobs included:
# - DownloadAnalyze (matrix: ARM64 + Intel)
# - SignBinaries (matrix: ARM64 + Intel)
# - CreateNotarizeBundle (matrix: ARM64 + Intel)
# - Notarize (matrix: ARM64 + Intel)
# - CreateFinalTarball (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
parameters:
MacosArm64Image: ${{ variables.macos_arm64_pool }}
MacosIntelImage: ${{ variables.macos_intel_pool }}
PythonVersion: ${{ parameters.PythonVersion }}
GitHubRepo: $(GitHubRepo)
Debug: ${{ parameters.Debug }}
dependsOn:
- CreateFinalTarball

# Jobs included:
# - TestTempTapCask (matrix: ARM64 + Intel) - tests cask with local file:// URLs
# - TestOfflineInstall (matrix: ARM64 + Intel) - tests direct tarball install

# ============================================================================
# PHASE 3b: PUBLISH (GitHub + Homebrew tap)
# ============================================================================
- ${{ if eq(variables['System.TeamProject'], 'release') }}:
- template: templates/macos/macos-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 }}
PythonVersion: ${{ parameters.PythonVersion }}
Debug: ${{ parameters.Debug }}
dependsOn:
- TestTempTapCask
- TestOfflineInstall

# Jobs included:
# - CreateGitHubRelease (conditional)
# - UpdateHomebrewCask (conditional)
# - PrintSummary

186 changes: 186 additions & 0 deletions .azure-pipelines/templates/macos/macos-build-jobs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# macOS Build Jobs Template
#
# Purpose: Build Azure CLI tar.gz for macOS (ARM64 + Intel)
# Usage: Can be called from main pipeline or standalone wrapper
#
# Parameters:
# - PythonVersion: Homebrew Python version (default: 3.13)
# - MacosArm64Image: VM image for ARM64 builds
# - MacosIntelImage: VM image for Intel builds
# - condition: Job execution condition
# - dependsOn: Jobs this depends on
#
# Artifacts Published:
# - macos-cli-build-unsigned-arm64
# - macos-cli-build-unsigned-x86_64

parameters:
- name: PythonVersion
type: string
default: '3.13'
- name: MacosArm64Image
type: string
default: 'macos-15-arm64'
- name: MacosIntelImage
type: string
default: 'macos-15'
- name: condition
type: string
default: 'succeeded()'
- name: dependsOn
type: object
default: []

jobs:
# ============================================================================
# JOB: BUILD MACOS CLI (ARM64 + Intel via Matrix)
# ============================================================================
- job: BuildMacOSCli
displayName: 'macOS | Build CLI'
condition: ${{ parameters.condition }}
dependsOn: ${{ parameters.dependsOn }}
strategy:
matrix:
ARM64:
Architecture: 'arm64'
vmImageName: ${{ parameters.MacosArm64Image }}
Intel:
Architecture: 'x86_64'
vmImageName: ${{ parameters.MacosIntelImage }}
pool:
vmImage: $(vmImageName)
timeoutInMinutes: 60

steps:
- checkout: self
fetchDepth: 1

- bash: |
set -e

echo "=== Installing Homebrew Python ${{ parameters.PythonVersion }} ==="
echo "Architecture: $(Architecture)"
brew install python@${{ parameters.PythonVersion }}

PYTHON_PATH=$(brew --prefix python@${{ parameters.PythonVersion }})/libexec/bin/python3
echo "Python path: $PYTHON_PATH"
$PYTHON_PATH --version

echo "##vso[task.setvariable variable=PythonPath]$PYTHON_PATH"
displayName: 'Install Homebrew Python'

- bash: |
set -e

PYTHON="$(PythonPath)"
ARCH="$(Architecture)"

echo "=== Building Azure CLI with Homebrew Python ==="
echo "Python: $PYTHON"
echo "Architecture: $ARCH"
$PYTHON --version

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

echo ""
echo "=== Build Output ==="
ls -lh dist/binary_tar_gz/

mkdir -p $(Build.ArtifactStagingDirectory)/cli-build
cp dist/binary_tar_gz/*.tar.gz $(Build.ArtifactStagingDirectory)/cli-build/
cp dist/binary_tar_gz/*.sha256 $(Build.ArtifactStagingDirectory)/cli-build/

displayName: 'Build Azure CLI Tarball'
env:
PYTHON_MAJOR_MINOR: ${{ parameters.PythonVersion }}

- 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: 'macos-cli-build-unsigned-$(Architecture)'
displayName: 'Publish Unsigned CLI Build ($(Architecture))'

# ============================================================================
# JOB: VERIFY MACOS CLI (ARM64 + Intel via Matrix)
# ============================================================================
- job: VerifyMacOSCli
displayName: 'macOS | Verify CLI'
dependsOn: BuildMacOSCli
condition: succeeded()
strategy:
matrix:
ARM64:
Architecture: 'arm64'
vmImageName: ${{ parameters.MacosArm64Image }}
Intel:
Architecture: 'x86_64'
vmImageName: ${{ parameters.MacosIntelImage }}
pool:
vmImage: $(vmImageName)

steps:
- checkout: none

- download: current
artifact: 'macos-cli-build-unsigned-$(Architecture)'
displayName: 'Download CLI Build ($(Architecture))'

- bash: |
set -e

ARCH="$(Architecture)"
TARBALL=$(find $(Pipeline.Workspace)/macos-cli-build-unsigned-$ARCH -name "azure-cli-*-macos-$ARCH-nopython.tar.gz" | head -1)
EXTRACT_DIR=$(mktemp -d)

echo "=== Tarball Analysis ==="
echo "Architecture: $ARCH"
echo "Tarball: $(basename "$TARBALL")"
TARBALL_SIZE=$(du -h "$TARBALL" | cut -f1)
echo "Size: $TARBALL_SIZE"

tar -xzf "$TARBALL" -C "$EXTRACT_DIR"

echo ""
echo "=== Native Extensions (.so files) ==="
find "$EXTRACT_DIR" -name "*.so" -type f | wc -l

echo ""
echo "=== Tarball Contents Summary ==="
echo "Extracted size: $(du -sh "$EXTRACT_DIR" | cut -f1)"
echo "File count: $(find "$EXTRACT_DIR" -type f | wc -l)"

rm -rf "$EXTRACT_DIR"
displayName: 'Analyze Tarball ($(Architecture))'

- bash: |
set -e

ARCH="$(Architecture)"
TARBALL=$(find $(Pipeline.Workspace)/macos-cli-build-unsigned-$ARCH -name "azure-cli-*-macos-$ARCH-nopython.tar.gz" | head -1)
EXTRACT_DIR=$(mktemp -d)

echo "=== Verifying Azure CLI on $ARCH ==="
tar -xzf "$TARBALL" -C "$EXTRACT_DIR"

if ! brew list python@${{ parameters.PythonVersion }} &>/dev/null; then
brew install python@${{ parameters.PythonVersion }}
fi

AZ_PYTHON="$(brew --prefix python@${{ parameters.PythonVersion }})/libexec/bin/python3"
export AZ_PYTHON

echo "System architecture: $(uname -m)"

export AZ_DEBUG=1
"$EXTRACT_DIR/bin/az" version

echo ""
echo "Azure CLI works correctly on $ARCH"

rm -rf "$EXTRACT_DIR"
displayName: 'Verify CLI Works ($(Architecture))'
Loading
Loading