feat(ci): add cd job to update groombook/infra image tags on main merge (GRO-178) #153

Closed
groombook-engineer[bot] wants to merge 1 commits from fix/gro-178-add-cd-job into main
+135
View File
@@ -268,3 +268,138 @@ jobs:
'Ready for UAT validation.'
].join('\n')
});
cd:
name: Update Infra Repo with New Image Tags
runs-on: ubuntu-latest
needs: [docker]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
pull-requests: write
steps:
- name: Generate image tag
id: version
run: |
TAG="$(date -u +%Y.%m.%d)-${GITHUB_SHA::7}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Image tag: $TAG"
- name: Checkout groombook/infra
uses: actions/checkout@v4
with:
repository: groombook/infra
token: ${{ secrets.GITHUB_TOKEN }}
path: infra
ref: main
- name: Update image tags in infra repo
run: |
TAG="${{ steps.version.outputs.tag }}"
# Update api.yaml — annotation + container image
sed -i "s|groombook.dev/image-version: \".*\"|groombook.dev/image-version: \"$TAG\"|" infra/apps/groombook/base/api.yaml
sed -i "s|ghcr.io/groombook/api:.*|ghcr.io/groombook/api:$TAG|" infra/apps/groombook/base/api.yaml
# Update web.yaml — annotation + container image
sed -i "s|groombook.dev/image-version: \".*\"|groombook.dev/image-version: \"$TAG\"|" infra/apps/groombook/base/web.yaml
sed -i "s|ghcr.io/groombook/web:.*|ghcr.io/groombook/web:$TAG|" infra/apps/groombook/base/web.yaml
# Update migrate-job.yaml — annotation + container image
sed -i "s|groombook.app/deploy-version: \".*\"|groombook.app/deploy-version: \"$TAG\"|" infra/apps/groombook/base/migrate-job.yaml
sed -i "s|ghcr.io/groombook/migrate:.*|ghcr.io/groombook/migrate:$TAG|" infra/apps/groombook/base/migrate-job.yaml
# Update seed-job.yaml — annotation + container image
sed -i "s|groombook.app/deploy-version: \".*\"|groombook.app/deploy-version: \"$TAG\"|" infra/apps/groombook/base/seed-job.yaml
sed -i "s|ghcr.io/groombook/seed:.*|ghcr.io/groombook/seed:$TAG|" infra/apps/groombook/base/seed-job.yaml
echo "Updated image tags to $TAG in:"
git -C infra diff --stat
- name: Create PR on groombook/infra
uses: actions/github-script@v7
with:
script: |
const tag = process.env.TAG;
const sha = process.env.GITHUB_SHA;
const shortSha = sha.slice(0, 7);
const branchName = `cd/update-images-${tag}`;
// Create a new branch
await github.rest.git.createRef({
owner: 'groombook',
repo: 'infra',
ref: `refs/heads/${branchName}`,
sha: sha
});
// Commit the changes
const fs = require('fs');
const path = require('path');
const files = [
'apps/groombook/base/api.yaml',
'apps/groombook/base/web.yaml',
'apps/groombook/base/migrate-job.yaml',
'apps/groombook/base/seed-job.yaml'
];
const commits = [];
for (const file of files) {
const filePath = path.join(process.env.GITHUB_WORKSPACE, 'infra', file);
const content = fs.readFileSync(filePath, 'utf8');
const encoded = Buffer.from(content).toString('base64');
await github.rest.repos.createOrUpdateFileContents({
owner: 'groombook',
repo: 'infra',
path: file,
message: `chore: update ${path.basename(file)} image tag to ${tag}`,
content: encoded,
branch: branchName
});
commits.push(`Updated ${path.basename(file)}`);
}
// Create PR
const pr = await github.rest.pulls.create({
owner: 'groombook',
repo: 'infra',
title: `chore: deploy images ${tag}`,
body: [
`## Image Update`,
``,
`Updating image tags to \`${tag}\` after main merge.`,
``,
`Files changed:`,
...commits.map(c => `- ${c}`),
``,
`**Build:** ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`,
``,
`⚠️ **Note on deploy-dev:** The \`deploy-dev\` job currently uses \`kubectl set image\` directly against the groombook-dev cluster, bypassing GitOps. This creates drift between committed infra manifests and actual cluster state.`,
``,
`Trade-off to consider:`,
`- **Current (kubectl):** Fast PR previews, no infra PR overhead`,
`- **GitOps route:** Consistent history, validated manifests, but slower preview loops`,
``,
`For production, the GitOps path via this PR is the correct approach.`
].join('\n'),
head: branchName,
base: 'main'
});
// Enable auto-merge
try {
await github.rest.pulls.merge({
owner: 'groombook',
repo: 'infra',
pull_number: pr.data.number,
merge_method: 'squash'
});
console.log(`Auto-merge enabled for PR #${pr.data.number}`);
} catch (e) {
console.log(`Could not enable auto-merge: ${e.message}`);
console.log(`PR #${pr.data.number} created — manual approval required.`);
}
// Output PR URL
console.log(`PR_URL=${pr.data.html_url}`);