Skip to content

Commit

Permalink
Merge pull request #86 from Staffbase/DIA-3549-avoid-image-rebuilding
Browse files Browse the repository at this point in the history
  • Loading branch information
kaitimmer authored May 24, 2024
2 parents bba0361 + 8c6f8e4 commit 632b54e
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 34 deletions.
64 changes: 33 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# 🚀 GitHub Action for GitOps

This GitHub Action can be used for our GitOps workflow.
The GitHub Action will build and push the Docker image for your service and deploys the new version at your Kubernetes clusters.
This GitHub Action can be used for our GitOps workflow. The GitHub Action will build and push the Docker image for your service and deploys
the new version at your Kubernetes clusters.

## Requirement

When you want to use this GitHub Action your GitHub repository should have a `dev` and `master` / `main` branch and it should use tags for releases.
When you want to use this GitHub Action your GitHub repository should have a `dev` and `master` / `main` branch and it should use tags for
releases.

- For the `dev` branch we will change the files specified under `gitops-dev`.
- For the `master` / `main` branch we will change the files specified under `gitops-stage`.
- For a new tag the files under `gitops-prod` will be used.

This GitOps setup should be the default for all your repositories.
However, if you have a special case, you can leave `gitops-dev`, `gitops-stage` and `gitops-prod` undefined, then those steps will be skipped.
This GitOps setup should be the default for all your repositories. However, if you have a special case, you can
leave `gitops-dev`, `gitops-stage` and `gitops-prod` undefined, then those steps will be skipped.

## Usages

Expand All @@ -21,7 +22,7 @@ However, if you have a special case, you can leave `gitops-dev`, `gitops-stage`
```yaml
name: CD

on: [push]
on: [ push ]

jobs:
ci-cd:
Expand Down Expand Up @@ -53,7 +54,7 @@ jobs:
```yaml
name: CD

on: [push]
on: [ push ]

jobs:
ci-cd:
Expand All @@ -78,7 +79,7 @@ jobs:
```yaml
name: CD

on: [push]
on: [ push ]

jobs:
ci-cd:
Expand All @@ -105,27 +106,29 @@ jobs:
## Inputs
| Name | Description | Default |
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
| `docker-registry` | Docker Registry | `staffbase.jfrog.io` |
| `docker-image` | Docker Image | |
| `docker-username` | Username for the Docker Registry | |
| `docker-password` | Password for the Docker Registry | |
| `docker-file` | Dockerfile | `./Dockerfile` |
| `docker-build-args` | List of build-time variables | |
| `docker-build-secrets` | List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken) | |
| `docker-build-secret-files` | List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt) | |
| `docker-build-target` | Sets the target stage to build like: "runtime" | |
| `docker-build-provenance` | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build | `false` |
| `gitops-organization` | GitHub Organization for GitOps | `Staffbase` |
| `gitops-repository` | GitHub Repository for GitOps | `mops` |
| `gitops-user` | GitHub User for GitOps | `Staffbot` |
| `gitops-email` | GitHub Email for GitOps | `[email protected]` |
| `gitops-token` | GitHub Token for GitOps | |
| `gitops-dev` | Files which should be updated by the GitHub Action for DEV, must be relative to the root of the GitOps repository | |
| `gitops-stage` | Files which should be updated by the GitHub Action for STAGE, must be relative to the root of the GitOps repository | |
| `gitops-prod` | Files which should be updated by the GitHub Action for PROD, must be relative to the root of the GitOps repository | |
| `working-directory` | The directory in which the GitOps action should be executed. The docker-file variable should be relative to working directory. | `.` |
| Name | Description | Default |
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|
| `docker-registry` | Docker Registry | `staffbase.jfrog.io` |
| `docker-registry-api` | Docker Registry API (used for retagging without pulling) | `https://staffbase.jfrog.io/artifactory/api/docker/` |
| `docker-image` | Docker Image | |
| `docker-username` | Username for the Docker Registry | |
| `docker-password` | Password for the Docker Registry | |
| `docker-file` | Dockerfile | `./Dockerfile` |
| `docker-build-args` | List of build-time variables | |
| `docker-build-secrets` | List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken) | |
| `docker-build-secret-files` | List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt) | |
| `docker-build-target` | Sets the target stage to build like: "runtime" | |
| `docker-build-provenance` | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build | `false` |
| `docker-disable-retagging` | Disables retagging of existing images and run a new build instead | `false` |
| `gitops-organization` | GitHub Organization for GitOps | `Staffbase` |
| `gitops-repository` | GitHub Repository for GitOps | `mops` |
| `gitops-user` | GitHub User for GitOps | `Staffbot` |
| `gitops-email` | GitHub Email for GitOps | `[email protected]` |
| `gitops-token` | GitHub Token for GitOps | |
| `gitops-dev` | Files which should be updated by the GitHub Action for DEV, must be relative to the root of the GitOps repository | |
| `gitops-stage` | Files which should be updated by the GitHub Action for STAGE, must be relative to the root of the GitOps repository | |
| `gitops-prod` | Files which should be updated by the GitHub Action for PROD, must be relative to the root of the GitOps repository | |
| `working-directory` | The directory in which the GitOps action should be executed. The docker-file variable should be relative to working directory. | `.` |

## Contributing

Expand All @@ -150,5 +153,4 @@ This project is licensed under the Apache-2.0 License - see the [LICENSE.md](LIC

## Releasing new versions

Go to the release overview page and publish the draft release with a new version number.
Make sure to update the floating version commit.
Go to the release overview page and publish the draft release with a new version number. Make sure to update the floating version commit.
54 changes: 51 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ inputs:
description: 'Docker Registry'
required: true
default: 'staffbase.jfrog.io'
docker-registry-api:
description: 'Docker Registry API'
required: false
default: 'https://staffbase.jfrog.io/artifactory/api/docker/'
docker-image:
description: 'Docker Image'
required: true
Expand Down Expand Up @@ -36,6 +40,10 @@ inputs:
description: "Generate provenance attestation for the build"
required: false
default: 'false'
docker-disable-retagging:
description: 'Disable retagging of existing images'
required: false
default: 'false'
gitops-organization:
description: 'GitHub Organization for GitOps'
required: true
Expand Down Expand Up @@ -81,6 +89,7 @@ runs:
id: preparation
shell: bash
run: |
BUILD="true"
if [[ $GITHUB_REF == refs/heads/master ]]; then
TAG="master-${GITHUB_SHA::8}"
LATEST="master"
Expand All @@ -97,10 +106,12 @@ runs:
TAG="${GITHUB_REF:11}"
LATEST="latest"
PUSH="true"
BUILD="${{ inputs.docker-disable-retagging }}"
elif [[ $GITHUB_REF == refs/tags/* ]]; then
TAG="${GITHUB_REF:10}"
LATEST="latest"
PUSH="true"
BUILD="${{ inputs.docker-disable-retagging }}"
else
TAG="${GITHUB_SHA::8}"
PUSH="false"
Expand All @@ -111,10 +122,11 @@ runs:
TAG_LIST+=",${{ inputs.docker-registry }}/${{ inputs.docker-image }}:${LATEST}"
fi
echo "tag_list=$TAG_LIST" >> $GITHUB_OUTPUT
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "build=$BUILD" >> $GITHUB_OUTPUT
echo "latest=$LATEST" >> $GITHUB_OUTPUT
echo "push=$PUSH" >> $GITHUB_OUTPUT
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "tag_list=$TAG_LIST" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
if: inputs.docker-username != '' && inputs.docker-password != ''
Expand All @@ -128,9 +140,10 @@ runs:
username: ${{ inputs.docker-username }}
password: ${{ inputs.docker-password }}


- name: Build
id: docker_build
if: inputs.docker-username != '' && inputs.docker-password != ''
if: steps.preparation.outputs.build == 'true' && inputs.docker-username != '' && inputs.docker-password != ''
uses: docker/build-push-action@v5
with:
context: ${{ inputs.working-directory }}
Expand All @@ -146,6 +159,41 @@ runs:
cache-to: type=gha,mode=max
provenance: ${{ inputs.docker-build-provenance }}

- name: Retag Existing Image
id: docker_retag
if: steps.preparation.outputs.build == 'false'
shell: bash
run: |
CHECK_EXISTING_TAGS="master-${GITHUB_SHA::8} main-${GITHUB_SHA::8}"
CONTENT_TYPE="application/vnd.docker.distribution.manifest.v2+json"
# split docker-image on / into repository and image
REPO=$(echo ${{ inputs.docker-image}} | cut -d'/' -f1)
IMAGE=$(echo ${{ inputs.docker-image}} | cut -d'/' -f2)
echo "CHECK_EXISTING_TAGS: ${CHECK_EXISTING_TAGS}"
echo "RELEASE_TAG: ${RELEASE_TAG:1}"
echo "Check if an image already exists for ${{ inputs.docker-image }}:main|master-${GITHUB_SHA::8} 🐋 ⬇"
MANIFEST=""
for tag in $CHECK_EXISTING_TAGS; do
MANIFEST=$(curl -H "Accept: ${CONTENT_TYPE}" -u "${{ inputs.docker-username }}:${{ inputs.docker-password }}" "${{ inputs.docker-registry-api }}${REPO}/v2/{$IMAGE}/manifests/${tag}")
if [[ $MANIFEST == *"errors"* ]]; then
echo "No image found for ${{ inputs.docker-image }}:${tag} 🚫"
continue
else
echo "Image found for ${{ inputs.docker-image }}:${tag} 🐋 ⬇"
break
fi
# Exit here if no existing manifest was found
exit 1
done
echo "Retagging image with release version and :latest tags for ${{ inputs.docker-image }} 🏷"
curl --fail-with-body -X PUT -H "Content-Type: ${CONTENT_TYPE}" -u "${{ inputs.docker-username }}:${{ inputs.docker-password }}" -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${REPO}/v2/{$IMAGE}/manifests/${{ steps.preparation.outputs.tag }}"
curl --fail-with-body -X PUT -H "Content-Type: ${CONTENT_TYPE}" -u "${{ inputs.docker-username }}:${{ inputs.docker-password }}" -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${REPO}/v2/{$IMAGE}/manifests/${{ steps.preparation.outputs.latest }}"
- name: Checkout GitOps Repository
if: inputs.gitops-token != ''
uses: actions/checkout@v4
Expand Down

0 comments on commit 632b54e

Please sign in to comment.