semantic-version

repository·master·Indexed 19 days ago

https://github.com/paulhatch/semantic-version

A CLI tool and GitHub Action that automates semantic versioning by analyzing Git commit messages and history. It supports deterministic version increments based on patterns like Conventional Commits, monorepo support via namespaces and change paths, and multiple release strategies including branch-based versioning.

Tokens
8.7K
Snippets
21
Records
28
Agent score
65%

What's inside semantic-version

  1. How Git-Based Semantic Versioning works

    master

    This tool automatically produces semantic versions for a repository by inspecting its Git history. It calculates the next implied version based on the most recent tag and the commit messages since that tag.

    Key Concepts:

    • Implied Version: The version calculated for the current commit. Unless the current commit is already tagged, the version produced will be one value ahead of the last tag.
    • Increment: A value tracking the number of commits since the last version change. This is useful for creating pre-release labels (e.g., 1.0.0-prerelease001).
    • Version Bumps: Commit messages determine if the next version is a major, minor, or patch bump. By default, it follows Conventional Commits:
      • feat: or feat(scope): triggers a minor bump.
      • ! suffix (e.g., feat!:) or BREAKING CHANGE: triggers a major bump.
    • Deterministic Resolution: The version is derived solely from the Git repository, ensuring it can be injected into builds without manual maintenance.
  2. Manage multiple versions in a single repository

    master

    If your repository contains multiple independent projects (e.g., a service and a database migration), you can version them separately using change_path and namespace.

    1. change_path: Limits the versioning logic to specific directories. If no files in this path change, changed is false and the increment does not increase.
    2. namespace: Appends a suffix to tags (e.g., v1.2.3-db). The action will only consider tags with this namespace when calculating versions for this specific instance.
    3. Custom Patterns: Use different major_pattern and minor_pattern values for each project to allow independent marking of changes.

    Example of two independent versioning steps in one workflow:

    - name: Application Version
      id: version
      uses: paulhatch/semantic-version@v5.4.0
      with:
        change_path: "src/service"
    - name: Database Version
      id: db-version
      uses: paulhatch/semantic-version@v5.4.0
      with:
        major_pattern: "(MAJOR-DB)"
        minor_pattern: "(MINOR-DB)"
        change_path: "src/migrations"
        namespace: db
  3. Configure semantic-version in GitHub Actions

    master

    To use the semantic-version action, include it in your workflow YAML. You can customize how versions are detected using patterns for major and minor changes, define the tag prefix, and specify the output format.

    - uses: paulhatch/semantic-version@v5.4.0
      with:
        tag_prefix: "v"
        major_pattern: "/!:|BREAKING CHANGE:/"
        major_regexp_flags: ""
        minor_pattern: "/feat(\(.+\))?:/"
        minor_regexp_flags: ""
        version_format: "${major}.${minor}.${patch}-prerelease${increment}"
        change_path: "src/my-service"
        namespace: my-service
        bump_each_commit: false
        bump_each_commit_patch_pattern: ""
        search_commit_body: false
        user_format_type: "csv"
        enable_prerelease_mode: true
        debug: false
        version_from_branch: false
  4. Choose a release strategy for GitHub Actions

    master

    The semantic-version action supports several release strategies depending on your project's needs. Choose the simplest one that fits your workflow:

    1. Increment Every Release: Automatically increments the version on every push to the default branch. Best for documentation or very small projects where broken versions are not a concern.
    2. Increment from Commit Message: Decides whether to increment based on the commit message. You can use bump_each_commit_patch_pattern to ensure only specific commits (e.g., those containing (PATCH)) trigger a patch increment.
    3. Tag Versioning (Default): The most common strategy. It decides the version after the build has run, based on existing Git tags. This is ideal for most libraries and web applications.
    4. Branch + Tag Versioning: Used for projects requiring ongoing maintenance of multiple major or minor versions (e.g., distributed software). It uses the branch name to determine the major/minor version and filters tags accordingly.
  5. Ensure full Git history is available for checkout

    master

    The actions/checkout action does not include tags or full history by default. Since semantic-version relies on Git history and tags to calculate versions, you must configure the checkout step to fetch the full history.

    Use fetch-depth: 0 to pull all history and tags:

    - name: Checkout
      uses: actions/checkout@v2
      with:
        fetch-depth: 0
        filter: blob:none
    - name: Checkout
      uses: actions/checkout@v2
      with:
        fetch-depth: 0    # fetch all history
        filter: blob:none # exclude file contents for faster checkout
  6. Configure Increment from Commit Message strategy

    master

    This strategy allows you to decide at commit-time whether to increment the version. By using bump_each_commit_patch_pattern, you can restrict patch increments to only those commits that match a specific pattern (e.g., (PATCH)).

    - uses: paulhatch/semantic-version@latest
      with:
        bump_each_commit: true
        bump_each_commit_patch_pattern: "(PATCH)"
  7. Configure Branch + Tag Versioning strategy

    master

    To support multiple active major or minor versions (e.g., maintaining v1.x while developing v2.x), enable version_from_branch. This causes the major and optionally the minor version to be derived from the branch name instead of tags.

    By default, it matches patterns like v1, v1.2, or 1.2. You can provide a custom regex to define how to extract the version from your branch names.

    # Using default branch pattern matching
    - uses: paulhatch/semantic-version@latest
      with:
        version_from_branch: true
    
    # Using a custom regex pattern
    - uses: paulhatch/semantic-version@latest
      with:
        version_from_branch: "/v([0-9]+.[0-9]+$|[0-9]+)$/"
  8. Configure Tag Versioning strategy

    master

    This is the default behavior of the action. It determines the next version based on existing Git tags, allowing you to decide to release only after a successful build. No special configuration is required.

    - uses: paulhatch/semantic-version@latest
  9. Configure Increment Every Release strategy

    master

    Use this strategy if you want to release a new version every time a commit is pushed to your default branch, regardless of the commit content. Note that if a build fails, you will have a broken version that requires another increment to fix.

    - uses: paulhatch/semantic-version@latest
      with:
        bump_each_commit: true
  10. Support Monorepos with Namespace and Change Path

    master

    For projects with multiple independent services (monorepos), use namespace and change_path. This ensures a specific service's version only increments when files within its designated path are modified.

    You can then use the changed output to conditionally run subsequent steps (like deployment) only if the service was actually updated.

    - id: version
      uses: paulhatch/semantic-version@latest
      with:
        change_path: "src/my-service"
        namespace: my-service
    - name: Cancel if Unchanged
      if: ${{ ! fromJSON(steps.version.outputs.changed) }}
      run: |
        gh run cancel ${{ github.run_id }}
        gh run watch ${{ github.run_id }}
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  11. Configure the semantic-version GitHub Action

    master

    The action is configured via input parameters. Below are the available configuration options:

    InputDescription
    branchThe branch to use for versioning logic
    tag_prefixPrefix to use for identifying version tags
    use_branchesDeprecated. Use branch-based versioning logic instead
    version_from_branchSpecifies the branch to derive the version from
    major_patternRegular expression (wrapped in /) to identify major (breaking) changes in commit messages
    minor_patternRegular expression (wrapped in /) to identify minor changes in commit messages
    major_regexp_flagsRegex flags for major_pattern (e.g., idgs)
    minor_regexp_flagsRegex flags for minor_pattern (e.g., idgs)
    version_formatThe format of the version output (Note: format is deprecated)
    change_pathPath to monitor for changes
    namespaceNamespace for versioning
    bump_each_commitWhether to bump the version for every commit
    search_commit_bodyWhether to search the commit body for patterns
    user_format_typeType of user-defined format
    enable_prerelease_modeEnables prerelease versioning mode
    bump_each_commit_patch_patternPattern for patching each commit
    ignore_commits_patternPattern to ignore specific commits
    debugEnables debug logging

    Deprecation Notes:

    • Use version_format instead of format.
    • short_tags is no longer supported.
    • use_branches is deprecated.
  12. Configure versioning from branch names

    master

    The BranchVersioningTagFormatter allows you to derive versioning information directly from your Git branch names. This is controlled via the versionFromBranch configuration key in your ActionConfig.

    Configuration Options for versionFromBranch

    • Boolean (true): If set to true, the formatter uses a default regular expression [0-9]+.[0-9]+$|[0-9]+$ to attempt to extract the version from the branch name. It expects the branch name to end with either major.minor or just major.
    • String (Regex Pattern): If a string is provided, it is treated as a regular expression pattern used to extract the version.
      • The pattern supports regex flags wrapped in slashes at the end, e.g., /pattern/i or /pattern/idgs.
      • The extracted string must be in the format major.minor or major.

    Error Conditions

    • If the branch name does not match the pattern, versioning from the branch is disabled.
    • If the extracted version string is not in major.minor or major format, an error is thrown.
    • If the extracted parts are not valid numbers, an error is thrown.