Skip to content

Commit 77e14a9

Browse files
Merge pull request #20 from bcit-tlu/devin/1779655268-standardize-patterns
- Delete build-and-push-app.yaml.inactive and VERSION file - Fix helm push error guard: use || { echo; exit 1; } pattern - Add FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 to all workflows - Use shell-safe env: blocks for GHA expressions - Add digest guard to release-retag sign step - Fix deployment.yaml affinity check: use ne (toJson) instead of if - Add x-release-please-version annotation to Chart.yaml version line - Fix Dockerfile comments (## -> #) - Update AGENTS.md to reflect manifest-based version tracking - Reduce verbose block comments across workflows Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: kyle_hunter@bcit.ca <kyle_hunter@bcit.ca>
2 parents 2466178 + b900f79 commit 77e14a9

11 files changed

Lines changed: 119 additions & 137 deletions

File tree

.github/workflows/build-and-push-app.yaml.inactive

Lines changed: 0 additions & 24 deletions
This file was deleted.

.github/workflows/ci.yaml

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: "[CI] Lint, build & publish"
22

3-
# Readable run titles in the Actions UI: PR runs show the PR number and
4-
# title; main pushes show the head commit subject.
3+
# PR runs show PR title; main runs show head commit subject.
54
run-name: >-
65
${{ github.event_name == 'pull_request'
76
&& format('PR #{0} — {1}', github.event.pull_request.number, github.event.pull_request.title)
@@ -16,18 +15,12 @@ on:
1615
env:
1716
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
1817

19-
# Least-privilege default: only read access at the workflow level.
20-
# Jobs that need more elevate locally.
18+
# Default to least privilege; jobs elevate only when needed.
2119
permissions:
2220
contents: read
2321

2422
jobs:
25-
# ── Quality gates ─────────────────────────────────────────
26-
#
27-
# Lint, test, and Helm lint run on every push + PR as parallel
28-
# quality gates. Their failure breaks the workflow status but
29-
# does not block the image build (surfaced via branch protection
30-
# required status checks).
23+
# Quality gates
3124

3225
test:
3326
runs-on: ubuntu-latest
@@ -66,16 +59,7 @@ jobs:
6659
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
6760
-ignore-missing-schemas
6861
69-
# ── Container image ──────────────────────────────────────
70-
#
71-
# The shared reusable workflow handles checkout, change
72-
# detection, Docker build/push, Cosign signing, and Trivy
73-
# scanning.
74-
#
75-
# `helm-lint` is intentionally NOT in `needs` — it runs as an
76-
# independent parallel job whose failure surfaces via branch
77-
# protection (required status check) rather than delaying or
78-
# blocking image builds.
62+
# Container image build/publish (reusable workflow)
7963

8064
build-open-data:
8165
uses: bcit-tlu/.github/.github/workflows/oci-build.yaml@main
@@ -92,12 +76,7 @@ jobs:
9276
tag_prefix: "v"
9377
secrets: inherit
9478

95-
# ── Helm chart → OCI registry (main push) ─────────────────
96-
#
97-
# Publishes the chart with the same RC version that the image
98-
# received so the chart and app tags stay in lockstep. Only
99-
# runs on main pushes when the component actually changed.
100-
# Release-time chart publishing is handled by helm-publish.yaml.
79+
# Publish chart from main pushes using the image RC version.
10180

10281
helm-publish:
10382
needs: [helm-lint, build-open-data]
@@ -119,30 +98,38 @@ jobs:
11998
- uses: sigstore/cosign-installer@v3
12099

121100
- name: Cosign login (OCI)
101+
env:
102+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
103+
REGISTRY: ${{ env.REGISTRY }}
104+
ACTOR: ${{ github.actor }}
122105
run: |
123-
echo "${{ secrets.GITHUB_TOKEN }}" | \
124-
cosign login "${{ env.REGISTRY }}" \
125-
-u "${{ github.actor }}" \
106+
echo "${GITHUB_TOKEN}" | \
107+
cosign login "${REGISTRY}" \
108+
-u "${ACTOR}" \
126109
--password-stdin
127110
128111
- name: Helm login (OCI)
112+
env:
113+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
114+
REGISTRY: ${{ env.REGISTRY }}
115+
ACTOR: ${{ github.actor }}
129116
run: |
130-
echo "${{ secrets.GITHUB_TOKEN }}" | \
131-
helm registry login "${{ env.REGISTRY }}" \
132-
-u "${{ github.actor }}" \
117+
echo "${GITHUB_TOKEN}" | \
118+
helm registry login "${REGISTRY}" \
119+
-u "${ACTOR}" \
133120
--password-stdin
134121
135122
- name: Package, push & sign chart
136123
shell: bash
137124
env:
138125
VERSION: ${{ needs.build-open-data.outputs.rc_version }}
126+
OCI_BASE: oci://${{ env.REGISTRY }}/${{ github.repository }}/charts
127+
IMAGE_BASE: ${{ env.REGISTRY }}/${{ github.repository }}/charts
139128
run: |
140129
set -euo pipefail
141130
142-
OCI_BASE="oci://${{ env.REGISTRY }}/${{ github.repository }}/charts"
143-
IMAGE_BASE="${{ env.REGISTRY }}/${{ github.repository }}/charts"
144131
CHART_DIR="charts"
145-
CHART_NAME=$(awk '/^name:/{print $2; exit}' "${CHART_DIR}/Chart.yaml")
132+
CHART_NAME=$(yq '.name' "${CHART_DIR}/Chart.yaml")
146133
DEST_DIR="/tmp/charts"
147134
mkdir -p "${DEST_DIR}"
148135
@@ -153,11 +140,15 @@ jobs:
153140
154141
PUSH_OUT=$(helm push \
155142
"${DEST_DIR}/${CHART_NAME}-${VERSION}.tgz" \
156-
"${OCI_BASE}" 2>&1) || true
143+
"${OCI_BASE}" 2>&1) || { echo "${PUSH_OUT}"; exit 1; }
157144
echo "${PUSH_OUT}"
158-
printf '%s\n' "${PUSH_OUT}" | grep -q '^Digest:' || { echo "::error::helm push failed for ${CHART_NAME}"; exit 1; }
159145
160-
DIGEST=$(printf '%s\n' "${PUSH_OUT}" | awk '/^Digest:/{print $2}')
161-
if [[ -n "${DIGEST}" ]]; then
162-
cosign sign --yes "${IMAGE_BASE}/${CHART_NAME}@${DIGEST}"
146+
# Tolerant digest parse: case-insensitive, allows leading whitespace.
147+
DIGEST=$(printf '%s\n' "${PUSH_OUT}" \
148+
| awk 'tolower($1)=="digest:"{print $2; exit}')
149+
if [[ -z "${DIGEST}" ]]; then
150+
echo "::error::helm push for ${CHART_NAME} succeeded but no digest found in output (helm output format may have changed)"
151+
exit 1
163152
fi
153+
154+
cosign sign --yes "${IMAGE_BASE}/${CHART_NAME}@${DIGEST}"

.github/workflows/helm-publish.yaml

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ permissions:
1717

1818
env:
1919
REGISTRY: ghcr.io
20+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
2021

2122
jobs:
2223
publish:
@@ -46,31 +47,42 @@ jobs:
4647

4748
- name: Cosign login (OCI)
4849
if: steps.parse.outputs.publish == 'true'
50+
env:
51+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
REGISTRY: ${{ env.REGISTRY }}
53+
ACTOR: ${{ github.actor }}
4954
run: |
50-
echo "${{ secrets.GITHUB_TOKEN }}" | \
51-
cosign login "${{ env.REGISTRY }}" \
52-
-u "${{ github.actor }}" \
55+
echo "${GITHUB_TOKEN}" | \
56+
cosign login "${REGISTRY}" \
57+
-u "${ACTOR}" \
5358
--password-stdin
5459
5560
- name: Helm login (OCI)
5661
if: steps.parse.outputs.publish == 'true'
5762
shell: bash
63+
env:
64+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65+
REGISTRY: ${{ env.REGISTRY }}
66+
ACTOR: ${{ github.actor }}
5867
run: |
59-
echo "${{ secrets.GITHUB_TOKEN }}" | \
60-
helm registry login "${{ env.REGISTRY }}" \
61-
-u "${{ github.actor }}" \
68+
echo "${GITHUB_TOKEN}" | \
69+
helm registry login "${REGISTRY}" \
70+
-u "${ACTOR}" \
6271
--password-stdin
6372
6473
- name: Package and push chart
6574
id: push
6675
if: steps.parse.outputs.publish == 'true'
6776
shell: bash
77+
env:
78+
VERSION: ${{ steps.parse.outputs.version }}
79+
OCI_REPO: oci://${{ env.REGISTRY }}/${{ github.repository }}/charts
6880
run: |
6981
set -euo pipefail
7082
71-
VERSION="${{ steps.parse.outputs.version }}"
7283
CHART_DIR="charts"
7384
DEST_DIR="/tmp/charts"
85+
CHART_NAME=$(yq '.name' "${CHART_DIR}/Chart.yaml")
7486
7587
mkdir -p "${DEST_DIR}"
7688
@@ -80,16 +92,25 @@ jobs:
8092
-d "${DEST_DIR}"
8193
8294
PUSH_OUT=$(helm push \
83-
"${DEST_DIR}/open-data-${VERSION}.tgz" \
84-
"oci://${{ env.REGISTRY }}/${{ github.repository }}/charts" 2>&1) || true
95+
"${DEST_DIR}/${CHART_NAME}-${VERSION}.tgz" \
96+
"${OCI_REPO}" 2>&1) || { echo "${PUSH_OUT}"; exit 1; }
8597
echo "${PUSH_OUT}"
86-
printf '%s\n' "${PUSH_OUT}" | grep -q '^Digest:' || { echo '::error::helm push failed'; exit 1; }
8798
88-
DIGEST=$(printf '%s\n' "${PUSH_OUT}" | awk '/^Digest:/{print $2}')
99+
# Tolerant digest parse: case-insensitive, allows leading whitespace.
100+
DIGEST=$(printf '%s\n' "${PUSH_OUT}" \
101+
| awk 'tolower($1)=="digest:"{print $2; exit}')
102+
if [[ -z "${DIGEST}" ]]; then
103+
echo "::error::helm push succeeded but no digest found in output (helm output format may have changed)"
104+
exit 1
105+
fi
106+
89107
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
108+
echo "chart_name=${CHART_NAME}" >> "$GITHUB_OUTPUT"
90109
91110
- name: Sign chart
92111
if: steps.parse.outputs.publish == 'true' && steps.push.outputs.digest != ''
112+
env:
113+
CHART_REF: ${{ env.REGISTRY }}/${{ github.repository }}/charts/${{ steps.push.outputs.chart_name }}
114+
DIGEST: ${{ steps.push.outputs.digest }}
93115
run: |
94-
cosign sign --yes \
95-
"${{ env.REGISTRY }}/${{ github.repository }}/charts/open-data@${{ steps.push.outputs.digest }}"
116+
cosign sign --yes "${CHART_REF}@${DIGEST}"

.github/workflows/pr-title-lint.yaml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
name: pr-title-lint
22

3-
# Gate non-conventional PR titles at the merge boundary so unparseable
4-
# squash-merge commits can't land on main and silently starve
5-
# release-please of the feat:/fix:/BREAKING signals it uses to open
6-
# release PRs.
3+
# Enforce Conventional Commit PR titles so release-please can parse changes.
74

85
on:
96
pull_request_target:
107
types: [opened, edited, reopened, synchronize]
118
branches: [main]
129

10+
env:
11+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
12+
1313
permissions:
1414
contents: read
1515
pull-requests: write
@@ -49,25 +49,25 @@ jobs:
4949
with:
5050
header: pr-title-lint
5151
message: |
52-
## PR title does not match Conventional Commits
53-
54-
**Why this matters (tl;dr)** — release-please reads PR titles on `main` to decide whether to cut a release, what version bump to apply, and how to group CHANGELOG entries. A title that doesn't parse is silently dropped; no release PR opens, no error, workflow still exits 0.
52+
## PR title must follow Conventional Commits
5553
56-
**Required structure**
54+
release-please uses PR titles on `main` to determine version bumps and changelog entries.
5755
5856
```
5957
<type>[optional scope][!]: <subject>
6058
```
6159
62-
- `<type>` — `feat` / `fix` / `docs` / `style` / `refactor` / `perf` / `test` / `build` / `ci` / `chore` / `revert`
63-
- `<subject>` — lowercase first letter, imperative mood, no trailing period
64-
- add `!` (or `BREAKING CHANGE:` in the body) for breaking changes
65-
66-
**Good** — `feat: add search page`, `fix: correct broken nav link`, `ci: tighten workflow permissions`
60+
- `type`: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
61+
- `subject`: start lowercase, imperative mood, no trailing period
62+
- breaking change: add `!` (or `BREAKING CHANGE:` in body)
6763
68-
**Bad** — `Add search page` (no type), `feat: Add search page` (uppercase subject)
64+
Examples:
65+
- ✅ `feat: add search page`
66+
- ✅ `fix: correct broken nav link`
67+
- ❌ `Add search page`
68+
- ❌ `feat: Add search page`
6969
70-
Edit the PR title in the GitHub UI — the check re-runs automatically within seconds, no push needed.
70+
Edit the PR title in GitHub; this check reruns automatically.
7171
7272
- name: Clear failure explainer on success
7373
if: success() && steps.lint.outcome == 'success'

.github/workflows/release-please.yaml

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ on:
44
push:
55
branches: [main]
66

7-
# Least-privilege default: only `checkout` needs read access.
8-
# Each job elevates permissions to just what that job requires.
7+
# Default to least privilege; jobs elevate only when needed.
98
permissions:
109
contents: read
1110

11+
env:
12+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
13+
1214
jobs:
1315
release:
1416
runs-on: ubuntu-latest
@@ -25,17 +27,8 @@ jobs:
2527
with:
2628
token: ${{ secrets.GITHUB_TOKEN }}
2729

28-
# `release-as` per-package is a one-shot: once the release PR it
29-
# triggered has merged and the manifest has caught up, the override
30-
# must be removed, otherwise every subsequent release-please run
31-
# keeps pinning the same version and blocks normal semver bumps
32-
# from feat:/fix: commits. This guard runs *after* release-please
33-
# and is skipped whenever `releases_created=true`, so the
34-
# tag/release finalization that happens on the merge-of-chore-PR
35-
# push (where manifest has just caught up to release-as) isn't
36-
# blocked. On any subsequent push where the state is still stale
37-
# and there's nothing to release, the workflow fails loudly to
38-
# force the cleanup PR.
30+
# `release-as` is one-shot. Once manifest catches up, remove it;
31+
# otherwise future semver bumps are pinned and releases stall.
3932
- uses: actions/checkout@v6
4033
if: steps.rp.outputs.releases_created != 'true'
4134
- name: Guard against stale `release-as` entries
@@ -59,9 +52,8 @@ jobs:
5952
sys.exit(1)
6053
PY
6154
62-
# Releases created via GITHUB_TOKEN do NOT trigger workflows that listen
63-
# on `release: published` or `push: tags:`. Dispatch helm-publish and
64-
# release-retag explicitly for the released tag.
55+
# Releases made with GITHUB_TOKEN do not trigger release/tag workflows.
56+
# Dispatch publish workflows explicitly for the new tag.
6557
dispatch-publish:
6658
needs: release
6759
if: needs.release.outputs.releases_created == 'true'

0 commit comments

Comments
 (0)