Skip to content

Versioning and Releases

James Daley edited this page Jun 20, 2026 · 4 revisions

Versioning and Releases

Forsetti uses Semantic Versioning (MAJOR.MINOR.PATCH) and conventional pull request titles to keep framework version changes explicit, repeatable, and reviewable.

Version Source Map

flowchart LR
    Version["Single version value"] --> TXT["version.txt"]
    Version --> Swift["ForsettiVersion.current"]
    Version --> Readme["README version marker"]
    TXT --> Runtime["Release and workflow scripts"]
    Swift --> Compatibility["Manifest compatibility checks"]
    Readme --> Users["Repository readers"]
    ReleaseState[".release-please-manifest.json"] --> Release["Retained release configuration state"]
Loading
File Owner Why It Exists
version.txt Repository workflow Plain SemVer value for automation.
Sources/ForsettiCore/ForsettiVersion.swift Runtime Supplies the version used by manifest compatibility checks.
README.md Documentation Displays the current framework version to users.

The three framework version values must match. .release-please-manifest.json is retained release configuration state and is not changed by the PR version workflow.

PR-Time Version Logic

.github/workflows/pr-version.yml updates framework version files on same-repository pull requests. It reads the target branch version, parses the PR title/body, writes the next SemVer, and commits the version update back to the PR branch when needed.

flowchart TD
    Open["PR opened, edited, reopened, synchronized, or marked ready"] --> Branch{"Head branch in same repository?"}
    Branch -- no --> NoWrite["Skip write workflow"]
    Branch -- yes --> ReadBase["Read version.txt from base branch"]
    ReadBase --> Parse["Parse PR title"]
    Parse --> Chore{"type == chore?"}
    Chore -- yes --> Skip["Skip version update"]
    Chore -- no --> Breaking{"! marker or BREAKING CHANGE"}
    Breaking -- yes --> Major["major + 1, minor = 0, patch = 0"]
    Breaking -- no --> Feature{"type == feat?"}
    Feature -- yes --> Minor["minor + 1, patch = 0"]
    Feature -- no --> Patch["patch + 1"]
    Major --> Write["Write version files"]
    Minor --> Write
    Patch --> Write
    Write --> Changed{"Diff exists?"}
    Changed -- no --> Done["No-op"]
    Changed -- yes --> Commit["Commit version update"]
    Commit --> Push["Push to PR branch"]
Loading

Bump Table

PR Title or Body Signal Version Change Example
type!: Major feat!: replace registration storage
BREAKING CHANGE: in body Major refactor: simplify runtime context with body marker
feat: Minor feat: add provider registration records
fix:, docs:, refactor:, test:, ci:, build:, style:, perf: Patch docs: expand wiki architecture guide
chore: None chore: rotate repository labels

The workflow uses the same supported title types as lint-pr.yml. The skip rule is intentional: a chore: PR means repository maintenance that should not represent a framework version change. The workflow fails chore PRs if version files already differ from the target branch.

Release Handoff

The PR version workflow keeps framework version files aligned before merge. It does not publish releases, tags, or changelog entries. Release publication is a separate post-merge process.

sequenceDiagram
    participant PR as Pull Request
    participant Version as PR Version Workflow
    participant Main as main
    participant Release as Release Process

    PR->>Version: title/body drive SemVer
    Version-->>PR: version files updated
    PR->>Main: merge
    Main->>Release: prepare changelog, tag, and release when applicable
Loading

Reviewer Checklist

  • PR title uses a supported conventional type.
  • Breaking changes use ! or a BREAKING CHANGE: body marker.
  • chore: is used only when no framework version change should occur.
  • Version commit, when present, changes only version.txt, Sources/ForsettiCore/ForsettiVersion.swift, and the README version marker.
  • Changelog and release notes remain accurate for user-visible behavior when a release is published.

Failure Modes

Symptom Cause Fix
Version workflow skipped PR branch is from a fork. Maintainer can run the version update locally or open a same-repository branch.
Workflow fails parsing title PR title is not conventional. Rename the PR, for example docs: expand lifecycle guide.
Version files drift Manual edit changed only one framework version surface. Re-run the workflow or update version.txt, ForsettiVersion.swift, and the README marker together.
Chore PR bumps version PR title is not chore: or version files were changed manually. Retitle the PR if it is truly repository maintenance, or remove the version-file changes.

Local Smoke Test

Run this from the repository root:

python3 -m py_compile Scripts/update-pr-version.py
tmpdir="$(mktemp -d)"
cp -R version.txt README.md Sources "$tmpdir/"
(
  cd "$tmpdir"
  python3 "$OLDPWD/Scripts/update-pr-version.py" \
    --base-version 0.1.3 \
    --title "docs: align documentation surfaces"
)

The copied files should update to 0.1.4; a chore: title should report skipped=true and leave the copied version files unchanged.

Clone this wiki locally