github.com/FollowTheProcess/tag@v0.4.2/README.md (about)

     1  <p align="center">
     2  <img src="https://github.com/FollowTheProcess/tag/raw/main/img/logo.png" alt="logo" width=50% height=50%>
     3  </p>
     4  
     5  # Tag
     6  
     7  [![License](https://img.shields.io/github/license/FollowTheProcess/tag)](https://github.com/FollowTheProcess/tag)
     8  [![Go Report Card](https://goreportcard.com/badge/github.com/FollowTheProcess/tag)](https://goreportcard.com/report/github.com/FollowTheProcess/tag)
     9  [![GitHub](https://img.shields.io/github/v/release/FollowTheProcess/tag?logo=github&sort=semver)](https://github.com/FollowTheProcess/tag)
    10  [![CI](https://github.com/FollowTheProcess/tag/workflows/CI/badge.svg)](https://github.com/FollowTheProcess/tag/actions?query=workflow%3ACI)
    11  
    12  The all in one semver management tool
    13  
    14  ## Project Description
    15  
    16  Releasing new versions of software can be hard! Most projects have CI/CD pipelines set up to help with this and these pipelines are typically triggered on push of a new [semver] tag e.g. `v1.2.4`.
    17  
    18  I made tag because I can never remember the commands to correctly issue and push a tag:
    19  
    20  * "Was it `git tag v1.2.4`?"
    21  * "Do I need to annotate it: `git tag -a v1.2.4`?"
    22  * "Do I need to add a message: `git tag -a v1.2.4 -m "Some message"`?
    23  * "Wait how do I push it again: `git push --tags` or `git push origin v1.2.4`?"
    24  
    25  This invariably ends up with me doing it differently across every project, spending (even more) time on stackoverflow googling random git commands.
    26  
    27  And not to mention having to replace versions in documentation, project metadata files etc.
    28  
    29  No more 🚀 `tag` has you covered!
    30  
    31  `tag` is cross-platform and is tested on mac, windows and linux. It'll run anywhere you can run Go!
    32  
    33  **Fun fact:** `tag` actually releases itself!
    34  
    35  ## Installation
    36  
    37  Compiled binaries for all supported platforms can be found in the [GitHub release]. There is also a [homebrew] tap:
    38  
    39  ```shell
    40  brew install FollowTheProcess/tap/tag
    41  ```
    42  
    43  ## Usage
    44  
    45  Tag has 2 modes of operating, one in which it doesn't find a config file in the current directory (`.tag.toml`), and one where it does. Let's start with the first mode.
    46  
    47  ### No Replace Mode
    48  
    49  If there is no config file present in `cwd`, tag will operate in "no replace" mode. This is it's most basic mode and when tag
    50  is in this mode all you can do with it is list, create, and push new [semver] tags.
    51  
    52  For example let's say you're working on a project currently at `v0.23.8` and you've decided you want to signal to the world that your project is stable, it's time for a major version bump! 🚀
    53  
    54  Your project also has a CI/CD pipeline where on the push of a new tag it gets compiled and packaged up and a new release gets created.
    55  
    56  So you need to create a new tag (`v1.0.0`) and push it. No problem!
    57  
    58  ```shell
    59  tag major --push
    60  ```
    61  
    62  This will create a new `v1.0.0` annotated git tag, and push it to the configured remote. Job done ✅
    63  
    64  ### Replace Mode
    65  
    66  Now this is already nice but wouldn't it be *even nicer* if you didn't have to manually bump version numbers in project metadata files, or maybe the README:
    67  
    68  ```markdown
    69  # My Project Readme
    70  
    71  This my project, version = 0.1.0
    72  ```
    73  
    74  `tag` can do that too! All you have to do is tell it what to do with which files to work on, enter the `.tag.toml` config file which should be placed in the root of your repo:
    75  
    76  ```toml
    77  version = '0.1.0'
    78  
    79  [[file]]
    80  path = 'README.md'
    81  search = 'My project, version {{.Current}}'
    82  
    83  [[file]]
    84  path = 'somewhereelse.txt'
    85  search = 'Replace me, version {{.Current}}'
    86  ```
    87  
    88  Tag uses two special variables `{{.Current}}` and `{{.Next}}` to substitute for the correct versions while bumping as well as the path (relative to `.tag.toml`) of the files you want to change.
    89  
    90  So now all you have to do is e.g.
    91  
    92  ```shell
    93  tag minor --push
    94  ```
    95  
    96  And then tag will:
    97  
    98  * Perform search and replace on all occurrences of your search string
    99  * Stage all the changes in git once the replacing is done
   100  * Commit the changes with a message like `Bump version 0.1.0 -> 0.2.0`
   101  * Push the changes
   102  * Push the new tag
   103  
   104  And then your CI/CD pipeline will take care of the rest! 🎉
   105  
   106  After bumping, your README will now look like this:
   107  
   108  ```markdown
   109  # My Project Readme
   110  
   111  This my project, version = 0.2.0
   112  ```
   113  
   114  ## Config File
   115  
   116  As mentioned above, `tag` has an optional config file (`.tag.toml`) to be placed at the root of your repo, we've seen specifying files to search and replace
   117  contents on, but it can do a bit more than that!
   118  
   119  A fully populated config file looks like this:
   120  
   121  ```toml
   122  version = '0.1.0'
   123  
   124  [git]
   125  default-branch = 'main'
   126  message-template = 'Bump version {{.Current}} -> {{.Next}}'
   127  tag-template = 'v{{.Next}}'
   128  
   129  [hooks]
   130  pre-replace = "echo 'I run before doing anything'"
   131  pre-commit = "echo 'I run after replacing but before committing changes'"
   132  pre-tag = "echo 'I run after committing changes but before tagging'"
   133  pre-push = "echo 'I run after tagging, but before pushing'"
   134  
   135  [[file]]
   136  path = 'pyproject.toml'
   137  search = 'version = "{{.Current}}"'
   138  
   139  [[file]]
   140  path = 'README.md'
   141  search = 'My project, version {{.Current}}'
   142  ```
   143  
   144  ### Git
   145  
   146  The git section allows you to specify how tag interacts with git whilst bumping versions. You can specify:
   147  
   148  * The default branch for your repo (defaults to `main`). This will be checked prior to bumping to ensure you don't issue a tag on a different branch
   149  * The commit message template (defaults to `Bump version {{.Current}} -> {{.Next}}`). This sets the message used for your bump commit after contents have been replaced
   150  * The tag message template (defaults to `v{{.Next}}`). Similar to the commit message but this one is associated to the tag itself.
   151  
   152  ### Hooks
   153  
   154  Tag also lets you hook into various stages of the replacement/bumping process and inject custom logic in the form of hooks. Hooks are small shell commands that
   155  let you update things that tag cannot see or run custom commands.
   156  
   157  A good use case is for example, issuing a new version of a rust project with a `Cargo.toml`. In the `Cargo.toml` you must specify a version of your crate:
   158  
   159  ```toml
   160  # Cargo.toml
   161  version = "0.1.0"
   162  ```
   163  
   164  When you compile your crate, it generates a `Cargo.lock` which *also* has the version. So if you use tag to bump the version in the `Cargo.toml` then the `Cargo.lock` can fall out of sync and then your crate will fail to build. Because we should never really interact with `Cargo.lock` manually, we can use hooks to re-build the crate
   165  after replacing the version in `Cargo.toml`:
   166  
   167  ```toml
   168  # .tag.toml
   169  [hooks]
   170  pre-commit = "cargo build" # Update the lockfile
   171  ```
   172  
   173  The hooks are split into stages:
   174  
   175  * **`pre-replace`**: This one runs first, more or less before tag does *anything* at all
   176  * **`pre-commit`**: Runs after replacing contents, but before those changes are added and committed to the repo
   177  * **`pre-tag`**: Runs after replacing and the changes have been committed, but before the new tag is created
   178  * **`pre-push`**: Runs last, after everything above is finished but before the tag is pushed to the remote (if the `--push` flag is used)
   179  
   180  [GitHub release]: https://github.com/FollowTheProcess/tag/releases
   181  [homebrew]: https://brew.sh
   182  [semver]: https://semver.org