mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-08 22:08:03 -05:00
ci: add tag-based multi-arch Docker publish to GHCR and Docker Hub
CHANGES - Add GitHub Actions workflow to publish Docker images on tags - Build multi-arch images with Buildx and QEMU across amd64, arm64 - Tag images using semver; push to GHCR and Docker Hub - Set :latest only for highest semver tag via imagetools - Gate patterns workflow steps on detected changes instead of failing - Auto-detect GitHub owner and repo from git remote URL - Remove hardcoded repository values in changelog release manager - Normalize image names to lowercase for registry compatibility - Enable GitHub Actions cache for faster Docker builds - Add VS Code dictionary entries for Docker-related terms
This commit is contained in:
149
.github/workflows/docker-publish-on-tag.yml
vendored
Normal file
149
.github/workflows/docker-publish-on-tag.yml
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
name: Release Docker image on tag (GHCR + Docker Hub)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"] # e.g., v1.4.300
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write # needed for GHCR with GITHUB_TOKEN
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
# Optional safety: only run from your fork
|
||||
if: ${{ github.repository_owner == 'ksylvan' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
is_latest: ${{ steps.latest.outputs.is_latest }}
|
||||
owner_lc: ${{ steps.vars.outputs.owner_lc }}
|
||||
repo_lc: ${{ steps.vars.outputs.repo_lc }}
|
||||
dockerhub_user_lc: ${{ steps.dh.outputs.user_lc }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # full history for tag comparisons
|
||||
|
||||
- name: Fetch all tags
|
||||
run: git fetch --tags --force
|
||||
|
||||
# More reliable cross-builds
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# Compute lowercase owner/repo for registry image names
|
||||
- name: Compute image names
|
||||
id: vars
|
||||
run: |
|
||||
OWNER="${GITHUB_REPOSITORY_OWNER}"
|
||||
REPO="${GITHUB_REPOSITORY#*/}"
|
||||
echo "owner_lc=${OWNER,,}" >> "$GITHUB_OUTPUT"
|
||||
echo "repo_lc=${REPO,,}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Lowercase Docker Hub username (belt & suspenders)
|
||||
- name: Lowercase Docker Hub username
|
||||
id: dh
|
||||
run: echo "user_lc=${DOCKERHUB_USERNAME,,}" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
|
||||
# Determine if the current tag is the highest vX.Y.Z (no pre-releases)
|
||||
- name: Is this the latest semver tag?
|
||||
id: latest
|
||||
shell: bash
|
||||
run: |
|
||||
CTAG="${GITHUB_REF_NAME}"
|
||||
LATEST="$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1)"
|
||||
echo "current_tag=$CTAG" >> "$GITHUB_OUTPUT"
|
||||
echo "latest_tag=$LATEST" >> "$GITHUB_OUTPUT"
|
||||
if [[ "$CTAG" == "$LATEST" ]]; then
|
||||
echo "is_latest=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "is_latest=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# Login to GHCR (uses built-in GITHUB_TOKEN)
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Login to Docker Hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ steps.dh.outputs.user_lc }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate versioned tags/labels for BOTH registries (no :latest here)
|
||||
- name: Extract metadata (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ steps.vars.outputs.repo_lc }}
|
||||
docker.io/${{ steps.dh.outputs.user_lc }}/${{ steps.vars.outputs.repo_lc }}
|
||||
tags: |
|
||||
type=ref,event=tag # v1.4.300
|
||||
type=semver,pattern={{version}} # 1.4.300 (optional)
|
||||
type=semver,pattern={{major}}.{{minor}} # 1.4 (optional)
|
||||
labels: |
|
||||
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
||||
|
||||
- name: Build and push (multi-arch)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# Separate job to (re)point :latest — serialized to avoid races
|
||||
move-latest:
|
||||
needs: build-and-push
|
||||
if: ${{ needs.build-and-push.outputs.is_latest == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Only one "latest" move at a time; newer runs cancel older in-progress ones
|
||||
concurrency:
|
||||
group: latest-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Tag :latest on GHCR
|
||||
run: |
|
||||
SRC="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
|
||||
DST="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
|
||||
docker buildx imagetools create -t "$DST" "$SRC"
|
||||
|
||||
- name: Tag :latest on Docker Hub
|
||||
run: |
|
||||
SRC="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
|
||||
DST="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
|
||||
docker buildx imagetools create -t "$DST" "$SRC"
|
||||
8
.github/workflows/patterns.yaml
vendored
8
.github/workflows/patterns.yaml
vendored
@@ -16,17 +16,23 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Changes in Patterns Folder
|
||||
id: check-changes
|
||||
run: |
|
||||
git fetch origin
|
||||
if git diff --quiet HEAD~1 -- data/patterns; then
|
||||
echo "No changes detected in patterns folder."
|
||||
exit 1
|
||||
echo "changes=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Changes detected in patterns folder."
|
||||
echo "changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Zip the Patterns Folder
|
||||
if: steps.check-changes.outputs.changes == 'true'
|
||||
run: zip -r patterns.zip data/patterns/
|
||||
|
||||
- name: Upload Patterns Artifact
|
||||
if: steps.check-changes.outputs.changes == 'true'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: patterns
|
||||
|
||||
Reference in New Issue
Block a user