From 783267be6946bcf454fcec01dd3ddf45c7830dbc Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 16 Apr 2024 03:02:03 -0400 Subject: [PATCH 01/19] Build Docker image and push to GHCR Up to this point, the project has been set up as a Docker action referencing the Dockerfile. The downside to using the Dockerfile for the action is that the Docker image must be built every time the action is used. This commit will set up the project to build the Docker image and push it to GitHub Container Registry (GHCR). This change will speed up user workflows every time the action is used because the workflows will simply pull the Docker image from GHCR instead of building again. Changes: - Add required metadata to Dockerfile - Build container image with GitHub Actions - Push container image to GHCR Docker actions support pulling in pre-built Docker images. The downside is that there's no way to specify the correct Docker tag because the GitHub Actions `image` and `uses:` keys don't accept any context. For example, if a user's workflow has `uses: pypa/gh-action-pypi-publish@release/v1.8`, then the action should pull in a Docker image built from the `release/v1.8` branch, something like `ghcr.io/pypa/gh-action-pypi-publish:release-v1.8` (Docker tags can't have `/`). The workaround is to switch the top-level `action.yml` to a composite action that then calls the Docker action, substituting the correct image name and tag. --- .../actions/run-docker-container/action.yml | 32 +++++++++ .../workflows/build-and-push-docker-image.yml | 29 ++++++++ .github/workflows/self-smoke-test-action.yml | 7 +- action.yml | 69 +++++++++++++++---- 4 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 .github/actions/run-docker-container/action.yml create mode 100644 .github/workflows/build-and-push-docker-image.yml diff --git a/.github/actions/run-docker-container/action.yml b/.github/actions/run-docker-container/action.yml new file mode 100644 index 0000000..05a04b1 --- /dev/null +++ b/.github/actions/run-docker-container/action.yml @@ -0,0 +1,32 @@ +--- +name: 🏃 +inputs: + user: + required: false + password: + required: false + repository-url: + required: false + packages-dir: + required: false + verify-metadata: + required: false + skip-existing: + required: false + verbose: + required: false + print-hash: + required: false +runs: + using: docker + image: {{image}} + args: + - ${{ inputs.user }} + - ${{ inputs.password }} + - ${{ inputs.repository-url }} + - ${{ inputs.packages-dir }} + - ${{ inputs.verify-metadata }} + - ${{ inputs.skip-existing }} + - ${{ inputs.verbose }} + - ${{ inputs.print-hash }} + - ${{ inputs.attestations }} diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml new file mode 100644 index 0000000..cd3c731 --- /dev/null +++ b/.github/workflows/build-and-push-docker-image.yml @@ -0,0 +1,29 @@ +--- + +name: 🏗️ + +on: # yamllint disable-line rule:truthy + pull_request: + push: + branches: ["release/*", "unstable/*"] + tags: ["*"] + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build Docker image + run: | + IMAGE="ghcr.io/$GITHUB_REPOSITORY:${GITHUB_REF_NAME/'/'/'-'}" + echo "IMAGE=$IMAGE" >>"$GITHUB_ENV" + docker build . \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --cache-from $IMAGE \ + --tag $IMAGE + - name: Push Docker image to GHCR + if: github.event_name != 'pull_request' + run: | + echo ${{ secrets.GITHUB_TOKEN }} | + docker login ghcr.io -u $GITHUB_ACTOR --password-stdin + docker push $IMAGE diff --git a/.github/workflows/self-smoke-test-action.yml b/.github/workflows/self-smoke-test-action.yml index b655019..0a88c1c 100644 --- a/.github/workflows/self-smoke-test-action.yml +++ b/.github/workflows/self-smoke-test-action.yml @@ -3,8 +3,10 @@ name: 🧪 on: # yamllint disable-line rule:truthy - push: pull_request: + workflow_run: + workflows: [🏗️] + types: [completed] env: devpi-password: abcd1234 @@ -28,6 +30,9 @@ env: jobs: smoke-test: + if: >- + github.event_name == 'pull_request' || + github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest services: diff --git a/action.yml b/action.yml index f71598d..e67f9c2 100644 --- a/action.yml +++ b/action.yml @@ -91,15 +91,60 @@ branding: color: yellow icon: upload-cloud runs: - using: docker - image: Dockerfile - args: - - ${{ inputs.user }} - - ${{ inputs.password }} - - ${{ inputs.repository-url }} - - ${{ inputs.packages-dir }} - - ${{ inputs.verify-metadata }} - - ${{ inputs.skip-existing }} - - ${{ inputs.verbose }} - - ${{ inputs.print-hash }} - - ${{ inputs.attestations }} + using: composite + steps: + - name: Reset path if needed + run: | + # Reset path if needed + # https://github.com/pypa/gh-action-pypi-publish/issues/112 + if [[ $PATH != *"/usr/bin"* ]]; then + echo "\$PATH=$PATH. Resetting \$PATH for GitHub Actions." + PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + echo "PATH=$PATH" >>"$GITHUB_ENV" + echo "$PATH" >>"$GITHUB_PATH" + echo "\$PATH reset. \$PATH=$PATH" + fi + shell: bash + - name: Set repo and ref from which to run Docker container action + id: set-repo-and-ref + run: | + # Set repo and ref from which to run Docker container action + # to handle cases in which `github.action_` context is not set + # https://github.com/actions/runner/issues/2473 + REF=${{ env.ACTION_REF || github.ref_name }} + REPO=${{ env.ACTION_REPO || github.repository }} + echo "ref=$REF" >>"$GITHUB_OUTPUT" + echo "repo=$REPO" >>"$GITHUB_OUTPUT" + shell: bash + env: + ACTION_REF: ${{ github.action_ref }} + ACTION_REPO: ${{ github.action_repository }} + - name: Set Docker image name and tag + run: | + # Set Docker image name and tag + # if action run was triggered by a pull request to this repo, + # build image from Dockerfile because it has not been pushed to GHCR, + # else pull image from GHCR + if [[ $GITHUB_EVENT_NAME == "pull_request" ]] && + [[ $GITHUB_REPOSITORY == "pypa/gh-action-pypi-publish" ]]; then + IMAGE="../../../Dockerfile" + else + REF=${{ steps.set-repo-and-ref.outputs.ref }} + REPO=${{ steps.set-repo-and-ref.outputs.repo }} + IMAGE="docker://ghcr.io/$REPO:${REF/'/'/'-'}" + fi + FILE=".github/actions/run-docker-container/action.yml" + sed -i -e "s|{{image}}|$IMAGE|g" "$FILE" + shell: bash + - name: Run Docker container + uses: ./.github/actions/run-docker-container + with: + user: ${{ inputs.user }} + password: ${{ inputs.password }} + repository-url: ${{ inputs.repository-url || inputs.repository_url }} + packages-dir: ${{ inputs.packages-dir || inputs.packages_dir }} + verify-metadata: ${{ inputs.verify-metadata || inputs.verify_metadata }} + skip-existing: ${{ inputs.skip-existing || inputs.skip_existing }} + verbose: ${{ inputs.verbose }} + print-hash: ${{ inputs.print-hash || inputs.print_hash }} + attestations: ${{ inputs.attestations }} From e453f8c630387210460e03d303395b75b19f3b99 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Thu, 18 Apr 2024 22:01:29 -0400 Subject: [PATCH 02/19] Fix pre-commit errors --- .github/actions/run-docker-container/action.yml | 15 ++++++++++++++- .github/workflows/build-and-push-docker-image.yml | 1 + .pre-commit-config.yaml | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/actions/run-docker-container/action.yml b/.github/actions/run-docker-container/action.yml index 05a04b1..e1b1ecd 100644 --- a/.github/actions/run-docker-container/action.yml +++ b/.github/actions/run-docker-container/action.yml @@ -1,25 +1,38 @@ --- name: 🏃 +description: >- + Run Docker container to + upload Python distribution packages to PyPI inputs: user: + description: PyPI user required: false password: + description: Password for your PyPI user or an access token required: false repository-url: + description: The repository URL to use required: false packages-dir: + description: The target directory for distribution required: false verify-metadata: + description: Check metadata before uploading required: false skip-existing: + description: >- + Do not fail if a Python package distribution + exists in the target package index required: false verbose: + description: Show verbose output. required: false print-hash: + description: Show hash values of files to be uploaded required: false runs: using: docker - image: {{image}} + image: "{{image}}" args: - ${{ inputs.user }} - ${{ inputs.password }} diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index cd3c731..57980fe 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -11,6 +11,7 @@ on: # yamllint disable-line rule:truthy jobs: build-and-push: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 - name: Build Docker image diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d5f5f7e..6f1ea80 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: args: - --builtin-schema - github-workflows-require-timeout - files: ^\.github/workflows/[^/]+$ + files: ^\.github\/workflows/[^/]+$ types: - yaml - id: check-readthedocs From 0d8d5059c85abef0befd45626d6d08c98a8a3680 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Fri, 26 Apr 2024 19:08:30 -0400 Subject: [PATCH 03/19] Separate `docker login` and `docker push` https://github.com/pypa/gh-action-pypi-publish/pull/230#discussion_r1578694138 --- .github/workflows/build-and-push-docker-image.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index 57980fe..d811267 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -22,9 +22,12 @@ jobs: --build-arg BUILDKIT_INLINE_CACHE=1 \ --cache-from $IMAGE \ --tag $IMAGE - - name: Push Docker image to GHCR + - name: Log in to GHCR if: github.event_name != 'pull_request' run: | echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin + - name: Push Docker image to GHCR + if: github.event_name != 'pull_request' + run: | docker push $IMAGE From aed6c4b1b02d8644667434f8e4c077b9a2db90b4 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Mon, 27 May 2024 13:45:20 -0400 Subject: [PATCH 04/19] Generate Docker container action with Python --- .../actions/run-docker-container/action.yml | 45 ---------- action.yml | 32 +++---- create-docker-action.py | 88 +++++++++++++++++++ requirements/github-actions.in | 2 + requirements/github-actions.txt | 8 ++ 5 files changed, 114 insertions(+), 61 deletions(-) delete mode 100644 .github/actions/run-docker-container/action.yml create mode 100644 create-docker-action.py create mode 100644 requirements/github-actions.in create mode 100644 requirements/github-actions.txt diff --git a/.github/actions/run-docker-container/action.yml b/.github/actions/run-docker-container/action.yml deleted file mode 100644 index e1b1ecd..0000000 --- a/.github/actions/run-docker-container/action.yml +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: 🏃 -description: >- - Run Docker container to - upload Python distribution packages to PyPI -inputs: - user: - description: PyPI user - required: false - password: - description: Password for your PyPI user or an access token - required: false - repository-url: - description: The repository URL to use - required: false - packages-dir: - description: The target directory for distribution - required: false - verify-metadata: - description: Check metadata before uploading - required: false - skip-existing: - description: >- - Do not fail if a Python package distribution - exists in the target package index - required: false - verbose: - description: Show verbose output. - required: false - print-hash: - description: Show hash values of files to be uploaded - required: false -runs: - using: docker - image: "{{image}}" - args: - - ${{ inputs.user }} - - ${{ inputs.password }} - - ${{ inputs.repository-url }} - - ${{ inputs.packages-dir }} - - ${{ inputs.verify-metadata }} - - ${{ inputs.skip-existing }} - - ${{ inputs.verbose }} - - ${{ inputs.print-hash }} - - ${{ inputs.attestations }} diff --git a/action.yml b/action.yml index e67f9c2..d051ab1 100644 --- a/action.yml +++ b/action.yml @@ -119,25 +119,25 @@ runs: env: ACTION_REF: ${{ github.action_ref }} ACTION_REPO: ${{ github.action_repository }} - - name: Set Docker image name and tag + - name: Check out action repo + uses: actions/checkout@v4 + with: + path: action-repo + ref: ${{ steps.set-repo-and-ref.outputs.ref }} + repository: ${{ steps.set-repo-and-ref.outputs.repo }} + - name: Create Docker container action run: | - # Set Docker image name and tag - # if action run was triggered by a pull request to this repo, - # build image from Dockerfile because it has not been pushed to GHCR, - # else pull image from GHCR - if [[ $GITHUB_EVENT_NAME == "pull_request" ]] && - [[ $GITHUB_REPOSITORY == "pypa/gh-action-pypi-publish" ]]; then - IMAGE="../../../Dockerfile" - else - REF=${{ steps.set-repo-and-ref.outputs.ref }} - REPO=${{ steps.set-repo-and-ref.outputs.repo }} - IMAGE="docker://ghcr.io/$REPO:${REF/'/'/'-'}" - fi - FILE=".github/actions/run-docker-container/action.yml" - sed -i -e "s|{{image}}|$IMAGE|g" "$FILE" + # Create Docker container action + python -m pip install -r requirements/github-actions.txt + python create-docker-action.py ${{ steps.set-image.outputs.image }} + env: + EVENT: ${{ github.event_name }} + REF: ${{ steps.set-repo-and-ref.outputs.ref }} + REPO: ${{ steps.set-repo-and-ref.outputs.repo }} shell: bash + working-directory: action-repo - name: Run Docker container - uses: ./.github/actions/run-docker-container + uses: ./action-repo/.github/actions/run-docker-container with: user: ${{ inputs.user }} password: ${{ inputs.password }} diff --git a/create-docker-action.py b/create-docker-action.py new file mode 100644 index 0000000..bc2e005 --- /dev/null +++ b/create-docker-action.py @@ -0,0 +1,88 @@ +import os +import pathlib + +import yaml + +DESCRIPTION = 'description' +REQUIRED = 'required' + +EVENT = os.environ['EVENT'] +REF = os.environ['REF'] +REPO = os.environ['REPO'] + + +def set_image(event: str, ref: str, repo: str) -> str: + if event == 'pull_request' and 'gh-action-pypi-publish' in repo: + return '../../../Dockerfile' + docker_ref = ref.replace('/', '-') + return f'docker://ghcr.io/{repo}:{docker_ref}' + + +image = set_image(EVENT, REF, REPO) + +action = { + 'name': '🏃', + DESCRIPTION: ( + 'Run Docker container to upload Python distribution packages to PyPI' + ), + 'inputs': { + 'user': {DESCRIPTION: 'PyPI user', REQUIRED: False}, + 'password': { + DESCRIPTION: 'Password for your PyPI user or an access token', + REQUIRED: False, + }, + 'repository-url': { + DESCRIPTION: 'The repository URL to use', + REQUIRED: False, + }, + 'packages-dir': { + DESCRIPTION: 'The target directory for distribution', + REQUIRED: False, + }, + 'verify-metadata': { + DESCRIPTION: 'Check metadata before uploading', + REQUIRED: False, + }, + 'skip-existing': { + DESCRIPTION: ( + 'Do not fail if a Python package distribution' + ' exists in the target package index' + ), + REQUIRED: False, + }, + 'verbose': {DESCRIPTION: 'Show verbose output.', REQUIRED: False}, + 'print-hash': { + DESCRIPTION: 'Show hash values of files to be uploaded', + REQUIRED: False, + }, + 'attestations': { + DESCRIPTION: ( + '[EXPERIMENTAL]' + ' Enable experimental support for PEP 740 attestations.' + ' Only works with PyPI and TestPyPI via Trusted Publishing.' + ), + REQUIRED: False, + } + }, + 'runs': { + 'using': 'docker', + 'image': image, + 'args': [ + '${{ inputs.user }}', + '${{ inputs.password }}', + '${{ inputs.repository-url }}', + '${{ inputs.packages-dir }}', + '${{ inputs.verify-metadata }}', + '${{ inputs.skip-existing }}', + '${{ inputs.verbose }}', + '${{ inputs.print-hash }}', + '${{ inputs.attestations }}', + ], + }, +} + +action_path = pathlib.Path('.github/actions/run-docker-container/action.yml') +action_path.parent.mkdir(parents=True, exist_ok=True) + +with action_path.open(mode='w', encoding='utf-8') as file: + yaml.dump(action, file, allow_unicode=True, sort_keys=False) diff --git a/requirements/github-actions.in b/requirements/github-actions.in new file mode 100644 index 0000000..2314722 --- /dev/null +++ b/requirements/github-actions.in @@ -0,0 +1,2 @@ +# NOTE: used by create-docker-action.py +pyyaml diff --git a/requirements/github-actions.txt b/requirements/github-actions.txt new file mode 100644 index 0000000..0f1caa2 --- /dev/null +++ b/requirements/github-actions.txt @@ -0,0 +1,8 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --allow-unsafe --config=../.pip-tools.toml --output-file=github-actions.txt --strip-extras github-actions.in +# +pyyaml==6.0.1 + # via -r github-actions.in From f1f014b445fb2d36e5923f270268cc003dedc729 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Mon, 27 May 2024 14:08:24 -0400 Subject: [PATCH 05/19] Reset pre-commit `files:` regex --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f1ea80..d5f5f7e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: args: - --builtin-schema - github-workflows-require-timeout - files: ^\.github\/workflows/[^/]+$ + files: ^\.github/workflows/[^/]+$ types: - yaml - id: check-readthedocs From cf5ce177daab78038d84aabd1e53da2b26e621f1 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Mon, 27 May 2024 14:00:48 -0400 Subject: [PATCH 06/19] Use YAML block strip syntax (`>-`) where possible --- .github/workflows/build-and-push-docker-image.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index d811267..417891c 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -24,10 +24,9 @@ jobs: --tag $IMAGE - name: Log in to GHCR if: github.event_name != 'pull_request' - run: | + run: >- echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin - name: Push Docker image to GHCR if: github.event_name != 'pull_request' - run: | - docker push $IMAGE + run: docker push $IMAGE From 5ded5310e7365c2319d8cefbe17deb18c87cec74 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Mon, 27 May 2024 14:39:55 -0400 Subject: [PATCH 07/19] Add `workflow_dispatch` trigger for Docker builds --- .github/workflows/build-and-push-docker-image.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index 417891c..f39a715 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -6,7 +6,12 @@ on: # yamllint disable-line rule:truthy pull_request: push: branches: ["release/*", "unstable/*"] - tags: ["*"] + workflow_dispatch: + inputs: + tag: + description: Docker image tag + required: true + type: string jobs: build-and-push: @@ -16,12 +21,14 @@ jobs: - uses: actions/checkout@v4 - name: Build Docker image run: | - IMAGE="ghcr.io/$GITHUB_REPOSITORY:${GITHUB_REF_NAME/'/'/'-'}" + IMAGE="ghcr.io/$GITHUB_REPOSITORY:${DOCKER_TAG/'/'/'-'}" echo "IMAGE=$IMAGE" >>"$GITHUB_ENV" docker build . \ --build-arg BUILDKIT_INLINE_CACHE=1 \ --cache-from $IMAGE \ --tag $IMAGE + env: + DOCKER_TAG: ${{ inputs.tag || github.ref_name }} - name: Log in to GHCR if: github.event_name != 'pull_request' run: >- From a869dd36b2474e3145d15d4d13013b7622bc12b0 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Thu, 30 May 2024 21:34:34 -0400 Subject: [PATCH 08/19] Checkout `github.head_ref` and repo for PRs https://github.com/actions/checkout/issues/27#issuecomment-535897113 https://github.com/actions/checkout/issues/1108 --- action.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index d051ab1..2ae5a8e 100644 --- a/action.yml +++ b/action.yml @@ -111,14 +111,16 @@ runs: # Set repo and ref from which to run Docker container action # to handle cases in which `github.action_` context is not set # https://github.com/actions/runner/issues/2473 - REF=${{ env.ACTION_REF || github.ref_name }} - REPO=${{ env.ACTION_REPO || github.repository }} + REF=${{ env.ACTION_REF || env.PR_REF || github.ref_name }} + REPO=${{ env.ACTION_REPO || env.PR_REPO || github.repository }} echo "ref=$REF" >>"$GITHUB_OUTPUT" echo "repo=$REPO" >>"$GITHUB_OUTPUT" shell: bash env: ACTION_REF: ${{ github.action_ref }} ACTION_REPO: ${{ github.action_repository }} + PR_REF: ${{ github.event.pull_request.head.ref }} + PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} - name: Check out action repo uses: actions/checkout@v4 with: From a360fcb184bd4cefddaef3d4bbdf179053dfcb3e Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Sat, 1 Jun 2024 17:08:20 -0400 Subject: [PATCH 09/19] Dump action as JSON --- action.yml | 3 +-- create-docker-action.py | 7 ++----- requirements/github-actions.in | 2 -- requirements/github-actions.txt | 8 -------- 4 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 requirements/github-actions.in delete mode 100644 requirements/github-actions.txt diff --git a/action.yml b/action.yml index 2ae5a8e..ea0a4d2 100644 --- a/action.yml +++ b/action.yml @@ -130,8 +130,7 @@ runs: - name: Create Docker container action run: | # Create Docker container action - python -m pip install -r requirements/github-actions.txt - python create-docker-action.py ${{ steps.set-image.outputs.image }} + python create-docker-action.py env: EVENT: ${{ github.event_name }} REF: ${{ steps.set-repo-and-ref.outputs.ref }} diff --git a/create-docker-action.py b/create-docker-action.py index bc2e005..dc36155 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -1,8 +1,7 @@ +import json import os import pathlib -import yaml - DESCRIPTION = 'description' REQUIRED = 'required' @@ -83,6 +82,4 @@ action = { action_path = pathlib.Path('.github/actions/run-docker-container/action.yml') action_path.parent.mkdir(parents=True, exist_ok=True) - -with action_path.open(mode='w', encoding='utf-8') as file: - yaml.dump(action, file, allow_unicode=True, sort_keys=False) +action_path.write_text(json.dumps(action, ensure_ascii=False), encoding='utf-8') diff --git a/requirements/github-actions.in b/requirements/github-actions.in deleted file mode 100644 index 2314722..0000000 --- a/requirements/github-actions.in +++ /dev/null @@ -1,2 +0,0 @@ -# NOTE: used by create-docker-action.py -pyyaml diff --git a/requirements/github-actions.txt b/requirements/github-actions.txt deleted file mode 100644 index 0f1caa2..0000000 --- a/requirements/github-actions.txt +++ /dev/null @@ -1,8 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --allow-unsafe --config=../.pip-tools.toml --output-file=github-actions.txt --strip-extras github-actions.in -# -pyyaml==6.0.1 - # via -r github-actions.in From f51682fb52eebc08c0cacb1386f97c89eff75cb3 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Sun, 9 Jun 2024 16:47:19 -0400 Subject: [PATCH 10/19] Check repo owner ID instead of repo name --- action.yml | 4 ++++ create-docker-action.py | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/action.yml b/action.yml index ea0a4d2..76e8eb6 100644 --- a/action.yml +++ b/action.yml @@ -113,14 +113,17 @@ runs: # https://github.com/actions/runner/issues/2473 REF=${{ env.ACTION_REF || env.PR_REF || github.ref_name }} REPO=${{ env.ACTION_REPO || env.PR_REPO || github.repository }} + REPO_OWNER_ID=${{ env.PR_REPO_OWNER_ID || github.repository_owner_id }} echo "ref=$REF" >>"$GITHUB_OUTPUT" echo "repo=$REPO" >>"$GITHUB_OUTPUT" + echo "repo-owner-id=$REPO_OWNER_ID" >>"$GITHUB_OUTPUT" shell: bash env: ACTION_REF: ${{ github.action_ref }} ACTION_REPO: ${{ github.action_repository }} PR_REF: ${{ github.event.pull_request.head.ref }} PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} + PR_REPO_OWNER_ID: ${{ github.event.pull_request.base.repo.owner.id }} - name: Check out action repo uses: actions/checkout@v4 with: @@ -135,6 +138,7 @@ runs: EVENT: ${{ github.event_name }} REF: ${{ steps.set-repo-and-ref.outputs.ref }} REPO: ${{ steps.set-repo-and-ref.outputs.repo }} + REPO_OWNER_ID: ${{ steps.set-repo-and-ref.outputs.repo-owner-id }} shell: bash working-directory: action-repo - name: Run Docker container diff --git a/create-docker-action.py b/create-docker-action.py index dc36155..a51d27d 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -8,16 +8,18 @@ REQUIRED = 'required' EVENT = os.environ['EVENT'] REF = os.environ['REF'] REPO = os.environ['REPO'] +REPO_OWNER_ID = os.environ['REPO_OWNER_ID'] +REPO_OWNER_ID_PYPA = '647025' -def set_image(event: str, ref: str, repo: str) -> str: - if event == 'pull_request' and 'gh-action-pypi-publish' in repo: +def set_image(event: str, ref: str, repo: str, repo_owner_id: str) -> str: + if event == 'pull_request' and repo_owner_id == REPO_OWNER_ID_PYPA: return '../../../Dockerfile' docker_ref = ref.replace('/', '-') return f'docker://ghcr.io/{repo}:{docker_ref}' -image = set_image(EVENT, REF, REPO) +image = set_image(EVENT, REF, REPO, REPO_OWNER_ID) action = { 'name': '🏃', From 7ea8313fc2c8774b7904a970426f44c5a8defbcc Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Sun, 9 Jun 2024 20:08:19 -0400 Subject: [PATCH 11/19] Check repo ID instead of repo owner ID --- action.yml | 8 ++++---- create-docker-action.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/action.yml b/action.yml index 76e8eb6..7320b86 100644 --- a/action.yml +++ b/action.yml @@ -113,17 +113,17 @@ runs: # https://github.com/actions/runner/issues/2473 REF=${{ env.ACTION_REF || env.PR_REF || github.ref_name }} REPO=${{ env.ACTION_REPO || env.PR_REPO || github.repository }} - REPO_OWNER_ID=${{ env.PR_REPO_OWNER_ID || github.repository_owner_id }} + REPO_ID=${{ env.PR_REPO_ID || github.repository_id }} echo "ref=$REF" >>"$GITHUB_OUTPUT" echo "repo=$REPO" >>"$GITHUB_OUTPUT" - echo "repo-owner-id=$REPO_OWNER_ID" >>"$GITHUB_OUTPUT" + echo "repo-id=$REPO_ID" >>"$GITHUB_OUTPUT" shell: bash env: ACTION_REF: ${{ github.action_ref }} ACTION_REPO: ${{ github.action_repository }} PR_REF: ${{ github.event.pull_request.head.ref }} PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} - PR_REPO_OWNER_ID: ${{ github.event.pull_request.base.repo.owner.id }} + PR_REPO_ID: ${{ github.event.pull_request.base.repo.id }} - name: Check out action repo uses: actions/checkout@v4 with: @@ -138,7 +138,7 @@ runs: EVENT: ${{ github.event_name }} REF: ${{ steps.set-repo-and-ref.outputs.ref }} REPO: ${{ steps.set-repo-and-ref.outputs.repo }} - REPO_OWNER_ID: ${{ steps.set-repo-and-ref.outputs.repo-owner-id }} + REPO_ID: ${{ steps.set-repo-and-ref.outputs.repo-id }} shell: bash working-directory: action-repo - name: Run Docker container diff --git a/create-docker-action.py b/create-docker-action.py index a51d27d..86adb19 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -8,18 +8,18 @@ REQUIRED = 'required' EVENT = os.environ['EVENT'] REF = os.environ['REF'] REPO = os.environ['REPO'] -REPO_OWNER_ID = os.environ['REPO_OWNER_ID'] -REPO_OWNER_ID_PYPA = '647025' +REPO_ID = os.environ['REPO_ID'] +REPO_ID_GH_ACTION = '178055147' -def set_image(event: str, ref: str, repo: str, repo_owner_id: str) -> str: - if event == 'pull_request' and repo_owner_id == REPO_OWNER_ID_PYPA: +def set_image(event: str, ref: str, repo: str, repo_id: str) -> str: + if event == 'pull_request' and repo_id == REPO_ID_GH_ACTION: return '../../../Dockerfile' docker_ref = ref.replace('/', '-') return f'docker://ghcr.io/{repo}:{docker_ref}' -image = set_image(EVENT, REF, REPO, REPO_OWNER_ID) +image = set_image(EVENT, REF, REPO, REPO_ID) action = { 'name': '🏃', From bacb62682c754871d3471af8890de22d03b01199 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 11 Jun 2024 12:53:35 -0400 Subject: [PATCH 12/19] Fail-fast in unsupported environments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/pypa/gh-action-pypi-publish/pull/230#discussion_r1632406604 Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- action.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/action.yml b/action.yml index 7320b86..508d4c6 100644 --- a/action.yml +++ b/action.yml @@ -93,6 +93,12 @@ branding: runs: using: composite steps: + - name: Fail-fast in unsupported environments + if: runner.os != 'Linux' + run: | + >&2 echo This action is only able to run under GNU/Linux environments + exit 1 + shell: bash -eEuo pipefail {0} - name: Reset path if needed run: | # Reset path if needed From d03addb8e640d5bc0f05e40dfc630b3fa59776d8 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 11 Jun 2024 13:01:29 -0400 Subject: [PATCH 13/19] Drop args from create-docker-action.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- create-docker-action.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/create-docker-action.py b/create-docker-action.py index 86adb19..cf3eb5f 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -68,17 +68,6 @@ action = { 'runs': { 'using': 'docker', 'image': image, - 'args': [ - '${{ inputs.user }}', - '${{ inputs.password }}', - '${{ inputs.repository-url }}', - '${{ inputs.packages-dir }}', - '${{ inputs.verify-metadata }}', - '${{ inputs.skip-existing }}', - '${{ inputs.verbose }}', - '${{ inputs.print-hash }}', - '${{ inputs.attestations }}', - ], }, } From 153ccde9bc89de7fabd26026009f28e4c3f5bae1 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Wed, 10 Jul 2024 18:40:53 -0400 Subject: [PATCH 14/19] Verify fail-fast in unsupported environments --- .github/workflows/self-smoke-test-action.yml | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/self-smoke-test-action.yml b/.github/workflows/self-smoke-test-action.yml index 0a88c1c..ddddf83 100644 --- a/.github/workflows/self-smoke-test-action.yml +++ b/.github/workflows/self-smoke-test-action.yml @@ -29,6 +29,34 @@ env: PYTEST_THEME_MODE jobs: + fail-fast: + if: >- + github.event_name == 'pull_request' || + github.event.workflow_run.conclusion == 'success' + + strategy: + matrix: + os: [macos-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + timeout-minutes: 2 + + steps: + - name: Check out the action locally + uses: actions/checkout@v3 + with: + path: test + - name: Fail-fast in unsupported environments + continue-on-error: true + id: fail-fast + uses: ./test + - name: Error if action did not fail-fast in unsupported environments + if: steps.fail-fast.outcome == 'success' + run: | + >&2 echo This action should fail-fast in unsupported environments. + exit 1 + smoke-test: if: >- github.event_name == 'pull_request' || From cfb9d93a2623522535b927826fc87684f70365d6 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Sat, 7 Sep 2024 14:28:31 -0400 Subject: [PATCH 15/19] Add Docker tags for major and minor versions --- .../workflows/build-and-push-docker-image.yml | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index f39a715..39f3163 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -9,8 +9,8 @@ on: # yamllint disable-line rule:truthy workflow_dispatch: inputs: tag: - description: Docker image tag - required: true + description: Docker image tag (optional, defaults to Git ref) + required: false type: string jobs: @@ -21,12 +21,21 @@ jobs: - uses: actions/checkout@v4 - name: Build Docker image run: | - IMAGE="ghcr.io/$GITHUB_REPOSITORY:${DOCKER_TAG/'/'/'-'}" + DOCKER_TAG="${DOCKER_TAG/'/'/'-'}" + DOCKER_TAG_MAJOR=$(echo "$DOCKER_TAG" | cut -d '.' -f 1) + DOCKER_TAG_MAJOR_MINOR=$(echo "$DOCKER_TAG" | cut -d '.' -f 1-2) + IMAGE="ghcr.io/$GITHUB_REPOSITORY:${DOCKER_TAG}" + IMAGE_MAJOR="ghcr.io/$GITHUB_REPOSITORY:${DOCKER_TAG_MAJOR}" + IMAGE_MAJOR_MINOR="ghcr.io/$GITHUB_REPOSITORY:${DOCKER_TAG_MAJOR_MINOR}" echo "IMAGE=$IMAGE" >>"$GITHUB_ENV" + echo "IMAGE_MAJOR=$IMAGE_MAJOR" >>"$GITHUB_ENV" + echo "IMAGE_MAJOR_MINOR=$IMAGE_MAJOR_MINOR" >>"$GITHUB_ENV" docker build . \ --build-arg BUILDKIT_INLINE_CACHE=1 \ --cache-from $IMAGE \ --tag $IMAGE + docker tag $IMAGE $IMAGE_MAJOR + docker tag $IMAGE $IMAGE_MAJOR_MINOR env: DOCKER_TAG: ${{ inputs.tag || github.ref_name }} - name: Log in to GHCR @@ -36,4 +45,7 @@ jobs: docker login ghcr.io -u $GITHUB_ACTOR --password-stdin - name: Push Docker image to GHCR if: github.event_name != 'pull_request' - run: docker push $IMAGE + run: | + docker push $IMAGE + docker push $IMAGE_MAJOR + docker push $IMAGE_MAJOR_MINOR From 1b9f21a74186d118c2657dfb4595b0526ecde1a8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:39:31 +0000 Subject: [PATCH 16/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- create-docker-action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create-docker-action.py b/create-docker-action.py index cf3eb5f..7b42ad8 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -63,7 +63,7 @@ action = { ' Only works with PyPI and TestPyPI via Trusted Publishing.' ), REQUIRED: False, - } + }, }, 'runs': { 'using': 'docker', From 80b1d50e0dd4d304b48449d781099aee65e1ee35 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Sat, 14 Sep 2024 14:05:40 -0400 Subject: [PATCH 17/19] Make `workflow_dispatch` Docker tag input required https://github.com/pypa/gh-action-pypi-publish/pull/230#discussion_r1759496153 --- .github/workflows/build-and-push-docker-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index 39f3163..f8e9ae5 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -9,8 +9,8 @@ on: # yamllint disable-line rule:truthy workflow_dispatch: inputs: tag: - description: Docker image tag (optional, defaults to Git ref) - required: false + description: Docker image tag + required: true type: string jobs: From da554410b00985409d772ab68bf845b44bbf5f4c Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Fri, 4 Oct 2024 18:20:25 -0400 Subject: [PATCH 18/19] Move smoke test to reusable workflow --- .../workflows/build-and-push-docker-image.yml | 4 ++++ ...e-test-action.yml => reusable-smoke-test.yml} | 16 ++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) rename .github/workflows/{self-smoke-test-action.yml => reusable-smoke-test.yml} (90%) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index f8e9ae5..fda55e5 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -49,3 +49,7 @@ jobs: docker push $IMAGE docker push $IMAGE_MAJOR docker push $IMAGE_MAJOR_MINOR + smoke-test: + needs: + - build-and-push + uses: ./.github/workflows/reusable-smoke-test.yml diff --git a/.github/workflows/self-smoke-test-action.yml b/.github/workflows/reusable-smoke-test.yml similarity index 90% rename from .github/workflows/self-smoke-test-action.yml rename to .github/workflows/reusable-smoke-test.yml index ddddf83..ac59f08 100644 --- a/.github/workflows/self-smoke-test-action.yml +++ b/.github/workflows/reusable-smoke-test.yml @@ -1,12 +1,9 @@ --- -name: 🧪 +name: ♻️ 🧪 on: # yamllint disable-line rule:truthy - pull_request: - workflow_run: - workflows: [🏗️] - types: [completed] + workflow_call: env: devpi-password: abcd1234 @@ -30,9 +27,6 @@ env: jobs: fail-fast: - if: >- - github.event_name == 'pull_request' || - github.event.workflow_run.conclusion == 'success' strategy: matrix: @@ -44,7 +38,7 @@ jobs: steps: - name: Check out the action locally - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: test - name: Fail-fast in unsupported environments @@ -58,9 +52,7 @@ jobs: exit 1 smoke-test: - if: >- - github.event_name == 'pull_request' || - github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest services: From 36965cb24aed76043aeb8f19062b6a31fa56b990 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Fri, 4 Oct 2024 18:23:49 -0400 Subject: [PATCH 19/19] Run smoke tests before Docker builds https://github.com/pypa/gh-action-pypi-publish/pull/230#discussion_r1787027821 --- .github/workflows/build-and-push-docker-image.yml | 11 +++++------ action.yml | 1 - create-docker-action.py | 7 +++---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index fda55e5..d8fd716 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -14,8 +14,13 @@ on: # yamllint disable-line rule:truthy type: string jobs: + smoke-test: + uses: ./.github/workflows/reusable-smoke-test.yml build-and-push: + if: github.event_name != 'pull_request' runs-on: ubuntu-latest + needs: + - smoke-test timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -39,17 +44,11 @@ jobs: env: DOCKER_TAG: ${{ inputs.tag || github.ref_name }} - name: Log in to GHCR - if: github.event_name != 'pull_request' run: >- echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin - name: Push Docker image to GHCR - if: github.event_name != 'pull_request' run: | docker push $IMAGE docker push $IMAGE_MAJOR docker push $IMAGE_MAJOR_MINOR - smoke-test: - needs: - - build-and-push - uses: ./.github/workflows/reusable-smoke-test.yml diff --git a/action.yml b/action.yml index 508d4c6..7f6b746 100644 --- a/action.yml +++ b/action.yml @@ -141,7 +141,6 @@ runs: # Create Docker container action python create-docker-action.py env: - EVENT: ${{ github.event_name }} REF: ${{ steps.set-repo-and-ref.outputs.ref }} REPO: ${{ steps.set-repo-and-ref.outputs.repo }} REPO_ID: ${{ steps.set-repo-and-ref.outputs.repo-id }} diff --git a/create-docker-action.py b/create-docker-action.py index 7b42ad8..16aa54c 100644 --- a/create-docker-action.py +++ b/create-docker-action.py @@ -5,21 +5,20 @@ import pathlib DESCRIPTION = 'description' REQUIRED = 'required' -EVENT = os.environ['EVENT'] REF = os.environ['REF'] REPO = os.environ['REPO'] REPO_ID = os.environ['REPO_ID'] REPO_ID_GH_ACTION = '178055147' -def set_image(event: str, ref: str, repo: str, repo_id: str) -> str: - if event == 'pull_request' and repo_id == REPO_ID_GH_ACTION: +def set_image(ref: str, repo: str, repo_id: str) -> str: + if repo_id == REPO_ID_GH_ACTION: return '../../../Dockerfile' docker_ref = ref.replace('/', '-') return f'docker://ghcr.io/{repo}:{docker_ref}' -image = set_image(EVENT, REF, REPO, REPO_ID) +image = set_image(REF, REPO, REPO_ID) action = { 'name': '🏃',