Skip to content

Commit fe531cf

Browse files
committed
fix(release): harden release tooling and fix doc link issues
Several correctness and safety issues addressed together: - Hardcoded `localhost:3000` URLs in MDX files would 404 in production; converted to relative `/docs/main/` paths. - `git tag --force` in the edge release script could silently overwrite an existing tag; switched to plain `git tag` and added an explicit same-day collision guard to fail fast instead. - Changelog validator now rejects `internal-docs` references that point to `/docs/` paths other than `/docs/main/`, preventing changelog entries from linking to the wrong versioned docs. - Check/Todo icon components were duplicated across every docs version directory, risking drift; extracted to `components/ui/` as shared `CheckCircleIcon` and `TodoIcon` components. - Release script now resets `changelog/main/review.yaml` after tagging so the next release cycle starts clean.
1 parent 78d664d commit fe531cf

15 files changed

Lines changed: 86 additions & 197 deletions

File tree

.claude/skills/changelog/scripts/validate-changelog.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const LOG_YAML_PATH = join(CHANGELOG_DIR, "main/log.yaml");
1414
const LOG_SCHEMA_PATH = join(CHANGELOG_DIR, "log.schema.json");
1515

1616
interface Finding {
17-
level: "WARN" | "INFO";
17+
level: "ERROR" | "WARN" | "INFO";
1818
changeIndex: number;
1919
changeType: string;
2020
message: string;
@@ -129,6 +129,24 @@ function validateChange(change: Change, index: number): Finding[] {
129129
}
130130
}
131131

132+
// Check: internal-docs references that start with /docs/ MUST use /docs/main/
133+
if (Array.isArray(change.references)) {
134+
for (const ref of change.references) {
135+
if (
136+
ref.type === "internal-docs" &&
137+
ref.link.startsWith("/docs/") &&
138+
!ref.link.startsWith("/docs/main/")
139+
) {
140+
findings.push({
141+
level: "ERROR",
142+
changeIndex: changeNumber,
143+
changeType,
144+
message: `${summaryLabel} has an internal-docs reference linking to "${ref.link}" — versioned docs references must point to /docs/main/`,
145+
});
146+
}
147+
}
148+
}
149+
132150
// Check: all entries with impacts SHOULD have impact summaries
133151
if (Array.isArray(change.impacts)) {
134152
for (const impact of change.impacts) {
@@ -248,6 +266,7 @@ function main(): void {
248266
console.log(`[${finding.level}] ${location}: ${finding.message}`);
249267
}
250268

269+
const errorCount = allFindings.filter((f) => f.level === "ERROR").length;
251270
const warnCount = allFindings.filter((f) => f.level === "WARN").length;
252271
const infoCount = allFindings.filter((f) => f.level === "INFO").length;
253272

@@ -256,11 +275,12 @@ function main(): void {
256275
}
257276

258277
console.log("Summary:");
278+
console.log(` Errors: ${errorCount}`);
259279
console.log(` Warnings: ${warnCount}`);
260280
console.log(` Info: ${infoCount}`);
261281
console.log(` Total changes checked: ${changes.length}`);
262282

263-
if (warnCount > 0) {
283+
if (errorCount > 0 || warnCount > 0) {
264284
process.exit(1);
265285
}
266286
}

packages/nix/localDevShell/scripts/ds-validate-changelog.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,29 @@ function validateFile(
9191
}
9292
}
9393

94+
// Validate that internal-docs references point to /docs/main/
95+
const changes = (logData["changes"] ?? []) as Array<{
96+
references?: Array<{ type: string; link: string }>;
97+
}>;
98+
for (let i = 0; i < changes.length; i++) {
99+
const refs = changes[i]?.references;
100+
if (!Array.isArray(refs)) continue;
101+
for (const ref of refs) {
102+
if (
103+
ref.type === "internal-docs" &&
104+
ref.link.startsWith("/docs/") &&
105+
!ref.link.startsWith("/docs/main/")
106+
) {
107+
result.errors.push(
108+
`Field "/changes/${i}/references": internal-docs reference links to "${ref.link}" but versioned docs references must point to /docs/main/`
109+
);
110+
}
111+
}
112+
}
113+
if (result.errors.length > 0) {
114+
return result;
115+
}
116+
94117
result.valid = true;
95118
return result;
96119
}

packages/nix/localDevShell/scripts/make-new-edge-release.sh

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ if [[ -n $(git status --porcelain) ]]; then
1919
exit 1
2020
fi
2121

22+
# Get the new version tag and derive the edge directory name (strip "edge." prefix)
23+
VERSION_TAG="edge.$(date +'%y-%m-%d')"
24+
EDGE_DATE="${VERSION_TAG#edge.}"
25+
EDGE_ENTRY_DIR="$CHANGELOG_DIR/edge/$EDGE_DATE"
26+
27+
# Guard against same-day release collision
28+
if git tag -l "$VERSION_TAG" | grep -q .; then
29+
echo "Error: Tag $VERSION_TAG already exists. Only one edge release per day is supported."
30+
exit 1
31+
fi
32+
if [ -d "$EDGE_ENTRY_DIR" ]; then
33+
echo "Error: Changelog directory $EDGE_ENTRY_DIR already exists. Only one edge release per day is supported."
34+
exit 1
35+
fi
36+
2237
# Remove existing edge release
2338
rm -rf "$DOCS_DIR/edge"
2439

@@ -31,11 +46,6 @@ find "$DOCS_DIR/edge" -type f -exec sed -i -E "s|([\"'(])/docs/main|\1/docs/edge
3146
# Search and replace __PANFACTUM_VERSION_MAIN__ with __PANFACTUM_VERSION_EDGE__ in all files
3247
find "$DOCS_DIR/edge" -type f -exec sed -i -E "s|__PANFACTUM_VERSION_MAIN__|__PANFACTUM_VERSION_EDGE__|g" {} \;
3348

34-
# Get the new version tag and derive the edge directory name (strip "edge." prefix)
35-
VERSION_TAG="edge.$(date +'%y-%m-%d')"
36-
EDGE_DATE="${VERSION_TAG#edge.}"
37-
EDGE_ENTRY_DIR="$CHANGELOG_DIR/edge/$EDGE_DATE"
38-
3949
# Update the version tag in constants
4050
jq --arg tag "$VERSION_TAG" '.versions.edge.ref = "\($tag)"' "$CONSTANTS_FILE" >"$CONSTANTS_FILE.tmp" && mv "$CONSTANTS_FILE.tmp" "$CONSTANTS_FILE"
4151

@@ -54,10 +64,16 @@ summary: ""
5464
changes: []
5565
EOF
5666

67+
# Reset main/review.yaml for the next release cycle
68+
cat >"$CHANGELOG_DIR/main/review.yaml" <<'EOF'
69+
todo: []
70+
validated: []
71+
EOF
72+
5773
# Commit the changes and create the tag
5874
git add "$REPO_ROOT"
5975
git commit -m "release: $VERSION_TAG"
60-
git tag --force "$VERSION_TAG"
76+
git tag "$VERSION_TAG"
6177

6278
# Push the changes
6379
git push --atomic origin main "$VERSION_TAG"

packages/website/src/content/docs/edge/guides/check.tsx renamed to packages/website/src/components/ui/CheckCircleIcon.tsx

File renamed without changes.
File renamed without changes.

packages/website/src/content/docs/edge/guides/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import Button from "@/components/ui/Button.tsx";
22
import ContentBlockWithImage, {
33
ContentBlockType,
44
} from "@/components/ui/ContentBlockWithImage.tsx";
5-
import Check from "@/content/docs/main/guides/check.tsx";
6-
import Todo from "@/content/docs/main/guides/todo.tsx";
5+
import Check from "@/components/ui/CheckCircleIcon.tsx";
6+
import Todo from "@/components/ui/TodoIcon.tsx";
77

88
export function RootDocumentLandingPage() {
99
return (

packages/website/src/content/docs/main/concepts/networking/cluster-networking/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ for the following reasons:
298298

299299
Ultimately, inbound traffic to clusters in the Panfactum Stack looks like the following: [^31]
300300

301-
[^31]: For more information on VPCs and subnets, see [these docs.](http://localhost:3000/docs/main/concepts/networking/aws-primitives)
301+
[^31]: For more information on VPCs and subnets, see [these docs.](/docs/main/concepts/networking/aws-primitives)
302302

303303
<MarkdownSVGImage src={ingressSVG} alt="Inbound network diagram" />
304304

@@ -321,7 +321,7 @@ CoreDNS is extremely performant and provides one of the most stable implementati
321321
This allows your workloads to connect to domains like `my-service.my-namespace.svc.cluster.local`.
322322

323323
We provide a module for deploying CoreDNS to Panfactum Stack clusters, [kube\_core\_dns](/docs/main/modules/kube_core_dns/overview),
324-
which is set up in [the bootstrapping guide.](http://localhost:3000/docs/main/guides/bootstrapping/internal-cluster-networking#deploy-coredns) [^20]
324+
which is set up in [the bootstrapping guide.](/docs/main/guides/bootstrapping/internal-cluster-networking#deploy-coredns) [^20]
325325

326326
[^20]: Note that EKS also deploys CoreDNS to newly provisioned clusters. However, their implementation is lacking in several
327327
areas such as in monitoring and high-availability, so we supply our own.

packages/website/src/content/docs/main/guides/check.tsx

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

packages/website/src/content/docs/main/guides/cicd/getting-started/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ To verify that everything was set up correctly:
102102
While the Event Bus will handle receiving and filtering events from your git repository, we still need to define
103103
what actions to take when events are received. This is done via Argo Workflows.
104104

105-
We provide [several prebuilt Workflows](http://localhost:3000/docs/main/guides/addons/workflow-engine/prebuilt-workflows)
105+
We provide [several prebuilt Workflows](/docs/main/guides/addons/workflow-engine/prebuilt-workflows)
106106
that you can use for common CI / CD tasks.
107107

108108
Right now, let's set up the IaC deployment workflow,

packages/website/src/content/docs/main/guides/contributing/releasing/index.mdx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ When you are ready to cut a new edge release:
1616

1717
The release script will automatically perform the following actions:
1818

19-
* Create the new release name based on today's date.
19+
* Create the new release name based on today's date (e.g., `edge.26-04-05`).
2020

2121
* Copy all the unreleased documentation (under `packages/website/src/content/docs/main`) to the
22-
edge documentation (under `packages/website/src/content/docs/edge`).
22+
edge documentation (under `packages/website/src/content/docs/edge`), rewriting internal links
23+
and version placeholders.
2324

24-
* Update the Changelog headers to include the new release.
25+
* Copy the unreleased changelog (`changelog/main/log.yaml`) into a dated edge entry
26+
(e.g., `changelog/edge/26-04-05/log.yaml`) and move any `upgrade.mdx` alongside it.
2527

26-
* Create and push the appropriate release tag and commit.
28+
* Reset `changelog/main/log.yaml` and `changelog/main/review.yaml` for the next release cycle.
29+
30+
* Update `constants.json` with the new edge version ref.
31+
32+
* Create and push the release commit and git tag.
2733

2834
## Stable Releases
2935

0 commit comments

Comments
 (0)