Add semantic-release for automated versioning and npm publishing
Summary
This issue tracks the work to set up semantic-release for @openedx/frontend-base to automate versioning and npm publishing on merge to main.
Findings
Branch configuration
Semantic-release requires at least one non-prerelease release branch. Since main will produce 1.0.0-alpha.X prereleases for now, a placeholder branch needs to exist on the repo to satisfy this constraint. It won't produce releases unless commits are pushed to it. Branch protection should be added to placeholder to prevent accidental pushes that could trigger a stable release.
Tag format
Existing tags use a v prefix (v1.0.0-alpha.13), so tagFormat must be set to v${version}.
npm channel
The package currently publishes to the latest dist-tag. Semantic-release's prerelease branch model defaults the npm dist-tag to the branch name, so channel: "latest" must be set explicitly to preserve the current publishing behavior.
Git notes migration
Semantic-release uses refs/notes/semantic-release to track which npm channel each release was published to. The existing tags have no notes, so a one-time migration is needed:
git notes --ref semantic-release add -m '{"channels":["latest"]}' v1.0.0-alpha.13^{}
git push origin refs/notes/semantic-release
Note: ^{} is required to dereference the annotated tag to its commit — adding the note to the tag object itself won't work.
Proposed .releaserc
{
"branches": [
"placeholder",
{
"name": "main",
"prerelease": "alpha",
"channel": "latest"
}
],
"tagFormat": "v${version}",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
"@semantic-release/github"
]
}
Testing
This was tested on a fork of this repo (brian-smith-tcril/frontend-base) on the test-semantic-release branch, which mirrors main at the time of testing. The .releaserc used for testing can be found at this commit.
The .releaserc on that branch differs from the proposed config above in a few ways:
test-semantic-release is used as the prerelease branch instead of main (so the dry run can execute from it)
repositoryUrl is explicitly set to the fork via SSH (git@github.com:brian-smith-tcril/frontend-base.git) — this is needed locally because semantic-release auto-detects the repo URL from package.json, which points to the upstream openedx/frontend-base. Without overriding it, branch validation fails against the upstream where the test branches don't exist. SSH is used because the auth verification step (git push --dry-run) requires push access, and SSH keys are configured locally. In CI, a GH_TOKEN would handle this via HTTPS instead.
@semantic-release/npm and @semantic-release/github plugins are omitted — these require NPM_TOKEN and GH_TOKEN respectively, which will be available in CI
The placeholder stable branch also exists on the fork.
To verify the git note on the fork:
git clone https://github.com/brian-smith-tcril/frontend-base.git
cd frontend-base
git fetch origin refs/notes/semantic-release:refs/notes/semantic-release
git notes --ref semantic-release show v1.0.0-alpha.13^{}
# Should output: {"channels":["latest"]}
Dry run result (run locally against the fork)
Found git tag v1.0.0-alpha.13 associated with version 1.0.0-alpha.13 on branch test-semantic-release
The next release version is 1.0.0-alpha.14
Remaining work
Future work
When this package is ready for a stable 1.0.0 release:
- Remove
prerelease and channel: "latest" from the main branch config so it produces stable versions
- Remove the
placeholder branch from .releaserc and the repo (it's only needed while main is a prerelease branch)
- At that point,
main will publish to latest as a proper stable release, and a separate prerelease branch (e.g. next) can be added for pre-release work
Add semantic-release for automated versioning and npm publishing
Summary
This issue tracks the work to set up semantic-release for
@openedx/frontend-baseto automate versioning and npm publishing on merge tomain.Findings
Branch configuration
Semantic-release requires at least one non-prerelease release branch. Since
mainwill produce1.0.0-alpha.Xprereleases for now, aplaceholderbranch needs to exist on the repo to satisfy this constraint. It won't produce releases unless commits are pushed to it. Branch protection should be added toplaceholderto prevent accidental pushes that could trigger a stable release.Tag format
Existing tags use a
vprefix (v1.0.0-alpha.13), sotagFormatmust be set tov${version}.npm channel
The package currently publishes to the
latestdist-tag. Semantic-release's prerelease branch model defaults the npm dist-tag to the branch name, sochannel: "latest"must be set explicitly to preserve the current publishing behavior.Git notes migration
Semantic-release uses
refs/notes/semantic-releaseto track which npm channel each release was published to. The existing tags have no notes, so a one-time migration is needed:git notes --ref semantic-release add -m '{"channels":["latest"]}' v1.0.0-alpha.13^{} git push origin refs/notes/semantic-releaseNote:
^{}is required to dereference the annotated tag to its commit — adding the note to the tag object itself won't work.Proposed
.releaserc{ "branches": [ "placeholder", { "name": "main", "prerelease": "alpha", "channel": "latest" } ], "tagFormat": "v${version}", "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", "@semantic-release/github" ] }Testing
This was tested on a fork of this repo (brian-smith-tcril/frontend-base) on the
test-semantic-releasebranch, which mirrorsmainat the time of testing. The.releasercused for testing can be found at this commit.The
.releasercon that branch differs from the proposed config above in a few ways:test-semantic-releaseis used as the prerelease branch instead ofmain(so the dry run can execute from it)repositoryUrlis explicitly set to the fork via SSH (git@github.com:brian-smith-tcril/frontend-base.git) — this is needed locally because semantic-release auto-detects the repo URL frompackage.json, which points to the upstreamopenedx/frontend-base. Without overriding it, branch validation fails against the upstream where the test branches don't exist. SSH is used because the auth verification step (git push --dry-run) requires push access, and SSH keys are configured locally. In CI, aGH_TOKENwould handle this via HTTPS instead.@semantic-release/npmand@semantic-release/githubplugins are omitted — these requireNPM_TOKENandGH_TOKENrespectively, which will be available in CIThe
placeholderstable branch also exists on the fork.To verify the git note on the fork:
Dry run result (run locally against the fork)
Remaining work
placeholderbranch on this repo with branch protection enabled.releasercOPENEDX_SEMANTIC_RELEASE_GITHUB_TOKENandNPM_TOKENsecrets)Future work
When this package is ready for a stable
1.0.0release:prereleaseandchannel: "latest"from themainbranch config so it produces stable versionsplaceholderbranch from.releasercand the repo (it's only needed whilemainis a prerelease branch)mainwill publish tolatestas a proper stable release, and a separate prerelease branch (e.g.next) can be added for pre-release work