From 044d01573a51f320a0caf410b231ee37478325ea Mon Sep 17 00:00:00 2001 From: Simon Diesenreiter Date: Sat, 30 Nov 2024 21:36:41 +0100 Subject: [PATCH] build: introduce conventional commits, ref NOISSUE --- .gitea/conventional_commits/commit-msg | 47 ++++++++ .../conventional_commits/generate-version.sh | 105 ++++++++++++++++++ .../conventional_commits/hooks/text-styles.sh | 44 ++++++++ .gitignore | 1 + Makefile | 26 +++-- 5 files changed, 214 insertions(+), 9 deletions(-) create mode 100755 .gitea/conventional_commits/commit-msg create mode 100755 .gitea/conventional_commits/generate-version.sh create mode 100755 .gitea/conventional_commits/hooks/text-styles.sh diff --git a/.gitea/conventional_commits/commit-msg b/.gitea/conventional_commits/commit-msg new file mode 100755 index 0000000..335984a --- /dev/null +++ b/.gitea/conventional_commits/commit-msg @@ -0,0 +1,47 @@ +#!/usr/bin/env sh +echo "Running commit message checks..." + +. "$(dirname -- "$0")/../../.gitea/conventional_commits/hooks/text-styles.sh" + + +# Get the commit message +commit="$(cat .git/COMMIT_EDITMSG)" +# Define the conventional commit regex +regex='^((build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.+\))?(!?):\s([a-zA-Z0-9-_!\&\.\%\(\)\=\w\s]+)\s?(,?\s?)((ref(s?):?\s?)(([A-Z0-9]+\-[0-9]+)|(NOISSUE))))|(release: .*)$' + +# Check if the commit message matches the conventional commit format +if ! echo "$commit" | grep -Pq "$regex" +then + echo + colorPrint red "❌ Failed to create commit. Your commit message does not follow the conventional commit format." + colorPrint red "Please use the following format: $(colorPrint brightRed 'type(scope)?: description')" + colorPrint red "Available types are listed below. Scope is optional. Use ! after type to indicate breaking change." + echo + colorPrint brightWhite "Quick examples:" + echo "feat: add email notifications on new direct messages refs ABC-1213" + echo "feat(shopping cart): add the amazing button ref: DEFG-23" + echo "feat!: remove ticket list endpoint ref DADA-109" + echo "fix(api): handle empty message in request body refs: MINE-82" + echo "chore(deps): bump some-package-name to version 2.0.0 refs ASDF-12" + echo + colorPrint brightWhite "Commit types:" + colorPrint brightCyan "build: $(colorPrint white "Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)" -n)" + colorPrint brightCyan "ci: $(colorPrint white "Changes to CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)" -n)" + colorPrint brightCyan "chore: $(colorPrint white "Changes which doesn't change source code or tests e.g. changes to the build process, auxiliary tools, libraries" -n)" + colorPrint brightCyan "docs: $(colorPrint white "Documentation only changes" -n)" + colorPrint brightCyan "feat: $(colorPrint white "A new feature" -n)" + colorPrint brightCyan "fix: $(colorPrint white "A bug fix" -n)" + colorPrint brightCyan "perf: $(colorPrint white "A code change that improves performance" -n)" + colorPrint brightCyan "refactor: $(colorPrint white "A code change that neither fixes a bug nor adds a feature" -n)" + colorPrint brightCyan "revert: $(colorPrint white "Revert a change previously introduced" -n)" + colorPrint brightCyan "test: $(colorPrint white "Adding missing tests or correcting existing tests" -n)" + echo + + colorPrint brightWhite "Reminders" + echo "Put newline before extended commit body" + echo "More details at $(underline "http://www.conventionalcommits.org")" + echo + echo "The commit message you attempted was: $commit" + echo + exit 1 +fi \ No newline at end of file diff --git a/.gitea/conventional_commits/generate-version.sh b/.gitea/conventional_commits/generate-version.sh new file mode 100755 index 0000000..b4654db --- /dev/null +++ b/.gitea/conventional_commits/generate-version.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Rules for generating semantic versioning +# major: breaking change +# minor: feat, style +# patch: build, fix, perf, refactor, revert + +PREVENT_REMOVE_FILE=$1 +TEMP_FILE_PATH=.gitea/conventional_commits/tmp + +LAST_TAG=$(git describe --tags --abbrev=0 --always) +echo "Last tag: #$LAST_TAG#" +PATTERN="^[0-9]+\.[0-9]+\.[0-9]+$" + +increment_version() { + local version=$1 + local increment=$2 + local major=$(echo $version | cut -d. -f1) + local minor=$(echo $version | cut -d. -f2) + local patch=$(echo $version | cut -d. -f3) + + if [ "$increment" == "major" ]; then + major=$((major + 1)) + minor=0 + patch=0 + elif [ "$increment" == "minor" ]; then + minor=$((minor + 1)) + patch=0 + elif [ "$increment" == "patch" ]; then + patch=$((patch + 1)) + fi + + echo "${major}.${minor}.${patch}" +} + +create_file() { + local with_range=$1 + if [ -s $TEMP_FILE_PATH/messages.txt ]; then + return 1 + fi + if [ "$with_range" == "true" ]; then + git log $LAST_TAG..HEAD --no-decorate --pretty=format:"%s" > $TEMP_FILE_PATH/messages.txt + else + git log --no-decorate --pretty=format:"%s" > $TEMP_FILE_PATH/messages.txt + fi +} + +get_commit_range() { + rm $TEMP_FILE_PATH/messages.txt + if [[ $LAST_TAG =~ $PATTERN ]]; then + create_file true + else + create_file + LAST_TAG="0.0.0" + fi + echo " " >> $TEMP_FILE_PATH/messages.txt +} + +start() { + mkdir -p $TEMP_FILE_PATH + get_commit_range + new_version=$LAST_TAG + increment_type="" + + while read message; do + echo $message + if echo $message | grep -Pq '(feat|style)(\([\w]+\))?!:([a-zA-Z0-9-_!\&\.\%\(\)\=\w\s]+)\s?(,?\s?)((ref(s?):?\s?)(([A-Z0-9]+\-[0-9]+)|(NOISSUE)))'; then + increment_type="major" + echo "a" + break + elif echo $message | grep -Pq '(feat|style)(\([\w]+\))?:([a-zA-Z0-9-_!\&\.\%\(\)\=\w\s]+)\s?(,?\s?)((ref(s?):?\s?)(([A-Z0-9]+\-[0-9]+)|(NOISSUE)))'; then + if [ -z "$increment_type" ] || [ "$increment_type" == "patch" ]; then + increment_type="minor" + echo "b" + fi + elif echo $message | grep -Pq '(build|fix|perf|refactor|revert)(\(.+\))?:\s([a-zA-Z0-9-_!\&\.\%\(\)\=\w\s]+)\s?(,?\s?)((ref(s?):?\s?)(([A-Z0-9]+\-[0-9]+)|(NOISSUE)))'; then + if [ -z "$increment_type" ]; then + increment_type="patch" + echo "c" + fi + fi + done < $TEMP_FILE_PATH/messages.txt + + if [ -n "$increment_type" ]; then + new_version=$(increment_version $LAST_TAG $increment_type) + echo "New version: $new_version" + + gitchangelog | grep -v "[rR]elease:" > HISTORY.md + git add DotnetTestLib/VERSION HISTORY.md + echo $new_version > DotnetTestLib/VERSION + git commit -m "release: version $new_version 🚀" + echo "creating git tag : $new_version" + git tag $new_version + git push -u origin HEAD --tags + echo "Gitea Actions will detect the new tag and release the new version." + else + echo "No changes requiring a version increment." + fi +} + +start + +if [ -z "$PREVENT_REMOVE_FILE" ]; then + rm -f $TEMP_FILE_PATH/messages.txt +fi \ No newline at end of file diff --git a/.gitea/conventional_commits/hooks/text-styles.sh b/.gitea/conventional_commits/hooks/text-styles.sh new file mode 100755 index 0000000..73d91ef --- /dev/null +++ b/.gitea/conventional_commits/hooks/text-styles.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +colorPrint() { + local color=$1 + local text=$2 + shift 2 + local newline="\n" + local tab="" + + for arg in "$@" + do + if [ "$arg" = "-t" ]; then + tab="\t" + elif [ "$arg" = "-n" ]; then + newline="" + fi + done + + case $color in + black) color_code="30" ;; + red) color_code="31" ;; + green) color_code="32" ;; + yellow) color_code="33" ;; + blue) color_code="34" ;; + magenta) color_code="35" ;; + cyan) color_code="36" ;; + white) color_code="37" ;; + brightBlack) color_code="90" ;; + brightRed) color_code="91" ;; + brightGreen) color_code="92" ;; + brightYellow) color_code="93" ;; + brightBlue) color_code="94" ;; + brightMagenta) color_code="95" ;; + brightCyan) color_code="96" ;; + brightWhite) color_code="97" ;; + *) echo "Invalid color"; return ;; + esac + + printf "\e[${color_code}m${tab}%s\e[0m${newline}" "$text" +} + +underline () { + printf "\033[4m%s\033[24m" "$1" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 10f38e6..c7519d3 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ dmypy.json # templates .gitea/templates/* development.db +.gitea/conventional_commits/tmp/* diff --git a/Makefile b/Makefile index 8644a01..4d8c3c4 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,14 @@ ENV_PREFIX=$(shell python -c "if __import__('pathlib').Path('.venv/bin/pip').exists(): print('.venv/bin/')") USING_POETRY=$(shell grep "tool.poetry" pyproject.toml && echo "yes") +.PHONY: issetup +issetup: + @[ -f .git/hooks/commit-msg ] || (echo "You must run 'make setup' first to initialize the repo!" && exit 1) + +.PHONY: setup +setup: + @cp .gitea/conventional_commits/commit-msg .git/hooks/ + .PHONY: help help: ## Show the help. @echo "Usage: make " @@ -19,19 +27,19 @@ show: ## Show the current environment. @$(ENV_PREFIX)python -m site .PHONY: install -install: ## Install the project in dev mode. +install: issetup ## Install the project in dev mode. @if [ "$(USING_POETRY)" ]; then poetry install && exit; fi @echo "Don't forget to run 'make virtualenv' if you got errors." $(ENV_PREFIX)pip install -e .[test] .PHONY: fmt -fmt: ## Format code using black & isort. +fmt: issetup ## Format code using black & isort. $(ENV_PREFIX)isort project_name/ $(ENV_PREFIX)black -l 79 project_name/ $(ENV_PREFIX)black -l 79 tests/ .PHONY: lint -lint: ## Run pep8, black, mypy linters. +lint: issetup ## Run pep8, black, mypy linters. $(ENV_PREFIX)flake8 project_name/ $(ENV_PREFIX)black -l 79 --check project_name/ $(ENV_PREFIX)black -l 79 --check tests/ @@ -44,7 +52,7 @@ test: lint ## Run tests and generate coverage report. $(ENV_PREFIX)coverage html .PHONY: watch -watch: ## Run tests on every change. +watch: issetup ## Run tests on every change. ls **/**.py | entr $(ENV_PREFIX)pytest -s -vvv -l --tb=long --maxfail=1 tests/ .PHONY: clean @@ -64,7 +72,7 @@ clean: ## Clean unused files. @rm -rf docs/_build .PHONY: virtualenv -virtualenv: ## Create a virtual environment. +virtualenv: issetup ## Create a virtual environment. @if [ "$(USING_POETRY)" ]; then poetry install && exit; fi @echo "creating virtualenv ..." @rm -rf .venv @@ -75,7 +83,7 @@ virtualenv: ## Create a virtual environment. @echo "!!! Please run 'source .venv/bin/activate' to enable the environment !!!" .PHONY: release -release: ## Create a new tag for release. +release: issetup ## Create a new tag for release. @echo "WARNING: This operation will create s version tag and push to gitea" @read -p "Version? (provide the next x.y.z semver) : " TAG @echo "creating git tag : $${TAG}" @@ -88,7 +96,7 @@ release: ## Create a new tag for release. @echo "Gitea Actions will detect the new tag and release the new version." .PHONY: docs -docs: ## Build the documentation. +docs: issetup ## Build the documentation. @echo "building documentation ..." @$(ENV_PREFIX)mkdocs build URL="site/index.html"; xdg-open $$URL || sensible-browser $$URL || x-www-browser $$URL || gnome-open $$URL @@ -111,8 +119,8 @@ switch-to-poetry: ## Switch to poetry package manager. @mv setup.py .gitea/backup @echo "You have switched to https://python-poetry.org/ package manager." @echo "Please run 'poetry shell' or 'poetry run project_name'" - - + + # This project has been generated from rochacbruno/flask-project-template # __author__ = 'rochacbruno' # __repo__ = https://github.com/rochacbruno/flask-project-template