Versioning
Shopfoo uses Semantic Release to automate versioning and changelog generation. The version is determined from commit messages following the Conventional Commits specification, computed during CI, embedded into the deployed application, and displayed in its About page.
Overview
The versioning pipeline runs in GitHub Actions and follows this flow:
A developer triggers the release workflow manually.
Semantic Release analyzes commit messages since the last release and determines the next version number.
The version and release date are written into
package.json.A changelog entry is generated in
CHANGELOG.md.Both files are committed and a GitHub release is created.
The application is built and deployed to Azure.
The version is then visible in the application's About page, imported directly from package.json at build time.
Commit conventions and release rules
Commit messages follow the Conventional Commits specification, written with Commitji β a dotnet tool that adds a Gitmoji-inspired emoji between the prefix and the description (e.g. feat: β¨ add stock adjustment). The emoji is purely decorative and does not affect versioning β only the prefix matters.
Semantic Release uses the conventionalcommits preset to map commit types to version bumps. The rules are defined in .releaserc.json:
breaking
Major
feat
Minor
fix
Patch
perf
Patch
refactor
Patch
test
No release
chore
No release
docs
No release
revert
No release
tidy
No release
wip
No release
For example, a commit message like feat: add stock adjustment triggers a minor version bump, while fix: correct price calculation triggers a patch bump.
Semantic Release configuration
The .releaserc.json file orchestrates six plugins in order:
Each plugin has a specific role:
commit-analyzer β Determines the version bump from commit messages.
release-notes-generator β Generates structured release notes from commits.
changelog β Appends the release notes to
CHANGELOG.md.npm β Updates the
versionfield inpackage.json(publishing is disabled since this is a private package).exec β Runs
update-release-date.jsto stamp the current date intopackage.json.git β Commits the updated
package.jsonandCHANGELOG.mdwith a[skip ci]marker to avoid retriggering the pipeline.github β Creates a GitHub release with the generated notes.
Release date script
The update-release-date.js script is called by the exec plugin during the release. It writes today's date (in YYYY-MM-DD format) into a custom releaseDate field in package.json:
After a release, package.json contains both the version and the release date:
Version in the application
The F# client imports metadata directly from package.json using Fable's [<ImportMember>] attribute:
Vite resolves the import from package.json at build time, so the values are inlined into the JavaScript bundle. There is no runtime fetch β the version is baked into the compiled output.
The About page displays this information using DaisyUI badges:
This renders as something like: π·οΈ Version 1.2.0 (2025-12-30).
See the About page section in General Features for a screenshot and a description of the information displayed.
GitHub Actions workflow
The release pipeline is defined in .github/workflows/release.yml and consists of three jobs:
Release
Runs Semantic Release via the cycjimmy/semantic-release-action action. It outputs two values consumed by downstream jobs:
new-release-publishedβ Whether a new version was created.new-release-versionβ The version string (e.g.1.2.0).
The checkout uses fetch-depth: 0 so that Semantic Release has access to the full commit history for analysis.
Build
Runs only if a new release was published (or if force_deploy is enabled). It checks out the code at the release tag, sets up .NET 9 and Node.js 22, then runs dotnet run Publish β the FAKE build target that compiles the server, transpiles the F# client via Fable, and bundles the front-end via Vite. The output is uploaded as a shopfoo-app artifact.
Deploy
Downloads the build artifact and deploys it to an Azure Web App.
Workflow inputs
The workflow is triggered manually (workflow_dispatch) with two optional inputs:
dry-runβ Runs Semantic Release without actually publishing. Useful for previewing what version would be created.force_deployβ Deploys from the latest existing release tag, bypassing the need for a new release. Useful for redeployments after infrastructure changes.
Changelog
The CHANGELOG.md file is generated automatically by the @semantic-release/changelog plugin. Each release entry includes:
A SemVer comparison link to the GitHub diff (e.g.
v1.1.0...v1.2.0).The release date.
Commits grouped by type (Features, Bug Fixes, etc.).
Links to individual commits on GitHub.
Data flow summary
The full versioning lifecycle:
Commit β Developers write commits following Conventional Commits with Commitji (
feat: β¨ add feature,fix: π fix bug, etc.).Release trigger β A maintainer manually triggers the release workflow in GitHub Actions.
Version calculation β Semantic Release analyzes commits since the last tag and determines the next SemVer version.
File updates β
package.jsongets the newversionandreleaseDate;CHANGELOG.mdgets a new entry.Git commit and tag β The updated files are committed with
[skip ci]and a Git tag is created.GitHub release β A GitHub release is published with auto-generated notes.
Build β Fable transpiles the F# client; Vite bundles the front-end, inlining the version from
package.json.Deploy β The built artifact is deployed to Azure Web App.
Display β The About page shows the version and release date imported from
package.json.
Last updated