├── .github ├── dependabot.yml └── workflows │ ├── approve.yml │ └── pr.yml ├── CHANGELOG.md ├── README.md └── commit-msg /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: '04:00' 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/approve.yml: -------------------------------------------------------------------------------- 1 | on: pull_request_target 2 | name: Approver 3 | 4 | jobs: 5 | 6 | approve: 7 | name: Dependabot PR Auto-approve 8 | if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]' 9 | runs-on: ubuntu-latest 10 | steps: 11 | - 12 | uses: hmarr/auto-approve-action@v3.2.1 13 | with: 14 | github-token: "${{ secrets.GITHUB_TOKEN }}" 15 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: shellcheck 2 | on: [pull_request] 3 | jobs: 4 | shellcheck: 5 | name: shellcheck 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4.1.1 9 | - name: shellcheck 10 | uses: reviewdog/action-shellcheck@v1.19 11 | with: 12 | github_token: ${{ secrets.github_token }} 13 | path: 'commit-msg' 14 | pattern: '*' 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2023-12-24 4 | 5 | - always require a valid type (do not allow this anymore: 'myscope: my message' or ': myscope: test' 6 | - https://www.conventionalcommits.org/en/v1.0.0/#specification (1) 7 | 8 | - add all valid semantic versioning types (build, ci, revert) 9 | - https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/config-conventional/index.js#L22 10 | 11 | - allow more characters in the scope (example: 'feat(my-scope, other-scope): my message') 12 | - https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/rules/src/scope-enum.test.ts#L11 13 | 14 | - allow optional exclamation mark before the colon to indicate a breaking change (example: 'feat(api)!: changed endpoint for travel times') 15 | - https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-scope-and--to-draw-attention-to-breaking-change 16 | 17 | - tested the regex on https://regex101.com with these values: 18 | 19 | ``` 20 | ===== Valid commit messages: ===== 21 | build: my message 22 | chore: my message 23 | ci: my message 24 | docs: my message 25 | feat: my message 26 | fix: my message 27 | perf: my message 28 | refactor: my message 29 | revert: my message 30 | style: my message 31 | test: my message 32 | build(my-scope): my message 33 | chore(my-scope): my message 34 | ci(my-scope): my message 35 | docs(my-scope): my message 36 | feat(my-scope): my message 37 | fix(my-scope): my message 38 | perf(my-scope): my message 39 | refactor(my-scope): my message 40 | revert(my-scope): my message 41 | style(my-scope): my message 42 | test(my-scope): my message 43 | feat(my-scope, other-scope): my message 44 | feat(my_scope): my message 45 | feat(my_scope): MY MESSAGE 46 | feat(my_scope)!: MY MESSAGE 47 | 48 | ===== Valid commit message examples from https://www.conventionalcommits.org/en/v1.0.0/#examples: ===== 49 | feat: allow provided config object to extend other configs 50 | feat!: send an email to the customer when a product is shipped 51 | feat(api)!: send an email to the customer when a product is shipped 52 | chore!: drop support for Node 6 53 | docs: correct spelling of CHANGELOG 54 | feat(lang): add Polish language 55 | fix: prevent racing of requests 56 | revert: let us never again speak of the noodle incident 57 | 58 | ===== Invalid commit messages: ===== 59 | feat:my message (no space after the colon) 60 | feat : my message (additional space not allowed) 61 | feat: my message (starting space not allowed) 62 | feat!(scope): my message (exclamation mark for blocking change should be right behind the colon) 63 | feat(!scope): my message (exclamation mark for blocking change should be right behind the colon) 64 | feat(scope!): my message (exclamation mark for blocking change should be right behind the colon) 65 | feat(scope):! my message (exclamation mark for blocking change should be right behind the colon) 66 | : myscope my message (no type) 67 | : myscope::: my message (no type) 68 | : my message (no type) 69 | myscope: my message (invalid type) 70 | myscope: my message (invalid type) 71 | FEAT(my-scope): my message (only lowercase allowed for type) 72 | feat(MY-SCOPE): my message (only lowercase allowed for scope) 73 | ``` 74 | 75 | ## 2023-05-01 76 | 77 | - fix: Fix vs code merges 78 | 79 | ## 2019-05-27 80 | 81 | - updated regex 82 | 83 | ## 2019-05-20 84 | 85 | - initial 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # semantic-commit-hook 2 | Git hook that enforces semantic commit messages. 3 | 4 | ## What is it 5 | Semantic versioning automatically assigns version numbers on your code based on your commit messages. 6 | This means that it recognizes hotfixes, refactors, breaking and non-breaking changes. 7 | In my case, it automatically builds and creates a new release on Github based on the work that has been done. 8 | 9 | You can read more about it [here](https://github.com/semantic-release/semantic-release#how-does-it-work). 10 | 11 | ## How to use 12 | Any commit to your local git repository will be rejected if the first line (the title) does not follow [the semantic versioning format](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format). 13 | 14 | For releasing, I use [go-semantic-release](https://github.com/go-semantic-release/semantic-release). 15 | 16 | ## Installation 17 | ```shell 18 | curl --fail -o .git/hooks/commit-msg https://raw.githubusercontent.com/hazcod/semantic-commit-hook/master/commit-msg \ 19 | && chmod 500 .git/hooks/commit-msg 20 | ``` 21 | -------------------------------------------------------------------------------- /commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Missing argument (commit message). Did you try to run this manually?" 5 | exit 1 6 | fi 7 | 8 | commitTitle="$(cat $1 | head -n1)" 9 | 10 | # ignore merge requests 11 | if echo "$commitTitle" | grep -qE "Merge branch"; then 12 | echo "Commit hook: ignoring branch merge" 13 | exit 0 14 | fi 15 | 16 | # check semantic versioning scheme 17 | if ! echo "$commitTitle" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\([a-z0-9\s\-\_\,]+\))?!?:\s\w'; then 18 | echo "Your commit message did not follow semantic versioning: $commitTitle" 19 | echo "" 20 | echo "Format: (): " 21 | echo "Example: feat(api): add endpoint" 22 | echo "" 23 | echo "Valid types: build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test" 24 | echo "" 25 | echo "Please see" 26 | echo "- https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format" 27 | echo "- https://www.conventionalcommits.org/en/v1.0.0/#summary" 28 | exit 1 29 | fi 30 | --------------------------------------------------------------------------------