11name : docker-compose-ci
22
33on :
4- workflow_dispatch :
4+ # workflow_dispatch:
55 push :
66 branches : ["master"]
7- tags : ["v*.*.*"]
8- pull_request :
9- branches : ["master"]
7+ paths-ignore :
8+ - " **/*.md"
9+ - " **/*.png"
10+ - " **/*.jpg"
11+ - " **/*.svg"
12+ # tags: ["v*.*.*"]
13+ # pull_request:
14+ # branches: ["master"]
1015
1116permissions :
1217 contents : read
@@ -19,8 +24,10 @@ concurrency:
1924
2025env :
2126 REPO_SLUG : centralized-logging
22- DOCKERHUB_NAMESPACE : " " # optional mirroring
2327 PLATFORMS : linux/amd64,linux/arm64
28+ DOCKERHUB_NAMESPACE : " hasanjaveddeveloper" # optional mirroring
29+ PUSH_IMAGES : " true" # always push in GitHub CI
30+ ALLOW_LOCAL_PUSH : " true" # allows push when not running under act
2431
2532jobs :
2633 images :
@@ -30,23 +37,39 @@ jobs:
3037 github.event_name == 'workflow_dispatch' ||
3138 startsWith(github.ref, 'refs/heads/master') ||
3239 startsWith(github.ref, 'refs/tags/v')
33- env :
34- DOCKERHUB_USERNAME : ${{ secrets.DOCKERHUB_USERNAME }}
35- DOCKERHUB_TOKEN : ${{ secrets.DOCKERHUB_TOKEN }}
3640 steps :
41+ # ---------- Source checkout ----------
42+ - name : Checkout (act)
43+ if : ${{ env.ACT }}
44+ run : echo "Repo mounted by act. Skipping actions/checkout."
45+
3746 - name : Checkout
47+ if : ${{ !env.ACT }}
3848 uses : actions/checkout@v4
39- with : { fetch-depth: 0 }
49+ with :
50+ fetch-depth : 1
4051
52+ # ---------- Tooling ----------
4153 - name : Set up QEMU
54+ if : ${{ !env.ACT }}
4255 uses : docker/setup-qemu-action@v3
4356
4457 - name : Set up Docker Buildx
58+ if : ${{ !env.ACT }}
4559 uses : docker/setup-buildx-action@v3
4660
47- # Build *lines* of overrides like:
48- # userapi.tags=ghcr.io/...:edge
49- # userapi.tags=ghcr.io/...:latest
61+ - name : Bootstrap buildx (act)
62+ if : ${{ env.ACT }}
63+ run : |
64+ docker buildx create --use --driver docker --name actdocker || true
65+ docker buildx inspect --bootstrap
66+
67+ - name : Force single-arch for act and non-tag builds
68+ run : |
69+ if [ -n "${ACT:-}" ]; then echo "PLATFORMS=linux/amd64" >> $GITHUB_ENV; fi
70+ if [[ "${GITHUB_REF}" != refs/tags/v* ]]; then echo "PLATFORMS=linux/amd64" >> $GITHUB_ENV; fi
71+ shell : bash
72+
5073 - name : Compute tag override lines
5174 id : tags
5275 shell : bash
@@ -55,106 +78,127 @@ jobs:
5578 OWNER_LC="${GITHUB_REPOSITORY_OWNER,,}"
5679 REPO_SLUG="${REPO_SLUG}"
5780 REF="${GITHUB_REF}"
81+ HUB_NS="${DOCKERHUB_NAMESPACE:-}"
5882
59- add_tags_lines () {
83+ add_lines () { # svc, tags...
6084 local svc="$1"; shift
6185 local -a tags=( "$@" )
62- for t in "${tags[@]}"; do
63- printf '%s.tags=%s\n' "$svc" "$t"
64- done
86+ for t in "${tags[@]}"; do printf '%s.tags=%s\n' "$svc" "$t"; done
6587 }
6688
67- user_tags=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:edge" )
68- api_tags=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:edge" )
69- web_tags=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:edge" )
89+ # GHCR base tags
90+ is_master=false
91+ is_tag=false
7092
7193 if [[ "$REF" == "refs/heads/master" ]]; then
94+ is_master=true
95+ elif [[ "$REF" == refs/tags/v* ]]; then
96+ is_tag=true
97+ fi
98+
99+ # Non-master, non-tag branches -> edge
100+ if ! $is_master && ! $is_tag; then
101+ user_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:edge" )
102+ api_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:edge" )
103+ web_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:edge" )
104+ fi
105+
106+ # Master branch -> latest
107+ if $is_master; then
72108 user_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:latest" )
73109 api_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:latest" )
74110 web_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:latest" )
75111 fi
76112
77- if [[ "$REF" == refs/tags/v* ]]; then
113+ # Release tags -> vX.Y.Z and X.Y (optionally also latest if you want)
114+ if $is_tag; then
78115 ver="${REF#refs/tags/}" # vX.Y.Z
79116 short="${ver#v}" # X.Y.Z
80117 minor="${short%.*}" # X.Y
81118 user_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:${ver}" "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:${minor}" )
82119 api_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:${ver}" "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:${minor}" )
83120 web_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:${ver}" "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:${minor}" )
121+
122+ # Uncomment if you want latest to follow releases instead of master:
123+ # user_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/userapi:latest" )
124+ # api_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/api:latest" )
125+ # web_tags+=( "ghcr.io/${OWNER_LC}/${REPO_SLUG}/web:latest" )
84126 fi
85127
86- user_lines="$(add_tags_lines userapi "${user_tags[@]}")"
87- api_lines="$(add_tags_lines api "${api_tags[@]}")"
88- web_lines="$(add_tags_lines web "${web_tags[@]}")"
128+ # Docker Hub mirrors (optional, only if namespace present)
129+ if [[ -n "$HUB_NS" ]]; then
130+ hub_user=( "${user_tags[@]/#ghcr.io\/${OWNER_LC}\/${REPO_SLUG}\/userapi:/docker.io/${HUB_NS}/${REPO_SLUG}-userapi:}" )
131+ hub_api=( "${api_tags[@]/#ghcr.io\/${OWNER_LC}\/${REPO_SLUG}\/api:/docker.io/${HUB_NS}/${REPO_SLUG}-api:}" )
132+ hub_web=( "${web_tags[@]/#ghcr.io\/${OWNER_LC}\/${REPO_SLUG}\/web:/docker.io/${HUB_NS}/${REPO_SLUG}-web:}" )
133+ user_tags+=( "${hub_user[@]}" )
134+ api_tags+=( "${hub_api[@]}" )
135+ web_tags+=( "${hub_web[@]}" )
136+ fi
89137
90138 {
91- echo "user_set<<EOF"
92- echo "${user_lines}"
93- echo "EOF"
94- echo "api_set<<EOF"
95- echo "${api_lines}"
96- echo "EOF"
97- echo "web_set<<EOF"
98- echo "${web_lines}"
99- echo "EOF"
139+ echo "user_set<<EOF"; add_lines userapi "${user_tags[@]}"; echo "EOF"
140+ echo "api_set<<EOF"; add_lines api "${api_tags[@]}"; echo "EOF"
141+ echo "web_set<<EOF"; add_lines web "${web_tags[@]}"; echo "EOF"
100142 } >> "$GITHUB_OUTPUT"
101143
144+ # ---------- GHCR login ----------
145+ - name : Login to GHCR (act)
146+ if : ${{ env.ACT }}
147+ shell : bash
148+ run : echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.repository_owner }}" --password-stdin
149+
102150 - name : Login to GHCR
151+ if : ${{ !env.ACT }}
103152 uses : docker/login-action@v3
104153 with :
105154 registry : ghcr.io
106155 username : ${{ github.repository_owner }}
107156 password : ${{ secrets.GITHUB_TOKEN }}
108157
109- - name : (Optional) Login to Docker Hub
110- if : ${{ env.DOCKERHUB_NAMESPACE != '' && env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
158+ # ACT: login to Docker Hub via CLI
159+ - name : Login to Docker Hub (act)
160+ shell : bash
161+ run : echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
162+
163+ # GitHub CI: login action
164+ - name : Login to Docker Hub
111165 uses : docker/login-action@v3
112166 with :
113- username : ${{ env .DOCKERHUB_USERNAME }}
114- password : ${{ env .DOCKERHUB_TOKEN }}
167+ username : ${{ secrets .DOCKERHUB_USERNAME }}
168+ password : ${{ secrets .DOCKERHUB_TOKEN }}
115169
116- - name : Restore build cache
117- uses : actions/cache@v4
118- with :
119- path : /tmp/.buildx-cache
120- key : ${{ runner.os }}-buildx-${{ github.sha }}
121- restore-keys : |
122- ${{ runner.os }}-buildx-
170+ # ---------- ACT: CLI bake (avoids dial-stdio) ----------
171+ - name : Bake (ACT)
172+ if : ${{ env.ACT }}
173+ shell : bash
174+ env :
175+ DO_PUSH : ${{ env.PUSH_IMAGES == 'true' && env.ALLOW_LOCAL_PUSH == 'true' && 'true' || 'false' }}
176+ run : |
177+ set -euo pipefail
178+ COMMON_SET=(
179+ "--set" "*.platform=${PLATFORMS}"
180+ "--set" "*.labels.org.opencontainers.image.revision=${GITHUB_SHA}"
181+ )
182+ while IFS= read -r l; do COMMON_SET+=( "--set" "$l" ); done <<< "${{ steps.tags.outputs.user_set }}"
183+ while IFS= read -r l; do COMMON_SET+=( "--set" "$l" ); done <<< "${{ steps.tags.outputs.api_set }}"
184+ while IFS= read -r l; do COMMON_SET+=( "--set" "$l" ); done <<< "${{ steps.tags.outputs.web_set }}"
185+
186+ if [ "$DO_PUSH" = "true" ]; then
187+ docker buildx bake -f ./docker-bake.hcl "${COMMON_SET[@]}" --push
188+ else
189+ docker buildx bake -f ./docker-bake.hcl "${COMMON_SET[@]}" --load
190+ fi
123191
124- - name : Bake and Push (multi-arch)
192+ # ---------- GitHub CI: bake action ----------
193+ - name : Bake and Push (GitHub)
194+ if : ${{ !env.ACT }}
125195 uses : docker/bake-action@v5
126196 with :
127197 files : ./docker-bake.hcl
128- push : true
198+ push : ${{ env.PUSH_IMAGES == ' true' }}
129199 set : |
130200 *.platform=${{ env.PLATFORMS }}
131- *.cache-from=type=local,src=/tmp/.buildx-cache
132- *.cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max
133201 *.labels.org.opencontainers.image.revision=${{ github.sha }}
134202 ${{ steps.tags.outputs.user_set }}
135203 ${{ steps.tags.outputs.api_set }}
136204 ${{ steps.tags.outputs.web_set }}
137-
138- - name : Save build cache
139- if : always()
140- run : |
141- rm -rf /tmp/.buildx-cache
142- mv /tmp/.buildx-cache-new /tmp/.buildx-cache
143-
144- - name : Mirror to Docker Hub (optional)
145- if : ${{ env.DOCKERHUB_NAMESPACE != '' && env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
146- run : |
147- set -euo pipefail
148- mirror() { local svc="$1"; shift; while read -r line; do
149- img="${line#*=}" # take rhs after '='
150- tag="${img##*:}"
151- hub="${DOCKERHUB_NAMESPACE}/${REPO_SLUG}-${svc}:${tag}"
152- echo "Mirroring $img -> $hub"
153- docker pull "$img"
154- docker tag "$img" "$hub"
155- docker push "$hub"
156- done; }
157- # reuse the same lines we fed to bake
158- awk -F= '/^userapi\.tags=/{print}' <<<"${{ steps.tags.outputs.user_set }}" | mirror userapi
159- awk -F= '/^api\.tags=/{print}' <<<"${{ steps.tags.outputs.api_set }}" | mirror api
160- awk -F= '/^web\.tags=/{print}' <<<"${{ steps.tags.outputs.web_set }}" | mirror web
0 commit comments