Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Docker image and push to GHCR #230

Merged
merged 19 commits into from
Nov 5, 2024
Merged

Conversation

br3ndonland
Copy link
Contributor

@br3ndonland br3ndonland commented Apr 19, 2024

Description

Closes #58

Up to this point, the project has been set up as a Docker action referencing the Dockerfile.

runs:
using: docker
image: Dockerfile

The downside to using the Dockerfile for the action is that the Docker image must be built every time the action is used (#58).

This PR 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

Build container image with GitHub Actions

This PR will build Docker images with the Docker CLI (docker build). Builds will include inline cache metadata so layers can be reused by future builds.

This PR only proposes to build container images for x86_64 (linux/amd64) because GitHub Actions Linux runners currently only support x86_64 CPU architectures (actions/runner-images#5631), and this project only supports GitHub Actions Linux runners. The README explains:

Since this GitHub Action is docker-based, it can only be used from within GNU/Linux based jobs in GitHub Actions CI/CD workflows. This is by design and is unlikely to change due to a number of considerations we rely on.

Push container image to GHCR

The workflow will log in to GHCR using the built-in GitHub token and push the Docker image. Workflow runs triggered by pull requests will build the Docker image and run the smoke tests but will not push the Docker image.

Update action to pull container image from GHCR

Docker actions support pulling in pre-built Docker images by supplying a registry address to the image: key. The downside to this syntax 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 ref, something like ghcr.io/pypa/gh-action-pypi-publish:release-v1.8 (Docker tags can't have /).

# this works but the image tag can't be customized
runs:
  using: docker
  image: docker://ghcr.io/pypa/gh-action-pypi-publish:release-v1.8
# this doesn't work because `image:` doesn't support context
runs:
  using: docker
  image: docker://ghcr.io/pypa/gh-action-pypi-publish:${{ github.action_ref }}

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.

Related

@webknjaz
Copy link
Member

This looks.. intriguing! I don't remember if I ever considered combining composite+docker actions (I did play with having two composites in the same repo in the past, though).

I'll need to take some time to think about it and look through the patch more closely. Please, don't expect an immediate review, however it does look very promising at glance!

Originally I thought that I'd have a workflow where I trigger a release, that release adds a commit that hardcodes an update to action.yml with the "future" version tag, tags that commit and pushes it (post docker publish). It wouldn't be on the main branch, the tags would be on the orphaned leaves.

This looks like a better idea so far. Thanks again!

br3ndonland added a commit to br3ndonland/gh-action-pypi-publish that referenced this pull request Apr 26, 2024
@br3ndonland
Copy link
Contributor Author

That sounds great. Take your time. Thanks for your consideration.

If you do decide to accept this change, I'm happy to help maintain the workflows in the future. Feel free to mention me @br3ndonland and I will help address any issues that come up.

webknjaz pushed a commit to br3ndonland/gh-action-pypi-publish that referenced this pull request May 16, 2024
@webknjaz
Copy link
Member

Thanks! I've hit "rebase" on the UI to get this on top of the recent changes/linting/lockfile bumps but haven't yet looked into it deeper.

pull_request:
workflow_run:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two separate workflow runs is often hard to track. Instead, I adopted a practice of modularizing the workflow pieces as reusable workflows having the reusable- prefix in their names. This allows embedding everything in all the right places. Let's try this, WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will return to this suggestion at a later time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be able to circle back to this already...

Copy link
Contributor Author

@br3ndonland br3ndonland Sep 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two separate workflow runs is often hard to track. Instead, I adopted a practice of modularizing the workflow pieces as reusable workflows having the reusable- prefix in their names. This allows embedding everything in all the right places. Let's try this, WDYT?

@webknjaz I removed workflow_call and switched to a reusable workflow instead.

Note that the required status checks for the repo will need to be updated.

.pre-commit-config.yaml Outdated Show resolved Hide resolved
Dockerfile Outdated Show resolved Hide resolved
action.yml Show resolved Hide resolved
action.yml Outdated Show resolved Hide resolved
action.yml Outdated Show resolved Hide resolved
action.yml Show resolved Hide resolved
@webknjaz
Copy link
Member

I'm done with the initial review. More is needed, but I'd rather accept what I can through separate PRs to make this one smaller. And the suggested refactoring could be done in parallel. I think that generating the file is a good idea. It should be possible to write the file without bringing in the PyYAML dependency. But it's not that easy for reading it. Can we make use of yq somehow, and convert YAML to JSON this way, maybe?

@br3ndonland
Copy link
Contributor Author

@webknjaz thank you for your detailed review. I've addressed most of your comments so far.

@webknjaz
Copy link
Member

Commits like 213c885ac41d769527ac150e2e633bb1ccd886d4 aren't really necessary since Git would automatically absorb changes applied separately. FYI. In fact, this one may have a harmful effect — when the label change is merged into the default branch, and this one rebased on top, Git will keep the removal commit and attempt deleting the label 🤷‍♂️

Anyway, we'll address this later on.

create-docker-action.py Outdated Show resolved Hide resolved
action.yml Outdated Show resolved Hide resolved
action.yml Outdated Show resolved Hide resolved
create-docker-action.py Outdated Show resolved Hide resolved
@webknjaz
Copy link
Member

@br3ndonland I'm sure my review is incomplete, but hopefully it gives you enough ideas to try out until the next time.

I think it'd be nice to get this in before #236 if at all possible.

@webknjaz
Copy link
Member

@br3ndonland could you also rebase this branch locally? The GH button doesn't work, meaning there's going to be some conflicts to resolve.

@br3ndonland
Copy link
Contributor Author

  1. When workflow_dispatch is triggered, and I type in 1.12.0, I understand that it'll publish ghcr.io/pypa/gh-action-pypi-publish:v1.12.0, ghcr.io/pypa/gh-action-pypi-publish:v1.12 and ghcr.io/pypa/gh-action-pypi-publish:v1.

At your request (#230 (comment)), the workflow_dispatch menu has two fields:

  1. Git ref (branch or tag)
  2. Docker image tag

After navigating to the action, there will be a "Run workflow" button. To publish an image for a specific release, v1.13.0 for example:

  1. Git ref - v1.13.0 (tag)
  2. Docker image tag - v1.13.0

But how about ghcr.io/pypa/gh-action-pypi-publish:release-v1 and ghcr.io/pypa/gh-action-pypi-publish:unstable-v1? What's the process for those?

Currently the workflow will automatically build and push Docker images whenever new commits are pushed to unstable/* or release/* branches.

on: # yamllint disable-line rule:truthy
pull_request:
push:
branches: ["release/*", "unstable/*"]

  1. Should the case of uses: pypa/gh-action-pypi-publish@unstable/v1 not hit the GHCR image and build the image like it does now? Does set_image() need to be modified to implement this?

Why wouldn't you want to push a Docker image for unstable/v1? I wouldn't want that as a user. It seems like it would just introduce more confusion and complication.

  1. Should the case of uses: pypa/gh-action-pypi-publish@release/v1 hit the :v1 image, or should the image generation workflow produce one more tag? It looks like these two bits aren't cohesive: reading the diff once again, it looks like if I enter release/v1.11.0, it'll produce ghcr.io/pypa/gh-action-pypi-publish:release-v1, ghcr.io/pypa/gh-action-pypi-publish:release-v1.11 and ghcr.io/pypa/gh-action-pypi-publish:release-v1.11.0 which would then not match references like uses: pypa/[email protected].

The case of uses: pypa/gh-action-pypi-publish@release/v1 will use the code on the release/v1 branch and will pull the Docker image built from that same branch.

if I enter release/v1.11.0

Your repo does not have any branches or tags named release/v1.11.0, so why would you do that?

If you're publishing a Docker image for a specific release, enter the name of the tag as I said above.

  1. Git ref - v1.13.0 (tag)
  2. Docker image tag - v1.13.0

uses: pypa/[email protected] will then pull the Docker image built from the v1.13.0 Git tag.

@webknjaz
Copy link
Member

webknjaz commented Nov 5, 2024

  1. When workflow_dispatch is triggered, and I type in 1.12.0, I understand that it'll publish ghcr.io/pypa/gh-action-pypi-publish:v1.12.0, ghcr.io/pypa/gh-action-pypi-publish:v1.12 and ghcr.io/pypa/gh-action-pypi-publish:v1.

At your request (#230 (comment)), the workflow_dispatch menu has two fields:

1. Git ref (branch or tag)

2. Docker image tag

After navigating to the action, there will be a "Run workflow" button. To publish an image for a specific release, v1.13.0 for example:

1. Git ref - v1.13.0 (tag)

2. Docker image tag - v1.13.0

Are you sure you're looking at the latest PR diff? Right now, when I look at https://github.com/pypa/gh-action-pypi-publish/pull/230/files#diff-63d86cca28be8586869affd2baf5d48489229f5d9b4684c11beb787eee6f614cR9-R14, I see a single input — tag. Is it possible that you might have a branch with something different?

Though, reading through the workflow, the docker image tag is computed from the tag input, which makes sense to me.

But how about ghcr.io/pypa/gh-action-pypi-publish:release-v1 and ghcr.io/pypa/gh-action-pypi-publish:unstable-v1? What's the process for those?

Currently the workflow will automatically build and push Docker images whenever new commits are pushed to unstable/* or release/* branches.

on: # yamllint disable-line rule:truthy
pull_request:
push:
branches: ["release/*", "unstable/*"]

Oh… That's the bit I've been overlooking.

  1. Should the case of uses: pypa/gh-action-pypi-publish@unstable/v1 not hit the GHCR image and build the image like it does now? Does set_image() need to be modified to implement this?

Why wouldn't you want to push a Docker image for unstable/v1? I wouldn't want that as a user. It seems like it would just introduce more confusion and complication.

Oh, I was just writing down my confusion. I didn't look into the PR in a while, so I didn't remember all the context and got lost. It makes sense now.

  1. Should the case of uses: pypa/gh-action-pypi-publish@release/v1 hit the :v1 image, or should the image generation workflow produce one more tag? It looks like these two bits aren't cohesive: reading the diff once again, it looks like if I enter release/v1.11.0, it'll produce ghcr.io/pypa/gh-action-pypi-publish:release-v1, ghcr.io/pypa/gh-action-pypi-publish:release-v1.11 and ghcr.io/pypa/gh-action-pypi-publish:release-v1.11.0 which would then not match references like uses: pypa/[email protected].

The case of uses: pypa/gh-action-pypi-publish@release/v1 will use the code on the release/v1 branch and will pull the Docker image built from that same branch.

if I enter release/v1.11.0

Your repo does not have any branches or tags named release/v1.11.0, so why would you do that?

If you're publishing a Docker image for a specific release, enter the name of the tag as I said above.

1. Git ref - v1.13.0 (tag)

2. Docker image tag - v1.13.0

uses: pypa/[email protected] will then pull the Docker image built from the v1.13.0 Git tag.

This was very helpful to refresh my understanding of the bits and pieces of the updates in the PR. Thank you!

I think I'm ready to merge it finally. I'll then try it out and let you know if something is still uncertain.

@webknjaz webknjaz merged commit 61da13d into pypa:unstable/v1 Nov 5, 2024
5 checks passed
@webknjaz
Copy link
Member

webknjaz commented Nov 5, 2024

I just pushed release/v1 and realized that people will be hitting a non-existing image if they attempt a release during the next few minutes… Hopefully, not many will hit this. For any following pushes, they'll just be getting a slightly outdated image, which should be mostly fine except for when the older image is incompatible.

webknjaz added a commit that referenced this pull request Nov 5, 2024
This is a follow-up for #230, which renamed the workflow filename.
@webknjaz
Copy link
Member

webknjaz commented Nov 6, 2024

@br3ndonland here are some regressions reported:

Could you help me figure them out?

PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
PR_REPO_ID: ${{ github.event.pull_request.base.repo.id }}
- name: Check out action repo
uses: actions/checkout@v4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@br3ndonland could you remind me — is this necessary because it should be within the work dir?

@webknjaz
Copy link
Member

webknjaz commented Nov 6, 2024

v1.12.1 addresses immediate problems from the list above. Long-term, the release process will need to be improved and made more cohesive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build&publish the base container to GHCR + point to it from action
3 participants