Skip to content

Commit afaa319

Browse files
committed
helm-diff: mirror gha-tools report (summary table + per-scenario +/- counts + detailed diffs; slim to table-only with job-summary links over comment size limit); minimize-outdated comments via github-script (drop marocchino); diff union of base+head scenarios
1 parent 8b54b3e commit afaa319

1 file changed

Lines changed: 147 additions & 43 deletions

File tree

.github/workflows/helm-diff.yaml

Lines changed: 147 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ name: Helm Render Diff
33
# Informational: renders every test-values scenario on both the PR base and head,
44
# diffs the resulting Kubernetes manifests, and posts a sticky PR comment so
55
# reviewers can see exactly what a change does to the rendered output.
6-
# Runs on GitHub-hosted runners with only public actions (public repo, no secrets
7-
# beyond the automatic GITHUB_TOKEN). Never fails the PR.
6+
#
7+
# This ports the diff/report logic from comet-ml/gha-tools helm/helm-diff, but
8+
# runs self-contained on GitHub-hosted runners with public actions — that private
9+
# action runs on the self-hosted `helm` runner and can't be used from a public
10+
# repo (fork PRs can't pull a private action, and self-hosted runners must not run
11+
# fork code). Never fails the PR (the hard gate is lint-render.yaml).
812

913
on:
1014
pull_request:
@@ -14,9 +18,14 @@ on:
1418
permissions:
1519
contents: read
1620
pull-requests: write
21+
issues: write
1722

1823
env:
1924
KUBE_VERSION: "1.29.0"
25+
CHART_PATH: charts/s3proxy
26+
# Match gha-tools helm-diff defaults so output is consistent with our other charts.
27+
RELEASE_NAME: release
28+
NAMESPACE: default
2029

2130
jobs:
2231
render-diff:
@@ -26,13 +35,13 @@ jobs:
2635
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
2736
with:
2837
ref: ${{ github.event.pull_request.head.sha }}
29-
path: head
38+
path: pr-repo
3039

3140
- name: Checkout base
3241
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3342
with:
3443
ref: ${{ github.event.pull_request.base.sha }}
35-
path: base
44+
path: base-repo
3645

3746
- name: Set up Helm
3847
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
@@ -42,74 +51,169 @@ jobs:
4251
- name: Render and diff
4352
run: |
4453
set -uo pipefail
54+
55+
# render <repo-dir> <values-relpath> <out-file>
56+
# Renders the chart if both the chart dir and the values file exist on
57+
# that side; otherwise writes an empty baseline (mirrors gha-tools, so a
58+
# values file that only exists on the PR shows up as fully added).
4559
render() {
46-
# render <repo-dir> <values-relpath> <out-file>
4760
local dir="$1" vals="$2" out="$3"
48-
if [ -f "${dir}/${vals}" ] && [ -d "${dir}/charts/s3proxy" ]
61+
if [ -f "${dir}/${vals}" ] && [ -d "${dir}/${CHART_PATH}" ]
4962
then
50-
helm template s3proxy "${dir}/charts/s3proxy" \
51-
--values "${dir}/${vals}" \
52-
--kube-version "${KUBE_VERSION}" > "$out" 2>"${out}.err" || {
53-
echo "render error for ${dir}/${vals}:"
54-
cat "${out}.err"
55-
: > "$out"
56-
}
63+
if ! helm template "${RELEASE_NAME}" "${dir}/${CHART_PATH}" \
64+
--namespace "${NAMESPACE}" \
65+
--values "${dir}/${vals}" \
66+
--kube-version "${KUBE_VERSION}" > "$out" 2>"${out}.err"
67+
then
68+
echo "⚠️ render error for ${dir}/${vals}:"
69+
cat "${out}.err"
70+
: > "$out"
71+
fi
5772
else
5873
: > "$out"
5974
fi
6075
}
6176
62-
summary=diff-summary.md
63-
echo "## 📊 Helm render diff (base vs PR)" > "$summary"
64-
echo "" >> "$summary"
65-
echo "_Rendered with Kubernetes ${KUBE_VERSION}. Informational only — this check never fails the PR._" >> "$summary"
77+
RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
78+
COMMENT_LIMIT=60000
79+
80+
# Union of scenario files across base and head, so a scenario removed in
81+
# the PR (present on base, absent on head) still shows up as a deletion.
82+
names="$(
83+
{ ls -1 pr-repo/test-values/*.yaml base-repo/test-values/*.yaml 2>/dev/null || true; } \
84+
| xargs -r -n1 basename | sort -u
85+
)"
6686
67-
changed=0
68-
for f in head/test-values/*.yaml
87+
# Two parts: a summary table (always small) and the detailed diffs.
88+
table=/tmp/table.md
89+
details=/tmp/details.md
90+
{
91+
echo "<!-- helm-render-diff -->"
92+
echo "## 📊 Helm Render Diff Summary"
93+
echo ""
94+
echo "Chart \`${CHART_PATH}\` rendered with Kubernetes \`${KUBE_VERSION}\`. Informational only — this check never fails the PR."
95+
echo ""
96+
echo "| Values File | Chart Path | Changes | Status |"
97+
echo "|-------------|------------|---------|--------|"
98+
} > "$table"
99+
echo "## 🔍 Detailed Changes" > "$details"
100+
101+
any_changes=0
102+
while IFS= read -r name
69103
do
70-
name="$(basename "$f")"
71-
render head "test-values/${name}" "/tmp/head-${name}"
72-
render base "test-values/${name}" "/tmp/base-${name}"
73-
if ! diff -u "/tmp/base-${name}" "/tmp/head-${name}" > "/tmp/diff-${name}"
104+
[ -n "$name" ] || continue
105+
render pr-repo "test-values/${name}" "/tmp/after-${name}"
106+
render base-repo "test-values/${name}" "/tmp/before-${name}"
107+
108+
diff -u "/tmp/before-${name}" "/tmp/after-${name}" > "/tmp/diff-${name}" || true
109+
110+
if [ -s "/tmp/diff-${name}" ]
74111
then
75-
changed=1
112+
any_changes=1
113+
# Additions/deletions, excluding the +++/--- file headers (as gha-tools does).
114+
additions=$(grep '^+' "/tmp/diff-${name}" | grep -vc '^+++' || true)
115+
deletions=$(grep '^-' "/tmp/diff-${name}" | grep -vc '^---' || true)
116+
echo "| \`test-values/${name}\` | \`${CHART_PATH}\` | +${additions} -${deletions} | 🔄 **Changes Detected** ([summary](${RUN_URL})) |" >> "$table"
76117
{
77118
echo ""
78-
echo "<details><summary>🔄 <code>${name}</code></summary>"
119+
echo "### 📝 Changes in \`${CHART_PATH}\` with \`test-values/${name}\`"
120+
echo ""
121+
echo "<details><summary>🔍 Click to view complete diff</summary>"
79122
echo ""
80123
echo '```diff'
81124
cat "/tmp/diff-${name}"
82125
echo '```'
83126
echo ""
84127
echo "</details>"
85-
} >> "$summary"
128+
} >> "$details"
129+
else
130+
echo "| \`test-values/${name}\` | \`${CHART_PATH}\` | - | ✅ No Changes |" >> "$table"
86131
fi
87-
done
132+
done <<< "$names"
88133
89-
if [ "$changed" -eq 0 ]
134+
if [ "$any_changes" -eq 0 ]
90135
then
91-
echo "" >> "$summary"
92-
echo "_No rendered manifest changes across the test-values scenarios._" >> "$summary"
136+
{
137+
echo ""
138+
echo "### 🎉 No changes detected in any of the tested configurations!"
139+
} >> "$table"
93140
fi
94141
95-
# Always publish the full diff to the job summary.
96-
cat "$summary" >> "$GITHUB_STEP_SUMMARY"
97-
98-
# Cap the PR comment to stay well under GitHub's 65536-char limit.
99-
if [ "$(wc -c < "$summary")" -gt 60000 ]
142+
# Full report (table + detailed diffs) always goes to the job summary.
143+
cat "$table" >> "$GITHUB_STEP_SUMMARY"
144+
if [ "$any_changes" -eq 1 ]
100145
then
101-
head -c 60000 "$summary" > diff-comment.md
102146
{
103147
echo ""
104-
echo "…diff truncated — see the full render diff in the workflow job summary."
105-
} >> diff-comment.md
148+
echo "---"
149+
echo ""
150+
cat "$details"
151+
} >> "$GITHUB_STEP_SUMMARY"
152+
fi
153+
154+
# PR comment: table + inline diffs when it fits, otherwise a slimmed
155+
# table-only comment linking to the full diffs in the job summary
156+
# (mirrors the self-hosted chart's behaviour on large diffs).
157+
{
158+
cat "$table"
159+
if [ "$any_changes" -eq 1 ]
160+
then
161+
echo ""
162+
echo "---"
163+
echo ""
164+
cat "$details"
165+
fi
166+
} > /tmp/comment-full.md
167+
168+
if [ "$(wc -c < /tmp/comment-full.md)" -le "$COMMENT_LIMIT" ]
169+
then
170+
cp /tmp/comment-full.md diff-comment.md
106171
else
107-
cp "$summary" diff-comment.md
172+
{
173+
cat "$table"
174+
echo ""
175+
echo "---"
176+
echo ""
177+
echo "> ℹ️ Per-scenario diffs are omitted from this comment because the full render diff exceeds GitHub's comment size limit. See the complete diffs in the [workflow job summary](${RUN_URL})."
178+
} > diff-comment.md
108179
fi
109180
110-
- name: Post sticky comment
181+
# Match the repo's preview-readme.yaml convention: minimize (collapse) any
182+
# previous render-diff comments as OUTDATED, then post a fresh one. Uses
183+
# first-party actions/github-script (no third-party comment action).
184+
# continue-on-error: fork PRs get a read-only token and cannot comment; the
185+
# full diff is still available in the job summary.
186+
- name: Minimize outdated diff comments and post the latest
111187
continue-on-error: true
112-
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
188+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
113189
with:
114-
header: helm-render-diff
115-
path: diff-comment.md
190+
script: |
191+
const fs = require('fs');
192+
const marker = '<!-- helm-render-diff -->';
193+
const body = fs.readFileSync('diff-comment.md', 'utf8');
194+
195+
const comments = await github.paginate(github.rest.issues.listComments, {
196+
owner: context.repo.owner,
197+
repo: context.repo.repo,
198+
issue_number: context.issue.number,
199+
});
200+
201+
for (const comment of comments) {
202+
if (comment.user.type === 'Bot' && comment.body.includes(marker)) {
203+
await github.graphql(
204+
`mutation($id: ID!) {
205+
minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) {
206+
clientMutationId
207+
}
208+
}`,
209+
{ id: comment.node_id },
210+
);
211+
}
212+
}
213+
214+
await github.rest.issues.createComment({
215+
owner: context.repo.owner,
216+
repo: context.repo.repo,
217+
issue_number: context.issue.number,
218+
body,
219+
});

0 commit comments

Comments
 (0)