EasyBuild.ShipIt 1.0.0

dotnet tool install --global EasyBuild.ShipIt --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local EasyBuild.ShipIt --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=EasyBuild.ShipIt&version=1.0.0
                    
nuke :add-package EasyBuild.ShipIt --version 1.0.0
                    

EasyBuild.ShipIt

NuGet

Sponsors badge link

Tool for generating changelog based on Git history based on Conventional Commits. It is using EasyBuild.CommitParser to parse commit messages check their documentation for more information about configuration.

Features

  • Easy integration into your CI/CD pipeline 🛠
  • Automatic versioning based on commit messages 🚀
  • Can create/update pull request for automatic releases 🔧
  • Support for monorepo 🔥

How does it work?

EasyBuild.ShipIt search for any CHANGELOG.md, for each of them look at the commits since the last released commit (based on the last_commit_released configuration) and generate a new changelog entry based on the commit messages.

Then, if the --skip-pull-request option is not passed, it will create a pull request with the updated changelog file.

Learn more about:

Usage

# Install the tool
dotnet tool install EasyBuild.ShipIt

# Run the tool
dotnet shipit

CLI manual

DESCRIPTION:
Automate changelog generation based on conventional commit messages and create pull requests for releases.

The tool will do its best to automatically detect the Git provider based on the git remote URL.
You can force it to use a specific provider using sub-commands, e.g. 'shipit github' to force using GitHub.

Learn more at https://github.com/easybuild-org/EasyBuild.ShipIt

USAGE:
    shipit [OPTIONS] [COMMAND]

OPTIONS:
                                        DEFAULT
    -h, --help                                          Prints help information
        --allow-branch <VALUES>         main            List of branches that are allowed to be used to generate the changelog
        --mode <MODE>                   pull-request    Mode of operation. Possible values are 'local', 'pull-request' and 'push'
        --pre-release [PREFIX]          beta            Indicate that the generated version is a pre-release version. Optionally, you can provide a prefix for the beta version. Default is 'beta'
        --remote-hostname <HOSTNAME>                    Git remote hostname, e.g. github.com, gitlab.com
        --remote-owner <OWNER>                          Git remote owner or organization name
        --remote-repo <REPO>                            Git remote repository name
        --skip-invalid-commit           False           Skip invalid commits instead of failing
        --skip-merge-commit             False           Skip merge commits when generating the changelog (commit messages starting with 'Merge ')
    -v, --version                                       Show version information

COMMANDS:
    version
    conventions    List supported Conventional Commit types
    github         Publish to GitHub

How is the version calculated?

Stable versions

The version is calculated based on the commit messages since last released, who are contributing to the changelog file (based on the include and exclude configuration).

Rules are the following:

  • A breaking change commit will bump the major version

    * chore: release 1.2.10
    * feat!: first feature # => 2.0.0
    
  • feat commits will bump the minor version

    * chore: release 1.2.10
    * feat: first feature
    * feat: second feature # => 1.3.0
    
  • perf commits will bump the minor version

    * chore: release 1.2.10
    * perf: first performance improvement
    * perf: second performance improvement # => 1.3.0
    
  • fix commits will bump the patch version

    * chore: release 1.2.10
    * fix: first fix
    * fix: second fix # => 1.2.11
    

You can mix different types of commits, the highest version will be used (breaking change > feat or perf > fix).

* chore: release 1.2.10
* feat: first feature
* perf: first performance improvement
* fix: first fix # => 1.3.0

Pre-release versions

A pre-release will be generated if you set pre_release configuration or if you pass --pre-release CLI option.

Rules are the following:

  • If the previous version is stable, then we compute the standard version bump and start a new pre-release version.

    * chore: release 1.2.10
    * feat: first feature
    * fix: first fix # => 1.3.0-beta.1
    
  • If the previous version is a pre-release, with the same suffix, then we increment the pre-release version.

    * chore: release 1.3.0-beta.10
    * feat: first feature
    * fix: first fix # => 1.3.0-beta.11
    
  • If the previous version is a pre-release, with a different suffix, then we use the same base version and start a new pre-release version.

    * chore: release 1.3.0-alpha.10
    * feat: first feature
    * fix: first fix # => 1.3.0-beta.1
    

💡 Tips

EasyBuild.Changelog use the last version in the changelog file to compute the next version.

For this reason, while working on a pre-release, it is advised to work in a separate branch from the main branch. This allows you to work on the pre-release while still being able to release new versions on the main branch.

* chore: release 1.2.10
| \
|  * feat!: remove `foo` API
|  * feat: add `bar` API        # => 2.0.0.beta.1
|  * fix: fix `baz` API
* fix: fix `qux` API
* chore: release 1.2.11
|  * fix: fix `qux` API         # => 2.0.0.beta.2
| /
* chore: release 2.0.0          # => 2.0.0

Moving out of pre-release

If you want to move out of pre-release, you need to remove the pre_release configuration or stop passing the --pre-release CLI option.

Then the next version will be released using the base version of the previous pre-release.

* chore: release 1.3.0-beta.10
* feat: first feature
* fix: first fix # => 1.3.0

If you are not sure what will be calculated, you can use the --mode local option to see the result without creating a pull request or committing any changes.

You can then reset the changelog using git restore path/to/CHANGELOG.md before re-running the command.

Overriding the computed version

If the computed version is not what you want, you can use force_version configuration to override the computed version for a specific release.

Commit conventions

EasyBuild.Shipit follows the Conventional Commits specification.

<type>[optional scope][optional !]: <description>

[optional body]

[optional footer]
  • [optional body] is a free-form text.

    This is a single line body.
    
    This is a
    
    multi-line body.
    
  • [optional footer] is inspired by git trailer format key: value but also allows key #value

    BREAKING CHANGE: <description>
    Signed-off-by: Alice <alice@example.com>
    Signed-off-by: Bob <bob@example.com>
    Refs #123
    Tag: cli
    

The following commit types are supported:

  • feat : A new feature
  • fix : A bug fix
  • ci : Changes to CI/CD configuration
  • chore : Changes to the build process or auxiliary tools and libraries such as documentation generation
  • docs : Documentation changes
  • test : Adding missing tests or correcting existing tests
  • style : Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor : A code change that neither fixes a bug nor adds a feature
  • perf : A code change that improves performance
  • revert : Reverts a previous commit
  • build : Changes that affect the build system or external dependencies

Extra changelog content

You can define additional content to be added in your changelog entry by surrounding it with === changelog === markers in your commit message body.

feat: add `String.split` API

=== changelog ===
```fs
let parts = String.split " " "Hello World"
```
=== changelog ===

Recommendations

Because EasyBuild.ShipIt relies on your commit messages, it is recommended to use Squash and Merge or Rebase and Merge when merging pull requests to keep a clean commit history.

This avoid the creation of invalid commits like Merge pull request ....

To help enforce this convention, you can go to your Org/Repo GitHub settings:

  1. Disable the Allow merge commits option in the General > Pull Requests section.
  2. Enable Allow squash merging option and choose Pull request title in the dropdown.

Additionally, you can configure this GitHub Actions to validate PRs titles.

# conventional-pr-title.yml
name: 'Lint PR'

on:
  pull_request_target:
    types:
      - opened
      - reopened
      - edited
      # - synchronize (if you use required Actions)

jobs:
  main:
    name: Validate PR title
    runs-on: ubuntu-slim
    permissions:
      pull-requests: read
    steps:
      - uses: amannn/action-semantic-pull-request@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CLI options

--remote-hostname, --remote-owner, --remote-repo

These options allow you to specify the Git remote information. This is useful when the tool is not able to automatically detect the Git provider based on the git remote URL.

This information is used to create links to commits, diff, etc. in the generated changelog file.

--allow-branch

type: string[] default: main

Restrict the branches that can be used to generate the changelog.

This is a safety measure to avoid generating changelog from a branch that is not intended to be released, e.g. a feature branch.

--skip-invalid-commit

type: bool default: false

When this option is passed, the tool will skip any commit that is not following the Conventional Commits format instead of failing.

--skip-merge-commit

type: bool default: false

When this option is passed, the tool will skip any merge commit (commit messages starting with 'Merge ') when generating the changelog.

--pre-release

type: string

When this option is passed, the generated version will be a pre-release version.

Optionsally, you can provide a prefix for the pre-release version. If no prefix is provided, it will default to beta.

--mode

type: string default: pull-request

Control the mode in which the tool operates.

  • local: Only generate the changelog file locally

  • pull-request: Create a pull request with the updated changelog file (default)

  • push: Push the updated changelog file directly to the current branch

    🚨 IMPORTANT: Make sure to configure --allow-branch option to avoid pushing changes to unintended branches.

Configuration

EasyBuild.ShipIt configuration lives as a front matter in your CHANGELOG.md file(s).

---
last_commit_released: abcd1234
include:
  - ../Shared/
---

# Changelog

All notable changes to this project will be documented in this file.

...

last_commit_released

type: string

This is the commit hash of the last released commit. It is used to determine which commits should be considered for the next release.

You should set it up manually only if you are adopting EasyBuild.ShipIt in an existing project. If you are starting a new project, you can leave it empty and it will be automatically set to the latest commit hash when you run the tool for the first time.

include

type: string[]

Allows to include commits from other paths. This is useful for monorepo where you have multiple projects in the same repository.

include:
  - ../Shared/
  - ../Lib/

It always include files in the same directory as the changelog file, so you don't need to include it in the configuration.

exclude

type: string[]

Allows to exclude commits from specific paths.

exclude:
  - tests/

pre_release

type: string

When set to a non-empty value, the generated version will be a pre-release version with the provided value as prefix.

pre_release: beta

priority

type: int

Lowest number has the highest priority. This is useful to determine which changelog file should be updated first when generating a new release.

If a changelog has no priority, it will be considered as having the lowest priority (i.e. it will be updated last).

priority: 1

name

type: string

Allows to override the name of the project used when reporting in PR.

By default, the project is named after the parent directory of the changelog file.

force_version

type: string

Allows to force the version to be used in the changelog. This is useful when you want to override the calculated version for a specific release.

This is not persisted in the generated changelog file, it is only used for the current run.

force_version: 2.0.0

updaters

type: Updater[]

List of updaters to run after generating the changelog. This allows you to automatically update other files in your repository, e.g. package.json or AssemblyInfo.cs, with the new version.

regex

type: object

Use a regex pattern to find the text to replace with the new version.

Property Description
file Relative path to the file to update. It is relative to the changelog file.
pattern Pattern used to find the text to replace.

The regex with replace the full match with the new version. Make sure to use a regex that only matches the version part of the file.

For example, if you want to update:

<Metadata>
  <Version>1.0.0</Version>
</Metadata>

Your regex should be (?<=<Version>).*(?=</Version>) to only replace the version part and not the full match.

updaters:
  - regex:
      file: Metadata.xml
      pattern: (?<=<Version>).*(?=</Version>)
package.json

type: object

Update the version field in a package.json file.

Property Description
file Relative path to the package.json file to update. It is relative to the changelog file.
updaters:
  - package.json:
      file: path/to/package.json
json

type: object

Update a JSON file using a JSON Patch. It uses the JSON Patch format to specify the changes to be made to the JSON file.

Property Description
file Relative path to the JSON file to update. It is relative to the changelog file.
pointer JSON pointer to the field to update.
updaters:
  - json:
      file: path/to/file.json
      pointer: /metadata/version
xml

type: object

Update an XML file using an XPath expression to find the node to update.

Property Description
file Relative path to the XML file to update. It is relative to the changelog file.
selector XPath expression to find the node to update.
updaters:
  - xml:
      file: path/to/file.xml
      selector: /Metadata/Version
command

type: string

Run an arbitrary command to update the version. The command will receive the new version as an argument in place of {version}.

updaters:
  - command: "./update-version.sh {version}"

Monorepo support

EasyBuild.ShipIt supports monorepo.

For example, if you have the following repository structure:

repo/
├── project-a/
│   ├── CHANGELOG.md
│   └── ...
├── project-b/
│   ├── CHANGELOG.md
│   └── ...
└── Shared/
    └── ...

It means that 2 projects will be released, project-a and project-b. By default, only the commits that are in the same directory as the changelog file will be considered for the release of each project.

If you want to include commits from the Shared directory for both projects, you can use the include configuration to include the Shared directory for both changelog files.

Learn more about the include configuration in the Configuration section.

Recipes

Prod / staging environments

When working with production and staging environments, you can use the pre_release configuration to generate pre-release versions for the staging environment and stable versions for the production environment.

To do that, you need use --pre-release CLI option in your staging environment and not use it in your production environment.

We want to use the CLI option here instead of the configuration as it allows to easily switch between pre-release and stable versions without having to change the configuration file.

GitHub Actions (auto release)

EasyBuild.ShipIt has been designed to make it easy to integrate into your CI/CD pipeline, and in particular with GitHub Actions.

Below is an example of how to use it, so it update the CHANGELOG.md file in a pull request. Once the pull request is merged, it will trigger a workflow to publish the packages.

Requirements
  1. Go to GitHub settings of your Org or Repo, and enable Actions > General > Allow GitHub Actions to create and approve pull requests.

    If you prefers, you can also create a Personal Access Token (PAT) and use it instead of secrets.GITHUB_TOKEN.

  2. Create a .github/workflows/easybuild-shipit.yml file with the following content:

on:
  push:
    branches:
      - main

permissions:
  contents: write
  pull-requests: write
  id-token: write

name: EasyBuild ShipIt

jobs:
  # Run tests and generate a Pull Request to prepare a release
  shipit-pr:
    name: ShipIt - Pull Request
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          # We need to fetch more than the last commit to be able to generate the changelog based on the commit history.
          # Adapt this value based on your needs.
          fetch-depth: 50
      - name: Setup .NET
        uses: actions/setup-dotnet@v5
        with:
          global-json-file: global.json
      # Run your tests before generating the changelog to make sure everything is working fine before creating a pull request.
      - name: Build and test
        run: echo "Run your build and tests here"
      - name: ShipIt (Pull Request)
        run: dotnet run --project src/ -c SHIPIT_EXCEPTION
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  release:
    name: Release
    runs-on: ubuntu-latest
    # Only trigger this workflow when a commit starting with `chore: release ` is pushed.
    if: "startsWith(github.event.head_commit.message, 'chore: release ')"
    steps:
      - uses: actions/checkout@v6
      # Configure how you want to publish your package, e.g. using the NuGet CLI, dotnet CLI, NPM, etc.
      # It is recommanded to use Trusted Publishing to avoid having to manage API keys in your repository.
      - name: Setup .NET
        uses: actions/setup-dotnet@v5
        with:
          global-json-file: global.json

      # Below is an example, for NuGet packages (to demonstrate that we are getting
      # the API key from the OIDC token exchange and not from a secret in the repository).
      - name: NuGet login (OIDC → temp API key)
        uses: NuGet/login@v1
        id: login
        with:
          # Secret is your NuGet username, e.g. andrewlock
          # This is actually a public information, so we can using a secret is probably overkill
          user: ${{ secrets.NUGET_USER }}

      - name: Build, Test and Release
        run: |
            dotnet pack src/ -c Release -o ./nupkgs
            dotnet nuget push ./nupkgs/*.nupkg --api-key $NUGET_KEY
        env:
          NUGET_KEY: ${{ steps.login.outputs.NUGET_API_KEY }}

Why the name "ShipIt"?

The name "ShipIt" is a reference to the famous phrase "Ship it!".

It is also to avoid future potential conflicts in case .NET team decide to add dotnet release in .NET CLI.

I felt like shipit was a fun and less risky in this regard.

Exit codes

  • 0: Success
  • 1: Error
  • 100: Help was requested
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.0.0 28 2/11/2026
0.1.0 50 2/10/2026

### 🏗️ Breaking changes

* Make PR title decision based on the presence of multiple CHANGELOG.md and not just the ones updated (#5) ([2c99db5](https://github.com/easybuild-org/EasyBuild.ShipIt/commit/2c99db550a7d742c10c92e5f27fcade930ea23a6))

<strong><small>[View changes on Github](https://github.com/easybuild-org/EasyBuild.ShipIt/compare/82fe7dd954f97861e55f8f3b328f89123b947dc3..2c99db550a7d742c10c92e5f27fcade930ea23a6)</small></strong>