ci(cd): add release-tag bootstrap image publish pipeline to 192.168.241.13:8080
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
257
.gitea/workflows/cd-bootstrap.yml
Normal file
257
.gitea/workflows/cd-bootstrap.yml
Normal file
@@ -0,0 +1,257 @@
|
||||
name: CD Bootstrap - Release Image Publish
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["CI Pipeline"]
|
||||
types: [completed]
|
||||
branches: [main]
|
||||
workflow_dispatch: # Manual trigger for testing
|
||||
|
||||
env:
|
||||
REGISTRY_HOST: 192.168.241.13:8080
|
||||
BACKEND_IMAGE: workclub-api
|
||||
FRONTEND_IMAGE: workclub-frontend
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
name: CI Success & Release Tag Gate
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
is_release_tag: ${{ steps.validate.outputs.is_release_tag }}
|
||||
image_tag: ${{ steps.validate.outputs.image_tag }}
|
||||
image_sha: ${{ steps.validate.outputs.image_sha }}
|
||||
|
||||
steps:
|
||||
- name: Check CI workflow conclusion
|
||||
if: ${{ github.event.workflow_run.conclusion != 'success' }}
|
||||
run: |
|
||||
echo "CI Pipeline did not succeed (conclusion: ${{ github.event.workflow_run.conclusion }})"
|
||||
exit 1
|
||||
|
||||
- name: Validate release tag and extract version
|
||||
id: validate
|
||||
run: |
|
||||
# Extract ref from workflow_run event or direct trigger
|
||||
REF="${{ github.event.workflow_run.head_branch }}"
|
||||
if [[ -z "$REF" ]]; then
|
||||
REF="${{ github.ref }}"
|
||||
fi
|
||||
|
||||
echo "Detected ref: $REF"
|
||||
|
||||
# Check if ref matches release tag pattern (refs/tags/v*)
|
||||
if [[ "$REF" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||
# Extract version tag (vX.Y.Z)
|
||||
IMAGE_TAG=$(echo "$REF" | sed 's|refs/tags/||')
|
||||
|
||||
# Extract short commit SHA (first 7 chars)
|
||||
IMAGE_SHA="${{ github.event.workflow_run.head_sha }}"
|
||||
if [[ -z "$IMAGE_SHA" ]]; then
|
||||
IMAGE_SHA="${{ github.sha }}"
|
||||
fi
|
||||
IMAGE_SHA_SHORT="${IMAGE_SHA:0:7}"
|
||||
|
||||
echo "is_release_tag=true" >> $GITHUB_OUTPUT
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
echo "image_sha=$IMAGE_SHA_SHORT" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "✅ Release tag detected: $IMAGE_TAG (SHA: $IMAGE_SHA_SHORT)"
|
||||
else
|
||||
echo "is_release_tag=false" >> $GITHUB_OUTPUT
|
||||
echo "⏭️ Not a release tag, skipping image publish"
|
||||
fi
|
||||
|
||||
backend-image:
|
||||
name: Build & Push Backend Image
|
||||
runs-on: ubuntu-latest
|
||||
needs: [gate]
|
||||
if: needs.gate.outputs.is_release_tag == 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to registry (if credentials provided)
|
||||
if: ${{ secrets.REGISTRY_USERNAME != '' && secrets.REGISTRY_PASSWORD != '' }}
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY_HOST }} \
|
||||
--username "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Build backend image
|
||||
working-directory: ./backend
|
||||
run: |
|
||||
docker build \
|
||||
-t ${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:${{ needs.gate.outputs.image_tag }} \
|
||||
-f Dockerfile \
|
||||
.
|
||||
|
||||
- name: Tag with commit SHA
|
||||
run: |
|
||||
docker tag \
|
||||
${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:${{ needs.gate.outputs.image_tag }} \
|
||||
${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}
|
||||
|
||||
- name: Push images to registry
|
||||
run: |
|
||||
docker push ${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}
|
||||
docker push ${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}
|
||||
|
||||
- name: Capture push evidence
|
||||
run: |
|
||||
mkdir -p .sisyphus/evidence
|
||||
cat > .sisyphus/evidence/task-31-backend-push.json <<EOF
|
||||
{
|
||||
"scenario": "backend_image_push",
|
||||
"result": "success",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"details": {
|
||||
"image": "${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}",
|
||||
"version_tag": "${{ needs.gate.outputs.image_tag }}",
|
||||
"sha_tag": "sha-${{ needs.gate.outputs.image_sha }}",
|
||||
"registry": "${{ env.REGISTRY_HOST }}"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Upload backend push evidence
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: backend-push-evidence
|
||||
path: .sisyphus/evidence/task-31-backend-push.json
|
||||
retention-days: 30
|
||||
|
||||
frontend-image:
|
||||
name: Build & Push Frontend Image
|
||||
runs-on: ubuntu-latest
|
||||
needs: [gate]
|
||||
if: needs.gate.outputs.is_release_tag == 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to registry (if credentials provided)
|
||||
if: ${{ secrets.REGISTRY_USERNAME != '' && secrets.REGISTRY_PASSWORD != '' }}
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY_HOST }} \
|
||||
--username "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Build frontend image
|
||||
working-directory: ./frontend
|
||||
run: |
|
||||
docker build \
|
||||
-t ${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:${{ needs.gate.outputs.image_tag }} \
|
||||
-f Dockerfile \
|
||||
.
|
||||
|
||||
- name: Tag with commit SHA
|
||||
run: |
|
||||
docker tag \
|
||||
${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:${{ needs.gate.outputs.image_tag }} \
|
||||
${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}
|
||||
|
||||
- name: Push images to registry
|
||||
run: |
|
||||
docker push ${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}
|
||||
docker push ${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}
|
||||
|
||||
- name: Capture push evidence
|
||||
run: |
|
||||
mkdir -p .sisyphus/evidence
|
||||
cat > .sisyphus/evidence/task-32-frontend-push.json <<EOF
|
||||
{
|
||||
"scenario": "frontend_image_push",
|
||||
"result": "success",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"details": {
|
||||
"image": "${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}",
|
||||
"version_tag": "${{ needs.gate.outputs.image_tag }}",
|
||||
"sha_tag": "sha-${{ needs.gate.outputs.image_sha }}",
|
||||
"registry": "${{ env.REGISTRY_HOST }}"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Upload frontend push evidence
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: frontend-push-evidence
|
||||
path: .sisyphus/evidence/task-32-frontend-push.json
|
||||
retention-days: 30
|
||||
|
||||
release-summary:
|
||||
name: Create Release Summary Evidence
|
||||
runs-on: ubuntu-latest
|
||||
needs: [gate, backend-image, frontend-image]
|
||||
if: always() && needs.gate.outputs.is_release_tag == 'true'
|
||||
|
||||
steps:
|
||||
- name: Generate release summary
|
||||
run: |
|
||||
mkdir -p .sisyphus/evidence
|
||||
|
||||
# Task 30 evidence: CI gate validation
|
||||
cat > .sisyphus/evidence/task-30-ci-gate.json <<EOF
|
||||
{
|
||||
"scenario": "ci_success_gate",
|
||||
"result": "passed",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"details": {
|
||||
"ci_workflow": "CI Pipeline",
|
||||
"ci_conclusion": "${{ github.event.workflow_run.conclusion }}",
|
||||
"source_ref": "${{ github.event.workflow_run.head_branch }}",
|
||||
"validated": "true"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Task 30 evidence: Non-tag skip proof (placeholder for documentation)
|
||||
cat > .sisyphus/evidence/task-30-non-tag-skip.json <<EOF
|
||||
{
|
||||
"scenario": "non_release_tag_skip",
|
||||
"result": "not_applicable",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"details": {
|
||||
"note": "This workflow only runs on release tags (refs/tags/v*)",
|
||||
"gate_condition": "is_release_tag == true",
|
||||
"current_execution": "release_tag_detected"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Task 33 evidence: CD bootstrap release summary
|
||||
cat > .sisyphus/evidence/task-33-cd-bootstrap-release.json <<EOF
|
||||
{
|
||||
"release_tag": "${{ needs.gate.outputs.image_tag }}",
|
||||
"commit_sha": "${{ needs.gate.outputs.image_sha }}",
|
||||
"backend_image": "${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}",
|
||||
"frontend_image": "${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}",
|
||||
"backend_job_conclusion": "${{ needs.backend-image.result }}",
|
||||
"frontend_job_conclusion": "${{ needs.frontend-image.result }}",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Upload all evidence artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cd-bootstrap-evidence
|
||||
path: .sisyphus/evidence/*.json
|
||||
retention-days: 30
|
||||
|
||||
- name: Summary report
|
||||
run: |
|
||||
echo "## 🚀 CD Bootstrap Release Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Release Tag:** ${{ needs.gate.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Commit SHA:** ${{ needs.gate.outputs.image_sha }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### Published Images" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Backend:** \`${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Backend SHA:** \`${{ env.REGISTRY_HOST }}/${{ env.BACKEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Frontend:** \`${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:${{ needs.gate.outputs.image_tag }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Frontend SHA:** \`${{ env.REGISTRY_HOST }}/${{ env.FRONTEND_IMAGE }}:sha-${{ needs.gate.outputs.image_sha }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### Job Results" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Backend Image: ${{ needs.backend-image.result }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Frontend Image: ${{ needs.frontend-image.result }}" >> $GITHUB_STEP_SUMMARY
|
||||
Reference in New Issue
Block a user