Conversation
There was a problem hiding this comment.
Pull request overview
This PR consolidates version management by making deno.json the single source of truth, updating runtime/version exports, scripts, and CI release workflows accordingly.
Changes:
- Replace hardcoded
src/version.tswith a JSON import fromdeno.jsonand add a unit test asserting they match. - Update release/tag/sync scripts to read/write
deno.json(and remove the legacyVERSIONfile). - Adjust GitHub Actions release workflows and tasks/permissions to align with the new version sync behavior.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/version_test.ts | Adds a test step to ensure src/version.ts version matches deno.json. |
| src/version.ts | Exports version by importing deno.json as JSON. |
| scripts/tag.ts | Reads version from deno.json and only commits/tags based on deno.json. |
| scripts/sync-version.ts | Now only updates deno.json (no git ops). |
| scripts/release.ts | Reads version from deno.json for release operations. |
| deno.json | Updates the version task permissions (drops --allow-run, adds --allow-env). |
| VERSION | Removes the legacy version file. |
| RELEASE.md | Documents the new release/version process. |
| .nsite/config.json | Normalizes indentation. |
| .github/workflows/release.yml | Runs version sync only for workflow_dispatch builds/publish steps. |
| .github/workflows/release-simple.yml | Adds a step to sync deno.json version before building. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| - name: Sync version in deno.json for build | ||
| if: ${{ github.event_name == 'workflow_dispatch' }} | ||
| run: deno run --allow-read --allow-write --allow-env scripts/sync-version.ts "${{ env.VERSION }}" | ||
|
|
There was a problem hiding this comment.
release.yml now only runs sync-version.ts on workflow_dispatch. For tag-push releases, there’s no verification that deno.json.version matches the pushed tag/version being built, so it’s possible to publish binaries/JSR with a mismatched internal --version. Consider adding a lightweight check step on tag events that reads deno.json and fails the job if denoJson.version != env.VERSION (or always sync for tag events if you prefer).
| - name: Verify deno.json version matches VERSION for tag builds | |
| if: ${{ github.event_name != 'workflow_dispatch' }} | |
| run: | | |
| DENO_JSON_VERSION=$(deno eval 'console.log(JSON.parse(Deno.readTextFileSync("deno.json")).version)') | |
| echo "deno.json version: $DENO_JSON_VERSION" | |
| echo "Tag/version from workflow: ${{ env.VERSION }}" | |
| if [ "$DENO_JSON_VERSION" != "${{ env.VERSION }}" ]; then | |
| echo "Error: deno.json.version ($DENO_JSON_VERSION) does not match env.VERSION (${{ env.VERSION }})." | |
| exit 1 | |
| fi |
| @@ -1 +1,2 @@ | |||
| export const version = "0.22.3"; | |||
| import denoConfig from "../deno.json" with { type: "json" }; | |||
| export const version: string = denoConfig.version; | |||
There was a problem hiding this comment.
denoConfig.version comes from a JSON import and isn’t guaranteed to be a string at runtime; exporting it as string without validation can result in version being undefined (and CLI --version outputting undefined) if deno.json is missing/invalid. Consider validating the value (and throwing a clear error) or narrowing the imported JSON type before exporting.
| export const version: string = denoConfig.version; | |
| const rawVersion = (denoConfig as { version?: unknown }).version; | |
| if (typeof rawVersion !== "string") { | |
| throw new Error('Invalid deno.json: "version" must be a string'); | |
| } | |
| export const version: string = rawVersion; |
| version = denoJson.version; | ||
| if (!version || !/^\d+\.\d+\.\d+([-.].+)?$/.test(version)) { | ||
| console.error(`Error: Version "${version}" in deno.json is not a valid semantic version.`); |
There was a problem hiding this comment.
The semver validation regex here (/^\d+\.\d+\.\d+([-.].+)?$/) rejects valid semver with build metadata (e.g. 1.2.3+build.1) and is also looser than semver in other places (it allows a . prefix in the suffix). Consider using a shared semver validator (e.g. @std/semver) or aligning the regex with the one used in unit tests so releases don’t unnecessarily fail for valid versions.
| version = denoJson.version; | ||
| if (!version || !/^\d+\.\d+\.\d+([-.].+)?$/.test(version)) { | ||
| console.error( | ||
| `Error: Version "${version}" in deno.json is not a valid semantic version.`, | ||
| ); | ||
| return; |
There was a problem hiding this comment.
The semver validation regex here (/^\d+\.\d+\.\d+([-.].+)?$/) rejects valid semver with build metadata (e.g. 1.2.3+build.1) and is inconsistent with the stricter semver pattern used elsewhere. Consider using @std/semver (or a shared helper) so release gating matches actual semver rules.
| const version = versionArg.startsWith("v") ? versionArg.slice(1) : versionArg; | ||
|
|
||
| await Deno.writeTextFile("VERSION", `${version}\n`); | ||
| await Deno.writeTextFile("src/version.ts", `export const version = "${version}";\n`); | ||
|
|
||
| const denoJsonPath = "deno.json"; | ||
| const denoJson = JSON.parse(await Deno.readTextFile(denoJsonPath)); | ||
| denoJson.version = version; | ||
| await Deno.writeTextFile(denoJsonPath, JSON.stringify(denoJson, null, 2) + "\n"); |
There was a problem hiding this comment.
sync-version.ts writes whatever string it’s given into deno.json without validating it as semver. Since CI workflows call this script, an invalid input would silently produce a bad deno.json version and later steps may publish/build inconsistent artifacts. Consider validating version (same rules as tag.ts/release.ts) and exiting non-zero on invalid input.
No description provided.