Skip to content

Merge pull request #713 from kristof-mattei/renovate/lock-file-mainte… #702

Merge pull request #713 from kristof-mattei/renovate/lock-file-mainte…

Merge pull request #713 from kristof-mattei/renovate/lock-file-mainte… #702

name: Retag containers after new push / PR
env:
# set this to true in GitHub variables to enable building the container
# HAS_CONTAINER: true
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
concurrency:
group: "${{ github.workflow }}" # last one must win
cancel-in-progress: false # no we need them
on:
# Triggers the workflow pushes to main. They can be either direct pushes, or PRs being merged
push:
branches: [main]
# note how we're not doing
# pull_request_target, as it isn't what we need.
# we need the push event to make it show up nicely in the UI
# this however brings a whole new slew of problems, like how do we identify the
# incoming PR's artifacts?
# well, we set a tag on that PR's artifact, in the form of
# pr-{head_of_pr}-{pr_head_of_main}
# when with git rev-parse HEAD^2 we can find the incoming PR's head
# Problem solved
permissions:
contents: write
packages: write
jobs:
repo-has-container:
name: Repo has container?
runs-on: ubuntu-latest
outputs:
has_container: ${{ steps.determine.outputs.has_container }}
steps:
- name: Repo has docker container?
id: determine
shell: bash
run: |
HAS_CONTAINER="${{ vars.HAS_CONTAINER }}"
echo "has_container=${HAS_CONTAINER:-false}" >> ${GITHUB_OUTPUT}
retag-containers:
name: Retag the containers
runs-on: ubuntu-latest
needs:
- repo-has-container
if: |
fromJSON(needs.repo-has-container.outputs.has_container) == true
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
show-progress: false
fetch-depth: 2
- name: Find out if current commit is a merge
shell: bash
run: |
EXIT_CODE=0
# a commit always has a parent, but if it has 2, the commit is a merge
# so lets see if we have one
# since we're listening to the push event we have to do this manually
PARENT2=$(git rev-parse "HEAD^2" --quiet 2>/dev/null) || EXIT_CODE=$?
if [ ${EXIT_CODE} -eq 0 ]
then
echo "The head of the incoming PR is ${PARENT2}"
echo "INCOMING_PR_HEAD_COMMIT=${PARENT2}" >> ${GITHUB_ENV}
else
echo "The incoming push isn't a merge, ergo it's not a PR"
fi
- name: Setup Node.js
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
with:
node-version-file: ".nvmrc"
cache: "npm"
cache-dependency-path: "**/package-lock.json"
- name: Install dependencies
shell: bash
run: |
npm ci --ignore-scripts
- name: Download crane tar, extract, and add folder to path.
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
with:
script: |
const tc = require("@actions/tool-cache");
const release = await github.rest.repos.getLatestRelease({
owner: "google",
repo: "go-containerregistry"
});
const asset = release.data.assets.find(asset => {
return asset["content_type"] === "application/gzip" && asset.name === "go-containerregistry_Linux_x86_64.tar.gz";
});
const urlToCraneTar = asset.browser_download_url
const craneTarPath = await tc.downloadTool(urlToCraneTar);
const craneExtractedFolder = await tc.extractTar(craneTarPath, null, ["--extract", "--gzip"]);
core.addPath(craneExtractedFolder);
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set full image name
shell: bash
run: |
echo "FULL_IMAGE_NAME=${REGISTRY,,}/${IMAGE_NAME,,}" >> ${GITHUB_ENV}
- name: Find all tags for ${{ env.FULL_IMAGE_NAME }}
shell: bash
run: |
crane ls ${FULL_IMAGE_NAME} >> existing_tags
echo "These are the existing tags on ${FULL_IMAGE_NAME}:"
cat existing_tags
- name: Check if the incoming PR has a Docker container, which will be our old tag, if not, or if it's just a push, find the appropriate old tag
env:
PR_TAG: "pr-${{ github.event.before }}-${{ env.INCOMING_PR_HEAD_COMMIT }}"
shell: bash
run: |
# search for the tag, there can only be zero or one match
# we need the || true because otherwise grep returns exit code 1 and github actions then dies
pr_tag_found=$(cat existing_tags | grep -c "^${PR_TAG}\$") || true
if [ $pr_tag_found -eq 1 ]
then
echo "Incoming PR produced a Docker image"
echo "OLD_TAG=${PR_TAG}" >> ${GITHUB_ENV}
echo "SUFFIX=actual" >> ${GITHUB_ENV}
else
# If we don't have an old tag, then the incoming PR didn't produce a container.
# In which case we're going to find the container referenced to the base commit, and add our current sha as a tag to it
echo "Incoming PR produced nothing, or there was just a push to main"
# so we find the last commit that github processed before this one
# which will have gone through the same retagging process
# and use that sha as our key to find the Docker container related to that commit
old_tag=$(cat existing_tags | grep "^sha-${{ github.event.before }}-.*\$") # .* is actual or retag
echo "OLD_TAG=${old_tag}" >> ${GITHUB_ENV}
echo "SUFFIX=retag" >> ${GITHUB_ENV}
fi
- name: Set the new TAGs
id: meta
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
flavor: |
latest=false
tags: |
type=edge,branch=main
type=sha,format=long,prefix=sha-,suffix=-${{ env.SUFFIX }}
- name: Actually re-tag the container
shell: bash
run: |
echo "${{ steps.meta.outputs.tags }}" | while read new_tag
do
crane cp "${FULL_IMAGE_NAME}:${OLD_TAG}" ${new_tag}
done