11name : docker-compose-ci
22
3-
43on :
4+ workflow_dispatch :
55 push :
6- branches : [ "master" ]
7- tags : [ ' v*.*.*' ] # v1.2.3 -> release images
6+ branches : ["master"]
7+ tags : [" v*.*.*"]
88 pull_request :
9- branches : [ "master" ]
9+ branches : ["master"]
1010
1111permissions :
1212 contents : read
13- packages : write # needed for GHCR
13+ packages : write
1414 id-token : write
1515
1616concurrency :
1717 group : docker-compose-ci-${{ github.ref }}
1818 cancel-in-progress : true
1919
2020env :
21- # Project namespace for your image path: ghcr.io/<owner>/<REPO_SLUG>/<service>
2221 REPO_SLUG : centralized-logging
23- # Optional: set to your Docker Hub namespace (lowercase). Leave empty to skip mirroring.
2422 DOCKERHUB_NAMESPACE : " "
25- # Multi-arch
2623 PLATFORMS : linux/amd64,linux/arm64
2724
2825jobs :
29- build-and-push :
26+ tests :
27+ name : Build and Test (.NET)
3028 runs-on : ubuntu-latest
31-
3229 steps :
3330 - name : Checkout
3431 uses : actions/checkout@v4
32+
33+ - name : Setup .NET
34+ uses : actions/setup-dotnet@v4
3535 with :
36- fetch-depth : 0
36+ dotnet-version : |
37+ 9.0.x
38+ 8.0.x
39+
40+ - name : Restore
41+ run : dotnet restore
42+
43+ - name : Build
44+ run : dotnet build --configuration Release --no-restore
45+
46+ - name : Test
47+ run : dotnet test --configuration Release --no-build --collect:"XPlat Code Coverage"
48+ env :
49+ DOTNET_CLI_TELEMETRY_OPTOUT : 1
50+
51+ images :
52+ name : Build and Push Images (GHCR)
53+ runs-on : ubuntu-latest
54+ needs : tests
55+ if : >
56+ github.event_name != 'pull_request' &&
57+ (startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/tags/v'))
58+ steps :
59+ - name : Checkout
60+ uses : actions/checkout@v4
3761
3862 - name : Set up QEMU
3963 uses : docker/setup-qemu-action@v3
4064
4165 - name : Set up Docker Buildx
4266 uses : docker/setup-buildx-action@v3
4367
44- # --- Compute tags per service (three separate metadata steps) ---
4568 - name : Meta (userapi)
4669 id : meta_user
4770 uses : docker/metadata-action@v5
4871 with :
4972 images : ghcr.io/${{ github.repository_owner }}/${{ env.REPO_SLUG }}/userapi
5073 tags : |
51- type=raw,value=edge,enable=${{ github.event_name != 'pull_request' }}
52- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
53- type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
54- type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
74+ type=raw,value=edge,enable=${{ startsWith( github.ref,'refs/heads/master') || startsWith(github.ref,'refs/tags/v') }}
75+ type=raw,value=latest,enable=${{ startsWith( github.ref, 'refs/heads/master') }}
76+ type=semver,pattern={{version}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
77+ type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
5578
5679 - name : Meta (api)
5780 id : meta_api
5881 uses : docker/metadata-action@v5
5982 with :
6083 images : ghcr.io/${{ github.repository_owner }}/${{ env.REPO_SLUG }}/api
6184 tags : |
62- type=raw,value=edge,enable=${{ github.event_name != 'pull_request' }}
63- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
64- type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
65- type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
85+ type=raw,value=edge,enable=${{ startsWith( github.ref,'refs/heads/master') || startsWith(github.ref,'refs/tags/v') }}
86+ type=raw,value=latest,enable=${{ startsWith( github.ref, 'refs/heads/master') }}
87+ type=semver,pattern={{version}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
88+ type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
6689
6790 - name : Meta (web)
6891 id : meta_web
6992 uses : docker/metadata-action@v5
7093 with :
7194 images : ghcr.io/${{ github.repository_owner }}/${{ env.REPO_SLUG }}/web
7295 tags : |
73- type=raw,value=edge,enable=${{ github.event_name != 'pull_request' }}
74- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
75- type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
76- type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
96+ type=raw,value=edge,enable=${{ startsWith( github.ref,'refs/heads/master') || startsWith(github.ref,'refs/tags/v') }}
97+ type=raw,value=latest,enable=${{ startsWith( github.ref, 'refs/heads/master') }}
98+ type=semver,pattern={{version}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
99+ type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref,'refs/tags/v') }}
77100
78101 - name : Login to GHCR
79- if : ${{ github.event_name != 'pull_request' }}
80102 uses : docker/login-action@v3
81103 with :
82104 registry : ghcr.io
83105 username : ${{ github.repository_owner }}
84106 password : ${{ secrets.GITHUB_TOKEN }}
85107
86- - name : Login to Docker Hub (optional)
87- if : ${{ github.event_name != 'pull_request' && env.DOCKERHUB_NAMESPACE != '' && secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
108+ - name : (Optional) Login to Docker Hub
109+ if : ${{ env.DOCKERHUB_NAMESPACE != '' && secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
88110 uses : docker/login-action@v3
89111 with :
90112 username : ${{ secrets.DOCKERHUB_USERNAME }}
91113 password : ${{ secrets.DOCKERHUB_TOKEN }}
92114
93- # Build cache (local dir cache)
94115 - name : Restore build cache
95116 uses : actions/cache@v4
96117 with :
@@ -99,24 +120,18 @@ jobs:
99120 restore-keys : |
100121 ${{ runner.os }}-buildx-
101122
102- - name : Bake & Push (multi-arch)
123+ - name : Bake and Push (multi-arch)
103124 uses : docker/bake-action@v5
104125 with :
105126 files : ./docker-bake.hcl
106- push : ${{ github.event_name != 'pull_request' }}
127+ push : true
107128 set : |
108- # Platforms & cache
109129 *.platform=${{ env.PLATFORMS }}
110130 *.cache-from=type=local,src=/tmp/.buildx-cache
111131 *.cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max
112- # Labels/injection
113132 *.labels.org.opencontainers.image.revision=${{ github.sha }}
114- # Bake variables (must match variable names in docker-bake.hcl)
115133 OWNER=${{ github.repository_owner }}
116134 REPO_SLUG=${{ env.REPO_SLUG }}
117- # If you customized REGISTRY_GHCR in the bake file, you could set it here too:
118- # REGISTRY_GHCR=ghcr.io
119- # Service-specific tags
120135 userapi.tags=${{ steps.meta_user.outputs.tags }}
121136 api.tags=${{ steps.meta_api.outputs.tags }}
122137 web.tags=${{ steps.meta_web.outputs.tags }}
@@ -128,26 +143,14 @@ jobs:
128143 mv /tmp/.buildx-cache-new /tmp/.buildx-cache
129144
130145 - name : Mirror to Docker Hub (optional)
131- if : ${{ github.event_name != 'pull_request' && env.DOCKERHUB_NAMESPACE != '' && secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
146+ if : ${{ env.DOCKERHUB_NAMESPACE != '' && secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
132147 run : |
133148 set -euo pipefail
149+ mirror() { local svc="$1"; shift; for t in "$@"; do tg="$(basename "$t")"; \
150+ ghcr="ghcr.io/${{ github.repository_owner }}/${{ env.REPO_SLUG }}/${svc}:${tg}"; \
151+ hub="${{ env.DOCKERHUB_NAMESPACE }}/${{ env.REPO_SLUG }}-${svc}:${tg}"; \
152+ echo "Mirroring $ghcr -> $hub"; docker pull "$ghcr"; docker tag "$ghcr" "$hub"; docker push "$hub"; done; }
134153 mapfile -t USER_TAGS <<< "${{ steps.meta_user.outputs.tags }}"
135154 mapfile -t API_TAGS <<< "${{ steps.meta_api.outputs.tags }}"
136155 mapfile -t WEB_TAGS <<< "${{ steps.meta_web.outputs.tags }}"
137-
138- mirror() {
139- local svc="$1"; shift
140- for t in "$@"; do
141- tg="$(basename "$t")"
142- ghcr="ghcr.io/${{ github.repository_owner }}/${{ env.REPO_SLUG }}/${svc}:${tg}"
143- hub="${{ env.DOCKERHUB_NAMESPACE }}/${{ env.REPO_SLUG }}-${svc}:${tg}"
144- echo "Mirroring $ghcr -> $hub"
145- docker pull "$ghcr"
146- docker tag "$ghcr" "$hub"
147- docker push "$hub"
148- done
149- }
150-
151- mirror userapi "${USER_TAGS[@]}"
152- mirror api "${API_TAGS[@]}"
153- mirror web "${WEB_TAGS[@]}"
156+ mirror userapi "${USER_TAGS[@]}"; mirror api "${API_TAGS[@]}"; mirror web "${WEB_TAGS[@]}"
0 commit comments