Build, test and push to the Client Library #23
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build, test and push to the Client Library | |
on: | |
workflow_dispatch: | |
inputs: | |
production: | |
description: | | |
'Push to production registries' | |
'not checked - to testing' | |
required: true | |
type: boolean | |
default: false | |
version_major: | |
description: 'AlmaLinux major version' | |
required: true | |
default: '9' | |
type: choice | |
options: | |
- 9 | |
- 8 | |
type_default: | |
description: 'default' | |
required: true | |
type: boolean | |
default: true | |
type_minimal: | |
description: 'minimal' | |
required: true | |
type: boolean | |
default: true | |
type_micro: | |
description: 'micro' | |
required: true | |
type: boolean | |
default: true | |
type_base: | |
description: 'base' | |
required: true | |
type: boolean | |
default: true | |
type_init: | |
description: 'init' | |
required: true | |
type: boolean | |
default: true | |
env: | |
# Latest version | |
version_latest: 9 | |
# Platforms list: linux/amd64, linux/ppc64le, linux/s390x, linux/arm64 | |
platforms: 'linux/amd64, linux/ppc64le, linux/s390x, linux/arm64' | |
# Registries list: | |
# for production: docker.io/almalinux, quay.io/almalinuxorg, ghcr.io/almalinux | |
# for testing: quay.io/almalinuxautobot | |
registries: ${{ inputs.production && 'docker.io/almalinux, quay.io/almalinuxorg, ghcr.io/almalinux' || 'quay.io/almalinuxautobot' }} | |
jobs: | |
build-test-push: | |
name: Deploy ${{ inputs.version_major }} ${{ matrix.image_types }} images | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
# Set image types matrix based on boolean inputs.type_* with true value | |
image_types: ${{ fromJSON(format('["{0}", "{1}", "{2}", "{3}", "{4}"]', ( inputs.type_default && 'default' ), ( inputs.type_minimal && 'minimal' ), ( inputs.type_micro && 'micro' ), ( inputs.type_base && 'base' ), ( inputs.type_init && 'init' ) )) }} | |
exclude: | |
- image_types: 'false' | |
steps: | |
- | |
name: Prepare AlmaLinux Minor version number | |
run: | | |
case ${{ inputs.version_major }} in | |
8) | |
version_minor="10" ;; | |
9) | |
version_minor="4" ;; | |
10) | |
version_minor="0" ;; | |
*) | |
echo "Almalinux ${{ inputs.version_major }} is not supported!" && false | |
esac | |
echo "version_minor=${version_minor}" >> $GITHUB_ENV | |
# [Debug] | |
echo "version_minor=${version_minor}" | |
- | |
name: Prepare date stamp | |
id: date_stamp | |
run: | | |
# date stamp | |
date_stamp=$(date -u '+%Y%m%d') | |
echo "date_stamp=${date_stamp}" >> $GITHUB_ENV | |
echo "date_stamp=${date_stamp}" >> "$GITHUB_OUTPUT" | |
[ -z "$date_stamp-x" ] && false | |
# [Debug] | |
echo "date_stamp=${date_stamp}" | |
- | |
name: Generate list of images to use as base name for tags | |
run: | | |
# list of registries to push to | |
REGISTRIES="${{ env.registries }}" | |
IMAGE_NAMES= | |
# generate image names in format $REGISTRY/almalinux or $REGISTRY/${{ inputs.version_major }}-${{ matrix.image_types }} | |
# image names are used by docker/metadata-action to set 'images' | |
for REGISTRY in ${REGISTRIES//,/ }; do | |
# 'default' images should not go to docker.io | |
[ "${{ matrix.image_types }}" = "default" ] && [[ $REGISTRY = *'docker.io'* ]] && continue | |
# 'default' images goes to $REGISTRY/almalinux | |
[ "${{ matrix.image_types }}" = "default" ] \ | |
&& IMAGE_NAME="$REGISTRY/almalinux" \ | |
|| IMAGE_NAME="$REGISTRY/${{ inputs.version_major }}-${{ matrix.image_types }}" | |
IMAGE_NAMES="${IMAGE_NAMES} ${IMAGE_NAME}" | |
unset IMAGE_NAME | |
done | |
# remove space at the beginning of string | |
IMAGE_NAMES=${IMAGE_NAMES# } | |
# separate with comma instead of space and export to the action | |
echo "IMAGE_NAMES=${IMAGE_NAMES// /,}" >> $GITHUB_ENV | |
# [Debug] | |
echo $IMAGE_NAMES | |
- | |
name: Enable containerd image store on Docker Engine | |
run: | | |
# Use containerd image store | |
sudo jq '.features |= . + { "containerd-snapshotter": true }' /etc/docker/daemon.json > ./daemon.json.${{ env.date_stamp }} && \ | |
sudo mv -f ./daemon.json.${{ env.date_stamp }} /etc/docker/daemon.json | |
sudo systemctl restart docker | |
docker info -f '{{ .DriverStatus }}' | |
- | |
name: Checkout ${{ github.repository }}, branch 'main' | |
uses: actions/checkout@v4 | |
- | |
name: Checkout ${{ github.repository }}, branch '${{ inputs.version_major }}', path '${{ inputs.version_major }}' | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ inputs.version_major }} | |
path: ${{ inputs.version_major }} | |
- | |
name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- | |
name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- | |
name: Login to Docker.io | |
if: contains(env.registries, 'docker.io') | |
uses: docker/login-action@v3 | |
with: | |
registry: docker.io | |
username: ${{ inputs.production && secrets.DOCKERHUB_USERNAME || secrets.TEST_DOCKERHUB_USERNAME }} | |
password: ${{ inputs.production && secrets.DOCKERHUB_TOKEN || secrets.TEST_DOCKERHUB_TOKEN }} | |
- | |
name: Login to Quay.io | |
if: contains(env.registries, 'quay.io') | |
uses: docker/login-action@v3 | |
with: | |
registry: quay.io | |
username: ${{ inputs.production && secrets.QUAY_IO_USERNAME || secrets.TEST_QUAY_IO_USERNAME }} | |
password: ${{ inputs.production && secrets.QUAY_IO_CLI_PASSWORD || secrets.TEST_QUAY_IO_CLI_PASSWORD }} | |
- | |
name: Login to Ghcr.io | |
if: contains(env.registries, 'ghcr.io') | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ inputs.production && secrets.GIT_HUB_USERNAME || secrets.TEST_GITHUB_USERNAME }} | |
password: ${{ inputs.production && secrets.GIT_HUB_TOKEN || secrets.TEST_GITHUB_TOKEN }} | |
- | |
name: Generate tags and prepare metadata to build and push | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
# list of Docker images to use as base names for tags | |
images: ${{ env.IMAGE_NAMES }} | |
# list of tags | |
tags: | | |
type=raw,value=latest,enable=${{ matrix.image_types != 'default' || ( matrix.image_types == 'default' && inputs.version_major == env.version_latest ) }} | |
type=raw,value=${{ inputs.version_major }},enable=true | |
type=raw,value=${{ inputs.version_major }}.${{ env.version_minor }},enable=true | |
type=raw,value=${{ inputs.version_major }}.${{ env.version_minor }}-${{ env.date_stamp }},enable=true | |
- | |
name: Build images | |
id: build-images | |
uses: docker/build-push-action@v5 | |
with: | |
provenance: false | |
context: "{{defaultContext}}:Containerfiles/${{ inputs.version_major }}" | |
file: ./Containerfile.${{ matrix.image_types }} | |
platforms: ${{ env.platforms }} | |
push: false | |
load: true | |
tags: ${{ steps.meta.outputs.tags }} | |
- | |
name: Test images | |
id: test-images | |
run: | | |
# [Test] | |
platforms="${{ env.platforms }}" | |
for platform in ${platforms//,/ }; do | |
echo "Testing AlmaLinux ${{ inputs.version_major }} ${{ matrix.image_types }} for ${platform} image:" | |
docker run --platform=${platform} ${{ steps.build-images.outputs.digest }} /bin/bash -c " \ | |
uname -m \ | |
&& cat /etc/almalinux-release \ | |
&& ( test "${{ matrix.image_types }}" != "micro" && rpm -q gpg-pubkey) || true " | |
done | |
- | |
name: Push images to Client Library | |
id: push-images | |
uses: docker/build-push-action@v5 | |
with: | |
provenance: false | |
context: "{{defaultContext}}:Containerfiles/${{ inputs.version_major }}" | |
file: ./Containerfile.${{ matrix.image_types }} | |
platforms: ${{ env.platforms }} | |
push: true | |
tags: ${{ steps.meta.outputs.tags }} | |
- | |
name: Extract RootFS (default and minimal only) | |
id: extract-rootfs | |
# 'default' or 'minimal' images only go to Docker Official Library | |
if: matrix.image_types == 'default' || matrix.image_types == 'minimal' | |
run: | | |
# [RootFS] | |
# File name for RootFS file (packed with tag + Xz) | |
name=almalinux-${{ inputs.version_major }}-${{ matrix.image_types }} | |
pwd=$( pwd ) | |
path=${pwd}/${name} | |
# The "tar file" for 'docker save' to write to | |
tar_name=${pwd}/${name}.tar | |
mkdir ${path} | |
cd ${path} | |
# Produce a tarred repository and save it to the "tar file". | |
docker save ${{ steps.build-images.outputs.digest }} -o ${tar_name} | |
# Extract the "tar file" | |
tar xf ${tar_name} | |
cd blobs/sha256 | |
# The "temporary Dockerfile" to build image based on RootFS | |
cat <<EOF > Dockerfile | |
FROM scratch | |
ADD rootfs.tar.gz / | |
CMD ["/bin/bash"] | |
EOF | |
# Loop blobs to find all zipped files that are RootFS for a particular architecture | |
for file in `find . -type f`; do | |
if file --brief ${file} | grep -i gzip >/dev/null; then | |
# Make a copy of "taken RootFS" | |
cp -av ${file} rootfs.tar.gz | |
# Build an image from the "temporary Dockerfile" | |
docker build -t rootfs . | |
# Run the image and query almalinux-release package's architecture | |
arch=$( docker run --rm rootfs /bin/bash -c "rpm -q --qf=%{ARCH} almalinux-release" ) | |
# Map found architecture to the corresponding platform | |
platform= | |
docker rmi rootfs | |
case ${arch} in | |
x86_64) | |
platform=amd64;; | |
ppc64le) | |
platform=ppc64le;; | |
s390x) | |
platform=s390x;; | |
aarch64) | |
platform=arm64;; | |
*) | |
echo "The '$arch' is incorrect or failed to determine architecture." && false;; | |
esac | |
# Delete copy of the "taken RootFS" | |
rm -f rootfs.tar.gz | |
# Copy the "taken RootFS" into corresponded .tar.xz | |
cp -av ${file} ${name}-${platform}.tar.gz | |
zcat ${name}-${platform}.tar.gz | xz -9 -e -T0 > ${pwd}/${{ inputs.version_major }}/${{ matrix.image_types }}/${platform}/${name}-${platform}.tar.xz | |
fi | |
done | |
# Clean up | |
rm -rf ${path} | |
echo "[Debug]" | |
ls -1 ${pwd}/${{ inputs.version_major }}/${{ matrix.image_types }}/*/*.tar.xz | |
# Change date stamp in '${version_major}/${image_types}/${arch}/Dockerfile' | |
- | |
name: Change date stamp in Dockerfile (default and minimal only) | |
# 'default' or 'minimal' images only go to Docker Official Library | |
if: matrix.image_types == 'default' || matrix.image_types == 'minimal' | |
run: | | |
# [Dockerfile] | |
platforms="${{ env.platforms }}" | |
for platform in ${platforms//,/ }; do | |
arch=${platform#linux/} | |
dockerfile=${{ inputs.version_major }}/${{ matrix.image_types }}/${arch}/Dockerfile | |
case ${{ matrix.image_types }} in | |
default) | |
tags="${{ inputs.version_major }}, ${{ inputs.version_major }}.${{ env.version_minor }}, ${{ inputs.version_major }}.${{ env.version_minor }}-${{ env.date_stamp }}" | |
[ "${{ inputs.version_major }}" = "9" ] && tags="latest, ${tags}" ;; | |
minimal) | |
tags="${{ inputs.version_major }}-${{ matrix.image_types }}, ${{ inputs.version_major }}.${{ env.version_minor }}-${{ matrix.image_types }}, ${{ inputs.version_major }}.${{ env.version_minor }}-${{ matrix.image_types }}-${{ env.date_stamp }}" | |
[ "${{ inputs.version_major }}" = "9" ] && tags="minimal, ${tags}" ;; | |
*) | |
esac | |
# Tags: 8, 8.9, 8.9-20231124 | |
sed -i "/^\([[:space:]]*#[[:space:]]*Tags: \).*/s//\1${tags}/" ${dockerfile} | |
echo "[Debug] ${dockerfile}" | |
cat ${dockerfile} | |
done | |
- | |
name: "Prepare time stamp" | |
id: time_stamp | |
run: | | |
# time stamp | |
time_stamp=$(date -u '+%H:%M:%S') | |
echo "time_stamp=${time_stamp}" >> $GITHUB_ENV | |
echo "time_stamp=${time_stamp}" >> "$GITHUB_OUTPUT" | |
[ -z "$time_stamp-x" ] && false | |
# [Debug] | |
echo "time_stamp=${time_stamp}" | |
# Commit '${version_major}/${image_types}/${arch}/*' | |
- | |
name: "Commit and push ${{ matrix.image_types }}/*/* Dockerfile and RootFS (branch ${{ inputs.version_major }})" | |
# 'default' or 'minimal' images only and 'Push to production' is checked | |
if: ( matrix.image_types == 'default' || matrix.image_types == 'minimal' ) && inputs.production | |
uses: EndBug/add-and-commit@v9 | |
with: | |
default_author: user_info | |
new_branch: ${{ inputs.version_major }} | |
cwd: ${{ inputs.version_major }} | |
pull: '--rebase --autostash' | |
message: "AlmaLinux ${{ inputs.version_major }} ${{ matrix.image_types }} - ${{ env.date_stamp }} ${{ env.time_stamp }} (generated on ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})." | |
push: true | |
outputs: | |
date_stamp: ${{ steps.date_stamp.outputs.date_stamp }} | |
time_stamp: ${{ steps.time_stamp.outputs.time_stamp }} | |
optimize-repo-size: | |
# 'default' or 'minimal' images only and 'Push to production' is checked | |
if: ( inputs.type_default || inputs.type_minimal ) && inputs.production | |
name: Optimize size of repository | |
runs-on: ubuntu-latest | |
needs: | |
- build-test-push | |
steps: | |
- | |
name: Checkout ${{ github.repository }}, branch '${{ inputs.version_major }}', path '${{ inputs.version_major }}' | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ inputs.version_major }} | |
path: ${{ inputs.version_major }} | |
- | |
name: Optimize size of branch the '${{ inputs.version_major }}' | |
run: | | |
date_stamp=${{ needs.build-test-push.outputs.date_stamp }} | |
cd ${{ inputs.version_major }} | |
echo "Prepare new branch 'tmp' based on ${{ inputs.version_major }}" | |
git checkout -b tmp | |
echo "Delete local branch '${{ inputs.version_major }}'" | |
git branch -D ${{ inputs.version_major }} | |
echo "Preserve resent data" | |
mkdir ../tmp-${date_stamp} | |
mv ./default ../tmp-${date_stamp}/ | |
mv ./minimal ../tmp-${date_stamp}/ | |
echo "Crete orphan branch '${{ inputs.version_major }}'" | |
git checkout --orphan ${{ inputs.version_major }} | |
echo "Clean up" | |
git rm --cached -r . | |
rm -rf ./default | |
rm -rf ./minimal | |
echo "Restore resent data" | |
mv ../tmp-${date_stamp}/default ./ | |
mv ../tmp-${date_stamp}/minimal ./ | |
echo "[Debug]" | |
git status | |
- | |
name: Commit and push ${{ github.repository }}, branch '${{ inputs.version_major }}' | |
uses: EndBug/add-and-commit@v9 | |
with: | |
default_author: user_info | |
message: "Update AlmaLinux ${{ inputs.version_major }} - ${{ needs.build-test-push.outputs.date_stamp }} ${{ needs.build-test-push.outputs.time_stamp }} (generated on ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})." | |
push: '--force --set-upstream origin ${{ inputs.version_major }}' | |
cwd: ${{ inputs.version_major }} |