mirror of
https://github.com/ObNitram/git-release.git
synced 2026-03-22 11:52:19 +01:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c1038a77d | |||
| 43375912d6 | |||
| ffc9ccb8e4 | |||
| 4bcb79a413 | |||
| 80852cf843 | |||
| f35f25e73f | |||
| 2e507d50e7 | |||
| c1aa7c9412 |
46
.github/workflows/release.yaml
vendored
Normal file
46
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Release ${{ steps.version.outputs.version }}
|
||||
body: |
|
||||
## git-release ${{ steps.version.outputs.version }}
|
||||
|
||||
Minimal tool to create and publish Git release tags following the vX.Y.Z format.
|
||||
|
||||
```bash
|
||||
# Quick install
|
||||
mkdir -p ${HOME}/.local/bin
|
||||
wget -qO ${HOME}/.local/bin/git-release https://github.com/ObNitram/git-release/releases/download/${{ steps.version.outputs.version }}/git-release
|
||||
chmod +x ${HOME}/.local/bin/git-release
|
||||
```
|
||||
|
||||
See the [README](https://github.com/${{ github.repository }}/blob/${{ steps.version.outputs.version }}/README.md) for more details.
|
||||
files: |
|
||||
git-release
|
||||
LICENSE
|
||||
README.md
|
||||
draft: false
|
||||
prerelease: false
|
||||
71
README.md
71
README.md
@@ -2,18 +2,71 @@
|
||||
|
||||
Minimal tool to create and publish Git release tags following the vX.Y.Z format.
|
||||
|
||||
```bash
|
||||
# Quick install
|
||||
mkdir -p ${HOME}/.local/bin
|
||||
wget -qO ${HOME}/.local/bin/git-release https://github.com/ObNitram/git-release/releases/latest/download/git-release
|
||||
chmod +x ${HOME}/.local/bin/git-release
|
||||
```
|
||||
|
||||
Installation
|
||||
- Make the script executable: `chmod +x git-release`
|
||||
- (Optional) Copy to PATH: `cp git-release $HOME/.local/bin/git-release`
|
||||
## Usage
|
||||
|
||||
Usage
|
||||
- From the repository root: `./git-release`
|
||||
- The script creates an annotated tag and pushes it to the configured remote.
|
||||
- If the script is in your PATH, you can run it directly with `git release`
|
||||
- From the repository root: `git release`
|
||||
- Select release type: patch, minor, major, or cancel
|
||||
- Confirm the new version
|
||||
- The script creates and pushes the new tag
|
||||
|
||||
Dependencies
|
||||
### Multi-project support
|
||||
|
||||
For repositories with multiple projects (monorepos), you can specify the project name as an argument:
|
||||
`git release <projectname>` will create a tag with the following format `<projectname>-vX.Y.Z`
|
||||
|
||||
## Example
|
||||
```
|
||||
$ git release
|
||||
📦 Current version: v0.0.0
|
||||
Select release type:
|
||||
1) patch
|
||||
2) minor
|
||||
3) major
|
||||
4) cancel
|
||||
#? 2
|
||||
🚀 Creating new release: v0.1.0
|
||||
Confirm? (y/N): y
|
||||
Enumerating objects: 6, done.
|
||||
Counting objects: 100% (6/6), done.
|
||||
Delta compression using up to 20 threads
|
||||
Compressing objects: 100% (4/4), done.
|
||||
Writing objects: 100% (4/4), 560 bytes | 560.00 KiB/s, done.
|
||||
Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
|
||||
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
|
||||
To github.com:ObNitram/git-release.git
|
||||
* [new tag] v0.1.0 -> v0.1.0
|
||||
✅ Release v0.1.0 created and pushed successfully!
|
||||
```
|
||||
|
||||
## Installation
|
||||
It's a single script file:
|
||||
- Download the `git-release` script from the repository.
|
||||
- Make it executable: `chmod +x git-release`
|
||||
- Place it in your PATH
|
||||
|
||||
It relies on the fact that if git does not find a command, it will look for a script named `git-<command>` in your PATH.
|
||||
So you can now run `git release` from any git repository.
|
||||
|
||||
|
||||
You can use the following commands to install it:
|
||||
```bash
|
||||
mkdir -p ${HOME}/.local/bin
|
||||
wget -qO ${HOME}/.local/bin/git-release https://github.com/ObNitram/git-release/releases/latest/download/git-release
|
||||
chmod +x ${HOME}/.local/bin/git-release
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Dependencies
|
||||
- git
|
||||
|
||||
License
|
||||
## License
|
||||
- MIT License
|
||||
- See the repository `LICENSE` file.
|
||||
59
git-release
59
git-release
@@ -2,35 +2,66 @@
|
||||
# git-release
|
||||
# https://github.com/obnitram/git-release
|
||||
# -------------------------------------------------
|
||||
# Only accepts tags of the form vX.Y.Z (no prerelease/build).
|
||||
# Usage: git-release [<projectname>] [-f]
|
||||
# Accepts tags of the form vX.Y.Z or <projectname>-vX.Y.Z (no prerelease/build).
|
||||
# Interactively bumps patch/minor/major, creates an annotated tag,
|
||||
# and pushes it to origin.
|
||||
#
|
||||
# Requirements:
|
||||
# - The last tag MUST match ^v[0-9]+\.[0-9]+\.[0-9]+$ (or none => starts from v0.0.0)
|
||||
# - Working tree must be clean.
|
||||
# - The last tag MUST match ^v[0-9]+\.[0-9]+\.[0-9]+$ or ^<projectname>-v[0-9]+\.[0-9]+\.[0-9]+$ (or none => starts from v0.0.0)
|
||||
# - Working tree must be clean (unless -f is used).
|
||||
|
||||
set -euo pipefail
|
||||
trap 'echo "❌ ${0##*/} failed at line $LINENO." >&2; exit 1' ERR
|
||||
|
||||
# --- Parse arguments ---
|
||||
FORCE_FLAG=false
|
||||
PROJECT_NAME=""
|
||||
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "-f" ]]; then
|
||||
FORCE_FLAG=true
|
||||
else
|
||||
PROJECT_NAME="$arg"
|
||||
fi
|
||||
done
|
||||
if [[ -n "$PROJECT_NAME" ]]; then
|
||||
TAG_PREFIX="${PROJECT_NAME}-v"
|
||||
TAG_PATTERN="${PROJECT_NAME}-v[0-9]*.[0-9]*.[0-9]*"
|
||||
TAG_REGEX="^${PROJECT_NAME}-v([0-9]+)\.([0-9]+)\.([0-9]+)$"
|
||||
DEFAULT_TAG="${PROJECT_NAME}-v0.0.0"
|
||||
else
|
||||
TAG_PREFIX="v"
|
||||
TAG_PATTERN="v[0-9]*.[0-9]*.[0-9]*"
|
||||
TAG_REGEX="^v([0-9]+)\.([0-9]+)\.([0-9]+)$"
|
||||
DEFAULT_TAG="v0.0.0"
|
||||
fi
|
||||
|
||||
# --- Safety: ensure we are inside a Git repository ---
|
||||
git rev-parse --is-inside-work-tree >/dev/null 2>&1
|
||||
|
||||
# --- Safety: require a clean working tree ---
|
||||
# --- Safety: require a clean working tree (unless -f flag is used) ---
|
||||
if [[ "$FORCE_FLAG" == false ]]; then
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
echo "⚠️ Uncommitted changes detected. Please commit or stash before releasing."
|
||||
echo " Or use -f flag to force the release anyway."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Get strictly matching tags and pick the highest (lexicographic by version) ---
|
||||
# Using Git's glob to only list vX.Y.Z, then version-sort.
|
||||
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' | sort -V | tail -n1)
|
||||
CURRENT_TAG=${LAST_TAG:-v0.0.0}
|
||||
# Using Git's glob to only list matching pattern, then version-sort.
|
||||
LAST_TAG=$(git tag --list "$TAG_PATTERN" | sort -V | tail -n1)
|
||||
CURRENT_TAG=${LAST_TAG:-$DEFAULT_TAG}
|
||||
|
||||
# --- Validate strict format (vX.Y.Z only) ---
|
||||
if [[ ! "$CURRENT_TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
echo "❌ Latest tag '$CURRENT_TAG' is not strictly 'vX.Y.Z'."
|
||||
# --- Validate strict format ---
|
||||
if [[ ! "$CURRENT_TAG" =~ $TAG_REGEX ]]; then
|
||||
echo "❌ Latest tag '$CURRENT_TAG' does not match expected format."
|
||||
if [[ -n "$PROJECT_NAME" ]]; then
|
||||
echo " Please create a proper base tag, e.g.: git tag -a ${PROJECT_NAME}-v0.0.0 -m 'init'"
|
||||
else
|
||||
echo " Please create a proper base tag, e.g.: git tag -a v0.0.0 -m 'init'"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -51,12 +82,12 @@ select TYPE in "patch" "minor" "major" "cancel"; do
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Build next tag (still strict vX.Y.Z) ---
|
||||
NEXT_TAG="v${MAJOR}.${MINOR}.${PATCH}"
|
||||
# --- Build next tag ---
|
||||
NEXT_TAG="${TAG_PREFIX}${MAJOR}.${MINOR}.${PATCH}"
|
||||
|
||||
# --- Double-check strictness before proceeding ---
|
||||
if [[ ! "$NEXT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "❌ Computed tag '$NEXT_TAG' is not strictly 'vX.Y.Z'. Aborting."
|
||||
if [[ ! "$NEXT_TAG" =~ $TAG_REGEX ]]; then
|
||||
echo "❌ Computed tag '$NEXT_TAG' does not match expected format. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user