Skip to content

Add semantic-release for automated versioning and npm publishing #174

@brian-smith-tcril

Description

@brian-smith-tcril

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

  • Run git notes migration
  • Create placeholder branch on this repo with branch protection enabled
  • Add .releaserc
  • Add release GitHub Actions workflow (using OPENEDX_SEMANTIC_RELEASE_GITHUB_TOKEN and NPM_TOKEN secrets)

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

Metadata

Metadata

Labels

No labels
No labels

Projects

Status

Blocked

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions