11name : Build and Push Docker image
22
33# CalVer Release Workflow
4- #
4+ #
55# Automatically creates a CalVer release on every push to main.
66# Version format: YYYY.MM.DD (e.g., 2026.01.16)
77# If multiple releases happen on the same day, adds sequence: YYYY.MM.DD.2, YYYY.MM.DD.3, etc.
88#
9- # Docker tags created:
10- # - CalVer tag (e.g., 2026.01.16)
9+ # Build strategy: native runners (no QEMU) for maximum speed
10+ # amd64 builds on ubuntu-latest
11+ # arm64 builds on ubuntu-24.04-arm
12+ #
13+ # Docker tags created (linux/amd64 + linux/arm64 multi-arch manifest):
14+ # - CalVer tag (e.g., 2026.01.16) [main only]
15+ # - latest [main only]
1116# - Branch name (e.g., main)
12- # - Git short hash (e.g., main-a1b2c3d)
13- # - latest (for main branch only)
17+ # - Branch + short sha (e.g., main-a1b2c3d)
1418
1519on :
1620 push :
1721 branches : [main, release-test]
1822 tags : ['v*']
1923
2024jobs :
21- build :
25+ prepare :
2226 runs-on : ubuntu-latest
2327 permissions :
24- contents : write # Need write for creating tags
25- packages : write
28+ contents : write # needed to create git tags
29+ outputs :
30+ version : ${{ steps.calver.outputs.version }}
31+ short_sha : ${{ steps.git.outputs.short_sha }}
32+ build_time : ${{ steps.git.outputs.build_time }}
2633
2734 steps :
2835 - name : Checkout code
@@ -33,50 +40,38 @@ jobs:
3340 - name : Generate CalVer version
3441 id : calver
3542 run : |
36- # Get today's date in YYYY.MM.DD format
3743 TODAY=$(date +"%Y.%m.%d")
38-
39- # Get all existing tags for today
4044 EXISTING_TAGS=$(git tag -l "${TODAY}*" | sort -V)
41-
45+
4246 if [ -z "$EXISTING_TAGS" ]; then
43- # No tags for today, use base date
4447 VERSION="${TODAY}"
4548 else
46- # Find the highest sequence number
4749 LAST_TAG=$(echo "$EXISTING_TAGS" | tail -1)
48-
4950 if [[ "$LAST_TAG" == "$TODAY" ]]; then
50- # First tag was just the date, next is .2
5151 VERSION="${TODAY}.2"
5252 elif [[ "$LAST_TAG" =~ ^${TODAY}\.([0-9]+)$ ]]; then
53- # Extract sequence number and increment
5453 SEQ="${BASH_REMATCH[1]}"
55- NEXT_SEQ=$((SEQ + 1))
56- VERSION="${TODAY}.${NEXT_SEQ}"
54+ VERSION="${TODAY}.$((SEQ + 1))"
5755 else
58- # Fallback
5956 VERSION="${TODAY}.2"
6057 fi
6158 fi
62-
59+
6360 echo "version=${VERSION}" >> $GITHUB_OUTPUT
6461 echo "Generated CalVer version: ${VERSION}"
6562
6663 - name : Get git commit info
6764 id : git
6865 run : |
6966 echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
70- echo "full_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
7167 echo "build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT
7268
7369 - name : Create git tag
7470 if : github.ref == 'refs/heads/main'
7571 run : |
7672 git config user.name "github-actions[bot]"
7773 git config user.email "github-actions[bot]@users.noreply.github.com"
78-
79- # Check if tag already exists
74+
8075 if git rev-parse "${{ steps.calver.outputs.version }}" >/dev/null 2>&1; then
8176 echo "Tag ${{ steps.calver.outputs.version }} already exists, skipping"
8277 else
8580 echo "Created and pushed tag ${{ steps.calver.outputs.version }}"
8681 fi
8782
83+ build :
84+ needs : prepare
85+ runs-on : ${{ matrix.runner }}
86+ permissions :
87+ contents : read
88+ packages : write
89+ strategy :
90+ matrix :
91+ include :
92+ - platform : linux/amd64
93+ platform_tag : amd64
94+ runner : ubuntu-latest
95+ - platform : linux/arm64
96+ platform_tag : arm64
97+ runner : ubuntu-24.04-arm
98+
99+ steps :
100+ - name : Checkout code
101+ uses : actions/checkout@v4
102+
88103 - name : Set up Docker Buildx
89104 uses : docker/setup-buildx-action@v3
90105
@@ -95,67 +110,94 @@ jobs:
95110 username : ${{ secrets.AWS_ACCESS_KEY }}
96111 password : ${{ secrets.AWS_SECRET }}
97112
98- - name : Extract metadata
99- id : meta
100- uses : docker/metadata-action@v5
101- with :
102- images : |
103- public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server
104- tags : |
105- # CalVer tag (e.g., 2026.01.16)
106- type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
107- # Branch name
108- type=ref,event=branch
109- # PR number
110- type=ref,event=pr
111- # Semver tags (for manual v* tags)
112- type=semver,pattern={{version}}
113- type=semver,pattern={{major}}.{{minor}}
114- # Git sha with branch prefix
115- type=sha,prefix={{branch}}-
116- # Latest tag for main branch
117- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
118-
119- - name : Build and push Docker image
113+ - name : Build and push (${{ matrix.platform_tag }})
120114 uses : docker/build-push-action@v5
121115 with :
122116 context : .
123117 file : ./docker/Dockerfile
124- platforms : linux/amd64
118+ platforms : ${{ matrix.platform }}
125119 push : true
126- cache-from : type=gha
127- cache-to : type=gha,mode=max
128- tags : ${{ steps.meta.outputs.tags }}
129- labels : ${{ steps.meta.outputs.labels }}
120+ cache-from : type=gha,scope=vcon-server-${{ matrix.platform_tag }}
121+ cache-to : type=gha,mode=max,scope=vcon-server-${{ matrix.platform_tag }}
122+ tags : public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:${{ github.ref_name }}-${{ matrix.platform_tag }}
130123 build-args : |
131- VCON_SERVER_VERSION=${{ steps.calver.outputs.version }}
132- VCON_SERVER_GIT_COMMIT=${{ steps.git.outputs.short_sha }}
133- VCON_SERVER_BUILD_TIME=${{ steps.git.outputs.build_time }}
124+ VCON_SERVER_VERSION=${{ needs.prepare.outputs.version }}
125+ VCON_SERVER_GIT_COMMIT=${{ needs.prepare.outputs.short_sha }}
126+ VCON_SERVER_BUILD_TIME=${{ needs.prepare.outputs.build_time }}
127+
128+ merge :
129+ needs : [prepare, build]
130+ runs-on : ubuntu-latest
131+ permissions :
132+ contents : read
133+ packages : write
134+
135+ steps :
136+ - name : Set up Docker Buildx
137+ uses : docker/setup-buildx-action@v3
134138
139+ - name : Log in to Amazon ECR Public
140+ uses : docker/login-action@v3
141+ with :
142+ registry : public.ecr.aws
143+ username : ${{ secrets.AWS_ACCESS_KEY }}
144+ password : ${{ secrets.AWS_SECRET }}
145+
146+ - name : Create multi-arch manifests
147+ env :
148+ IMAGE : public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server
149+ VERSION : ${{ needs.prepare.outputs.version }}
150+ SHORT_SHA : ${{ needs.prepare.outputs.short_sha }}
151+ BRANCH : ${{ github.ref_name }}
152+ run : |
153+ AMD64="${IMAGE}:${BRANCH}-amd64"
154+ ARM64="${IMAGE}:${BRANCH}-arm64"
155+
156+ # Branch tag (always)
157+ docker buildx imagetools create --tag "${IMAGE}:${BRANCH}" "${AMD64}" "${ARM64}"
158+
159+ # Branch + sha tag (always)
160+ docker buildx imagetools create --tag "${IMAGE}:${BRANCH}-${SHORT_SHA}" "${AMD64}" "${ARM64}"
161+
162+ # CalVer and latest (main only)
163+ if [ "${BRANCH}" = "main" ]; then
164+ docker buildx imagetools create --tag "${IMAGE}:${VERSION}" "${AMD64}" "${ARM64}"
165+ docker buildx imagetools create --tag "${IMAGE}:latest" "${AMD64}" "${ARM64}"
166+ fi
167+
168+ release :
169+ needs : [prepare, merge]
170+ runs-on : ubuntu-latest
171+ if : github.ref == 'refs/heads/main'
172+ permissions :
173+ contents : write
174+
175+ steps :
135176 - name : Create GitHub Release
136- if : github.ref == 'refs/heads/main'
137177 uses : softprops/action-gh-release@v1
138178 with :
139- tag_name : ${{ steps.calver .outputs.version }}
140- name : Release ${{ steps.calver .outputs.version }}
179+ tag_name : ${{ needs.prepare .outputs.version }}
180+ name : Release ${{ needs.prepare .outputs.version }}
141181 body : |
142- ## Release ${{ steps.calver .outputs.version }}
143-
144- **Commit:** ${{ steps.git .outputs.short_sha }}
145- **Build Time:** ${{ steps.git .outputs.build_time }}
146-
182+ ## Release ${{ needs.prepare .outputs.version }}
183+
184+ **Commit:** ${{ needs.prepare .outputs.short_sha }}
185+ **Build Time:** ${{ needs.prepare .outputs.build_time }}
186+
147187 ### Docker Images
148-
188+
189+ Both `linux/amd64` and `linux/arm64` are supported.
190+
149191 Pull using CalVer:
150192 ```bash
151- docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:${{ steps.calver .outputs.version }}
193+ docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:${{ needs.prepare .outputs.version }}
152194 ```
153-
195+
154196 Pull using git hash:
155197 ```bash
156- docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:main-${{ steps.git .outputs.short_sha }}
198+ docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:main-${{ needs.prepare .outputs.short_sha }}
157199 ```
158-
200+
159201 Pull latest:
160202 ```bash
161203 docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server:latest
@@ -171,12 +213,13 @@ jobs:
171213 echo "" >> $GITHUB_STEP_SUMMARY
172214 echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
173215 echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
174- echo "| **Version** | ${{ steps.calver .outputs.version }} |" >> $GITHUB_STEP_SUMMARY
175- echo "| **Git Commit** | ${{ steps.git .outputs.short_sha }} |" >> $GITHUB_STEP_SUMMARY
176- echo "| **Build Time** | ${{ steps.git .outputs.build_time }} |" >> $GITHUB_STEP_SUMMARY
216+ echo "| **Version** | ${{ needs.prepare .outputs.version }} |" >> $GITHUB_STEP_SUMMARY
217+ echo "| **Git Commit** | ${{ needs.prepare .outputs.short_sha }} |" >> $GITHUB_STEP_SUMMARY
218+ echo "| **Build Time** | ${{ needs.prepare .outputs.build_time }} |" >> $GITHUB_STEP_SUMMARY
177219 echo "| **Branch** | ${{ github.ref_name }} |" >> $GITHUB_STEP_SUMMARY
178220 echo "" >> $GITHUB_STEP_SUMMARY
179- echo "### Docker Tags" >> $GITHUB_STEP_SUMMARY
180- echo '```' >> $GITHUB_STEP_SUMMARY
181- echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
182- echo '```' >> $GITHUB_STEP_SUMMARY
221+ echo "### Docker Tags (linux/amd64 + linux/arm64)" >> $GITHUB_STEP_SUMMARY
222+ echo "- \`${{ needs.prepare.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
223+ echo "- \`latest\`" >> $GITHUB_STEP_SUMMARY
224+ echo "- \`main\`" >> $GITHUB_STEP_SUMMARY
225+ echo "- \`main-${{ needs.prepare.outputs.short_sha }}\`" >> $GITHUB_STEP_SUMMARY
0 commit comments