dash.js Release Procedure
Branching model
dash.js follows a Gitflow-style model with three kinds of branches:
development— the integration branch. It is always open: feature and enhancement PRs for the next version keep merging here throughout the entire release cycle. It is never frozen.RC_vX.X.X— the release (stabilization) branch for one specific version. It is cut fromdevelopmentat code freeze and receives only bug fixes for that version. This is the branch testers build against and the branch the release candidates are cut from. It is a branch, not a tag.master— the released state. Each release is a merge of the finishedRC_vX.X.Xbranch intomaster, taggedvX.X.X, with builtdistfiles.
The key idea: the release branch is what gets frozen, not development. Cutting RC_vX.X.X isolates the release so it can be stabilized and tested while day-to-day development continues in parallel. New feature PRs never have to be held back — they simply target development and ship with the next version.
development ──●──●───────────●───────────●──●──► next-version PRs keep landing
\ ↑ back-merge ↑ final back-merge (RC → development)
\ / each fix /
RC_vX.X.X ●──●───●───────●────────● only fixes; rc.0, rc.1 … tested here
\
master ──────────────────────────────────●──► merge, tag vX.X.X, build dist, publishKeeping the two lines in sync
Every fix that lands on RC_vX.X.X must also reach development, or development silently regresses (a bug fixed in the RC reappears in the next version). Do this continuously, not only at the end:
- Merge
RC_vX.X.Xback intodevelopmentafter each RC (or cherry-pick each fix as it lands). Periodic merges are far less painful than one large merge at the very end. - At release time, do a final back-merge of
RC_vX.X.Xintodevelopmentbefore deleting the branch, so nothing from the release is lost.
Pre-release (post code-freeze date)
- Cut the release branch
RC_vX.X.Xfromdevelopment. From this point,developmentstays open for next-version work — only fixes for this release go ontoRC_vX.X.X. - Keep the version numbers in
package.jsonon theRC_vX.X.Xbranch at the finalX.X.Xrelease version. Use a short-lived_npmbranch for anyX.X.X-rc.Nnpm prerelease builds. - Every change pulled into this release gets a release candidate, even if the changes are minor.
- Create the Release Notes and share them on the Google Groups mailing list for feedback.
During the RC / testing phase
- Only bug fixes go onto
RC_vX.X.X. Build the candidates from this branch and hand them to testers. - Feature work continues on
developmentfor the next version — no freeze. - Back-merge every fix from
RC_vX.X.Xintodevelopment(see Keeping the two lines in sync above) so the next version inherits all the fixes. - Optionally publish
x.y.z-rc.Nbuilds to npm under thenexttag so testers can install them like a real user (see Publishing to npm → Release candidate). - Iterate: fix on
RC_vX.X.X, cut a new candidate, re-test, until the branch is clean.
Release
- Merge the finished
RC_vX.X.Xbranch intomaster. (mastershould end up in the exact state of the latest, approved RC branch.) - Pull
masterlocally and build thedistfiles withnpm run build. - Push the resulting
distfiles tomaster. - Draft the release with the Git Release UI:
- Tag the release with the version number, e.g.
vX.X.X. - Title the release
dash.js vX.X.X. - Add the release notes created beforehand.
- Save as a draft for now.
- Tag the release with the version number, e.g.
- Update and upload the archive index page for the player.
- Publish the Git release by opening the saved draft and clicking publish.
- Publish to npm following the procedure below.
- Back-merge
RC_vX.X.Xintodevelopmentone final time so the release state (final version bump, any last fixes) is reflected there. - Get the tag release URL and send out the official dash.js release email.
- Delete all
RC_vX.X.Xbranches for cleanup.
Publishing to npm
Publishing happens exclusively through the manually triggered Publish to NPM GitHub Actions workflow (.github/workflows/publish_npm.yml). Never run npm publish locally: the workflow uses npm trusted publishing (OIDC, no tokens) and verifies the exact tarball before it ships — tests, lint, dist build, tarball content assertions and a consumer-app playback smoke test all have to pass first.
Keep in mind: npm versions are immutable. Once a version is published it can never be replaced or reused, even after unpublishing. The steps below exist to make sure a broken build never reaches latest.
1. Prepare
- Bump the version in
package.jsonon theRC_vX.X.Xbranch. The workflow refuses versions that already exist on npm. Use the formatx.y.z-rc.N. - Commit and push. The workflow publishes the ref you dispatch it from.
2. Rehearse (always)
- GitHub → Actions →
Publish to NPM→ Run workflow, keep the defaults (dry_run: true). - This runs the complete pipeline including
npm publish --dry-run— nothing is published. - Fix anything that fails and repeat until green.
3. Release candidate (recommended for major or risky releases)
Publish x.y.z-rc.N to npm under the next tag so testers can install it exactly like a real user. The -rc.N version bump needs its own commit, but you don't want that commit in the history that gets merged into master and back into development. So do the bump on a short throwaway branch cut from the current state of RC_vX.X.X — only the workflow needs to see it. The stabilization branch RC_vX.X.X keeps its package.json at the plain release version.
- Create a short throwaway branch from the current RC state:bash
git checkout RC_vX.X.X git checkout -b RC_vX.X.X_npm - Set the
versionfield tox.y.z-rc.0(updatespackage.jsonandpackage-lock.json):bashnpm version x.y.z-rc.0 --no-git-tag-version - Commit and push the branch:bash
git commit -am "Bump version to x.y.z-rc.0" git push -u origin RC_vX.X.X_npm - Dispatch
Publish to NPMwithdry_run: falseandtag: next, and select the throwaway branch in the "Use workflow from" dropdown — the workflow publishes thepackage.jsonof the branch it runs on. - This is a real publish to the real registry, but
lateststays untouched. The workflow blocks prerelease versions on thelatesttag. - Verify from the outside, exactly like a user would:bashLoad the player and play a stream.
mkdir /tmp/dashjs-rc-check && cd /tmp/dashjs-rc-check && npm init -y npm install dashjs@next - If the RC is broken: fix on
RC_vX.X.X, re-cut the throwaway branch, bump to-rc.1, repeat. Nothing is lost, and the fix is already on the branch that will be released. - Delete the throwaway
_npmbranch once you're done with prerelease publishing. The final release in step 4 happens onRC_vX.X.Xitself, so no-rc.Nversion bump ever pollutes the released history.
4. Final publish
- On the
RC_vX.X.Xbranch, set theversionfield inpackage.jsonto the finalx.y.z(e.g.npm version x.y.z --no-git-tag-version), commit and push, run step 2 once more, then dispatch withdry_run: falseandtag: latest.
5. Verify the published package
npm view dashjs versionshows the new version.npm install dashjs@latestin a scratch project installs and plays.
If a broken version reaches npm anyway
Never try to republish the same version number — npm will reject it. Fix forward:
- Bump the patch version, fix the problem and publish again.
- Deprecate the broken version so installs warn about it:bash
npm deprecate dashjs@x.y.z "Broken release, use x.y.z+1 instead" - If the broken version holds the
latesttag and the fix needs time, pointlatestback to the last good version in the meantime:bashnpm dist-tag add dashjs@<last-good-version> latest
