From 40ce32a15ac3bed5b91a7b5afe0bb66861f202ff Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:15:57 +0200 Subject: [PATCH 1/2] refactor(ci): standardize CST and restore safe dependency-update flow Route container-structure tests through devops-infra/action-container-structure-test instead of the deprecated upstream CST image, and move the CST config into the tests/docker layout used by current repo automation. Restore a repo-specific dependency-update workflow so weekly checks build and test candidate images under the test- prefix before opening a PR, rather than publishing updated working-tree images to production tags. Refresh the Docker Hub README content and align Alpine/version assertions with the current base image. --- .github/workflows/cron-dependency-update.yml | 6 +- .github/workflows/manual-release-create.yml | 72 +++++++++++++++++--- README.md | 70 +++++++++---------- Taskfile.scripts.yml | 10 +-- tests/{ => docker}/azure.yml | 7 +- 5 files changed, 109 insertions(+), 56 deletions(-) rename tests/{ => docker}/azure.yml (91%) diff --git a/.github/workflows/cron-dependency-update.yml b/.github/workflows/cron-dependency-update.yml index 19b3503..ea1226d 100644 --- a/.github/workflows/cron-dependency-update.yml +++ b/.github/workflows/cron-dependency-update.yml @@ -2,7 +2,7 @@ name: (C) Dependency Update on: schedule: - - cron: 0 5 * * 6 + - cron: 0 5 * * 1 workflow_dispatch: permissions: @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 fetch-tags: true @@ -63,7 +63,7 @@ jobs: uses: devops-infra/action-pull-request@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} - target_branch: master + target_branch: ${{ github.event.repository.default_branch }} title: "chore(deps): bump ${{ env.VERSION_TAG }}" template: .tmp/PULL_REQUEST_TEMPLATE.md get_diff: true diff --git a/.github/workflows/manual-release-create.yml b/.github/workflows/manual-release-create.yml index 6ed3995..2f47d86 100644 --- a/.github/workflows/manual-release-create.yml +++ b/.github/workflows/manual-release-create.yml @@ -4,12 +4,17 @@ on: workflow_dispatch: inputs: version: - description: Azure CLI version to publish. Leave empty to use the Dockerfile version. + description: Azure CLI version to release. Leave empty to use the Dockerfile version. required: false type: string + build_only: + description: Build and push images without creating a git tag, GitHub release, or Docker Hub description update. + required: false + default: false + type: boolean permissions: - contents: read + contents: write packages: write jobs: @@ -18,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 fetch-tags: true @@ -38,7 +43,10 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + fetch-depth: 0 + fetch-tags: true - name: Install Task uses: go-task/setup-task@v2 @@ -51,14 +59,22 @@ jobs: set -eu current="$(task version:get)" requested="${{ inputs.version }}" + if [ -n "$requested" ] && [ "$requested" != "$current" ]; then echo "❌ Requested version '$requested' does not match Dockerfile version '$current'" exit 1 fi + if ! printf '%s' "$current" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then echo "❌ Invalid Azure CLI version: $current" exit 1 fi + + if [ "${{ inputs.build_only }}" != "true" ] && git ls-remote --tags origin "refs/tags/${current}" | grep -q .; then + echo "❌ Git tag '${current}' already exists on origin" + exit 1 + fi + echo "version=$current" >> "$GITHUB_OUTPUT" build-and-push: @@ -68,7 +84,7 @@ jobs: needs: [lint, prepare] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 fetch-tags: true @@ -113,8 +129,48 @@ jobs: done - name: Run container-structure-tests - env: - IMAGE: devopsinfra/docker-azure-cli:${{ needs.prepare.outputs.version }} + uses: devops-infra/action-container-structure-test@v1 + with: + image: devopsinfra/docker-azure-cli:${{ needs.prepare.outputs.version }} + config: tests/docker/azure.yml + pull: true + + release: + name: Release + if: ${{ !inputs.build_only }} + runs-on: ubuntu-24.04 + needs: [prepare, build-and-push] + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Push git tag run: | + set -eu VERSION="${{ needs.prepare.outputs.version }}" - task test:structure VERSION_OVERRIDE="$VERSION" IMAGE="$IMAGE" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "$VERSION" -m "$VERSION" + git push origin "$VERSION" + + - name: Create GitHub release + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ needs.prepare.outputs.version }} + name: ${{ needs.prepare.outputs.version }} + draft: false + prerelease: false + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update Docker Hub description + uses: peter-evans/dockerhub-description@v5 + with: + username: ${{ vars.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + repository: ${{ vars.DOCKER_ORG_NAME }}/${{ github.event.repository.name }} + short-description: ${{ github.event.repository.description }} diff --git a/README.md b/README.md index 5624783..6dd16c2 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,53 @@ -# `docker-azure-cli` - -Minimal Alpine-based Azure CLI base image for the `devops-infra` organization. - -## Source and Images - -- Source: -- Docker Hub: -- GHCR: - -## Current Version - -| Image | Current Azure CLI version | -| --- | --- | -| `docker-azure-cli` | `2.87.0` | - -Published image tags: - -- `2.87.0` -- `2.87` -- `latest` +# Azure CLI Docker Image +**Minimal Alpine-based Azure CLI base image for the `devops-infra` organization** + +## Available on +- **Docker Hub:** [devopsinfra/docker-azure-cli:latest](https://hub.docker.com/repository/docker/devopsinfra/docker-azure-cli) +- **GitHub Packages:** [ghcr.io/devops-infra/docker-azure-cli:latest](https://github.com/devops-infra/docker-azure-cli/pkgs/container/docker-azure-cli) +- **Source:** [devops-infra/docker-azure-cli](https://github.com/devops-infra/docker-azure-cli) + +## Badges +[ +![GitHub repo](https://img.shields.io/badge/GitHub-devops--infra%2Fdocker--azure--cli-2496ED?style=plastic&logo=github) +![GitHub last commit](https://img.shields.io/github/last-commit/devops-infra/docker-azure-cli?color=2496ED&label=Last%20commit&logo=github&style=plastic) +![Pull Request](https://github.com/devops-infra/docker-azure-cli/actions/workflows/auto-pull-request-create.yml/badge.svg) +](https://github.com/devops-infra/docker-azure-cli "shields.io") +
+[ +![DockerHub](https://img.shields.io/badge/DockerHub-devopsinfra%2Fdocker--azure--cli-0db7ed.svg?style=plastic&logo=docker) +![Docker version](https://img.shields.io/docker/v/devopsinfra/docker-azure-cli/latest?color=0db7ed&label=Version&logo=docker&style=plastic) +![Image size](https://img.shields.io/docker/image-size/devopsinfra/docker-azure-cli/latest?label=Image%20size&style=plastic&logo=docker) +![Docker Pulls](https://img.shields.io/docker/pulls/devopsinfra/docker-azure-cli?color=0db7ed&label=Pulls&logo=docker&style=plastic) +](https://hub.docker.com/r/devopsinfra/docker-azure-cli "shields.io") + +## Current image tags +- Exact Azure CLI tag: `2.87.0` +- Minor Azure CLI tag: `2.87` +- Floating tag: `latest` All published images are multi-architecture: - - `linux/amd64` - `linux/arm64` -## What Is Included - -- `alpine:3.24.x` +## What is included - `bash` - `ca-certificates` - `jq` -- `python3` (`python`) -- `pip3` (`pip`) +- `python3` with `python` +- `pip3` with `pip` - `azure-cli` -This image intentionally does **not** include: - +This image intentionally does not include: - AWS CLI - Google Cloud SDK - Terraform - OpenTofu - Terragrunt -## Local Usage +## Validation +Container Structure Tests for this repository are run with [`devops-infra/action-container-structure-test@v1`](https://github.com/devops-infra/action-container-structure-test), and the local `task test:structure` helper uses the same published runtime image. +## Local usage Build the image for the local host platform: ```bash @@ -63,14 +66,13 @@ Check for Azure CLI and Alpine package updates: task dependency:update ``` -Run container-structure-tests against the built image: +Run Container Structure Tests against the built image: ```bash task test:structure ``` -## Downstream Usage - +## Downstream usage Use this image as a base for Azure-enabled Docker images: ```dockerfile @@ -84,9 +86,7 @@ docker run --rm -it devopsinfra/docker-azure-cli:latest az version ``` ## Automation - The repository includes workflows for: - - dependency update pull requests when a new Azure CLI version is published - manual multi-arch image publishing to Docker Hub and GHCR - automatic pull request creation for non-default branches diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml index 8c7791c..a10347e 100644 --- a/Taskfile.scripts.yml +++ b/Taskfile.scripts.yml @@ -235,14 +235,13 @@ tasks: set -eu image="${IMAGE:-{{.DOCKER_NAME}}:{{.EXACT_TAG}}}" docker run --rm \ - -e AZ_VERSION='{{.VERSION_FULL}}' \ + -e INPUT_IMAGE="$image" \ + -e INPUT_CONFIG=tests/docker/azure.yml \ + -e INPUT_PULL=false \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD:/work" \ -w /work \ - gcr.io/gcp-runtimes/container-structure-test:v1.19.3 \ - test \ - --image "$image" \ - --config tests/azure.yml + devopsinfra/action-container-structure-test:v1 packages:update: desc: Update Alpine package pins in alpine-packages.txt @@ -386,6 +385,7 @@ tasks: echo "Current Azure CLI: $current | Latest: $az_latest" set_arg Dockerfile AZ_VERSION "$az_latest" update_file README.md "$current" "$az_latest" + update_file tests/docker/azure.yml "$current" "$az_latest" version_tag="" [ "$current" = "$az_latest" ] || version_tag="$version_tag az-$az_latest" diff --git a/tests/azure.yml b/tests/docker/azure.yml similarity index 91% rename from tests/azure.yml rename to tests/docker/azure.yml index 5566237..e8dc0be 100644 --- a/tests/azure.yml +++ b/tests/docker/azure.yml @@ -4,16 +4,13 @@ commandTests: - name: Alpine version command: cat args: [/etc/os-release] - expectedOutput: [VERSION_ID=3\.24] + expectedOutput: [VERSION_ID=3\.24\.1] - name: Azure CLI exact version command: bash - envVars: - - key: EXPECTED_AZ_VERSION - value: ${AZ_VERSION} args: - -lc - - test "$(az version --output json | jq -r '."azure-cli"')" = "${EXPECTED_AZ_VERSION}" + - test "$(az version --output json | jq -r '."azure-cli"')" = "2.87.0" - name: Runtime tools smoke tests command: bash From 029145465383a3e01928f9f577ff3d346117747b Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:54:39 +0200 Subject: [PATCH 2/2] feat: use VERSION_SUFFIX --- .github/workflows/cron-dependency-update.yml | 60 ++------------------ README.md | 1 + Taskfile.scripts.yml | 12 ++-- Taskfile.variables.yml | 13 ++--- 4 files changed, 18 insertions(+), 68 deletions(-) diff --git a/.github/workflows/cron-dependency-update.yml b/.github/workflows/cron-dependency-update.yml index ea1226d..38d9180 100644 --- a/.github/workflows/cron-dependency-update.yml +++ b/.github/workflows/cron-dependency-update.yml @@ -12,58 +12,8 @@ permissions: issues: read jobs: - check: - name: Check for Azure CLI updates - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v7 - with: - fetch-depth: 0 - fetch-tags: true - - - name: Install Task - uses: go-task/setup-task@v2 - with: - version: 3.x - - - name: Install Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Check for new versions - run: task dependency:update - - - name: Run linters - run: task lint - - - name: Build candidate image - if: env.VERSION_TAG != '' - run: task docker:build VERSION_PREFIX=test- - - - name: Run container-structure-tests - if: env.VERSION_TAG != '' - run: task test:structure VERSION_PREFIX=test- - - - name: Commit and push changes - if: env.VERSION_TAG != '' - uses: devops-infra/action-commit-push@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - target_branch: dependency/${{ env.VERSION_BRANCH }} - commit_message: "chore(deps): bump ${{ env.VERSION_TAG }}" - signing_mode: ssh - signing_key: ${{ secrets.SSH_SIGNING_KEY }} - - - name: Get template - if: env.VERSION_TAG != '' - run: task git:get-pr-template - - - name: Create pull request - if: env.VERSION_TAG != '' - uses: devops-infra/action-pull-request@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - target_branch: ${{ github.event.repository.default_branch }} - title: "chore(deps): bump ${{ env.VERSION_TAG }}" - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true + call: + uses: devops-infra/.github/.github/workflows/reusable-cron-dependency-update.yml@v1 + with: + profile: dockerized + secrets: inherit diff --git a/README.md b/README.md index 6dd16c2..5eca959 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ This image intentionally does not include: ## Validation Container Structure Tests for this repository are run with [`devops-infra/action-container-structure-test@v1`](https://github.com/devops-infra/action-container-structure-test), and the local `task test:structure` helper uses the same published runtime image. +CI candidate images use the shared suffix tag format: `-test`. ## Local usage Build the image for the local host platform: diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml index a10347e..f609613 100644 --- a/Taskfile.scripts.yml +++ b/Taskfile.scripts.yml @@ -137,13 +137,13 @@ tasks: cmd+=(--label "org.label-schema.vcs-url={{.LABEL_REPO_URL}}") cmd+=(--label "org.label-schema.vcs-ref={{.GIT_SHA}}") cmd+=(--label "org.label-schema.vendor={{.LABEL_VENDOR}}") - cmd+=(--label "org.label-schema.version={{.VERSION_FULL}}") + cmd+=(--label "org.label-schema.version={{.VERSION_TAG}}") cmd+=(--label "org.opencontainers.image.created={{.BUILD_DATE}}") cmd+=(--label "org.opencontainers.image.authors={{.LABEL_AUTHOR}}") cmd+=(--label "org.opencontainers.image.url={{.LABEL_HOMEPAGE}}") cmd+=(--label "org.opencontainers.image.documentation={{.LABEL_DOCS_URL}}") cmd+=(--label "org.opencontainers.image.source={{.LABEL_REPO_URL}}") - cmd+=(--label "org.opencontainers.image.version={{.VERSION_FULL}}") + cmd+=(--label "org.opencontainers.image.version={{.VERSION_TAG}}") cmd+=(--label "org.opencontainers.image.revision={{.GIT_SHA}}") cmd+=(--label "org.opencontainers.image.vendor={{.LABEL_VENDOR}}") cmd+=(--label "org.opencontainers.image.licenses={{.LABEL_LICENSE}}") @@ -181,13 +181,13 @@ tasks: cmd+=(--annotation 'index:org.label-schema.vcs-url={{.LABEL_REPO_URL}}') cmd+=(--annotation 'index:org.label-schema.vcs-ref={{.GIT_SHA}}') cmd+=(--annotation 'index:org.label-schema.vendor={{.LABEL_VENDOR}}') - cmd+=(--annotation 'index:org.label-schema.version={{.VERSION_FULL}}') + cmd+=(--annotation 'index:org.label-schema.version={{.VERSION_TAG}}') cmd+=(--annotation 'index:org.opencontainers.image.created={{.BUILD_DATE}}') cmd+=(--annotation 'index:org.opencontainers.image.authors={{.LABEL_AUTHOR}}') cmd+=(--annotation 'index:org.opencontainers.image.url={{.LABEL_HOMEPAGE}}') cmd+=(--annotation 'index:org.opencontainers.image.documentation={{.LABEL_DOCS_URL}}') cmd+=(--annotation 'index:org.opencontainers.image.source={{.LABEL_REPO_URL}}') - cmd+=(--annotation 'index:org.opencontainers.image.version={{.VERSION_FULL}}') + cmd+=(--annotation 'index:org.opencontainers.image.version={{.VERSION_TAG}}') cmd+=(--annotation 'index:org.opencontainers.image.revision={{.GIT_SHA}}') cmd+=(--annotation 'index:org.opencontainers.image.vendor={{.LABEL_VENDOR}}') cmd+=(--annotation 'index:org.opencontainers.image.licenses={{.LABEL_LICENSE}}') @@ -202,13 +202,13 @@ tasks: cmd+=(--label "org.label-schema.vcs-url={{.LABEL_REPO_URL}}") cmd+=(--label "org.label-schema.vcs-ref={{.GIT_SHA}}") cmd+=(--label "org.label-schema.vendor={{.LABEL_VENDOR}}") - cmd+=(--label "org.label-schema.version={{.VERSION_FULL}}") + cmd+=(--label "org.label-schema.version={{.VERSION_TAG}}") cmd+=(--label "org.opencontainers.image.created={{.BUILD_DATE}}") cmd+=(--label "org.opencontainers.image.authors={{.LABEL_AUTHOR}}") cmd+=(--label "org.opencontainers.image.url={{.LABEL_HOMEPAGE}}") cmd+=(--label "org.opencontainers.image.documentation={{.LABEL_DOCS_URL}}") cmd+=(--label "org.opencontainers.image.source={{.LABEL_REPO_URL}}") - cmd+=(--label "org.opencontainers.image.version={{.VERSION_FULL}}") + cmd+=(--label "org.opencontainers.image.version={{.VERSION_TAG}}") cmd+=(--label "org.opencontainers.image.revision={{.GIT_SHA}}") cmd+=(--label "org.opencontainers.image.vendor={{.LABEL_VENDOR}}") cmd+=(--label "org.opencontainers.image.licenses={{.LABEL_LICENSE}}") diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml index f3397f4..5d82e46 100644 --- a/Taskfile.variables.yml +++ b/Taskfile.variables.yml @@ -43,8 +43,8 @@ vars: else echo master fi - VERSION_PREFIX: - sh: echo "${VERSION_PREFIX:-}" + VERSION_SUFFIX: + sh: echo "${VERSION_SUFFIX:-}" VERSION_OVERRIDE: sh: echo "${VERSION_OVERRIDE:-}" AZ_VERSION: @@ -59,6 +59,7 @@ vars: VERSION_FULL: '{{.VERSION}}' VERSION_MINOR: sh: printf "%s" "{{.VERSION}}" | awk -F. '{print $1 "." $2}' + VERSION_TAG: '{{.VERSION_FULL}}{{.VERSION_SUFFIX}}' DOCKER_USERNAME: sh: echo "${DOCKER_USERNAME:-christophshyper}" DOCKER_ORG_NAME: @@ -93,8 +94,6 @@ vars: LABEL_VENDOR: DevOps-Infra LABEL_LICENSE: MIT DOCKERFILE: Dockerfile - EFFECTIVE_PREFIX: - sh: printf "%s" "${VERSION_PREFIX:-}" - EXACT_TAG: '{{.EFFECTIVE_PREFIX}}{{.VERSION_FULL}}' - MINOR_TAG: '{{.EFFECTIVE_PREFIX}}{{.VERSION_MINOR}}' - LATEST_TAG: '{{.EFFECTIVE_PREFIX}}latest' + EXACT_TAG: '{{.VERSION_FULL}}{{.VERSION_SUFFIX}}' + MINOR_TAG: '{{.VERSION_MINOR}}{{.VERSION_SUFFIX}}' + LATEST_TAG: 'latest{{.VERSION_SUFFIX}}'