diff --git a/.github/scripts/git/create_tags.py b/.github/scripts/git/create_tags.py new file mode 100644 index 00000000..cbe8d055 --- /dev/null +++ b/.github/scripts/git/create_tags.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +""" +Script to create git tags corresponding to Docker tags. + +This allows Dependabot to update images that use our images as bases. +https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories#docker +""" + +import argparse +import subprocess +import sys +from typing import List, Set + + +def run_command(cmd: List[str]) -> subprocess.CompletedProcess[str]: + print(f"Running: `{' '.join(cmd)}`") + try: + result = subprocess.run(cmd, check=True, capture_output=True, text=True) + if result.stdout: + print(f" stdout: {result.stdout.strip()}") + if result.stderr: + print(f" stderr: {result.stderr.strip()}") + return result + except subprocess.CalledProcessError as e: + print(f"Command failed with exit code {e.returncode}") + print(f" stdout: {e.stdout}") + print(f" stderr: {e.stderr}") + raise + + +def configure_git(username: str = "pulumi-bot", email: str = "bot@pulumi.com"): + run_command(["git", "config", "user.name", username]) + run_command(["git", "config", "user.email", email]) + + +def tag_exists_locally(tag: str) -> bool: + result = run_command(["git", "tag", "-l", tag]) + return tag in result.stdout.strip().split("\n") if result.stdout.strip() else False + + +def delete_tag(tag: str): + """Delete a tag locally & remotely. Assumes we have a current checkout with the tags present.""" + if tag_exists_locally(tag): + run_command(["git", "tag", "-d", tag]) + run_command(["git", "push", "origin", f":refs/tags/{tag}"]) + + +def create_and_push_tag(tag: str): + delete_tag(tag) + run_command(["git", "tag", tag]) + run_command(["git", "push", "origin", tag]) + + +def generate_git_tags(pulumi_version: str, tag_latest: bool) -> Set[str]: + tags = set[str]() + + tags.add(pulumi_version) + tags.add(f"{pulumi_version}-amd64") + tags.add(f"{pulumi_version}-arm64") + tags.add(f"{pulumi_version}-nonroot") + tags.add(f"{pulumi_version}-nonroot-amd64") + tags.add(f"{pulumi_version}-nonroot-arm64") + tags.add(f"{pulumi_version}-debian") + tags.add(f"{pulumi_version}-debian-amd64") + tags.add(f"{pulumi_version}-debian-arm64") + tags.add(f"{pulumi_version}-ubi") + if tag_latest: + tags.add("latest") + tags.add("latest-nonroot") + + return tags + + +def main(): + parser = argparse.ArgumentParser(description="Create git tags for Docker releases") + parser.add_argument( + "--pulumi-version", required=True, help="Pulumi version (e.g., 3.186.0)" + ) + parser.add_argument( + "--tag-latest", action="store_true", help="Also create latest tags" + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what tags would be created without creating them", + ) + args = parser.parse_args() + + all_tags = generate_git_tags(args.pulumi_version, args.tag_latest) + print("Tags:") + for tag in sorted(all_tags): + print(f" {tag}") + + if args.dry_run: + print("\nDry run mode - no tags were created") + return + + configure_git() + + failed_tags: list[str] = [] + + for tag in sorted(all_tags): + try: + print(f"\nCreating tag: {tag}") + create_and_push_tag(tag) + except subprocess.CalledProcessError as e: + print(f"Failed to create tag {tag}: {e}") + failed_tags.append(tag) + continue + + if failed_tags: + print(f"\nFailed to create {len(failed_tags)} tags:") + for tag in failed_tags: + print(f" {tag}") + sys.exit(1) + else: + print(f"\nSuccessfully created and pushed {len(all_tags)} tags!") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 403a39d0..8e9c77d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,9 @@ env: ESC_ACTION_OIDC_REQUESTED_TOKEN_TYPE: urn:pulumi:token-type:access_token:organization ESC_ACTION_ENVIRONMENT: imports/github-secrets ESC_ACTION_EXPORT_ENVIRONMENT_VARIABLES: GITHUB_TOKEN=PULUMI_BOT_TOKEN,PULUMI_ACCESS_TOKEN,ARM_CLIENT_ID,ARM_CLIENT_SECRET,ARM_TENANT_ID,ARM_SUBSCRIPTION_ID + # Automatically set labels like org.opencontainers.image.source on the docker images + # https://docs.docker.com/build/building/variables/#buildx_git_labels + BUILDX_GIT_LABELS: full jobs: comment-notification: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a53edf8..c790fb23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,6 +52,9 @@ env: ESC_ACTION_OIDC_REQUESTED_TOKEN_TYPE: urn:pulumi:token-type:access_token:organization ESC_ACTION_ENVIRONMENT: imports/github-secrets ESC_ACTION_EXPORT_ENVIRONMENT_VARIABLES: GITHUB_TOKEN=PULUMI_BOT_TOKEN,PULUMI_ACCESS_TOKEN,ARM_CLIENT_ID,ARM_CLIENT_SECRET,ARM_TENANT_ID,ARM_SUBSCRIPTION_ID + # Automatically set labels like org.opencontainers.image.source on the docker images + # https://docs.docker.com/build/building/variables/#buildx_git_labels + BUILDX_GIT_LABELS: full jobs: kitchen-sink: @@ -759,7 +762,14 @@ jobs: start-syncs: name: Start syncs to other container registries - needs: ["kitchen-sink", "base-manifests", "debian-sdk-manifests", "ubi-sdk"] + needs: + [ + "kitchen-sink-manifests", + "provider-build-environment-manifests", + "base-manifests", + "debian-sdk-manifests", + "ubi-sdk", + ] runs-on: ubuntu-latest # This workflow can be triggered by 2 events: workflow_dispatch, i.e., a # manual run, or repository_dispatch, which is triggered by a Pulumi @@ -787,3 +797,27 @@ jobs: run: pulumictl dispatch -r pulumi/pulumi-docker-containers -c sync-ecr ${{ env.PULUMI_VERSION }} - name: Kick off GHCR sync run: pulumictl dispatch -r pulumi/pulumi-docker-containers -c sync-ghcr ${{ env.PULUMI_VERSION }} + + create-git-tags: + name: Create git tags for Docker releases + needs: + [ + "kitchen-sink-manifests", + "provider-build-environment-manifests", + "base-manifests", + "debian-sdk-manifests", + "ubi-sdk", + ] + runs-on: ubuntu-latest + if: ${{ github.event.inputs.force_release || github.event_name == 'repository_dispatch' }} + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.13" + - name: Create git tags + run: | + python ./.github/scripts/git/create_tags.py \ + --pulumi-version ${{ env.PULUMI_VERSION }} \ + ${{ (github.event.inputs.tag_latest || github.event_name == 'repository_dispatch') && '--tag-latest' || '' }} diff --git a/CHANGELOG.md b/CHANGELOG.md index b39b3da4..fa4cbcbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,14 @@ ## Unreleased +- Add tags and labels for dependabot + ([#510](https://github.com/pulumi/pulumi-docker-containers/pull/510)) + - Add Bun to allow using it as a package manager for Node.js programs - ([509](https://github.com/pulumi/pulumi-docker-containers/pull/509)) + ([#509](https://github.com/pulumi/pulumi-docker-containers/pull/509)) - Add pnpm to Node.js images - ([509](https://github.com/pulumi/pulumi-docker-containers/pull/509)) + ([#509](https://github.com/pulumi/pulumi-docker-containers/pull/509)) - Fix pushing all image variants of pulumi/pulumi to ECR and GHCR ([#492](https://github.com/pulumi/pulumi-docker-containers/pull/492))