Simplify container registry overrides by using `matrix_container_glob… #272
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: CI | |
on: | |
push: | |
branches: [ "main", "fresh" ] | |
env: | |
alpine: "3.21" | |
ansible: "11.2.0" | |
ansible_core: "2.18.2" | |
permissions: | |
checks: write | |
contents: write | |
packages: write | |
pull-requests: read | |
jobs: | |
build-base: | |
name: Build base image | |
runs-on: ubuntu-latest | |
if: ${{ github.ref == 'refs/heads/fresh' }} | |
steps: | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v1 | |
- name: Login to ghcr.io | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Check if Docker image exists | |
id: check | |
run: | | |
IMAGE_TAG="ghcr.io/${{ github.repository }}/base:${{ env.alpine }}-${{ env.ansible_core }}-${{ env.ansible }}" | |
if docker manifest inspect "$IMAGE_TAG" > /dev/null 2>&1; then echo "exists=yes" >> "$GITHUB_OUTPUT"; else echo "exists=no" >> "$GITHUB_OUTPUT"; fi | |
- name: Extract metadata (tags, labels) for Docker | |
if: ${{ steps.check.outputs.exists == 'no' }} | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ghcr.io/${{ github.repository }}/base | |
tags: | | |
type=raw,value=latest,enable=${{ github.ref_name == 'fresh' }} | |
type=raw,value=${{ env.alpine }}-${{ env.ansible_core }}-${{ env.ansible }},enable=${{ github.ref_name == 'fresh' }} | |
- name: Build and push | |
if: ${{ steps.check.outputs.exists == 'no' }} | |
uses: docker/build-push-action@v6 | |
with: | |
platforms: linux/amd64,linux/arm64 | |
file: Dockerfile.base | |
push: true | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
build-args: | | |
ALPINE=${{ env.alpine }} | |
ANSIBLE=${{ env.ansible }} | |
ANSIBLE_CORE=${{ env.ansible_core }} | |
sync-images: | |
name: Sync images | |
needs: build-base | |
runs-on: self-hosted | |
if: ${{ github.ref == 'refs/heads/fresh' }} | |
container: | |
image: ghcr.io/${{ github.repository }}/base | |
options: --user root | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
submodules: 'recursive' | |
- name: Sync images | |
env: | |
ANISBLE_LOG_PATH: " " | |
run: | | |
apk --no-cache add skopeo parallel | |
skopeo login --username etkecc --password ${{ secrets.DOCKER_HUB_PASSWORD }} docker.io | |
cp -r .config/inventory ../ | |
ansible-playbook play/all.yml -l localhost -t skopeo -e target=localhost | |
sh play/.skopeo-parallel | |
rm -rf ./* && rm -rf .git .github .config | |
build-fresh: | |
name: Build ansible image (fresh) | |
needs: sync-images | |
runs-on: self-hosted | |
if: ${{ github.ref == 'refs/heads/fresh' }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v1 | |
- name: Login to ghcr.io | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
ghcr.io/${{ github.repository }} | |
registry.etke.cc/${{ github.repository }} | |
tags: | | |
type=raw,value=fresh,enable=${{ github.ref_name == 'fresh' }} | |
- name: Build and push | |
uses: docker/build-push-action@v6 | |
with: | |
platforms: linux/amd64,linux/arm64 | |
push: true | |
context: . | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
build-args: | | |
ALPINE=${{ env.alpine }} | |
ANSIBLE=${{ env.ansible }} | |
ANSIBLE_CORE=${{ env.ansible_core }} | |
test: | |
name: Test | |
needs: build-fresh | |
runs-on: self-hosted | |
if: ${{ github.ref == 'refs/heads/fresh' }} | |
steps: | |
- name: Trigger maintenance run | |
env: | |
TOKEN: ${{ secrets.TESTING_TOKEN }} | |
API: ${{ secrets.TESTING_API }} | |
run: | | |
# wait for any ongoing process to finish | |
while true; do STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$API/lock"); if [ "$STATUS" -eq 200 ]; then echo "Another command is still in progress, retrying in 1 minute..." && sleep 60; elif [ "$STATUS" -eq 204 ]; then echo "No commands are running, the test may proceed"; break; else echo "Failed to check lock (HTTP $STATUS)" && exit 1; fi; done | |
# trigger maintenance run | |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"command": "maintenance"}' "$API/commands") | |
if [ "$STATUS" -eq 204 ]; then echo "Maintenance run triggered"; else echo "Failed to trigger maintenance run (HTTP $STATUS). If that's expected, you can (locally): docker pull gchr.io/${{ github.repository }}:fresh && docker tag ghcr.io/${{ github.repository }}:fresh ghcr.io/${{ github.repository }}:latest && docker tag ghcr.io/${{ github.repository }}:fresh registry.etke.cc/${{ github.repository }}:latest && docker push ghcr.io/${{ github.repository }}:latest && docker push registry.etke.cc/${{ github.repository }}:latest" && exit 1; fi | |
# check progress | |
while true; do STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$API/lock"); if [ "$STATUS" -eq 200 ]; then echo "Maintenance is still in progress, retrying in 1 minute..." && sleep 60; elif [ "$STATUS" -eq 204 ]; then echo "Maintenance has been finished"; break; else echo "Failed to check maintenance progress (HTTP $STATUS)" && exit 1; fi; done | |
# check notifications | |
NOTIFICATIONS=$(curl -s -H "Authorization: Bearer $TOKEN" "$API/notifications") | |
echo "Notifications:" | |
echo "$NOTIFICATIONS" | jq | |
# cleanup notifications | |
echo "Cleaning up notifications..." | |
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "$API/notifications" | |
# check result | |
ERROR=$(echo "$NOTIFICATIONS" | jq -r --arg date "$(date +%Y-%m-%d)" '[.[] | select(.event_id | startswith("admin-run-maintenance-\($date)"))] | last | select(.error != null) | .error') | |
if [ -n "$ERROR" ]; then echo -e "Error found in the last maintenance event: $ERROR" && exit 1; else echo "Maintenance finished successfully"; fi | |
# done | |
echo "Finished" | |
build-stable: | |
name: Build ansible image (stable) | |
needs: test | |
runs-on: self-hosted | |
if: ${{ github.ref == 'refs/heads/fresh' }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v1 | |
- name: Login to ghcr.io | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
ghcr.io/${{ github.repository }} | |
registry.etke.cc/${{ github.repository }} | |
tags: | | |
type=raw,value=latest,enable=${{ github.ref_name == 'fresh' }} | |
- name: Build and push | |
uses: docker/build-push-action@v6 | |
with: | |
platforms: linux/amd64,linux/arm64 | |
push: true | |
context: . | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
build-args: | | |
ALPINE=${{ env.alpine }} | |
ANSIBLE=${{ env.ansible }} | |
ANSIBLE_CORE=${{ env.ansible_core }} | |
- name: Notify about changes | |
env: | |
MATRIX_TOKEN: ${{ secrets.MATRIX_TOKEN }} | |
MATRIX_URL_FRESH: ${{ secrets.MATRIX_URL_FRESH }} | |
CI_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} | |
run: | | |
./bin/ci-notify.sh |