Skip to content

Pre-release (base) - Adding pretender to Exegol-Images #83

Pre-release (base) - Adding pretender to Exegol-Images

Pre-release (base) - Adding pretender to Exegol-Images #83

name: Pre-release (base)
run-name: Pre-release (base) - ${{ github.event.pull_request.title }}
on:
pull_request:
branches: [main]
paths-ignore: # not always respected. See https://github.com/actions/runner/issues/2324#issuecomment-1703345084
- ".github/**"
- "**.md"
# cf https://github.com/actions/runner/issues/2324, paths-ignore will only be respected at PR creation
# all new commits then added in the PR will trigger the workflow
env:
# intermediate registry in which architecture-specific images and base images must be pushed
INTERMEDIATE_IMAGES_BUILDS_REGISTRY: "nwodtuhs/exegol-builds"
# base image is used as initial layer when building the final image
IMAGE_TARGET_REGISTRY: "nwodtuhs/exegol-misc-preprod"
IMAGE_TAG: "base"
DOCKERFILE: "./sources/dockerfiles/base.dockerfile"
jobs:
# https://github.com/orgs/community/discussions/26671, "can’t pass ENV variables to the reusable workflow"
init:
if: ${{ startsWith(github.event.pull_request.title, 'Release') }}
name: Initialize
runs-on: self-hosted
outputs:
INTERMEDIATE_IMAGES_BUILDS_REGISTRY: ${{ steps.varset.outputs.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}
IMAGE_TARGET_REGISTRY: ${{ steps.varset.outputs.IMAGE_TARGET_REGISTRY }}
IMAGE_TAG: ${{ steps.varset.outputs.IMAGE_TAG }}
IMAGE_VERSION: ${{ steps.varset.outputs.IMAGE_VERSION }}
DOCKERFILE: ${{ steps.varset.outputs.DOCKERFILE }}
image_exists: ${{ steps.check_remote_image.outputs.image_exists }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Setting variables
id: varset
run: |
echo "INTERMEDIATE_IMAGES_BUILDS_REGISTRY=${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}" >> $GITHUB_OUTPUT
echo "IMAGE_TARGET_REGISTRY=${{ env.IMAGE_TARGET_REGISTRY }}" >> $GITHUB_OUTPUT
echo "IMAGE_TAG=${{ env.IMAGE_TAG }}" >> $GITHUB_OUTPUT
echo "IMAGE_VERSION=$(echo ${{ github.event.pull_request.title }} | cut -d ' ' -f 2)" >> $GITHUB_OUTPUT
echo "DOCKERFILE=${{ env.DOCKERFILE }}" >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT
- name: Checking if remote image exists
id: check_remote_image
run: |
echo "docker manifest inspect ${{ env.IMAGE_TARGET_REGISTRY }}:${{ env.IMAGE_TAG }}-${{ steps.varset.outputs.IMAGE_VERSION }}"
if docker manifest inspect ${{ env.IMAGE_TARGET_REGISTRY }}:${{ env.IMAGE_TAG }}-${{ steps.varset.outputs.IMAGE_VERSION }}; then
echo "Image exists"
echo "image_exists=true" >> $GITHUB_OUTPUT
else
echo "Image does not exist"
echo "image_exists=false" >> $GITHUB_OUTPUT
fi
cat $GITHUB_OUTPUT
- name: Check changes
id: check_changes
run: |
# we get all changes in the PR, need only the most recent
file_list=$(git diff --name-only HEAD HEAD~1)
files_to_check=(
"sources/install/package_base.sh"
"sources/install/entrypoint.sh"
"sources/install/package_desktop.sh"
"sources/install/post_install.sh"
)
for file_to_check in "${files_to_check[@]}"; do
if [[ $file_list =~ $file_to_check ]]; then
echo "Base layer must be compiled"
echo "base_changed=true" >> $GITHUB_OUTPUT
break
fi
done
- name: (dbg) print changes
run: git diff --name-only HEAD^1 HEAD
- name: (dbg) print result
run: echo ${{ steps.check_changes.outputs.base_changed }}
code_check:
if: ${{ startsWith(github.event.pull_request.title, 'Release') }}
name: Code compliance check
uses: ./.github/workflows/sub_code_check.yml
build:
name: Image build
needs: [ init, code_check ]
# only building base if ccc was a success and image doesn't already exist
if: needs.code_check.result == 'success' && needs.init.outputs.image_exists == 'false'
strategy:
fail-fast: false
matrix:
arch: [ arm64, amd64 ]
uses: ./.github/workflows/sub_build_belt.yml
with:
# ex: nwodtuhs/exegol-builds
IMAGE_REGISTRY: ${{ needs.init.outputs.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}
# ex: base
IMAGE_TAG: ${{ needs.init.outputs.IMAGE_TAG }}
# ex: base-1.2.3-arm64
IMAGE_NAME: ${{ needs.init.outputs.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}-${{ matrix.arch }}
# ex: 1.2.3
IMAGE_VERSION: ${{ needs.init.outputs.IMAGE_VERSION }}
# ex: base.dockerfile
DOCKERFILE: ${{ needs.init.outputs.DOCKERFILE }}
# ex: arm64
ARCH: ${{ matrix.arch }}
EXPORT_TOOLS: false
PUSH_IMAGE: true
secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
publish:
name: Publish image
needs: [ init, build ]
# only publishing if the tests were a success (implicit by the success of build).
if: needs.build.result == 'success'
timeout-minutes: 60
runs-on: self-hosted
strategy:
fail-fast: false
matrix:
image: [ "${{ needs.init.outputs.IMAGE_TAG }}", "${{ needs.init.outputs.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}" ]
steps:
- name: Login to Dockerhub
if: success()
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create manifest
id: create_manifest
if: success()
# ex: docker manifest create nwodtuhs/exegol-misc-preprod:base nwodtuhs/exegol-builds:base-1.2.3-arm64 nwodtuhs/exegol-builds:base-1.2.3-amd64
# ex: docker manifest create nwodtuhs/exegol-misc-preprod:base-1.2.3 nwodtuhs/exegol-builds:base-1.2.3-arm64 nwodtuhs/exegol-builds:base-1.2.3-amd64
run: docker manifest create ${{ env.IMAGE_TARGET_REGISTRY }}:${{ matrix.image }} ${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}:${{ env.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}-arm64 ${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}:${{ env.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}-amd64
- name: Push manifest to remote
if: success()
# ex: docker manifest push nwodtuhs/exegol-misc-preprod:base
# ex: docker manifest push nwodtuhs/exegol-misc-preprod:base-1.2.3
run: docker manifest push ${{ env.IMAGE_TARGET_REGISTRY }}:${{ matrix.image }}
- name: Remove manifest locally
if: always() && steps.create_manifest.outcome == 'success'
# ex: docker manifest rm nwodtuhs/exegol-misc-preprod:base
# ex: docker manifest rm nwodtuhs/exegol-misc-preprod:base-1.2.3
run: docker manifest rm ${{ env.IMAGE_TARGET_REGISTRY }}:${{ matrix.image }}
clean_runners:
name: Clean runner
needs: [ init, publish ]
if: always() && ${{ startsWith(github.event.pull_request.title, 'Release') }}
# even if this job fails, it won't affect the success/fail status of the whole workflow
continue-on-error: true
strategy:
fail-fast: false
matrix:
arch: [ arm64, amd64 ]
runs-on:
- self-hosted
- builder
- ${{ matrix.arch }}
steps:
- name: List docker images
run: docker image ls
- name: Remove local image
# always removing image, no need to keep it on the runner
if: always()
# ex: docker rmi nwodtuhs/exegol-builds:base-1.2.3-arm64
run: docker rmi ${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}:${{ env.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}-${{ matrix.arch }}
clean_registries:
name: Clean registries
needs: [ init, publish ]
if: always() && needs.publish.result == 'success'
runs-on: self-hosted
# only cleaning if publish was a success. And publish requires that tests were a success.
# If tests were a success, there's no need for debugging the images, they can be removed from the exegol-builds registry
strategy:
fail-fast: false
matrix:
arch: [ arm64, amd64 ]
steps:
- name: Remove remote arch-specific images in ${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}
# ex: curl [...] --request DELETE [...]exegol-builds/tags/base-1.2.3-arm64
run: |
HUB_TOKEN=$(curl --silent --header "Content-Type: application/json" --request POST --data "{\"username\": \"${{ secrets.DOCKER_USERNAME }}\", \"password\": \"${{ secrets.DOCKER_PASSWORD }}\"}" https://hub.docker.com/v2/users/login/ | jq -r .token)
curl --fail-with-body --include --request DELETE -H "Accept: application/json" --header "Authorization: JWT $HUB_TOKEN" https://hub.docker.com/v2/repositories/${{ env.INTERMEDIATE_IMAGES_BUILDS_REGISTRY }}/tags/${{ env.IMAGE_TAG }}-${{ needs.init.outputs.IMAGE_VERSION }}-${{ matrix.arch }}/
add_label:
name: Trigger image builds
needs: [ init, clean_registries ]
# running either if publish and clean_registries were a success, or if the image already existed on remote
if: always() && ${{ startsWith(github.event.pull_request.title, 'Release') }} && ( needs.clean_registries.result == 'success' || needs.init.outputs.image_exists == 'true' )
runs-on: ubuntu-latest
# Cannot use secrets.GITHUB_TOKEN as it is the default "github-actions bot" token, and "An action in a workflow run can’t trigger a new workflow run."
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#about-workflow-events
# https://github.com/orgs/community/discussions/25565
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT_BASE_TRIGGER }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: List labels
run: gh pr view --json labels ${{ github.event.number }} -q '.labels[].name'
- name: Label "base success" already set?
id: already_labeled
run: |
if gh pr view --json labels ${{ github.event.number }} -q '.labels[].name' | grep -q "base success"
then
echo "PR already labeled"
echo "already_labeled=true" >> $GITHUB_OUTPUT
else
echo "PR not already labeled"
echo "already_labeled=false" >> $GITHUB_OUTPUT
fi
cat $GITHUB_OUTPUT
- name: Remove label
# removing and re-adding label in order to re-trigger next preprod workflows
if: steps.already_labeled.outputs.already_labeled == 'true'
run: gh pr edit --remove-label "base success" ${{ github.event.number }}
- name: Add label
if: always()
run: gh pr edit --add-label "base success" ${{ github.event.number }}