From 104bf53067840afa02562af83413e2a20743a276 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 40fed97..0eb72fd 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 e098680f1b5a0091078fbeed2d7f7234b1554f23 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 27ce557201234bcf416a3a9a21b6d1be6b496438 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 9d14a8ddfbd6da7bafe911e5bdc9bd3d57bcb864 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 0eb72fd..7af05ef 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 3f3acc27e9f5498dfebc97b4aeaa7347c7d821bb 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 20c36db5513fd24d712bbbefd1e7f5f7106aaf1b 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 b3ac857fc2685e60b57cb66b4d1369c8b8503f10 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 7085596c2075aac5b5c77cfef05f1eee8753841c 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 7af05ef..9c34ad7 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 f8e87467b5c0346ab4a6720a5ba8a0c0140ef7e6 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 9c34ad7..486e39d 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 27defc63eebe11000fe0c8efeeb53eb9a4f712c4 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 486e39d..99c6838 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 7cd4e877757f0baec8773ee05be74d6926632f3d 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 99c6838..d52e9d5 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 640fe61d1dcb9c17e292b908dd829da255aa1dad 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 d52e9d5..695a8d6 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 483a6a6c8b019ff017d2da361ad71b12dcd82c29 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 16c36691e676004680ce518f7598b3cbb104fe4c 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 6a5d17f6a72937e53be16949db5d2757dbb28487 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 e6d63cd9babb31b0aaa024bd5be86bdb711e3d09 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 3a538c1fe8701bc875ca8ed4433fc7af023bedee 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 11e5cd5789314cace263d7db497538cd70442540 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 54e5a03d420eb87cc0123e930dd7c68f7fed9b27 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 695a8d6..66c6639 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': '🏃',