├── .gitattributes
├── .githooks
└── pre-commit
├── .github
├── CODEOWNERS
├── dependabot.yml
├── stale.yml
└── workflows
│ ├── build.yml
│ ├── lint.yml
│ └── release.yml
├── .gitignore
├── .golangci.yaml
├── .goreleaser.yml
├── .svu.yaml
├── LICENSE
├── Makefile
├── README.md
├── add.go
├── add_test.go
├── chglog_test.go
├── cmd
└── chglog
│ ├── config.go
│ └── main.go
├── files.go
├── format.go
├── format_test.go
├── git.go
├── go.mod
├── go.sum
├── init.go
├── init_test.go
├── order_test.go
├── pkg
└── commands
│ ├── add.go
│ ├── commands.go
│ ├── config.go
│ ├── format.go
│ ├── init.go
│ └── version.go
├── templates.go
├── testdata
├── TestFormatChangelog-deb
├── TestFormatChangelog-release
├── TestFormatChangelog-repo
├── TestFormatChangelog-rpm
├── add-repo-annotated-tag
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── 43
│ │ │ └── 3581c28b23426dee2c498da28defa9f5bd4f63
│ │ ├── 55
│ │ │ └── 2682b593e1bea86425fd6d9520f2687b28487b
│ │ ├── 09
│ │ │ └── 5b7b431351080c1edfe7de73db893e6b59ddce
│ │ ├── 2c
│ │ │ ├── 499787328348f09ae1e8f03757c6483b9a938a
│ │ │ └── c00abc77d401a541d18c26e5c7fbef1effd3ed
│ │ ├── 3e
│ │ │ └── c1e9a60d07cc060cee727c97ffc8aac5713943
│ │ ├── 6f
│ │ │ ├── 59e5e770be445518775b22bbe25e89339b778b
│ │ │ └── 6c178ef5f187bb7d4088a0415ac5a9ff0aef45
│ │ ├── ab
│ │ │ └── 515204e62e6fd2b468736de7aadcaca4d9dffd
│ │ ├── c2
│ │ │ └── b01f193085b4bc020ef62b93d9dc44d9eca7a4
│ │ ├── e6
│ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ │ └── ea
│ │ │ └── 2b12e15f99419047f49d5fc5dc844073899da8
│ └── refs
│ │ ├── heads
│ │ └── master
│ │ └── tags
│ │ ├── v0.0.1
│ │ └── v0.0.2
├── add-repo
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── pre-receive.sample
│ │ ├── prepare-commit-msg.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── 43
│ │ │ └── 3581c28b23426dee2c498da28defa9f5bd4f63
│ │ ├── 2c
│ │ │ ├── 499787328348f09ae1e8f03757c6483b9a938a
│ │ │ └── c00abc77d401a541d18c26e5c7fbef1effd3ed
│ │ ├── 3e
│ │ │ └── c1e9a60d07cc060cee727c97ffc8aac5713943
│ │ ├── 6f
│ │ │ └── 59e5e770be445518775b22bbe25e89339b778b
│ │ ├── ab
│ │ │ └── 515204e62e6fd2b468736de7aadcaca4d9dffd
│ │ ├── c2
│ │ │ └── b01f193085b4bc020ef62b93d9dc44d9eca7a4
│ │ ├── e6
│ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ │ └── ea
│ │ │ └── 2b12e15f99419047f49d5fc5dc844073899da8
│ └── refs
│ │ ├── heads
│ │ └── master
│ │ └── tags
│ │ └── v0.0.1
├── gold-add-changelog-with-annotated-commit.yml
├── gold-add-changelog.yml
├── gold-init-changelog-with-merge-commit.yml
├── gold-init-changelog-without-merge-commit.yml
├── gold-init-changelog.yml
├── gold-order-changelog.yml
├── init-repo-with-merge-commit
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── pre-receive.sample
│ │ ├── prepare-commit-msg.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── 25
│ │ │ └── c55c716f1f18bb91aafa55f98a02315f59afe6
│ │ ├── 2c
│ │ │ ├── 499787328348f09ae1e8f03757c6483b9a938a
│ │ │ └── c00abc77d401a541d18c26e5c7fbef1effd3ed
│ │ ├── 3e
│ │ │ └── c1e9a60d07cc060cee727c97ffc8aac5713943
│ │ ├── 6f
│ │ │ └── 59e5e770be445518775b22bbe25e89339b778b
│ │ ├── ab
│ │ │ └── 515204e62e6fd2b468736de7aadcaca4d9dffd
│ │ ├── d3
│ │ │ └── 0b6cdff6d118d97095f39b2982d4fa237d33d1
│ │ ├── e6
│ │ │ ├── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ │ │ └── f123d7d0aa2025ce61d28e2d34f94f3a6b5218
│ │ └── ea
│ │ │ └── 2b12e15f99419047f49d5fc5dc844073899da8
│ ├── packed-refs
│ └── refs
│ │ ├── heads
│ │ └── master
│ │ └── tags
│ │ └── v0.0.1
└── init-repo
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ └── update.sample
│ ├── info
│ └── exclude
│ ├── objects
│ ├── 2c
│ │ ├── 499787328348f09ae1e8f03757c6483b9a938a
│ │ └── c00abc77d401a541d18c26e5c7fbef1effd3ed
│ ├── 3e
│ │ └── c1e9a60d07cc060cee727c97ffc8aac5713943
│ ├── 6f
│ │ └── 59e5e770be445518775b22bbe25e89339b778b
│ ├── ab
│ │ └── 515204e62e6fd2b468736de7aadcaca4d9dffd
│ ├── e6
│ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ └── ea
│ │ └── 2b12e15f99419047f49d5fc5dc844073899da8
│ └── refs
│ ├── heads
│ └── master
│ └── tags
│ └── v0.0.1
└── types.go
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 |
3 | # Denote all files that are truly binary and should not be modified.
4 | *.png binary
5 | *.jpg binary
6 | *.ico binary
--------------------------------------------------------------------------------
/.githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | FILES=$(git diff --staged --diff-filter=AM --no-renames --name-only)
3 | make fmt lint test && git add $FILES
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @goreleaser/everyone
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "gomod"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | time: "08:00"
8 | labels:
9 | - "dependencies"
10 | commit-message:
11 | prefix: "chore"
12 | include: "scope"
13 | - package-ecosystem: "github-actions"
14 | directory: "/"
15 | schedule:
16 | interval: "daily"
17 | time: "08:00"
18 | labels:
19 | - "dependencies"
20 | commit-message:
21 | prefix: "chore"
22 | include: "scope"
23 | - package-ecosystem: "docker"
24 | directory: "/"
25 | schedule:
26 | interval: "daily"
27 | time: "08:00"
28 | labels:
29 | - "dependencies"
30 | commit-message:
31 | prefix: "chore"
32 | include: "scope"
33 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 14
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: wontfix
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs. Thank you
15 | for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false
18 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches:
6 | - "main"
7 | pull_request:
8 |
9 | jobs:
10 | build:
11 | strategy:
12 | fail-fast: true
13 | matrix:
14 | os: [ubuntu-latest, windows-latest]
15 | runs-on: ${{ matrix.os }}
16 | steps:
17 | - uses: actions/checkout@v4
18 | - uses: actions/setup-go@v5
19 | with:
20 | go-version: "stable"
21 | - uses: goreleaser/goreleaser-action@v6
22 | with:
23 | install-only: true
24 | - run: goreleaser build --snapshot --clean --snapshot
25 | - run: go test -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.out ./... -timeout=5m
26 | - uses: codecov/codecov-action@v5
27 | with:
28 | token: ${{ secrets.CODECOV_TOKEN }}
29 | file: ./coverage.out
30 | dependabot:
31 | needs: [build]
32 | runs-on: ubuntu-latest
33 | permissions:
34 | pull-requests: write
35 | contents: write
36 | if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}}
37 | steps:
38 | - id: metadata
39 | uses: dependabot/fetch-metadata@v2
40 | with:
41 | github-token: "${{ secrets.GITHUB_TOKEN }}"
42 | - run: |
43 | gh pr review --approve "$PR_URL"
44 | gh pr merge --squash --auto "$PR_URL"
45 | env:
46 | PR_URL: ${{github.event.pull_request.html_url}}
47 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
48 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: golangci-lint
2 | on:
3 | push:
4 | tags:
5 | - v*
6 | branches:
7 | - main
8 | pull_request:
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | golangci:
14 | permissions:
15 | contents: read
16 | pull-requests: read
17 | name: lint
18 | runs-on: ubuntu-latest
19 | steps:
20 | - uses: actions/checkout@v4
21 | - uses: actions/setup-go@v5
22 | with:
23 | go-version: "stable"
24 | - name: golangci-lint
25 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9
26 | with:
27 | skip-go-installation: true
28 | args: --timeout=5m
29 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: releaese
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v*"
7 |
8 | jobs:
9 | goreleaser:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4
13 | with:
14 | fetch-depth: 0
15 | - uses: actions/setup-go@v5
16 | with:
17 | go-version: "stable"
18 | - uses: goreleaser/goreleaser-action@v6
19 | with:
20 | version: latest
21 | args: release --clean
22 | env:
23 | GITHUB_TOKEN: ${{ secrets.GH_PAT }}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.rpm
3 | coverage.txt
4 | dist
5 | .DS_Store
6 | bin
7 | coverage.out
8 | chglog
9 | !chglog/
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | run:
2 | go: "1.22"
3 | timeout: 5m
4 | linters:
5 | enable:
6 | - thelper
7 | - gofumpt
8 | - tparallel
9 | - unconvert
10 | - unparam
11 | - wastedassign
12 | - revive
13 | - forbidigo
14 | - tagliatelle
15 | - misspell
16 | - depguard
17 | - testifylint
18 | - gocritic
19 | linters-settings:
20 | staticcheck:
21 | checks:
22 | - all
23 | - "-SA1019"
24 | forbidigo:
25 | forbid:
26 | - 'ioutil\.*'
27 | tagliatelle:
28 | case:
29 | use-field-name: false
30 | rules:
31 | yaml: snake
32 | json: snake
33 | depguard:
34 | rules:
35 | main:
36 | deny:
37 | - pkg: "github.com/pkg/errors"
38 | desc: "use stdlib instead"
39 | gocritic:
40 | enabled-checks:
41 | - exitAfterDefer
42 | testifylint:
43 | enable-all: true
44 | disable:
45 | - error-is-as # false positive
46 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | before:
4 | hooks:
5 | - go mod tidy
6 |
7 | gomod:
8 | proxy: true
9 |
10 | builds:
11 | - main: ./cmd/chglog
12 | env:
13 | - CGO_ENABLED=0
14 | goos:
15 | - linux
16 | - darwin
17 | - windows
18 | goarch:
19 | - amd64
20 | - arm64
21 | mod_timestamp: "{{ .CommitTimestamp }}"
22 | flags:
23 | - -trimpath
24 | ldflags:
25 | - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
26 |
27 | changelog:
28 | sort: asc
29 | use: github
30 | filters:
31 | exclude:
32 | - "^test:"
33 | - "^chore"
34 | - "merge conflict"
35 | - Merge pull request
36 | - Merge remote-tracking branch
37 | - Merge branch
38 | - go mod tidy
39 | groups:
40 | - title: Dependency updates
41 | regexp: "^.*feat\\(deps\\)*:+.*$"
42 | order: 300
43 | - title: "New Features"
44 | regexp: "^.*feat[(\\w)]*:+.*$"
45 | order: 100
46 | - title: "Bug fixes"
47 | regexp: "^.*fix[(\\w)]*:+.*$"
48 | order: 200
49 | - title: "Documentation updates"
50 | regexp: "^.*docs[(\\w)]*:+.*$"
51 | order: 400
52 | - title: Other work
53 | order: 9999
54 |
55 | archives:
56 | - name_template: >-
57 | {{ .ProjectName }}_
58 | {{- title .Os }}_
59 | {{- if eq .Arch "amd64" }}x86_64
60 | {{- else if eq .Arch "386" }}i386
61 | {{- else }}{{ .Arch }}{{ end }}
62 | {{- if .Arm }}v{{ .Arm }}{{ end }}
63 | brews:
64 | - repository:
65 | owner: goreleaser
66 | name: homebrew-tap
67 | directory: Formula
68 | homepage: https://github.com/goreleaser/chglog
69 | description: chglog is a changelog management library and tool
70 | test: |
71 | system "#{bin}/chglog version"
72 | nfpms:
73 | - file_name_template: "{{ .ProjectName }}_{{ .Arch }}"
74 | homepage: https://github.com/goreleaser/chglog
75 | description: chglog is a changelog management library and tool
76 | maintainer: Dj Gilcrease
77 | license: MIT
78 | vendor: GoReleaser
79 | formats:
80 | - deb
81 | - rpm
82 | scoops:
83 | - repository:
84 | owner: goreleaser
85 | name: scoop-bucket
86 | homepage: https://goreleaser.com
87 | directory: bucket
88 | description: Deliver Go binaries as fast and easily as possible
89 | license: MIT
90 |
91 | release:
92 | footer: |
93 | **Full Changelog**: https://github.com/goreleaser/goreleaser/compare/{{ .PreviousTag }}...{{ .Tag }}
94 |
95 | ## What to do next?
96 |
97 | - Read the [documentation](https://goreleaser.com/intro/)
98 | - Check out the [GoReleaser Pro](https://goreleaser.com/pro) distribution
99 | - Join our [Discord server](https://discord.gg/RGEBtg8vQ6)
100 | - Follow us on [Twitter](https://twitter.com/goreleaser)
101 |
--------------------------------------------------------------------------------
/.svu.yaml:
--------------------------------------------------------------------------------
1 | # svu configuration.
2 | #
3 | # https://github.com/caarlos0/svu
4 | tag.prefix: "v"
5 | verbose: true
6 | always: true
7 | v0: true
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Dj Gilcrease
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SOURCE_FILES?=./...
2 | TEST_PATTERN?=.
3 | TEST_OPTIONS?=
4 | TEST_TIMEOUT?=5m
5 |
6 | test:
7 | go test $(TEST_OPTIONS) -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.out $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=$(TEST_TIMEOUT)
8 | .PHONY: test
9 |
10 | cover: test
11 | go tool cover -html=coverage.out
12 | .PHONY: cover
13 |
14 | fmt:
15 | go mod tidy
16 | gofumpt -w -l .
17 | .PHONY: fmt
18 |
19 | ci: build test
20 | .PHONY: ci
21 |
22 | build:
23 | goreleaser build --clean --snapshot --single-target -o chglog
24 | .PHONY: build
25 |
26 | .DEFAULT_GOAL := build
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
chglog
4 | chglog is a changelog management library and tool
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ## Why
19 |
20 | While there are other tool out there that will create a changelog output as part
21 | of their workflow none of the ones I could find did so in a way that allowed
22 | formatting the output via multiple templates.
23 |
24 | The need to multiple output formats was being driven by the desire to add
25 | changelog support to https://github.com/goreleaser/nfpm and the deb and rpm
26 | changelog formats not being the same.
27 |
28 | ## Goals
29 |
30 | - [x] be simple to use
31 | - [x] provide decent default templates for deb, rpm, release and repository
32 | style changelog formats
33 | - [x] be distributed as a single binary
34 | - [x] reproducible results
35 | - [x] depend on the fewer external things as possible
36 | - [x] store changelog in a transportable format (.yml)
37 | - [x] be possible to use it as a lib in other go projects (namely
38 | [goreleaser](https://goreleaser.com) itself)
39 |
40 | ## Install
41 |
42 | ```bash
43 | go install github.com/goreleaser/chglog/cmd/chglog@latest
44 | ```
45 |
46 | ## Usage
47 |
48 | The first steps are to run `chglog config` to initialize a configuration file
49 | (`.chglog.yml`) and edit the generated file according to your needs:
50 |
51 | ```yaml
52 | conventional-commits: false
53 | exclude-merge-commits: false
54 | deb:
55 | distribution: []
56 | urgency: ""
57 | debug: false
58 | owner: ""
59 | package-name: ""
60 | ```
61 |
62 | The next step is to run `chglog init`.
63 |
64 | ```yaml
65 | - semver: 0.0.1
66 | date: 2019-10-18T16:05:33-07:00
67 | packager: dj gilcrease
68 | changes:
69 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
70 | note: |-
71 | oops i forgot to use Conventional Commits style message
72 |
73 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
74 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
75 | note: |-
76 | feat: added file two feature
77 |
78 | BREAKING CHANGE: this is a backwards incompatible change
79 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
80 | note: |-
81 | feat: added the fileone feature
82 |
83 | * This is a test repo
84 | * so ya!
85 | ```
86 |
87 | Then to generate a `CHANGELOG.md` file you would do `chglog format --template
88 | repo > CHANGELOG.md`
89 |
90 | Now whenever you go to do another release you would do `chglog add --version
91 | v#.#.#` (version MUST be semver format)
92 |
93 | And that's it!
94 |
95 | ## Usage as lib
96 |
97 | You can look at the code of chglog itself to see how to use it as a library
98 |
99 | ## Status
100 |
101 | - alpha
102 |
103 | ## Donate
104 |
105 | Donations are very much appreciated! You can donate/sponsor on the main
106 | [goreleaser OpenCollective](https://opencollective.com/goreleaser)! It's
107 | easy and will surely help the developers at least buy some ☕️ or 🍺!
108 |
109 | ## Stargazers over time
110 |
111 | [](https://starchart.cc/goreleaser/chglog)
112 |
113 | ---
114 |
115 | Would you like to fix something in the documentation? Feel free to open an
116 | [issue](https://github.com/goreleaser/chglog/issues).
117 |
--------------------------------------------------------------------------------
/add.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "regexp"
7 | "sort"
8 | "strings"
9 | "time"
10 |
11 | "github.com/go-git/go-git/v5"
12 | "github.com/go-git/go-git/v5/plumbing"
13 | "github.com/go-git/go-git/v5/plumbing/object"
14 | conventional_commit "gitlab.com/digitalxero/go-conventional-commit"
15 | )
16 |
17 | // ErrNoCommits happens when no commits are found for a given entry.
18 | var ErrNoCommits = errors.New("no commits found for this entry")
19 |
20 | var signedOffRegEx = regexp.MustCompile(`(?m)(?:^.*Signed-off-by:.*>$)`)
21 |
22 | // AddEntry add a ChangeLog entry to an existing ChangeLogEntries that.
23 | func AddEntry(
24 | gitRepo *git.Repository,
25 | version fmt.Stringer,
26 | owner string,
27 | notes *ChangeLogNotes,
28 | deb *ChangelogDeb,
29 | current ChangeLogEntries,
30 | useConventionalCommits bool,
31 | excludeMergeCommits bool,
32 | ) (cle ChangeLogEntries, err error) {
33 | var (
34 | ref *plumbing.Reference
35 | from, to plumbing.Hash
36 | commits []*object.Commit
37 | )
38 |
39 | if ref, err = gitRepo.Head(); err != nil {
40 | return nil, fmt.Errorf("error adding entry: %w", err)
41 | }
42 | from = ref.Hash()
43 |
44 | to = plumbing.ZeroHash
45 | if len(current) > 0 {
46 | if to, err = GitHashFotTag(gitRepo, current[0].Semver); err != nil {
47 | return nil, fmt.Errorf("error adding entry: %w", err)
48 | }
49 | }
50 |
51 | cle = append(cle, current...)
52 | if commits, err = CommitsBetween(gitRepo, from, to, excludeMergeCommits); err != nil {
53 | return nil, fmt.Errorf("error adding entry: %w", err)
54 | }
55 |
56 | if len(commits) == 0 {
57 | return nil, ErrNoCommits
58 | }
59 |
60 | cle = append(cle, CreateEntry(time.Now(), version, owner, notes, deb, commits, useConventionalCommits))
61 | sort.Sort(sort.Reverse(cle))
62 |
63 | return cle, nil
64 | }
65 |
66 | func processMsg(msg string) string {
67 | msg = strings.ReplaceAll(strings.ReplaceAll(msg, "\r\n\r\n", "\n\n"), "\r", "")
68 | msg = signedOffRegEx.ReplaceAllString(msg, "")
69 | msg = strings.ReplaceAll(strings.Trim(msg, "\n"), "\n\n\n", "\n")
70 |
71 | return msg
72 | }
73 |
74 | // CreateEntry create a ChangeLog object.
75 | func CreateEntry(date time.Time, version fmt.Stringer, owner string, notes *ChangeLogNotes, deb *ChangelogDeb, commits []*object.Commit, useConventionalCommits bool) (changelog *ChangeLog) {
76 | var cc *conventional_commit.ConventionalCommit
77 | changelog = &ChangeLog{
78 | Semver: version.String(),
79 | Date: date,
80 | Packager: owner,
81 | Notes: notes,
82 | }
83 | if len(commits) == 0 {
84 | return
85 | }
86 | changelog.Changes = make(ChangeLogChanges, len(commits))
87 | changelog.Deb = deb
88 |
89 | for idx, c := range commits {
90 | msg := processMsg(c.Message)
91 | if useConventionalCommits {
92 | cc = conventional_commit.ParseConventionalCommit(msg)
93 | }
94 | changelog.Changes[idx] = &ChangeLogChange{
95 | Commit: c.Hash.String(),
96 | Note: msg,
97 | Committer: &User{
98 | Name: c.Committer.Name,
99 | Email: c.Committer.Email,
100 | },
101 | Author: &User{
102 | Name: c.Author.Name,
103 | Email: c.Author.Email,
104 | },
105 | ConventionalCommit: cc,
106 | }
107 | }
108 |
109 | return changelog
110 | }
111 |
--------------------------------------------------------------------------------
/add_test.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "log"
5 | "testing"
6 |
7 | "github.com/Masterminds/semver/v3"
8 | "github.com/go-git/go-git/v5"
9 | "github.com/smartystreets/goconvey/convey"
10 | )
11 |
12 | func TestAddEntry(t *testing.T) {
13 | t.Run("lightweight tag", func(t *testing.T) {
14 | testAddEntry(t, "./testdata/add-repo", "./testdata/gold-add-changelog.yml")
15 | })
16 | t.Run("annotated tag", func(t *testing.T) {
17 | testAddEntry(t, "./testdata/add-repo-annotated-tag", "./testdata/gold-add-changelog-with-annotated-commit.yml")
18 | })
19 | }
20 |
21 | func testAddEntry(t *testing.T, repo, goldclePath string) {
22 | t.Helper()
23 | var (
24 | err error
25 | gitRepo *git.Repository
26 | testCLE ChangeLogEntries
27 | )
28 | goldcle, err := Parse(goldclePath)
29 | if err != nil {
30 | t.Fatal(err)
31 | }
32 |
33 | if gitRepo, err = GitRepo(repo, false); err != nil {
34 | log.Fatal(err)
35 | }
36 |
37 | testCLE, err = InitChangelog(gitRepo, "", nil, nil, true, false)
38 | if err != nil {
39 | t.Fatal(err)
40 | }
41 | version, _ := semver.NewVersion("1.0.0-b1+git.123")
42 | header := `
43 | This is a test
44 | ======
45 |
46 | header entry
47 | `
48 | testCLE, err = AddEntry(gitRepo, version, "Dj Gilcrease", createNote(header, ""), nil, testCLE, true, false)
49 | if err != nil {
50 | t.Fatal(err)
51 | }
52 | if len(goldcle) != len(testCLE) {
53 | t.Fatal("differing results")
54 | }
55 |
56 | // Fix the date since AddEntry uses time.Now
57 | for i, e := range goldcle {
58 | testCLE[i].Date = e.Date
59 | }
60 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
61 | convey.So(testCLE, convey.ShouldResemble, goldcle)
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/chglog_test.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | func createNote(header, footer string) *ChangeLogNotes {
4 | if header == "" && footer == "" {
5 | return nil
6 | }
7 | ret := &ChangeLogNotes{}
8 | if header != "" {
9 | ret.Header = &header
10 | }
11 | if footer != "" {
12 | ret.Footer = &footer
13 | }
14 |
15 | return ret
16 | }
17 |
--------------------------------------------------------------------------------
/cmd/chglog/config.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/spf13/viper"
7 | )
8 |
9 | func setupConfig(cfgFile string) *viper.Viper {
10 | config := viper.New()
11 | config.SetEnvPrefix(pkgName)
12 | config.AutomaticEnv()
13 | config.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", ""))
14 | config.SetDefault("debug", false)
15 | config.SetConfigFile(cfgFile)
16 | _ = config.ReadInConfig()
17 | config.Set("app.name", pkgName)
18 | config.Set("app.version", version)
19 | config.Set("app.commit", commit)
20 |
21 | return config
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/chglog/main.go:
--------------------------------------------------------------------------------
1 | // Package main contains the main nfpm cli source code.
2 | package main
3 |
4 | import (
5 | "fmt"
6 | "os"
7 | "path"
8 |
9 | "github.com/goreleaser/chglog/pkg/commands"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | // nolint: gochecknoglobals, gocritic
14 | var (
15 | pkgName = "chglog"
16 | version = "v0.0.0"
17 | commit = "local"
18 | )
19 |
20 | func main() {
21 | cmdRoot := &cobra.Command{
22 | Use: pkgName,
23 | Short: "Changelog generator",
24 | SilenceUsage: true,
25 | }
26 | cwd, _ := os.Getwd()
27 | cfgFile := path.Join(cwd, fmt.Sprintf(".%s.yml", pkgName))
28 | config := setupConfig(cfgFile)
29 |
30 | cmdRoot.PersistentFlags().StringVarP(
31 | &cfgFile,
32 | "config-file",
33 | "c",
34 | cfgFile,
35 | ``)
36 | _ = config.BindPFlag("config-file", cmdRoot.PersistentFlags().Lookup("config-file"))
37 |
38 | cmdRoot.PersistentPreRunE = func(*cobra.Command, []string) error {
39 | if cfgFile == config.GetString("config-file") {
40 | return nil
41 | }
42 |
43 | config.SetConfigFile(cfgFile)
44 | config.Set("config-file", cfgFile)
45 | return config.ReadInConfig()
46 | }
47 |
48 | cmdRoot.AddCommand(
49 | commands.AddCmd(config),
50 | commands.InitCmd(config),
51 | commands.VersionCmd(config),
52 | commands.ConfigCmd(config),
53 | commands.FormatCmd(config),
54 | )
55 |
56 | if err := cmdRoot.Execute(); err != nil {
57 | // nolint: gomnd, gocritic
58 | os.Exit(127)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/files.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "gopkg.in/yaml.v3"
8 | )
9 |
10 | // Parse parse a changelog.yml into ChangeLogEntries.
11 | func Parse(file string) (entries ChangeLogEntries, err error) {
12 | var body []byte
13 | body, err = os.ReadFile(file) // nolint: gosec,gocritic
14 | switch {
15 | case os.IsNotExist(err):
16 | return make(ChangeLogEntries, 0), nil
17 | case err != nil:
18 | return nil, fmt.Errorf("error parsing %s: %w", file, err)
19 | }
20 |
21 | if err = yaml.Unmarshal(body, &entries); err != nil {
22 | return entries, fmt.Errorf("error parsing %s: %w", file, err)
23 | }
24 |
25 | return entries, nil
26 | }
27 |
28 | // Save save ChangeLogEntries to a yml file.
29 | func (c *ChangeLogEntries) Save(file string) (err error) {
30 | data, _ := yaml.Marshal(c)
31 | // nolint: gosec,gocritic
32 | return os.WriteFile(file, data, 0o644)
33 | }
34 |
--------------------------------------------------------------------------------
/format.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "text/template"
7 | )
8 |
9 | // FormatChangelog format pkgLogs from a text/template.
10 | func FormatChangelog(pkgLogs *PackageChangeLog, tpl *template.Template) (string, error) {
11 | var data bytes.Buffer
12 | if err := tpl.Execute(&data, pkgLogs); err != nil {
13 | return data.String(), fmt.Errorf("error formatting: %w", err)
14 | }
15 |
16 | return data.String(), nil
17 | }
18 |
--------------------------------------------------------------------------------
/format_test.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "os"
7 | "testing"
8 |
9 | "github.com/go-git/go-git/v5"
10 | "github.com/google/go-cmp/cmp"
11 | )
12 |
13 | // nolint: gochecknoglobals,gocritic
14 | var formats = map[string]string{"rpm": rpmTpl, "deb": debTpl, "release": releaseTpl, "repo": repoTpl}
15 |
16 | func TestFormatChangelog(t *testing.T) {
17 | var (
18 | err error
19 | gitRepo *git.Repository
20 | testCLE ChangeLogEntries
21 | )
22 | t.Parallel()
23 | if gitRepo, err = GitRepo("./testdata/init-repo", false); err != nil {
24 | log.Fatal(err)
25 | }
26 |
27 | if testCLE, err = InitChangelog(gitRepo, "", nil, nil, true, false); err != nil {
28 | t.Error(err)
29 |
30 | return
31 | }
32 |
33 | for tmplType, tmplData := range formats {
34 | tmplData := tmplData
35 | pkg := PackageChangeLog{fmt.Sprintf("TestFormatChangelog-%s", tmplType), testCLE}
36 | t.Run(tmplType, func(t *testing.T) {
37 | t.Parallel()
38 | accept(t, tmplData, pkg)
39 | })
40 | }
41 | }
42 |
43 | func accept(t *testing.T, tmplData string, pkg PackageChangeLog) {
44 | t.Helper()
45 |
46 | tpl, err := LoadTemplateData(tmplData)
47 | if err != nil {
48 | t.Error(err)
49 |
50 | return
51 | }
52 |
53 | testdata, err := FormatChangelog(&pkg, tpl)
54 | if err != nil {
55 | t.Error(err)
56 |
57 | return
58 | }
59 |
60 | golddata, _ := os.ReadFile(fmt.Sprintf("./testdata/%s", pkg.Name))
61 | if diff := cmp.Diff(string(golddata), testdata); diff != "" {
62 | t.Errorf("FormatChangelog mismatch (+got -want):\n%s", diff)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/git.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "strings"
7 |
8 | "github.com/go-git/go-git/v5"
9 | "github.com/go-git/go-git/v5/plumbing"
10 | "github.com/go-git/go-git/v5/plumbing/object"
11 | )
12 |
13 | var errReachedToCommit = errors.New("reached to commit")
14 |
15 | // GitRepo open a GitRepo to use to build the changelog from.
16 | func GitRepo(gitPath string, detectDotGit bool) (*git.Repository, error) {
17 | return git.PlainOpenWithOptions(gitPath, &git.PlainOpenOptions{
18 | DetectDotGit: detectDotGit,
19 | })
20 | }
21 |
22 | // GitHashFotTag return the git sha for a particular tag.
23 | func GitHashFotTag(gitRepo *git.Repository, tagName string) (hash plumbing.Hash, err error) {
24 | var ref *plumbing.Reference
25 | ref, err = gitRepo.Tag(tagName)
26 | if errors.Is(err, git.ErrTagNotFound) && !strings.HasPrefix(tagName, "v") {
27 | ref, err = gitRepo.Tag("v" + tagName)
28 | }
29 | if err != nil {
30 | return plumbing.ZeroHash, fmt.Errorf("error getting commit for tag %s: %w", tagName, err)
31 | }
32 |
33 | // If the tag is annotated, we need to grab the actual commit hash.
34 | obj, err := gitRepo.TagObject(ref.Hash())
35 | if err != nil {
36 | // Not an annotated tag
37 | return ref.Hash(), nil
38 | }
39 |
40 | commit, err := obj.Commit()
41 | if err != nil {
42 | return plumbing.ZeroHash, fmt.Errorf("error getting commit for tag %s: %w", tagName, err)
43 | }
44 |
45 | return commit.Hash, nil
46 | }
47 |
48 | // CommitsBetween return the list of commits between two commits.
49 | func CommitsBetween(gitRepo *git.Repository, start, end plumbing.Hash, excludeMergeCommits bool) (commits []*object.Commit, err error) {
50 | var commitIter object.CommitIter
51 | if commitIter, err = gitRepo.Log(&git.LogOptions{
52 | From: start,
53 | Order: git.LogOrderCommitterTime,
54 | }); err != nil {
55 | return nil, fmt.Errorf("error getting commits between %v & %v: %w", start, end, err)
56 | }
57 | defer commitIter.Close()
58 | err = commitIter.ForEach(func(c *object.Commit) error {
59 | // If no previous tag is found then from and to are equal
60 | if end == start {
61 | return nil
62 | }
63 | if c.Hash == end {
64 | return errReachedToCommit
65 | }
66 | if excludeMergeCommits && len(c.ParentHashes) > 1 {
67 | return nil
68 | }
69 |
70 | commits = append(commits, c)
71 |
72 | return nil
73 | })
74 |
75 | if err != nil && !errors.Is(err, errReachedToCommit) {
76 | return nil, fmt.Errorf("error getting commits between %v & %v: %w", start, end, err)
77 | }
78 |
79 | return commits, nil
80 | }
81 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/goreleaser/chglog
2 |
3 | go 1.23.0
4 |
5 | require (
6 | github.com/Masterminds/semver/v3 v3.3.1
7 | github.com/Masterminds/sprig/v3 v3.3.0
8 | github.com/go-git/go-billy/v5 v5.6.2
9 | github.com/go-git/go-git/v5 v5.16.1
10 | github.com/google/go-cmp v0.7.0
11 | github.com/smartystreets/goconvey v1.8.1
12 | github.com/spf13/cobra v1.9.1
13 | github.com/spf13/viper v1.20.1
14 | gitlab.com/digitalxero/go-conventional-commit v1.0.7
15 | gopkg.in/yaml.v3 v3.0.1
16 | )
17 |
18 | require (
19 | dario.cat/mergo v1.0.1 // indirect
20 | github.com/Masterminds/goutils v1.1.1 // indirect
21 | github.com/Microsoft/go-winio v0.6.2 // indirect
22 | github.com/ProtonMail/go-crypto v1.1.6 // indirect
23 | github.com/cloudflare/circl v1.6.1 // indirect
24 | github.com/cyphar/filepath-securejoin v0.4.1 // indirect
25 | github.com/emirpasic/gods v1.18.1 // indirect
26 | github.com/fsnotify/fsnotify v1.8.0 // indirect
27 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
28 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
29 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
30 | github.com/google/uuid v1.6.0 // indirect
31 | github.com/gopherjs/gopherjs v1.17.2 // indirect
32 | github.com/huandu/xstrings v1.5.0 // indirect
33 | github.com/inconshreveable/mousetrap v1.1.0 // indirect
34 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
35 | github.com/jtolds/gls v4.20.0+incompatible // indirect
36 | github.com/kevinburke/ssh_config v1.2.0 // indirect
37 | github.com/mitchellh/copystructure v1.2.0 // indirect
38 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
39 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect
40 | github.com/pjbgf/sha1cd v0.3.2 // indirect
41 | github.com/sagikazarmark/locafero v0.7.0 // indirect
42 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
43 | github.com/shopspring/decimal v1.4.0 // indirect
44 | github.com/skeema/knownhosts v1.3.1 // indirect
45 | github.com/smarty/assertions v1.15.0 // indirect
46 | github.com/sourcegraph/conc v0.3.0 // indirect
47 | github.com/spf13/afero v1.12.0 // indirect
48 | github.com/spf13/cast v1.7.1 // indirect
49 | github.com/spf13/pflag v1.0.6 // indirect
50 | github.com/subosito/gotenv v1.6.0 // indirect
51 | github.com/xanzy/ssh-agent v0.3.3 // indirect
52 | go.uber.org/atomic v1.9.0 // indirect
53 | go.uber.org/multierr v1.9.0 // indirect
54 | golang.org/x/crypto v0.37.0 // indirect
55 | golang.org/x/net v0.39.0 // indirect
56 | golang.org/x/sys v0.32.0 // indirect
57 | golang.org/x/text v0.24.0 // indirect
58 | gopkg.in/warnings.v0 v0.1.2 // indirect
59 | )
60 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
2 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
4 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
5 | github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
6 | github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
7 | github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
8 | github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
9 | github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
10 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
11 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
12 | github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
13 | github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
14 | github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
15 | github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
16 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
17 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
18 | github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
19 | github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
20 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
21 | github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
22 | github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
23 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
25 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
26 | github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
27 | github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
28 | github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
29 | github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
30 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
31 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
32 | github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
33 | github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
34 | github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
35 | github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
36 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
37 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
38 | github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
39 | github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
40 | github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
41 | github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
42 | github.com/go-git/go-git/v5 v5.16.1 h1:TuxMBWNL7R05tXsUGi0kh1vi4tq0WfXNLlIrAkXG1k8=
43 | github.com/go-git/go-git/v5 v5.16.1/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
44 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
45 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
46 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
47 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
48 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
49 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
50 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
51 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
52 | github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
53 | github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
54 | github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
55 | github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
56 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
57 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
58 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
59 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
60 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
61 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
62 | github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
63 | github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
64 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
65 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
66 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
67 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
68 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
69 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
70 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
71 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
72 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
73 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
74 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
75 | github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
76 | github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
77 | github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
78 | github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
79 | github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
80 | github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
81 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
82 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
83 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
84 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
85 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
86 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
87 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
88 | github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
89 | github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
90 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
91 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
92 | github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
93 | github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
94 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
95 | github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
96 | github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
97 | github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
98 | github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
99 | github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
100 | github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
101 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
102 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
103 | github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
104 | github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
105 | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
106 | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
107 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
108 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
109 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
110 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
111 | github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
112 | github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
113 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
114 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
115 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
116 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
117 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
118 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
119 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
120 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
121 | github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
122 | github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
123 | gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
124 | gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
125 | go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
126 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
127 | go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
128 | go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
129 | golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
130 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
131 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
132 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
133 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
134 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
135 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
136 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
137 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
138 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
139 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
140 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
141 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
142 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
143 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
144 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
145 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
146 | golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
147 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
148 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
149 | golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
150 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
151 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
152 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
153 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
154 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
155 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
156 | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
157 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
158 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
159 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
160 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
161 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
162 |
--------------------------------------------------------------------------------
/init.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "sort"
7 |
8 | "github.com/Masterminds/semver/v3"
9 | "github.com/go-git/go-git/v5"
10 | "github.com/go-git/go-git/v5/plumbing"
11 | "github.com/go-git/go-git/v5/plumbing/object"
12 | )
13 |
14 | func versionsInRepo(gitRepo *git.Repository) (map[plumbing.Hash]*semver.Version, error) {
15 | tagRefs, err := gitRepo.Tags()
16 | if err != nil {
17 | return nil, err
18 | }
19 |
20 | defer tagRefs.Close()
21 |
22 | tags := make(map[plumbing.Hash]*semver.Version)
23 |
24 | err = tagRefs.ForEach(func(t *plumbing.Reference) error {
25 | var (
26 | version *semver.Version
27 | tag *object.Tag
28 | )
29 |
30 | tagName := t.Name().Short()
31 | hash := t.Hash()
32 |
33 | if version, err = semver.NewVersion(tagName); err != nil || version == nil {
34 | fmt.Fprintf(os.Stderr, "Warning: unable to parse version from tag: %s : %v\n", tagName, err)
35 | return nil
36 | }
37 |
38 | // If this is an annotated tag look up the hash of the commit and use that.
39 | if tag, err = gitRepo.TagObject(t.Hash()); err == nil {
40 | var c *object.Commit
41 |
42 | if c, err = tag.Commit(); err != nil {
43 | return fmt.Errorf("cannot dereference annotated tag: %s : %w", tagName, err)
44 | }
45 | hash = c.Hash
46 | }
47 |
48 | tags[hash] = version
49 |
50 | return nil
51 | })
52 | if err != nil {
53 | return nil, err
54 | }
55 |
56 | return tags, nil
57 | }
58 |
59 | func versionsOnBranch(gitRepo *git.Repository) (map[*semver.Version]plumbing.Hash, error) {
60 | repoVersions, err := versionsInRepo(gitRepo)
61 | if err != nil {
62 | return nil, err
63 | }
64 |
65 | refs, err := gitRepo.Log(&git.LogOptions{})
66 | if err != nil {
67 | return nil, err
68 | }
69 |
70 | defer refs.Close()
71 |
72 | versions := make(map[*semver.Version]plumbing.Hash)
73 |
74 | err = refs.ForEach(func(c *object.Commit) error {
75 | if v, ok := repoVersions[c.Hash]; ok {
76 | versions[v] = c.Hash
77 | }
78 | return nil
79 | })
80 |
81 | return versions, err
82 | }
83 |
84 | // InitChangelog create a new ChangeLogEntries from a git repo.
85 | func InitChangelog(gitRepo *git.Repository, owner string, notes *ChangeLogNotes, deb *ChangelogDeb, useConventionalCommits bool, excludeMergeCommits bool) (cle ChangeLogEntries, err error) {
86 | var start, end plumbing.Hash
87 |
88 | cle = make(ChangeLogEntries, 0)
89 | end = plumbing.ZeroHash
90 |
91 | versions, err := versionsOnBranch(gitRepo)
92 | if err != nil {
93 | return nil, err
94 | }
95 |
96 | tags := make([]*semver.Version, 0, len(versions))
97 | for v := range versions {
98 | tags = append(tags, v)
99 | }
100 |
101 | sort.Slice(tags, func(i, j int) bool { return tags[i].LessThan(tags[j]) })
102 |
103 | for _, version := range tags {
104 | var (
105 | commits []*object.Commit
106 | commitObject *object.Commit
107 | )
108 |
109 | if version.Prerelease() != "" {
110 | // Do not need change logs for pre-release entries
111 | continue
112 | }
113 |
114 | start = versions[version]
115 |
116 | if commitObject, err = gitRepo.CommitObject(start); err != nil {
117 | return nil, fmt.Errorf("unable to fetch commit from tag %v: %w", version.Original(), err)
118 | }
119 |
120 | if owner == "" {
121 | owner = fmt.Sprintf("%s <%s>", commitObject.Committer.Name, commitObject.Committer.Email)
122 | }
123 | if commits, err = CommitsBetween(gitRepo, start, end, excludeMergeCommits); err != nil {
124 | return nil, fmt.Errorf("unable to find commits between %s & %s: %w", end, start, err)
125 | }
126 |
127 | changelog := CreateEntry(commitObject.Committer.When, version, owner, notes, deb, commits, useConventionalCommits)
128 | cle = append(cle, changelog)
129 | end = start
130 | }
131 |
132 | sort.Sort(sort.Reverse(cle))
133 |
134 | return cle, nil
135 | }
136 |
--------------------------------------------------------------------------------
/init_test.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "log"
5 | "testing"
6 |
7 | "github.com/go-git/go-git/v5"
8 | "github.com/smartystreets/goconvey/convey"
9 | )
10 |
11 | func TestInitChangelog(t *testing.T) {
12 | var (
13 | err error
14 | gitRepo *git.Repository
15 | testCLE ChangeLogEntries
16 | )
17 |
18 | goldcle, err := Parse("./testdata/gold-init-changelog.yml")
19 | if err != nil {
20 | t.Fatal(err)
21 | }
22 | if gitRepo, err = GitRepo("./testdata/init-repo", false); err != nil {
23 | log.Fatal(err)
24 | }
25 |
26 | testCLE, err = InitChangelog(gitRepo, "", nil, nil, true, false)
27 | if err != nil {
28 | t.Fatal(err)
29 | }
30 | if len(goldcle) != len(testCLE) {
31 | t.Fatal("differing results")
32 | }
33 |
34 | // Fix the date since AddEntry uses time.Now
35 | for i, e := range goldcle {
36 | testCLE[i].Date = e.Date
37 | }
38 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
39 | convey.So(testCLE, convey.ShouldResemble, goldcle)
40 | })
41 | }
42 |
43 | func TestInitChangelogWithoutMergeCommits(t *testing.T) {
44 | var (
45 | err error
46 | gitRepo *git.Repository
47 | testCLE ChangeLogEntries
48 | )
49 |
50 | goldcle, err := Parse("./testdata/gold-init-changelog-without-merge-commit.yml")
51 | if err != nil {
52 | t.Fatal(err)
53 | }
54 | if gitRepo, err = GitRepo("./testdata/init-repo-with-merge-commit", false); err != nil {
55 | log.Fatal(err)
56 | }
57 |
58 | testCLE, err = InitChangelog(gitRepo, "", nil, nil, true, true)
59 | if err != nil {
60 | t.Fatal(err)
61 | }
62 | if len(goldcle) != len(testCLE) {
63 | t.Fatal("differing results")
64 | }
65 |
66 | // Fix the date since AddEntry uses time.Now
67 | for i, e := range goldcle {
68 | testCLE[i].Date = e.Date
69 | }
70 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
71 | convey.So(testCLE, convey.ShouldResemble, goldcle)
72 | })
73 | }
74 |
75 | func TestInitChangelogWithMergeCommits(t *testing.T) {
76 | var (
77 | err error
78 | gitRepo *git.Repository
79 | testCLE ChangeLogEntries
80 | )
81 |
82 | goldcle, err := Parse("./testdata/gold-init-changelog-with-merge-commit.yml")
83 | if err != nil {
84 | t.Fatal(err)
85 | }
86 | if gitRepo, err = GitRepo("./testdata/init-repo-with-merge-commit", false); err != nil {
87 | log.Fatal(err)
88 | }
89 |
90 | testCLE, err = InitChangelog(gitRepo, "", nil, nil, true, false)
91 | if err != nil {
92 | t.Fatal(err)
93 | }
94 | if len(goldcle) != len(testCLE) {
95 | t.Fatal("differing results")
96 | }
97 |
98 | // Fix the date since AddEntry uses time.Now
99 | for i, e := range goldcle {
100 | testCLE[i].Date = e.Date
101 | }
102 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
103 | convey.So(testCLE, convey.ShouldResemble, goldcle)
104 | })
105 | }
106 |
--------------------------------------------------------------------------------
/order_test.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "os"
7 | "testing"
8 | "time"
9 |
10 | "github.com/go-git/go-billy/v5"
11 | "github.com/go-git/go-billy/v5/memfs"
12 | "github.com/go-git/go-git/v5"
13 | "github.com/go-git/go-git/v5/plumbing"
14 | "github.com/go-git/go-git/v5/plumbing/object"
15 | "github.com/go-git/go-git/v5/storage/memory"
16 | "github.com/smartystreets/goconvey/convey"
17 | )
18 |
19 | type testRepo struct {
20 | Git *git.Repository
21 | Source *git.Worktree
22 | seqno int
23 | }
24 |
25 | func newTestRepo() *testRepo {
26 | var (
27 | repo *git.Repository
28 | tree *git.Worktree
29 | err error
30 | )
31 |
32 | fs := memfs.New()
33 |
34 | if repo, err = git.Init(memory.NewStorage(), fs); err != nil {
35 | log.Fatal(err)
36 | }
37 |
38 | if tree, err = repo.Worktree(); err != nil {
39 | log.Fatal(err)
40 | }
41 |
42 | return &testRepo{
43 | Git: repo,
44 | Source: tree,
45 | }
46 | }
47 |
48 | // modifyAndCommit creates the file if it does not exist, appends a
49 | // change, commits the file, and returns the hash of the commit.
50 | func (r *testRepo) modifyAndCommit(opts *git.CommitOptions) plumbing.Hash {
51 | filename := "file"
52 | var (
53 | hash plumbing.Hash
54 | err error
55 | file billy.File
56 | )
57 |
58 | if file, err = r.Source.Filesystem.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666); err != nil {
59 | log.Fatal(err)
60 | }
61 |
62 | if _, err = fmt.Fprintf(file, "commit %d\n", r.seqno); err != nil {
63 | log.Fatal(err)
64 | }
65 | _ = file.Close()
66 |
67 | if _, err = r.Source.Add(filename); err != nil {
68 | log.Fatal(err)
69 | }
70 |
71 | if hash, err = r.Source.Commit(fmt.Sprintf("commit %d", r.seqno), opts); err != nil {
72 | log.Fatal(err)
73 | }
74 |
75 | r.seqno++
76 |
77 | return hash
78 | }
79 |
80 | func defSignature() *object.Signature {
81 | tm, err := time.Parse(time.RFC3339, "2000-01-01T12:00:00+07:00")
82 | if err != nil {
83 | tm = time.Now()
84 | }
85 |
86 | return &object.Signature{
87 | Name: "John Doe",
88 | Email: "John.Doe@example.com",
89 | When: tm,
90 | }
91 | }
92 |
93 | func defCommitOptions() *git.CommitOptions {
94 | return &git.CommitOptions{
95 | Author: defSignature(),
96 | Committer: defSignature(),
97 | }
98 | }
99 |
100 | func TestOrderChangelog(t *testing.T) {
101 | goldCLE, err := Parse("./testdata/gold-order-changelog.yml")
102 | if err != nil {
103 | t.Fatal(err)
104 | }
105 |
106 | repo := newTestRepo()
107 |
108 | for i := 0; i <= 10; i++ {
109 | hash := repo.modifyAndCommit(defCommitOptions())
110 |
111 | if _, err = repo.Git.CreateTag(fmt.Sprintf("v0.%d.0", i), hash, nil); err != nil {
112 | t.Fatal(err)
113 | }
114 | }
115 |
116 | testCLE, err := InitChangelog(repo.Git, "", nil, nil, false, false)
117 | if err != nil {
118 | t.Fatal(err)
119 | }
120 |
121 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
122 | convey.So(testCLE, convey.ShouldResemble, goldCLE)
123 | })
124 | }
125 |
126 | func TestOffBranchTags(t *testing.T) {
127 | cle, err := Parse("./testdata/gold-order-changelog.yml")
128 | if err != nil {
129 | t.Fatal(err)
130 | }
131 |
132 | // remove odd entries
133 |
134 | goldCLE := make(ChangeLogEntries, len(cle)/2+1)
135 | for i := range cle {
136 | if i%2 == 0 {
137 | goldCLE[i/2] = cle[i]
138 | }
139 | }
140 |
141 | repo := newTestRepo()
142 | tree, err := repo.Git.Worktree()
143 | if err != nil {
144 | t.Fatal(err)
145 | }
146 |
147 | // initial commit on master
148 |
149 | hash := repo.modifyAndCommit(defCommitOptions())
150 | if _, err = repo.Git.CreateTag("v0.0.0", hash, nil); err != nil {
151 | t.Fatal(err)
152 | }
153 |
154 | // second commit on develop
155 |
156 | err = tree.Checkout(&git.CheckoutOptions{
157 | Branch: plumbing.NewBranchReferenceName("develop"),
158 | Create: true,
159 | })
160 | if err != nil {
161 | t.Fatal(err)
162 | }
163 |
164 | hash = repo.modifyAndCommit(defCommitOptions())
165 | if _, err = repo.Git.CreateTag("v0.1.0", hash, nil); err != nil {
166 | t.Fatal(err)
167 | }
168 |
169 | // alternate branches for commits
170 |
171 | master := plumbing.NewBranchReferenceName("master")
172 | develop := plumbing.NewBranchReferenceName("develop")
173 |
174 | for i := 2; i <= 10; i++ {
175 | branch := master
176 | if i%2 != 0 {
177 | branch = develop
178 | }
179 |
180 | t.Logf("%v branch=%v\n", i, branch)
181 |
182 | err = tree.Checkout(&git.CheckoutOptions{Branch: branch})
183 | if err != nil {
184 | t.Fatal(err)
185 | }
186 |
187 | hash := repo.modifyAndCommit(defCommitOptions())
188 |
189 | if _, err = repo.Git.CreateTag(fmt.Sprintf("v0.%d.0", i), hash, nil); err != nil {
190 | t.Fatal(err)
191 | }
192 | }
193 |
194 | testCLE, err := InitChangelog(repo.Git, "", nil, nil, false, false)
195 | if err != nil {
196 | t.Fatal(err)
197 | }
198 |
199 | // zero all commit hashes (don't care about these)
200 |
201 | for i := range testCLE {
202 | for j := range testCLE[i].Changes {
203 | testCLE[i].Changes[j].Commit = ""
204 | }
205 | }
206 | for i := range goldCLE {
207 | for j := range goldCLE[i].Changes {
208 | goldCLE[i].Changes[j].Commit = ""
209 | }
210 | }
211 |
212 | convey.Convey("Generated entry should be the same as the golden entry", t, func() {
213 | convey.So(testCLE, convey.ShouldResemble, goldCLE)
214 | })
215 | }
216 |
217 | func TestSemverTag(t *testing.T) {
218 | repo := newTestRepo()
219 | tag := "1.0.0"
220 |
221 | convey.Convey("Semver tags should be parsed", t, func() {
222 | hash := repo.modifyAndCommit(defCommitOptions())
223 |
224 | if _, err := repo.Git.CreateTag(tag, hash, nil); err != nil {
225 | t.Fatal(err)
226 | }
227 |
228 | cle, err := InitChangelog(repo.Git, "", nil, nil, false, false)
229 | if err != nil {
230 | t.Fatal(err)
231 | }
232 |
233 | convey.So(cle, convey.ShouldHaveLength, 1)
234 | convey.So(cle[0].Semver, convey.ShouldEqual, tag)
235 | })
236 |
237 | convey.Convey("Not Semver tags should be ignored", t, func() {
238 | hash := repo.modifyAndCommit(defCommitOptions())
239 |
240 | if _, err := repo.Git.CreateTag("text", hash, nil); err != nil {
241 | t.Fatal(err)
242 | }
243 |
244 | cle, err := InitChangelog(repo.Git, "", nil, nil, false, false)
245 | if err != nil {
246 | t.Fatal(err)
247 | }
248 |
249 | convey.So(cle, convey.ShouldHaveLength, 1)
250 | convey.So(cle[0].Semver, convey.ShouldEqual, tag)
251 | })
252 | }
253 |
--------------------------------------------------------------------------------
/pkg/commands/add.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 |
9 | "github.com/Masterminds/semver/v3"
10 | "github.com/go-git/go-git/v5"
11 | "github.com/spf13/cobra"
12 | "github.com/spf13/viper"
13 |
14 | "github.com/goreleaser/chglog"
15 | )
16 |
17 | // nolint: gocognit, funlen, gocritic
18 | func AddCmd(config *viper.Viper) (cmd *cobra.Command) {
19 | var (
20 | input,
21 | output,
22 | version,
23 | header,
24 | footer,
25 | headerFile,
26 | footerFile string
27 | semv *semver.Version
28 | )
29 | cmd, config = commonFlags(&cobra.Command{
30 | Use: "add [PATH]",
31 | Short: "add new changelog entry for [PATH]",
32 | Args: cobra.MaximumNArgs(1),
33 | }, config)
34 |
35 | cmd.Flags().StringVarP(
36 | &output,
37 | "output",
38 | "o",
39 | "changelog.yml",
40 | "file to save the updated changelog to")
41 | cmd.Flags().StringVarP(
42 | &input,
43 | "input",
44 | "i",
45 | "changelog.yml",
46 | "starting changelog.yml file")
47 | cmd.Flags().StringVarP(
48 | &version,
49 | "version",
50 | "",
51 | "",
52 | "Version for this entry")
53 | cmd.Flags().StringVarP(
54 | &header,
55 | "header",
56 | "",
57 | "",
58 | "Header note for this entry")
59 | cmd.Flags().StringVarP(
60 | &footer,
61 | "footer",
62 | "",
63 | "",
64 | "Footer note for this entry")
65 | cmd.Flags().StringVarP(
66 | &headerFile,
67 | "header-file",
68 | "",
69 | "",
70 | "Header note for this entry")
71 | cmd.Flags().StringVarP(
72 | &footerFile,
73 | "footer-file",
74 | "",
75 | "",
76 | "Footer note for this entry")
77 |
78 | cmd.RunE = func(_ *cobra.Command, args []string) (err error) {
79 | var (
80 | repoPath string
81 | gitRepo *git.Repository
82 | entries chglog.ChangeLogEntries
83 | notes *chglog.ChangeLogNotes
84 | data []byte
85 | )
86 |
87 | if repoPath, err = os.Getwd(); err != nil {
88 | return fmt.Errorf("error adding entry: %w", err)
89 | }
90 |
91 | if len(args) == 1 {
92 | if repoPath, err = filepath.Abs(args[0]); err != nil {
93 | return fmt.Errorf("error adding entry: %w", err)
94 | }
95 | }
96 |
97 | if entries, err = chglog.Parse(input); err != nil {
98 | return fmt.Errorf("error adding entry: %w", err)
99 | }
100 |
101 | if gitRepo, err = chglog.GitRepo(repoPath, true); err != nil {
102 | return fmt.Errorf("error adding entry: %w", err)
103 | }
104 |
105 | if headerFile != "" {
106 | // nolint: gosec, gocritic
107 | if data, err = os.ReadFile(headerFile); err != nil {
108 | return fmt.Errorf("error adding entry: %w", err)
109 | }
110 | header = string(data)
111 | }
112 |
113 | if footerFile != "" {
114 | // nolint: gosec, gocritic
115 | if data, err = os.ReadFile(footerFile); err != nil {
116 | return fmt.Errorf("error adding entry: %w", err)
117 | }
118 | footer = string(data)
119 | }
120 |
121 | if header != "" || footer != "" {
122 | notes = &chglog.ChangeLogNotes{}
123 | if header != "" {
124 | header = strings.ReplaceAll(header, "\\n", "\n")
125 | notes.Header = &header
126 | }
127 | if footer != "" {
128 | notes.Footer = &footer
129 | }
130 | }
131 |
132 | if semv, err = semver.NewVersion(version); err != nil {
133 | return fmt.Errorf("error adding entry: %w", err)
134 | }
135 |
136 | if entries, err = chglog.AddEntry(gitRepo, semv, config.GetString("owner"), notes, getDeb(config), entries, config.GetBool("conventional-commits"), config.GetBool("exclude-merge-commits")); err != nil {
137 | return fmt.Errorf("error adding entry: %w", err)
138 | }
139 |
140 | if len(entries) == 0 {
141 | return fmt.Errorf("%w: %s", ErrNoTags, repoPath)
142 | }
143 |
144 | return entries.Save(output)
145 | }
146 |
147 | return cmd
148 | }
149 |
--------------------------------------------------------------------------------
/pkg/commands/commands.go:
--------------------------------------------------------------------------------
1 | // Package commands contain the commands for the cli
2 | package commands
3 |
4 | import (
5 | "github.com/goreleaser/chglog"
6 | "github.com/spf13/cobra"
7 | "github.com/spf13/viper"
8 | )
9 |
10 | func commonFlags(cmd *cobra.Command, config *viper.Viper) (*cobra.Command, *viper.Viper) {
11 | var (
12 | urgency, owner string
13 | distribution []string
14 | conventionalCommits bool
15 | excludeMergeCommits bool
16 | )
17 | cmd.Flags().BoolVarP(
18 | &conventionalCommits,
19 | "conventional-commits",
20 | "",
21 | conventionalCommits,
22 | `Use conventional commits parsing`)
23 | cmd.Flags().BoolVarP(
24 | &excludeMergeCommits,
25 | "exclude-merge-commits",
26 | "",
27 | excludeMergeCommits,
28 | `Exclude merge commits`)
29 | cmd.Flags().StringVarP(
30 | &owner,
31 | "owner",
32 | "",
33 | owner,
34 | `set package owner`)
35 | cmd.Flags().StringVarP(
36 | &urgency,
37 | "deb-urgency",
38 | "",
39 | urgency,
40 | `set debian urgency for`)
41 | cmd.Flags().StringSliceVarP(
42 | &distribution,
43 | "deb-distribution",
44 | "",
45 | distribution,
46 | `set debian distributions for`)
47 |
48 | cmd.PreRunE = func(*cobra.Command, []string) error {
49 | if err := config.BindPFlag("conventional-commits", cmd.Flags().Lookup("conventional-commits")); err != nil {
50 | return err
51 | }
52 | if err := config.BindPFlag("exclude-merge-commits", cmd.Flags().Lookup("exclude-merge-commits")); err != nil {
53 | return err
54 | }
55 | if err := config.BindPFlag("owner", cmd.Flags().Lookup("owner")); err != nil {
56 | return err
57 | }
58 | if err := config.BindPFlag("deb.urgency", cmd.Flags().Lookup("deb-urgency")); err != nil {
59 | return err
60 | }
61 | return config.BindPFlag("deb.distribution", cmd.Flags().Lookup("deb-distribution"))
62 | }
63 |
64 | return cmd, config
65 | }
66 |
67 | func getDeb(config *viper.Viper) (deb *chglog.ChangelogDeb) {
68 | var (
69 | urgency string
70 | distributions []string
71 | )
72 | urgency = config.GetString("deb.urgency")
73 | distributions = config.GetStringSlice("deb.distribution")
74 | if len(distributions) > 0 && urgency != "" {
75 | deb = &chglog.ChangelogDeb{
76 | Urgency: urgency,
77 | Distributions: distributions,
78 | }
79 | }
80 |
81 | return deb
82 | }
83 |
--------------------------------------------------------------------------------
/pkg/commands/config.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | "github.com/spf13/viper"
6 | )
7 |
8 | func ConfigCmd(config *viper.Viper) (cmd *cobra.Command) {
9 | var pkg string
10 | cmd = &cobra.Command{
11 | Use: "config",
12 | Short: "save config data",
13 | }
14 |
15 | cmd, config = commonFlags(cmd, config)
16 | cmd.Flags().StringVarP(
17 | &pkg,
18 | "package-name",
19 | "p",
20 | "",
21 | "package name to use in formatting")
22 |
23 | cmd.PreRunE = func(cmd *cobra.Command, _ []string) error {
24 | return config.BindPFlag("package-name", cmd.Flags().Lookup("package-name"))
25 | }
26 |
27 | cmd.RunE = func(*cobra.Command, []string) error {
28 | // Filter some config settings
29 | cfgMap := config.AllSettings()
30 | delete(cfgMap, "app")
31 | delete(cfgMap, "config-file")
32 | v := viper.New()
33 | if err := v.MergeConfigMap(cfgMap); err != nil {
34 | return err
35 | }
36 |
37 | return v.WriteConfigAs(config.GetString("config-file"))
38 | }
39 |
40 | return cmd
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/commands/format.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os"
7 | "strings"
8 | "text/template"
9 |
10 | "github.com/goreleaser/chglog"
11 | "github.com/spf13/cobra"
12 | "github.com/spf13/viper"
13 | )
14 |
15 | // ErrTemplateFlags occurs when the user tries to use both --template and --template-file flags.
16 | var ErrTemplateFlags = errors.New("--template and --template-file are mutually exclusive")
17 |
18 | // nolint: funlen, gocritic
19 | func FormatCmd(config *viper.Viper) (cmd *cobra.Command) {
20 | var input,
21 | output,
22 | pkg,
23 | templateName,
24 | templateFile string
25 | cmd = &cobra.Command{
26 | Use: "format",
27 | Short: "format entries to a specific template",
28 | }
29 | cmd.Flags().StringVarP(
30 | &output,
31 | "output",
32 | "o",
33 | "-",
34 | "file to save the output to (- is stdout)")
35 | cmd.Flags().StringVarP(
36 | &input,
37 | "input",
38 | "i",
39 | "changelog.yml",
40 | "changelog.yml file to use as the basis for formatting")
41 | cmd.Flags().StringVarP(
42 | &pkg,
43 | "package-name",
44 | "p",
45 | "",
46 | "package name to use in formatting")
47 |
48 | cmd.Flags().StringVarP(
49 | &templateName,
50 | "template",
51 | "t",
52 | "",
53 | "builtin template to use ('deb', 'rpm', 'release', 'repo')")
54 | cmd.Flags().StringVarP(
55 | &templateFile,
56 | "template-file",
57 | "",
58 | "",
59 | "custom template file to use")
60 |
61 | cmd.PreRunE = func(cmd *cobra.Command, _ []string) error {
62 | return config.BindPFlag("package-name", cmd.Flags().Lookup("package-name"))
63 | }
64 |
65 | cmd.RunE = func(*cobra.Command, []string) (err error) {
66 | var (
67 | tpl *template.Template
68 | data []byte
69 | ret string
70 | fmtPackage = new(chglog.PackageChangeLog)
71 | )
72 | if templateName != "" && templateFile != "" {
73 | return ErrTemplateFlags
74 | }
75 |
76 | switch strings.ToLower(templateName) {
77 | case "deb":
78 | tpl, err = chglog.DebTemplate()
79 | case "rpm":
80 | tpl, err = chglog.RPMTemplate()
81 | case "release":
82 | tpl, err = chglog.ReleaseTemplate()
83 | case "repo":
84 | tpl, err = chglog.RepoTemplate()
85 | default:
86 | // nolint: gosec, gocritic
87 | if data, err = os.ReadFile(templateFile); err != nil {
88 | return fmt.Errorf("error formatting entries: %w", err)
89 | }
90 | tpl, err = chglog.LoadTemplateData(string(data))
91 | }
92 | if err != nil {
93 | return fmt.Errorf("error formatting entries: %w", err)
94 | }
95 |
96 | fmtPackage.Name = config.GetString("package-name")
97 |
98 | if fmtPackage.Entries, err = chglog.Parse(input); err != nil {
99 | return fmt.Errorf("error formatting entries: %w", err)
100 | }
101 |
102 | if ret, err = chglog.FormatChangelog(fmtPackage, tpl); err != nil {
103 | return fmt.Errorf("error formatting entries: %w", err)
104 | }
105 |
106 | if output == "-" {
107 | fmt.Println(ret)
108 |
109 | return
110 | }
111 |
112 | // nolint: gosec, gocritic
113 | return os.WriteFile(output, []byte(ret), 0o644)
114 | }
115 |
116 | return cmd
117 | }
118 |
--------------------------------------------------------------------------------
/pkg/commands/init.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/go-git/go-git/v5"
10 | "github.com/goreleaser/chglog"
11 | "github.com/spf13/cobra"
12 | "github.com/spf13/viper"
13 | )
14 |
15 | // ErrNoTags happens when a repository has no tags.
16 | var ErrNoTags = errors.New("no versioned releases found, check the output of `git tag`")
17 |
18 | func InitCmd(config *viper.Viper) (cmd *cobra.Command) {
19 | var output string
20 | cmd = &cobra.Command{
21 | Use: "init [PATH]",
22 | Short: "create a new changelog file for [PATH]",
23 | Args: cobra.MaximumNArgs(1),
24 | }
25 |
26 | cmd, config = commonFlags(cmd, config)
27 | cmd.Flags().StringVarP(
28 | &output,
29 | "output",
30 | "o",
31 | "changelog.yml",
32 | "file to save the new changelog to")
33 |
34 | cmd.RunE = func(_ *cobra.Command, args []string) (err error) {
35 | var (
36 | repoPath string
37 | gitRepo *git.Repository
38 | entries chglog.ChangeLogEntries
39 | )
40 | if repoPath, err = os.Getwd(); err != nil {
41 | return fmt.Errorf("error initialzing change log: %w", err)
42 | }
43 |
44 | if len(args) == 1 {
45 | if repoPath, err = filepath.Abs(args[0]); err != nil {
46 | return fmt.Errorf("error initialzing change log: %w", err)
47 | }
48 | }
49 |
50 | if gitRepo, err = chglog.GitRepo(repoPath, true); err != nil {
51 | return fmt.Errorf("error initialzing change log: %w", err)
52 | }
53 |
54 | if entries, err = chglog.InitChangelog(gitRepo, config.GetString("owner"), nil, getDeb(config), config.GetBool("conventional-commits"), config.GetBool("exclude-merge-commits")); err != nil {
55 | return fmt.Errorf("error initialzing change log: %w", err)
56 | }
57 |
58 | if len(entries) == 0 {
59 | return fmt.Errorf("%w: %s", ErrNoTags, repoPath)
60 | }
61 |
62 | if err := entries.Save(output); err != nil {
63 | return err
64 | }
65 |
66 | fmt.Println("created:", output)
67 | return nil
68 | }
69 |
70 | return cmd
71 | }
72 |
--------------------------------------------------------------------------------
/pkg/commands/version.go:
--------------------------------------------------------------------------------
1 | package commands
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/spf13/cobra"
7 | "github.com/spf13/viper"
8 | )
9 |
10 | func VersionCmd(config *viper.Viper) (cmd *cobra.Command) {
11 | cmd = &cobra.Command{
12 | Use: "version",
13 | Short: "display version info",
14 | }
15 | cmd.Run = func(*cobra.Command, []string) {
16 | version := fmt.Sprintf("%s %s", config.GetString("app.name"), config.GetString("app.version"))
17 | if config.GetBool("debug") {
18 | version = fmt.Sprintf("%s+%s", version, config.GetString("app.commit"))
19 | }
20 | fmt.Println(version)
21 | }
22 |
23 | return cmd
24 | }
25 |
--------------------------------------------------------------------------------
/templates.go:
--------------------------------------------------------------------------------
1 | package chglog
2 |
3 | import (
4 | "text/template"
5 |
6 | "github.com/Masterminds/sprig/v3"
7 | )
8 |
9 | const (
10 | rpmTpl = `
11 | {{- range .Entries }}{{$version := semver .Semver}}
12 | * {{ date_in_zone "Mon Jan 2 2006" .Date "UTC" }} {{ .Packager }} - {{ $version.Major }}.{{ $version.Minor }}.{{ $version.Patch }}{{if $version.Prerelease}}-{{ $version.Prerelease }}{{end}}
13 | {{- range .Changes }}{{$note := splitList "\n" .Note}}
14 | - {{ first $note }}{{ range $i,$n := (rest $note) }}{{if ne $n "\n"}} {{$n}}{{end}}
15 | {{end}}
16 | {{- end }}
17 | {{ end }}
18 | `
19 | debTpl = `{{- $name := .Name}}
20 | {{- range .Entries }}
21 | {{ $name }} ({{ .Semver }}){{if .Deb}} {{default "" (.Deb.Distributions | join " ")}}; urgency={{default "low" .Deb.Urgency}}{{end}}
22 | {{- range .Changes }}{{$note := splitList "\n" .Note}}
23 | * {{ first $note }}
24 | {{- range $i,$n := (rest $note) }}
25 | {{- if ne (trim $n) ""}}
26 | - {{$n}}{{end}}
27 | {{- end}}{{end}}
28 |
29 | -- {{ .Packager }} {{ date_in_zone "Mon, 02 Jan 2006 15:04:05 -0700" .Date "UTC" }}
30 | {{ end }}
31 | `
32 | releaseTpl = `
33 | Changelog
34 | =========
35 | {{- with (first .Entries)}}
36 | {{range .Changes }}{{$note := splitList "\n" .Note}}
37 | {{substr 0 8 .Commit}} {{ first $note }}{{end}}
38 | {{ end}}
39 | `
40 | repoTpl = `
41 | {{- range .Entries }}
42 | {{ .Semver }}
43 | =============
44 | {{ date_in_zone "2006-01-02" .Date "UTC" }}
45 | {{range .Changes }}{{$note := splitList "\n" .Note}}
46 | * {{ first $note }} ({{substr 0 8 .Commit}}){{end}}
47 | {{ end}}
48 | `
49 | )
50 |
51 | // LoadTemplateData load a template from string with all of the sprig.TxtFuncMap loaded.
52 | func LoadTemplateData(data string) (*template.Template, error) {
53 | return template.New("base").Funcs(sprig.TxtFuncMap()).Parse(data)
54 | }
55 |
56 | // DebTemplate load default debian template.
57 | func DebTemplate() (*template.Template, error) {
58 | return LoadTemplateData(debTpl)
59 | }
60 |
61 | // RPMTemplate load default RPM template.
62 | func RPMTemplate() (*template.Template, error) {
63 | return LoadTemplateData(rpmTpl)
64 | }
65 |
66 | // ReleaseTemplate load default release template.
67 | func ReleaseTemplate() (*template.Template, error) {
68 | return LoadTemplateData(releaseTpl)
69 | }
70 |
71 | // RepoTemplate load default repo template.
72 | func RepoTemplate() (*template.Template, error) {
73 | return LoadTemplateData(repoTpl)
74 | }
75 |
--------------------------------------------------------------------------------
/testdata/TestFormatChangelog-deb:
--------------------------------------------------------------------------------
1 |
2 | TestFormatChangelog-deb (0.0.1)
3 | * oops i forgot to use Conventional Commits style message
4 | - This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
5 | * feat: added file two feature
6 | - BREAKING CHANGE: this is a backwards incompatible change
7 | * feat: added the fileone feature
8 | - * This is a test repo
9 | - * so ya!
10 |
11 | -- Dj Gilcrease Fri, 18 Oct 2019 23:05:33 +0000
12 |
13 |
--------------------------------------------------------------------------------
/testdata/TestFormatChangelog-release:
--------------------------------------------------------------------------------
1 |
2 | Changelog
3 | =========
4 |
5 | 2c499787 oops i forgot to use Conventional Commits style message
6 | 3ec1e9a6 feat: added file two feature
7 | 2cc00abc feat: added the fileone feature
8 |
9 |
--------------------------------------------------------------------------------
/testdata/TestFormatChangelog-repo:
--------------------------------------------------------------------------------
1 |
2 | 0.0.1
3 | =============
4 | 2019-10-18
5 |
6 | * oops i forgot to use Conventional Commits style message (2c499787)
7 | * feat: added file two feature (3ec1e9a6)
8 | * feat: added the fileone feature (2cc00abc)
9 |
10 |
--------------------------------------------------------------------------------
/testdata/TestFormatChangelog-rpm:
--------------------------------------------------------------------------------
1 |
2 | * Fri Oct 18 2019 Dj Gilcrease - 0.0.1
3 | - oops i forgot to use Conventional Commits style message
4 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
5 |
6 | - feat: added file two feature
7 | BREAKING CHANGE: this is a backwards incompatible change
8 |
9 | - feat: added the fileone feature
10 | * This is a test repo
11 | * so ya!
12 |
13 |
14 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/master
2 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = true
5 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/09/5b7b431351080c1edfe7de73db893e6b59ddce:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/09/5b7b431351080c1edfe7de73db893e6b59ddce
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/2c/499787328348f09ae1e8f03757c6483b9a938a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/2c/499787328348f09ae1e8f03757c6483b9a938a
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/43/3581c28b23426dee2c498da28defa9f5bd4f63:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/43/3581c28b23426dee2c498da28defa9f5bd4f63
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/55/2682b593e1bea86425fd6d9520f2687b28487b:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/55/2682b593e1bea86425fd6d9520f2687b28487b
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/6f/59e5e770be445518775b22bbe25e89339b778b:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/6f/59e5e770be445518775b22bbe25e89339b778b
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/6f/6c178ef5f187bb7d4088a0415ac5a9ff0aef45:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/6f/6c178ef5f187bb7d4088a0415ac5a9ff0aef45
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/c2/b01f193085b4bc020ef62b93d9dc44d9eca7a4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/c2/b01f193085b4bc020ef62b93d9dc44d9eca7a4
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo-annotated-tag/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/refs/heads/master:
--------------------------------------------------------------------------------
1 | 095b7b431351080c1edfe7de73db893e6b59ddce
2 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/refs/tags/v0.0.1:
--------------------------------------------------------------------------------
1 | 2c499787328348f09ae1e8f03757c6483b9a938a
2 |
--------------------------------------------------------------------------------
/testdata/add-repo-annotated-tag/refs/tags/v0.0.2:
--------------------------------------------------------------------------------
1 | 552682b593e1bea86425fd6d9520f2687b28487b
2 |
--------------------------------------------------------------------------------
/testdata/add-repo/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/master
2 |
--------------------------------------------------------------------------------
/testdata/add-repo/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = true
5 |
--------------------------------------------------------------------------------
/testdata/add-repo/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/applypatch-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message taken by
4 | # applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit. The hook is
8 | # allowed to edit the commit message file.
9 | #
10 | # To enable this hook, rename this file to "applypatch-msg".
11 |
12 | . git-sh-setup
13 | commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
14 | test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
15 | :
16 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message.
4 | # Called by "git commit" with one argument, the name of the file
5 | # that has the commit message. The hook should exit with non-zero
6 | # status after issuing an appropriate message if it wants to stop the
7 | # commit. The hook is allowed to edit the commit message file.
8 | #
9 | # To enable this hook, rename this file to "commit-msg".
10 |
11 | # Uncomment the below to add a Signed-off-by line to the message.
12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg
13 | # hook is more suited to it.
14 | #
15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
17 |
18 | # This example catches duplicate Signed-off-by lines.
19 |
20 | test "" = "$(grep '^Signed-off-by: ' "$1" |
21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
22 | echo >&2 Duplicate Signed-off-by lines.
23 | exit 1
24 | }
25 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/fsmonitor-watchman.sample:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use IPC::Open2;
6 |
7 | # An example hook script to integrate Watchman
8 | # (https://facebook.github.io/watchman/) with git to speed up detecting
9 | # new and modified files.
10 | #
11 | # The hook is passed a version (currently 1) and a time in nanoseconds
12 | # formatted as a string and outputs to stdout all files that have been
13 | # modified since the given time. Paths must be relative to the root of
14 | # the working tree and separated by a single NUL.
15 | #
16 | # To enable this hook, rename this file to "query-watchman" and set
17 | # 'git config core.fsmonitor .git/hooks/query-watchman'
18 | #
19 | my ($version, $time) = @ARGV;
20 |
21 | # Check the hook interface version
22 |
23 | if ($version == 1) {
24 | # convert nanoseconds to seconds
25 | $time = int $time / 1000000000;
26 | } else {
27 | die "Unsupported query-fsmonitor hook version '$version'.\n" .
28 | "Falling back to scanning...\n";
29 | }
30 |
31 | my $git_work_tree;
32 | if ($^O =~ 'msys' || $^O =~ 'cygwin') {
33 | $git_work_tree = Win32::GetCwd();
34 | $git_work_tree =~ tr/\\/\//;
35 | } else {
36 | require Cwd;
37 | $git_work_tree = Cwd::cwd();
38 | }
39 |
40 | my $retry = 1;
41 |
42 | launch_watchman();
43 |
44 | sub launch_watchman {
45 |
46 | my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
47 | or die "open2() failed: $!\n" .
48 | "Falling back to scanning...\n";
49 |
50 | # In the query expression below we're asking for names of files that
51 | # changed since $time but were not transient (ie created after
52 | # $time but no longer exist).
53 | #
54 | # To accomplish this, we're using the "since" generator to use the
55 | # recency index to select candidate nodes and "fields" to limit the
56 | # output to file names only. Then we're using the "expression" term to
57 | # further constrain the results.
58 | #
59 | # The category of transient files that we want to ignore will have a
60 | # creation clock (cclock) newer than $time_t value and will also not
61 | # currently exist.
62 |
63 | my $query = <<" END";
64 | ["query", "$git_work_tree", {
65 | "since": $time,
66 | "fields": ["name"],
67 | "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
68 | }]
69 | END
70 |
71 | print CHLD_IN $query;
72 | close CHLD_IN;
73 | my $response = do {local $/; };
74 |
75 | die "Watchman: command returned no output.\n" .
76 | "Falling back to scanning...\n" if $response eq "";
77 | die "Watchman: command returned invalid output: $response\n" .
78 | "Falling back to scanning...\n" unless $response =~ /^\{/;
79 |
80 | my $json_pkg;
81 | eval {
82 | require JSON::XS;
83 | $json_pkg = "JSON::XS";
84 | 1;
85 | } or do {
86 | require JSON::PP;
87 | $json_pkg = "JSON::PP";
88 | };
89 |
90 | my $o = $json_pkg->new->utf8->decode($response);
91 |
92 | if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
93 | print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
94 | $retry--;
95 | qx/watchman watch "$git_work_tree"/;
96 | die "Failed to make watchman watch '$git_work_tree'.\n" .
97 | "Falling back to scanning...\n" if $? != 0;
98 |
99 | # Watchman will always return all files on the first query so
100 | # return the fast "everything is dirty" flag to git and do the
101 | # Watchman query just to get it over with now so we won't pay
102 | # the cost in git to look up each individual file.
103 | print "/\0";
104 | eval { launch_watchman() };
105 | exit 0;
106 | }
107 |
108 | die "Watchman: $o->{error}.\n" .
109 | "Falling back to scanning...\n" if $o->{error};
110 |
111 | binmode STDOUT, ":utf8";
112 | local $, = "\0";
113 | print @{$o->{files}};
114 | }
115 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/post-update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare a packed repository for use over
4 | # dumb transports.
5 | #
6 | # To enable this hook, rename this file to "post-update".
7 |
8 | exec git update-server-info
9 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/pre-applypatch.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed
4 | # by applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit.
8 | #
9 | # To enable this hook, rename this file to "pre-applypatch".
10 |
11 | . git-sh-setup
12 | precommit="$(git rev-parse --git-path hooks/pre-commit)"
13 | test -x "$precommit" && exec "$precommit" ${1+"$@"}
14 | :
15 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/pre-commit.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed.
4 | # Called by "git commit" with no arguments. The hook should
5 | # exit with non-zero status after issuing an appropriate message if
6 | # it wants to stop the commit.
7 | #
8 | # To enable this hook, rename this file to "pre-commit".
9 |
10 | if git rev-parse --verify HEAD >/dev/null 2>&1
11 | then
12 | against=HEAD
13 | else
14 | # Initial commit: diff against an empty tree object
15 | against=$(git hash-object -t tree /dev/null)
16 | fi
17 |
18 | # If you want to allow non-ASCII filenames set this variable to true.
19 | allownonascii=$(git config --bool hooks.allownonascii)
20 |
21 | # Redirect output to stderr.
22 | exec 1>&2
23 |
24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent
25 | # them from being added to the repository. We exploit the fact that the
26 | # printable range starts at the space character and ends with tilde.
27 | if [ "$allownonascii" != "true" ] &&
28 | # Note that the use of brackets around a tr range is ok here, (it's
29 | # even required, for portability to Solaris 10's /usr/bin/tr), since
30 | # the square bracket bytes happen to fall in the designated range.
31 | test $(git diff --cached --name-only --diff-filter=A -z $against |
32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
33 | then
34 | cat <<\EOF
35 | Error: Attempt to add a non-ASCII file name.
36 |
37 | This can cause problems if you want to work with people on other platforms.
38 |
39 | To be portable it is advisable to rename the file.
40 |
41 | If you know what you are doing you can disable this check using:
42 |
43 | git config hooks.allownonascii true
44 | EOF
45 | exit 1
46 | fi
47 |
48 | # If there are whitespace errors, print the offending file names and fail.
49 | exec git diff-index --check --cached $against --
50 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/pre-push.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # An example hook script to verify what is about to be pushed. Called by "git
4 | # push" after it has checked the remote status, but before anything has been
5 | # pushed. If this script exits with a non-zero status nothing will be pushed.
6 | #
7 | # This hook is called with the following parameters:
8 | #
9 | # $1 -- Name of the remote to which the push is being done
10 | # $2 -- URL to which the push is being done
11 | #
12 | # If pushing without using a named remote those arguments will be equal.
13 | #
14 | # Information about the commits which are being pushed is supplied as lines to
15 | # the standard input in the form:
16 | #
17 | #
18 | #
19 | # This sample shows how to prevent push of commits where the log message starts
20 | # with "WIP" (work in progress).
21 |
22 | remote="$1"
23 | url="$2"
24 |
25 | z40=0000000000000000000000000000000000000000
26 |
27 | while read local_ref local_sha remote_ref remote_sha
28 | do
29 | if [ "$local_sha" = $z40 ]
30 | then
31 | # Handle delete
32 | :
33 | else
34 | if [ "$remote_sha" = $z40 ]
35 | then
36 | # New branch, examine all commits
37 | range="$local_sha"
38 | else
39 | # Update to existing branch, examine new commits
40 | range="$remote_sha..$local_sha"
41 | fi
42 |
43 | # Check for WIP commit
44 | commit=`git rev-list -n 1 --grep '^WIP' "$range"`
45 | if [ -n "$commit" ]
46 | then
47 | echo >&2 "Found WIP commit in $local_ref, not pushing"
48 | exit 1
49 | fi
50 | fi
51 | done
52 |
53 | exit 0
54 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/pre-rebase.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Copyright (c) 2006, 2008 Junio C Hamano
4 | #
5 | # The "pre-rebase" hook is run just before "git rebase" starts doing
6 | # its job, and can prevent the command from running by exiting with
7 | # non-zero status.
8 | #
9 | # The hook is called with the following parameters:
10 | #
11 | # $1 -- the upstream the series was forked from.
12 | # $2 -- the branch being rebased (or empty when rebasing the current branch).
13 | #
14 | # This sample shows how to prevent topic branches that are already
15 | # merged to 'next' branch from getting rebased, because allowing it
16 | # would result in rebasing already published history.
17 |
18 | publish=next
19 | basebranch="$1"
20 | if test "$#" = 2
21 | then
22 | topic="refs/heads/$2"
23 | else
24 | topic=`git symbolic-ref HEAD` ||
25 | exit 0 ;# we do not interrupt rebasing detached HEAD
26 | fi
27 |
28 | case "$topic" in
29 | refs/heads/??/*)
30 | ;;
31 | *)
32 | exit 0 ;# we do not interrupt others.
33 | ;;
34 | esac
35 |
36 | # Now we are dealing with a topic branch being rebased
37 | # on top of master. Is it OK to rebase it?
38 |
39 | # Does the topic really exist?
40 | git show-ref -q "$topic" || {
41 | echo >&2 "No such branch $topic"
42 | exit 1
43 | }
44 |
45 | # Is topic fully merged to master?
46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
47 | if test -z "$not_in_master"
48 | then
49 | echo >&2 "$topic is fully merged to master; better remove it."
50 | exit 1 ;# we could allow it, but there is no point.
51 | fi
52 |
53 | # Is topic ever merged to next? If so you should not be rebasing it.
54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
55 | only_next_2=`git rev-list ^master ${publish} | sort`
56 | if test "$only_next_1" = "$only_next_2"
57 | then
58 | not_in_topic=`git rev-list "^$topic" master`
59 | if test -z "$not_in_topic"
60 | then
61 | echo >&2 "$topic is already up to date with master"
62 | exit 1 ;# we could allow it, but there is no point.
63 | else
64 | exit 0
65 | fi
66 | else
67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
68 | /usr/bin/perl -e '
69 | my $topic = $ARGV[0];
70 | my $msg = "* $topic has commits already merged to public branch:\n";
71 | my (%not_in_next) = map {
72 | /^([0-9a-f]+) /;
73 | ($1 => 1);
74 | } split(/\n/, $ARGV[1]);
75 | for my $elem (map {
76 | /^([0-9a-f]+) (.*)$/;
77 | [$1 => $2];
78 | } split(/\n/, $ARGV[2])) {
79 | if (!exists $not_in_next{$elem->[0]}) {
80 | if ($msg) {
81 | print STDERR $msg;
82 | undef $msg;
83 | }
84 | print STDERR " $elem->[1]\n";
85 | }
86 | }
87 | ' "$topic" "$not_in_next" "$not_in_master"
88 | exit 1
89 | fi
90 |
91 | <<\DOC_END
92 |
93 | This sample hook safeguards topic branches that have been
94 | published from being rewound.
95 |
96 | The workflow assumed here is:
97 |
98 | * Once a topic branch forks from "master", "master" is never
99 | merged into it again (either directly or indirectly).
100 |
101 | * Once a topic branch is fully cooked and merged into "master",
102 | it is deleted. If you need to build on top of it to correct
103 | earlier mistakes, a new topic branch is created by forking at
104 | the tip of the "master". This is not strictly necessary, but
105 | it makes it easier to keep your history simple.
106 |
107 | * Whenever you need to test or publish your changes to topic
108 | branches, merge them into "next" branch.
109 |
110 | The script, being an example, hardcodes the publish branch name
111 | to be "next", but it is trivial to make it configurable via
112 | $GIT_DIR/config mechanism.
113 |
114 | With this workflow, you would want to know:
115 |
116 | (1) ... if a topic branch has ever been merged to "next". Young
117 | topic branches can have stupid mistakes you would rather
118 | clean up before publishing, and things that have not been
119 | merged into other branches can be easily rebased without
120 | affecting other people. But once it is published, you would
121 | not want to rewind it.
122 |
123 | (2) ... if a topic branch has been fully merged to "master".
124 | Then you can delete it. More importantly, you should not
125 | build on top of it -- other people may already want to
126 | change things related to the topic as patches against your
127 | "master", so if you need further changes, it is better to
128 | fork the topic (perhaps with the same name) afresh from the
129 | tip of "master".
130 |
131 | Let's look at this example:
132 |
133 | o---o---o---o---o---o---o---o---o---o "next"
134 | / / / /
135 | / a---a---b A / /
136 | / / / /
137 | / / c---c---c---c B /
138 | / / / \ /
139 | / / / b---b C \ /
140 | / / / / \ /
141 | ---o---o---o---o---o---o---o---o---o---o---o "master"
142 |
143 |
144 | A, B and C are topic branches.
145 |
146 | * A has one fix since it was merged up to "next".
147 |
148 | * B has finished. It has been fully merged up to "master" and "next",
149 | and is ready to be deleted.
150 |
151 | * C has not merged to "next" at all.
152 |
153 | We would want to allow C to be rebased, refuse A, and encourage
154 | B to be deleted.
155 |
156 | To compute (1):
157 |
158 | git rev-list ^master ^topic next
159 | git rev-list ^master next
160 |
161 | if these match, topic has not merged in next at all.
162 |
163 | To compute (2):
164 |
165 | git rev-list master..topic
166 |
167 | if this is empty, it is fully merged to "master".
168 |
169 | DOC_END
170 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/pre-receive.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to make use of push options.
4 | # The example simply echoes all push options that start with 'echoback='
5 | # and rejects all pushes when the "reject" push option is used.
6 | #
7 | # To enable this hook, rename this file to "pre-receive".
8 |
9 | if test -n "$GIT_PUSH_OPTION_COUNT"
10 | then
11 | i=0
12 | while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
13 | do
14 | eval "value=\$GIT_PUSH_OPTION_$i"
15 | case "$value" in
16 | echoback=*)
17 | echo "echo from the pre-receive-hook: ${value#*=}" >&2
18 | ;;
19 | reject)
20 | exit 1
21 | esac
22 | i=$((i + 1))
23 | done
24 | fi
25 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/prepare-commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare the commit log message.
4 | # Called by "git commit" with the name of the file that has the
5 | # commit message, followed by the description of the commit
6 | # message's source. The hook's purpose is to edit the commit
7 | # message file. If the hook fails with a non-zero status,
8 | # the commit is aborted.
9 | #
10 | # To enable this hook, rename this file to "prepare-commit-msg".
11 |
12 | # This hook includes three examples. The first one removes the
13 | # "# Please enter the commit message..." help message.
14 | #
15 | # The second includes the output of "git diff --name-status -r"
16 | # into the message, just before the "git status" output. It is
17 | # commented because it doesn't cope with --amend or with squashed
18 | # commits.
19 | #
20 | # The third example adds a Signed-off-by line to the message, that can
21 | # still be edited. This is rarely a good idea.
22 |
23 | COMMIT_MSG_FILE=$1
24 | COMMIT_SOURCE=$2
25 | SHA1=$3
26 |
27 | /usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
28 |
29 | # case "$COMMIT_SOURCE,$SHA1" in
30 | # ,|template,)
31 | # /usr/bin/perl -i.bak -pe '
32 | # print "\n" . `git diff --cached --name-status -r`
33 | # if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
34 | # *) ;;
35 | # esac
36 |
37 | # SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
38 | # git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
39 | # if test -z "$COMMIT_SOURCE"
40 | # then
41 | # /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
42 | # fi
43 |
--------------------------------------------------------------------------------
/testdata/add-repo/hooks/update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to block unannotated tags from entering.
4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
5 | #
6 | # To enable this hook, rename this file to "update".
7 | #
8 | # Config
9 | # ------
10 | # hooks.allowunannotated
11 | # This boolean sets whether unannotated tags will be allowed into the
12 | # repository. By default they won't be.
13 | # hooks.allowdeletetag
14 | # This boolean sets whether deleting tags will be allowed in the
15 | # repository. By default they won't be.
16 | # hooks.allowmodifytag
17 | # This boolean sets whether a tag may be modified after creation. By default
18 | # it won't be.
19 | # hooks.allowdeletebranch
20 | # This boolean sets whether deleting branches will be allowed in the
21 | # repository. By default they won't be.
22 | # hooks.denycreatebranch
23 | # This boolean sets whether remotely creating branches will be denied
24 | # in the repository. By default this is allowed.
25 | #
26 |
27 | # --- Command line
28 | refname="$1"
29 | oldrev="$2"
30 | newrev="$3"
31 |
32 | # --- Safety check
33 | if [ -z "$GIT_DIR" ]; then
34 | echo "Don't run this script from the command line." >&2
35 | echo " (if you want, you could supply GIT_DIR then run" >&2
36 | echo " $0 [ )" >&2
37 | exit 1
38 | fi
39 |
40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
41 | echo "usage: $0 ][ " >&2
42 | exit 1
43 | fi
44 |
45 | # --- Config
46 | allowunannotated=$(git config --bool hooks.allowunannotated)
47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
48 | denycreatebranch=$(git config --bool hooks.denycreatebranch)
49 | allowdeletetag=$(git config --bool hooks.allowdeletetag)
50 | allowmodifytag=$(git config --bool hooks.allowmodifytag)
51 |
52 | # check for no description
53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description")
54 | case "$projectdesc" in
55 | "Unnamed repository"* | "")
56 | echo "*** Project description file hasn't been set" >&2
57 | exit 1
58 | ;;
59 | esac
60 |
61 | # --- Check types
62 | # if $newrev is 0000...0000, it's a commit to delete a ref.
63 | zero="0000000000000000000000000000000000000000"
64 | if [ "$newrev" = "$zero" ]; then
65 | newrev_type=delete
66 | else
67 | newrev_type=$(git cat-file -t $newrev)
68 | fi
69 |
70 | case "$refname","$newrev_type" in
71 | refs/tags/*,commit)
72 | # un-annotated tag
73 | short_refname=${refname##refs/tags/}
74 | if [ "$allowunannotated" != "true" ]; then
75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
77 | exit 1
78 | fi
79 | ;;
80 | refs/tags/*,delete)
81 | # delete tag
82 | if [ "$allowdeletetag" != "true" ]; then
83 | echo "*** Deleting a tag is not allowed in this repository" >&2
84 | exit 1
85 | fi
86 | ;;
87 | refs/tags/*,tag)
88 | # annotated tag
89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
90 | then
91 | echo "*** Tag '$refname' already exists." >&2
92 | echo "*** Modifying a tag is not allowed in this repository." >&2
93 | exit 1
94 | fi
95 | ;;
96 | refs/heads/*,commit)
97 | # branch
98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
99 | echo "*** Creating a branch is not allowed in this repository" >&2
100 | exit 1
101 | fi
102 | ;;
103 | refs/heads/*,delete)
104 | # delete branch
105 | if [ "$allowdeletebranch" != "true" ]; then
106 | echo "*** Deleting a branch is not allowed in this repository" >&2
107 | exit 1
108 | fi
109 | ;;
110 | refs/remotes/*,commit)
111 | # tracking branch
112 | ;;
113 | refs/remotes/*,delete)
114 | # delete tracking branch
115 | if [ "$allowdeletebranch" != "true" ]; then
116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2
117 | exit 1
118 | fi
119 | ;;
120 | *)
121 | # Anything else (is there anything else?)
122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
123 | exit 1
124 | ;;
125 | esac
126 |
127 | # --- Finished
128 | exit 0
129 |
--------------------------------------------------------------------------------
/testdata/add-repo/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/add-repo/objects/2c/499787328348f09ae1e8f03757c6483b9a938a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/2c/499787328348f09ae1e8f03757c6483b9a938a
--------------------------------------------------------------------------------
/testdata/add-repo/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed
--------------------------------------------------------------------------------
/testdata/add-repo/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943
--------------------------------------------------------------------------------
/testdata/add-repo/objects/43/3581c28b23426dee2c498da28defa9f5bd4f63:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/43/3581c28b23426dee2c498da28defa9f5bd4f63
--------------------------------------------------------------------------------
/testdata/add-repo/objects/6f/59e5e770be445518775b22bbe25e89339b778b:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/6f/59e5e770be445518775b22bbe25e89339b778b
--------------------------------------------------------------------------------
/testdata/add-repo/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd
--------------------------------------------------------------------------------
/testdata/add-repo/objects/c2/b01f193085b4bc020ef62b93d9dc44d9eca7a4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/c2/b01f193085b4bc020ef62b93d9dc44d9eca7a4
--------------------------------------------------------------------------------
/testdata/add-repo/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
--------------------------------------------------------------------------------
/testdata/add-repo/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/add-repo/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8
--------------------------------------------------------------------------------
/testdata/add-repo/refs/heads/master:
--------------------------------------------------------------------------------
1 | 433581c28b23426dee2c498da28defa9f5bd4f63
2 |
--------------------------------------------------------------------------------
/testdata/add-repo/refs/tags/v0.0.1:
--------------------------------------------------------------------------------
1 | 2c499787328348f09ae1e8f03757c6483b9a938a
2 |
--------------------------------------------------------------------------------
/testdata/gold-add-changelog-with-annotated-commit.yml:
--------------------------------------------------------------------------------
1 | - semver: 1.0.0-b1+git.123
2 | date: 2019-10-18T18:17:57.934767812-07:00
3 | packager: Dj Gilcrease
4 | notes:
5 | header: |2
6 |
7 | This is a test
8 | ======
9 |
10 | header entry
11 | changes:
12 | - commit: 095b7b431351080c1edfe7de73db893e6b59ddce
13 | note: "chore: add another file"
14 | author:
15 | name: Nicholas Jackson
16 | email: nicholas.jackson@zii.aero
17 | committer:
18 | name: Nicholas Jackson
19 | email: nicholas.jackson@zii.aero
20 | conventional_commit:
21 | category: chore
22 | scope: ""
23 | description: add another file
24 | body: ""
25 | - semver: 0.0.2
26 | date: 2019-10-18T18:53:50-07:00
27 | packager: Dj Gilcrease
28 | changes:
29 | - commit: 433581c28b23426dee2c498da28defa9f5bd4f63
30 | note: "chore: add a new file"
31 | author:
32 | name: Dj Gilcrease
33 | email: d.gilcrease@f5.com
34 | committer:
35 | name: Dj Gilcrease
36 | email: d.gilcrease@f5.com
37 | conventional_commit:
38 | category: chore
39 | scope: ""
40 | description: add a new file
41 | body: ""
42 | - semver: 0.0.1
43 | date: 2019-10-18T16:05:33-07:00
44 | packager: Dj Gilcrease
45 | changes:
46 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
47 | note: |-
48 | oops i forgot to use Conventional Commits style message
49 |
50 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
51 | author:
52 | name: Dj Gilcrease
53 | email: d.gilcrease@f5.com
54 | committer:
55 | name: Dj Gilcrease
56 | email: d.gilcrease@f5.com
57 | conventional_commit:
58 | category: chore
59 | scope: ""
60 | description: oops i forgot to use Conventional Commits style message
61 | body: This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
62 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
63 | note: |-
64 | feat: added file two feature
65 |
66 | BREAKING CHANGE: this is a backwards incompatible change
67 | author:
68 | name: Dj Gilcrease
69 | email: d.gilcrease@f5.com
70 | committer:
71 | name: Dj Gilcrease
72 | email: d.gilcrease@f5.com
73 | conventional_commit:
74 | category: feat
75 | scope: ""
76 | description: added file two feature
77 | body: ""
78 | footer:
79 | - "BREAKING CHANGE: this is a backwards incompatible change"
80 | major: true
81 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
82 | note: |-
83 | feat: added the fileone feature
84 |
85 | * This is a test repo
86 | * so ya!
87 | author:
88 | name: Dj Gilcrease
89 | email: d.gilcrease@f5.com
90 | committer:
91 | name: Dj Gilcrease
92 | email: d.gilcrease@f5.com
93 | conventional_commit:
94 | category: feat
95 | scope: ""
96 | description: added the fileone feature
97 | body: |-
98 | * This is a test repo
99 | * so ya!
100 | minor: true
101 |
--------------------------------------------------------------------------------
/testdata/gold-add-changelog.yml:
--------------------------------------------------------------------------------
1 | - semver: 1.0.0-b1+git.123
2 | date: 2019-10-18T18:17:57.934767812-07:00
3 | packager: Dj Gilcrease
4 | notes:
5 | header: |2
6 |
7 | This is a test
8 | ======
9 |
10 | header entry
11 | changes:
12 | - commit: 433581c28b23426dee2c498da28defa9f5bd4f63
13 | note: 'chore: add a new file'
14 | author:
15 | name: Dj Gilcrease
16 | email: d.gilcrease@f5.com
17 | committer:
18 | name: Dj Gilcrease
19 | email: d.gilcrease@f5.com
20 | conventional_commit:
21 | category: chore
22 | scope: ""
23 | breaking: false
24 | description: add a new file
25 | body: ""
26 | - semver: 0.0.1
27 | date: 2019-10-18T16:05:33-07:00
28 | packager: Dj Gilcrease
29 | changes:
30 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
31 | note: |-
32 | oops i forgot to use Conventional Commits style message
33 |
34 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
35 | author:
36 | name: Dj Gilcrease
37 | email: d.gilcrease@f5.com
38 | committer:
39 | name: Dj Gilcrease
40 | email: d.gilcrease@f5.com
41 | conventional_commit:
42 | category: "chore"
43 | scope: ""
44 | breaking: false
45 | description: oops i forgot to use Conventional Commits style message
46 | body: This should NOT break anything even if I am asking to build the changelog
47 | using Conventional Commits style message
48 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
49 | note: |-
50 | feat: added file two feature
51 |
52 | BREAKING CHANGE: this is a backwards incompatible change
53 | author:
54 | name: Dj Gilcrease
55 | email: d.gilcrease@f5.com
56 | committer:
57 | name: Dj Gilcrease
58 | email: d.gilcrease@f5.com
59 | conventional_commit:
60 | category: feat
61 | scope: ""
62 | breaking: true
63 | description: added file two feature
64 | major: true
65 | footer:
66 | - 'BREAKING CHANGE: this is a backwards incompatible change'
67 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
68 | note: |-
69 | feat: added the fileone feature
70 |
71 | * This is a test repo
72 | * so ya!
73 | author:
74 | name: Dj Gilcrease
75 | email: d.gilcrease@f5.com
76 | committer:
77 | name: Dj Gilcrease
78 | email: d.gilcrease@f5.com
79 | conventional_commit:
80 | category: feat
81 | scope: ""
82 | breaking: false
83 | description: added the fileone feature
84 | minor: true
85 | body: |-
86 | * This is a test repo
87 | * so ya!
88 |
--------------------------------------------------------------------------------
/testdata/gold-init-changelog-with-merge-commit.yml:
--------------------------------------------------------------------------------
1 | - semver: 0.0.1
2 | date: 2024-01-21T15:37:29+01:00
3 | packager: Arne Jørgensen
4 | changes:
5 | - commit: e6f123d7d0aa2025ce61d28e2d34f94f3a6b5218
6 | note: Merge branch 'mergetest'
7 | author:
8 | name: Arne Jørgensen
9 | email: arne@arnested.dk
10 | committer:
11 | name: Arne Jørgensen
12 | email: arne@arnested.dk
13 | conventional_commit:
14 | category: chore
15 | scope: ""
16 | description: Merge branch 'mergetest'
17 | body: ""
18 | major: false
19 | minor: false
20 | patch: false
21 | - commit: 25c55c716f1f18bb91aafa55f98a02315f59afe6
22 | note: 'feat: add file to be merged in later'
23 | author:
24 | name: Arne Jørgensen
25 | email: arne@arnested.dk
26 | committer:
27 | name: Arne Jørgensen
28 | email: arne@arnested.dk
29 | conventional_commit:
30 | category: feat
31 | scope: ""
32 | description: add file to be merged in later
33 | body: ""
34 | major: false
35 | minor: true
36 | patch: false
37 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
38 | note: |-
39 | oops i forgot to use Conventional Commits style message
40 |
41 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
42 | author:
43 | name: Dj Gilcrease
44 | email: d.gilcrease@f5.com
45 | committer:
46 | name: Dj Gilcrease
47 | email: d.gilcrease@f5.com
48 | conventional_commit:
49 | category: chore
50 | scope: ""
51 | description: oops i forgot to use Conventional Commits style message
52 | body: This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
53 | major: false
54 | minor: false
55 | patch: false
56 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
57 | note: |-
58 | feat: added file two feature
59 |
60 | BREAKING CHANGE: this is a backwards incompatible change
61 | author:
62 | name: Dj Gilcrease
63 | email: d.gilcrease@f5.com
64 | committer:
65 | name: Dj Gilcrease
66 | email: d.gilcrease@f5.com
67 | conventional_commit:
68 | category: feat
69 | scope: ""
70 | description: added file two feature
71 | body: ""
72 | footer:
73 | - 'BREAKING CHANGE: this is a backwards incompatible change'
74 | major: true
75 | minor: false
76 | patch: false
77 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
78 | note: |-
79 | feat: added the fileone feature
80 |
81 | * This is a test repo
82 | * so ya!
83 | author:
84 | name: Dj Gilcrease
85 | email: d.gilcrease@f5.com
86 | committer:
87 | name: Dj Gilcrease
88 | email: d.gilcrease@f5.com
89 | conventional_commit:
90 | category: feat
91 | scope: ""
92 | description: added the fileone feature
93 | body: |-
94 | * This is a test repo
95 | * so ya!
96 | major: false
97 | minor: true
98 | patch: false
99 |
--------------------------------------------------------------------------------
/testdata/gold-init-changelog-without-merge-commit.yml:
--------------------------------------------------------------------------------
1 | - semver: 0.0.1
2 | date: 2024-01-21T15:37:29+01:00
3 | packager: Arne Jørgensen
4 | changes:
5 | - commit: 25c55c716f1f18bb91aafa55f98a02315f59afe6
6 | note: 'feat: add file to be merged in later'
7 | author:
8 | name: Arne Jørgensen
9 | email: arne@arnested.dk
10 | committer:
11 | name: Arne Jørgensen
12 | email: arne@arnested.dk
13 | conventional_commit:
14 | category: feat
15 | scope: ""
16 | description: add file to be merged in later
17 | body: ""
18 | major: false
19 | minor: true
20 | patch: false
21 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
22 | note: |-
23 | oops i forgot to use Conventional Commits style message
24 |
25 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
26 | author:
27 | name: Dj Gilcrease
28 | email: d.gilcrease@f5.com
29 | committer:
30 | name: Dj Gilcrease
31 | email: d.gilcrease@f5.com
32 | conventional_commit:
33 | category: chore
34 | scope: ""
35 | description: oops i forgot to use Conventional Commits style message
36 | body: This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
37 | major: false
38 | minor: false
39 | patch: false
40 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
41 | note: |-
42 | feat: added file two feature
43 |
44 | BREAKING CHANGE: this is a backwards incompatible change
45 | author:
46 | name: Dj Gilcrease
47 | email: d.gilcrease@f5.com
48 | committer:
49 | name: Dj Gilcrease
50 | email: d.gilcrease@f5.com
51 | conventional_commit:
52 | category: feat
53 | scope: ""
54 | description: added file two feature
55 | body: ""
56 | footer:
57 | - 'BREAKING CHANGE: this is a backwards incompatible change'
58 | major: true
59 | minor: false
60 | patch: false
61 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
62 | note: |-
63 | feat: added the fileone feature
64 |
65 | * This is a test repo
66 | * so ya!
67 | author:
68 | name: Dj Gilcrease
69 | email: d.gilcrease@f5.com
70 | committer:
71 | name: Dj Gilcrease
72 | email: d.gilcrease@f5.com
73 | conventional_commit:
74 | category: feat
75 | scope: ""
76 | description: added the fileone feature
77 | body: |-
78 | * This is a test repo
79 | * so ya!
80 | major: false
81 | minor: true
82 | patch: false
83 |
--------------------------------------------------------------------------------
/testdata/gold-init-changelog.yml:
--------------------------------------------------------------------------------
1 | - semver: 0.0.1
2 | date: 2019-10-18T16:05:33-07:00
3 | packager: Dj Gilcrease
4 | changes:
5 | - commit: 2c499787328348f09ae1e8f03757c6483b9a938a
6 | note: |-
7 | oops i forgot to use Conventional Commits style message
8 |
9 | This should NOT break anything even if I am asking to build the changelog using Conventional Commits style message
10 | author:
11 | name: Dj Gilcrease
12 | email: d.gilcrease@f5.com
13 | committer:
14 | name: Dj Gilcrease
15 | email: d.gilcrease@f5.com
16 | conventional_commit:
17 | category: "chore"
18 | scope: ""
19 | breaking: false
20 | description: oops i forgot to use Conventional Commits style message
21 | body: This should NOT break anything even if I am asking to build the changelog
22 | using Conventional Commits style message
23 | - commit: 3ec1e9a60d07cc060cee727c97ffc8aac5713943
24 | note: |-
25 | feat: added file two feature
26 |
27 | BREAKING CHANGE: this is a backwards incompatible change
28 | author:
29 | name: Dj Gilcrease
30 | email: d.gilcrease@f5.com
31 | committer:
32 | name: Dj Gilcrease
33 | email: d.gilcrease@f5.com
34 | conventional_commit:
35 | category: feat
36 | scope: ""
37 | breaking: true
38 | description: added file two feature
39 | major: true
40 | footer:
41 | - 'BREAKING CHANGE: this is a backwards incompatible change'
42 | - commit: 2cc00abc77d401a541d18c26e5c7fbef1effd3ed
43 | note: |-
44 | feat: added the fileone feature
45 |
46 | * This is a test repo
47 | * so ya!
48 | author:
49 | name: Dj Gilcrease
50 | email: d.gilcrease@f5.com
51 | committer:
52 | name: Dj Gilcrease
53 | email: d.gilcrease@f5.com
54 | conventional_commit:
55 | category: feat
56 | scope: ""
57 | breaking: false
58 | description: added the fileone feature
59 | minor: true
60 | body: |-
61 | * This is a test repo
62 | * so ya!
63 |
--------------------------------------------------------------------------------
/testdata/gold-order-changelog.yml:
--------------------------------------------------------------------------------
1 | - semver: 0.10.0
2 | date: 2000-01-01T12:00:00+07:00
3 | packager: John Doe
4 | changes:
5 | - commit: 6cfa531ce3ac4bd4b4ec2522c2ab8d252e722a2c
6 | note: commit 10
7 | author:
8 | name: John Doe
9 | email: John.Doe@example.com
10 | committer:
11 | name: John Doe
12 | email: John.Doe@example.com
13 | - semver: 0.9.0
14 | date: 2000-01-01T12:00:00+07:00
15 | packager: John Doe
16 | changes:
17 | - commit: 66ec5a3714a3ea6dbaa8843f4d63cc377bf31d77
18 | note: commit 9
19 | author:
20 | name: John Doe
21 | email: John.Doe@example.com
22 | committer:
23 | name: John Doe
24 | email: John.Doe@example.com
25 | - semver: 0.8.0
26 | date: 2000-01-01T12:00:00+07:00
27 | packager: John Doe
28 | changes:
29 | - commit: 70b65ab708ffb8a0935da4bb8d3831f8c2230c5c
30 | note: commit 8
31 | author:
32 | name: John Doe
33 | email: John.Doe@example.com
34 | committer:
35 | name: John Doe
36 | email: John.Doe@example.com
37 | - semver: 0.7.0
38 | date: 2000-01-01T12:00:00+07:00
39 | packager: John Doe
40 | changes:
41 | - commit: c0510b7bd8342631a45a9ea67481ad0d9822f60b
42 | note: commit 7
43 | author:
44 | name: John Doe
45 | email: John.Doe@example.com
46 | committer:
47 | name: John Doe
48 | email: John.Doe@example.com
49 | - semver: 0.6.0
50 | date: 2000-01-01T12:00:00+07:00
51 | packager: John Doe
52 | changes:
53 | - commit: 677fb751e382174fc2d53068ee25f2d3863ccd19
54 | note: commit 6
55 | author:
56 | name: John Doe
57 | email: John.Doe@example.com
58 | committer:
59 | name: John Doe
60 | email: John.Doe@example.com
61 | - semver: 0.5.0
62 | date: 2000-01-01T12:00:00+07:00
63 | packager: John Doe
64 | changes:
65 | - commit: 85816484794feac8d53e0a13d14254972edbbddf
66 | note: commit 5
67 | author:
68 | name: John Doe
69 | email: John.Doe@example.com
70 | committer:
71 | name: John Doe
72 | email: John.Doe@example.com
73 | - semver: 0.4.0
74 | date: 2000-01-01T12:00:00+07:00
75 | packager: John Doe
76 | changes:
77 | - commit: 6ac70628dc692b5dec91438e133c97808256a035
78 | note: commit 4
79 | author:
80 | name: John Doe
81 | email: John.Doe@example.com
82 | committer:
83 | name: John Doe
84 | email: John.Doe@example.com
85 | - semver: 0.3.0
86 | date: 2000-01-01T12:00:00+07:00
87 | packager: John Doe
88 | changes:
89 | - commit: 6271fd4a63f296e3df46e4c0e7dcb948e2a3b066
90 | note: commit 3
91 | author:
92 | name: John Doe
93 | email: John.Doe@example.com
94 | committer:
95 | name: John Doe
96 | email: John.Doe@example.com
97 | - semver: 0.2.0
98 | date: 2000-01-01T12:00:00+07:00
99 | packager: John Doe
100 | changes:
101 | - commit: 6bfe64ae8f93108e5e0a85f43736459ac6ee0642
102 | note: commit 2
103 | author:
104 | name: John Doe
105 | email: John.Doe@example.com
106 | committer:
107 | name: John Doe
108 | email: John.Doe@example.com
109 | - semver: 0.1.0
110 | date: 2000-01-01T12:00:00+07:00
111 | packager: John Doe
112 | changes:
113 | - commit: 3b2811fc8b1a7a073ffb739e3766b47a3c81286d
114 | note: commit 1
115 | author:
116 | name: John Doe
117 | email: John.Doe@example.com
118 | committer:
119 | name: John Doe
120 | email: John.Doe@example.com
121 | - semver: 0.0.0
122 | date: 2000-01-01T12:00:00+07:00
123 | packager: John Doe
124 | changes:
125 | - commit: 1807a212fb257a8258a238d2028c6622fa71035c
126 | note: commit 0
127 | author:
128 | name: John Doe
129 | email: John.Doe@example.com
130 | committer:
131 | name: John Doe
132 | email: John.Doe@example.com
133 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/master
2 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = false
5 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/applypatch-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message taken by
4 | # applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit. The hook is
8 | # allowed to edit the commit message file.
9 | #
10 | # To enable this hook, rename this file to "applypatch-msg".
11 |
12 | . git-sh-setup
13 | commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
14 | test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
15 | :
16 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message.
4 | # Called by "git commit" with one argument, the name of the file
5 | # that has the commit message. The hook should exit with non-zero
6 | # status after issuing an appropriate message if it wants to stop the
7 | # commit. The hook is allowed to edit the commit message file.
8 | #
9 | # To enable this hook, rename this file to "commit-msg".
10 |
11 | # Uncomment the below to add a Signed-off-by line to the message.
12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg
13 | # hook is more suited to it.
14 | #
15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
17 |
18 | # This example catches duplicate Signed-off-by lines.
19 |
20 | test "" = "$(grep '^Signed-off-by: ' "$1" |
21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
22 | echo >&2 Duplicate Signed-off-by lines.
23 | exit 1
24 | }
25 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/fsmonitor-watchman.sample:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use IPC::Open2;
6 |
7 | # An example hook script to integrate Watchman
8 | # (https://facebook.github.io/watchman/) with git to speed up detecting
9 | # new and modified files.
10 | #
11 | # The hook is passed a version (currently 1) and a time in nanoseconds
12 | # formatted as a string and outputs to stdout all files that have been
13 | # modified since the given time. Paths must be relative to the root of
14 | # the working tree and separated by a single NUL.
15 | #
16 | # To enable this hook, rename this file to "query-watchman" and set
17 | # 'git config core.fsmonitor .git/hooks/query-watchman'
18 | #
19 | my ($version, $time) = @ARGV;
20 |
21 | # Check the hook interface version
22 |
23 | if ($version == 1) {
24 | # convert nanoseconds to seconds
25 | $time = int $time / 1000000000;
26 | } else {
27 | die "Unsupported query-fsmonitor hook version '$version'.\n" .
28 | "Falling back to scanning...\n";
29 | }
30 |
31 | my $git_work_tree;
32 | if ($^O =~ 'msys' || $^O =~ 'cygwin') {
33 | $git_work_tree = Win32::GetCwd();
34 | $git_work_tree =~ tr/\\/\//;
35 | } else {
36 | require Cwd;
37 | $git_work_tree = Cwd::cwd();
38 | }
39 |
40 | my $retry = 1;
41 |
42 | launch_watchman();
43 |
44 | sub launch_watchman {
45 |
46 | my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
47 | or die "open2() failed: $!\n" .
48 | "Falling back to scanning...\n";
49 |
50 | # In the query expression below we're asking for names of files that
51 | # changed since $time but were not transient (ie created after
52 | # $time but no longer exist).
53 | #
54 | # To accomplish this, we're using the "since" generator to use the
55 | # recency index to select candidate nodes and "fields" to limit the
56 | # output to file names only. Then we're using the "expression" term to
57 | # further constrain the results.
58 | #
59 | # The category of transient files that we want to ignore will have a
60 | # creation clock (cclock) newer than $time_t value and will also not
61 | # currently exist.
62 |
63 | my $query = <<" END";
64 | ["query", "$git_work_tree", {
65 | "since": $time,
66 | "fields": ["name"],
67 | "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
68 | }]
69 | END
70 |
71 | print CHLD_IN $query;
72 | close CHLD_IN;
73 | my $response = do {local $/; };
74 |
75 | die "Watchman: command returned no output.\n" .
76 | "Falling back to scanning...\n" if $response eq "";
77 | die "Watchman: command returned invalid output: $response\n" .
78 | "Falling back to scanning...\n" unless $response =~ /^\{/;
79 |
80 | my $json_pkg;
81 | eval {
82 | require JSON::XS;
83 | $json_pkg = "JSON::XS";
84 | 1;
85 | } or do {
86 | require JSON::PP;
87 | $json_pkg = "JSON::PP";
88 | };
89 |
90 | my $o = $json_pkg->new->utf8->decode($response);
91 |
92 | if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
93 | print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
94 | $retry--;
95 | qx/watchman watch "$git_work_tree"/;
96 | die "Failed to make watchman watch '$git_work_tree'.\n" .
97 | "Falling back to scanning...\n" if $? != 0;
98 |
99 | # Watchman will always return all files on the first query so
100 | # return the fast "everything is dirty" flag to git and do the
101 | # Watchman query just to get it over with now so we won't pay
102 | # the cost in git to look up each individual file.
103 | print "/\0";
104 | eval { launch_watchman() };
105 | exit 0;
106 | }
107 |
108 | die "Watchman: $o->{error}.\n" .
109 | "Falling back to scanning...\n" if $o->{error};
110 |
111 | binmode STDOUT, ":utf8";
112 | local $, = "\0";
113 | print @{$o->{files}};
114 | }
115 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/post-update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare a packed repository for use over
4 | # dumb transports.
5 | #
6 | # To enable this hook, rename this file to "post-update".
7 |
8 | exec git update-server-info
9 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/pre-applypatch.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed
4 | # by applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit.
8 | #
9 | # To enable this hook, rename this file to "pre-applypatch".
10 |
11 | . git-sh-setup
12 | precommit="$(git rev-parse --git-path hooks/pre-commit)"
13 | test -x "$precommit" && exec "$precommit" ${1+"$@"}
14 | :
15 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/pre-commit.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed.
4 | # Called by "git commit" with no arguments. The hook should
5 | # exit with non-zero status after issuing an appropriate message if
6 | # it wants to stop the commit.
7 | #
8 | # To enable this hook, rename this file to "pre-commit".
9 |
10 | if git rev-parse --verify HEAD >/dev/null 2>&1
11 | then
12 | against=HEAD
13 | else
14 | # Initial commit: diff against an empty tree object
15 | against=$(git hash-object -t tree /dev/null)
16 | fi
17 |
18 | # If you want to allow non-ASCII filenames set this variable to true.
19 | allownonascii=$(git config --bool hooks.allownonascii)
20 |
21 | # Redirect output to stderr.
22 | exec 1>&2
23 |
24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent
25 | # them from being added to the repository. We exploit the fact that the
26 | # printable range starts at the space character and ends with tilde.
27 | if [ "$allownonascii" != "true" ] &&
28 | # Note that the use of brackets around a tr range is ok here, (it's
29 | # even required, for portability to Solaris 10's /usr/bin/tr), since
30 | # the square bracket bytes happen to fall in the designated range.
31 | test $(git diff --cached --name-only --diff-filter=A -z $against |
32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
33 | then
34 | cat <<\EOF
35 | Error: Attempt to add a non-ASCII file name.
36 |
37 | This can cause problems if you want to work with people on other platforms.
38 |
39 | To be portable it is advisable to rename the file.
40 |
41 | If you know what you are doing you can disable this check using:
42 |
43 | git config hooks.allownonascii true
44 | EOF
45 | exit 1
46 | fi
47 |
48 | # If there are whitespace errors, print the offending file names and fail.
49 | exec git diff-index --check --cached $against --
50 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/pre-push.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # An example hook script to verify what is about to be pushed. Called by "git
4 | # push" after it has checked the remote status, but before anything has been
5 | # pushed. If this script exits with a non-zero status nothing will be pushed.
6 | #
7 | # This hook is called with the following parameters:
8 | #
9 | # $1 -- Name of the remote to which the push is being done
10 | # $2 -- URL to which the push is being done
11 | #
12 | # If pushing without using a named remote those arguments will be equal.
13 | #
14 | # Information about the commits which are being pushed is supplied as lines to
15 | # the standard input in the form:
16 | #
17 | #
18 | #
19 | # This sample shows how to prevent push of commits where the log message starts
20 | # with "WIP" (work in progress).
21 |
22 | remote="$1"
23 | url="$2"
24 |
25 | z40=0000000000000000000000000000000000000000
26 |
27 | while read local_ref local_sha remote_ref remote_sha
28 | do
29 | if [ "$local_sha" = $z40 ]
30 | then
31 | # Handle delete
32 | :
33 | else
34 | if [ "$remote_sha" = $z40 ]
35 | then
36 | # New branch, examine all commits
37 | range="$local_sha"
38 | else
39 | # Update to existing branch, examine new commits
40 | range="$remote_sha..$local_sha"
41 | fi
42 |
43 | # Check for WIP commit
44 | commit=`git rev-list -n 1 --grep '^WIP' "$range"`
45 | if [ -n "$commit" ]
46 | then
47 | echo >&2 "Found WIP commit in $local_ref, not pushing"
48 | exit 1
49 | fi
50 | fi
51 | done
52 |
53 | exit 0
54 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/pre-rebase.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Copyright (c) 2006, 2008 Junio C Hamano
4 | #
5 | # The "pre-rebase" hook is run just before "git rebase" starts doing
6 | # its job, and can prevent the command from running by exiting with
7 | # non-zero status.
8 | #
9 | # The hook is called with the following parameters:
10 | #
11 | # $1 -- the upstream the series was forked from.
12 | # $2 -- the branch being rebased (or empty when rebasing the current branch).
13 | #
14 | # This sample shows how to prevent topic branches that are already
15 | # merged to 'next' branch from getting rebased, because allowing it
16 | # would result in rebasing already published history.
17 |
18 | publish=next
19 | basebranch="$1"
20 | if test "$#" = 2
21 | then
22 | topic="refs/heads/$2"
23 | else
24 | topic=`git symbolic-ref HEAD` ||
25 | exit 0 ;# we do not interrupt rebasing detached HEAD
26 | fi
27 |
28 | case "$topic" in
29 | refs/heads/??/*)
30 | ;;
31 | *)
32 | exit 0 ;# we do not interrupt others.
33 | ;;
34 | esac
35 |
36 | # Now we are dealing with a topic branch being rebased
37 | # on top of master. Is it OK to rebase it?
38 |
39 | # Does the topic really exist?
40 | git show-ref -q "$topic" || {
41 | echo >&2 "No such branch $topic"
42 | exit 1
43 | }
44 |
45 | # Is topic fully merged to master?
46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
47 | if test -z "$not_in_master"
48 | then
49 | echo >&2 "$topic is fully merged to master; better remove it."
50 | exit 1 ;# we could allow it, but there is no point.
51 | fi
52 |
53 | # Is topic ever merged to next? If so you should not be rebasing it.
54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
55 | only_next_2=`git rev-list ^master ${publish} | sort`
56 | if test "$only_next_1" = "$only_next_2"
57 | then
58 | not_in_topic=`git rev-list "^$topic" master`
59 | if test -z "$not_in_topic"
60 | then
61 | echo >&2 "$topic is already up to date with master"
62 | exit 1 ;# we could allow it, but there is no point.
63 | else
64 | exit 0
65 | fi
66 | else
67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
68 | /usr/bin/perl -e '
69 | my $topic = $ARGV[0];
70 | my $msg = "* $topic has commits already merged to public branch:\n";
71 | my (%not_in_next) = map {
72 | /^([0-9a-f]+) /;
73 | ($1 => 1);
74 | } split(/\n/, $ARGV[1]);
75 | for my $elem (map {
76 | /^([0-9a-f]+) (.*)$/;
77 | [$1 => $2];
78 | } split(/\n/, $ARGV[2])) {
79 | if (!exists $not_in_next{$elem->[0]}) {
80 | if ($msg) {
81 | print STDERR $msg;
82 | undef $msg;
83 | }
84 | print STDERR " $elem->[1]\n";
85 | }
86 | }
87 | ' "$topic" "$not_in_next" "$not_in_master"
88 | exit 1
89 | fi
90 |
91 | <<\DOC_END
92 |
93 | This sample hook safeguards topic branches that have been
94 | published from being rewound.
95 |
96 | The workflow assumed here is:
97 |
98 | * Once a topic branch forks from "master", "master" is never
99 | merged into it again (either directly or indirectly).
100 |
101 | * Once a topic branch is fully cooked and merged into "master",
102 | it is deleted. If you need to build on top of it to correct
103 | earlier mistakes, a new topic branch is created by forking at
104 | the tip of the "master". This is not strictly necessary, but
105 | it makes it easier to keep your history simple.
106 |
107 | * Whenever you need to test or publish your changes to topic
108 | branches, merge them into "next" branch.
109 |
110 | The script, being an example, hardcodes the publish branch name
111 | to be "next", but it is trivial to make it configurable via
112 | $GIT_DIR/config mechanism.
113 |
114 | With this workflow, you would want to know:
115 |
116 | (1) ... if a topic branch has ever been merged to "next". Young
117 | topic branches can have stupid mistakes you would rather
118 | clean up before publishing, and things that have not been
119 | merged into other branches can be easily rebased without
120 | affecting other people. But once it is published, you would
121 | not want to rewind it.
122 |
123 | (2) ... if a topic branch has been fully merged to "master".
124 | Then you can delete it. More importantly, you should not
125 | build on top of it -- other people may already want to
126 | change things related to the topic as patches against your
127 | "master", so if you need further changes, it is better to
128 | fork the topic (perhaps with the same name) afresh from the
129 | tip of "master".
130 |
131 | Let's look at this example:
132 |
133 | o---o---o---o---o---o---o---o---o---o "next"
134 | / / / /
135 | / a---a---b A / /
136 | / / / /
137 | / / c---c---c---c B /
138 | / / / \ /
139 | / / / b---b C \ /
140 | / / / / \ /
141 | ---o---o---o---o---o---o---o---o---o---o---o "master"
142 |
143 |
144 | A, B and C are topic branches.
145 |
146 | * A has one fix since it was merged up to "next".
147 |
148 | * B has finished. It has been fully merged up to "master" and "next",
149 | and is ready to be deleted.
150 |
151 | * C has not merged to "next" at all.
152 |
153 | We would want to allow C to be rebased, refuse A, and encourage
154 | B to be deleted.
155 |
156 | To compute (1):
157 |
158 | git rev-list ^master ^topic next
159 | git rev-list ^master next
160 |
161 | if these match, topic has not merged in next at all.
162 |
163 | To compute (2):
164 |
165 | git rev-list master..topic
166 |
167 | if this is empty, it is fully merged to "master".
168 |
169 | DOC_END
170 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/pre-receive.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to make use of push options.
4 | # The example simply echoes all push options that start with 'echoback='
5 | # and rejects all pushes when the "reject" push option is used.
6 | #
7 | # To enable this hook, rename this file to "pre-receive".
8 |
9 | if test -n "$GIT_PUSH_OPTION_COUNT"
10 | then
11 | i=0
12 | while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
13 | do
14 | eval "value=\$GIT_PUSH_OPTION_$i"
15 | case "$value" in
16 | echoback=*)
17 | echo "echo from the pre-receive-hook: ${value#*=}" >&2
18 | ;;
19 | reject)
20 | exit 1
21 | esac
22 | i=$((i + 1))
23 | done
24 | fi
25 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/prepare-commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare the commit log message.
4 | # Called by "git commit" with the name of the file that has the
5 | # commit message, followed by the description of the commit
6 | # message's source. The hook's purpose is to edit the commit
7 | # message file. If the hook fails with a non-zero status,
8 | # the commit is aborted.
9 | #
10 | # To enable this hook, rename this file to "prepare-commit-msg".
11 |
12 | # This hook includes three examples. The first one removes the
13 | # "# Please enter the commit message..." help message.
14 | #
15 | # The second includes the output of "git diff --name-status -r"
16 | # into the message, just before the "git status" output. It is
17 | # commented because it doesn't cope with --amend or with squashed
18 | # commits.
19 | #
20 | # The third example adds a Signed-off-by line to the message, that can
21 | # still be edited. This is rarely a good idea.
22 |
23 | COMMIT_MSG_FILE=$1
24 | COMMIT_SOURCE=$2
25 | SHA1=$3
26 |
27 | /usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
28 |
29 | # case "$COMMIT_SOURCE,$SHA1" in
30 | # ,|template,)
31 | # /usr/bin/perl -i.bak -pe '
32 | # print "\n" . `git diff --cached --name-status -r`
33 | # if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
34 | # *) ;;
35 | # esac
36 |
37 | # SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
38 | # git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
39 | # if test -z "$COMMIT_SOURCE"
40 | # then
41 | # /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
42 | # fi
43 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/hooks/update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to block unannotated tags from entering.
4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
5 | #
6 | # To enable this hook, rename this file to "update".
7 | #
8 | # Config
9 | # ------
10 | # hooks.allowunannotated
11 | # This boolean sets whether unannotated tags will be allowed into the
12 | # repository. By default they won't be.
13 | # hooks.allowdeletetag
14 | # This boolean sets whether deleting tags will be allowed in the
15 | # repository. By default they won't be.
16 | # hooks.allowmodifytag
17 | # This boolean sets whether a tag may be modified after creation. By default
18 | # it won't be.
19 | # hooks.allowdeletebranch
20 | # This boolean sets whether deleting branches will be allowed in the
21 | # repository. By default they won't be.
22 | # hooks.denycreatebranch
23 | # This boolean sets whether remotely creating branches will be denied
24 | # in the repository. By default this is allowed.
25 | #
26 |
27 | # --- Command line
28 | refname="$1"
29 | oldrev="$2"
30 | newrev="$3"
31 |
32 | # --- Safety check
33 | if [ -z "$GIT_DIR" ]; then
34 | echo "Don't run this script from the command line." >&2
35 | echo " (if you want, you could supply GIT_DIR then run" >&2
36 | echo " $0 ][ )" >&2
37 | exit 1
38 | fi
39 |
40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
41 | echo "usage: $0 ][ " >&2
42 | exit 1
43 | fi
44 |
45 | # --- Config
46 | allowunannotated=$(git config --bool hooks.allowunannotated)
47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
48 | denycreatebranch=$(git config --bool hooks.denycreatebranch)
49 | allowdeletetag=$(git config --bool hooks.allowdeletetag)
50 | allowmodifytag=$(git config --bool hooks.allowmodifytag)
51 |
52 | # check for no description
53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description")
54 | case "$projectdesc" in
55 | "Unnamed repository"* | "")
56 | echo "*** Project description file hasn't been set" >&2
57 | exit 1
58 | ;;
59 | esac
60 |
61 | # --- Check types
62 | # if $newrev is 0000...0000, it's a commit to delete a ref.
63 | zero="0000000000000000000000000000000000000000"
64 | if [ "$newrev" = "$zero" ]; then
65 | newrev_type=delete
66 | else
67 | newrev_type=$(git cat-file -t $newrev)
68 | fi
69 |
70 | case "$refname","$newrev_type" in
71 | refs/tags/*,commit)
72 | # un-annotated tag
73 | short_refname=${refname##refs/tags/}
74 | if [ "$allowunannotated" != "true" ]; then
75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
77 | exit 1
78 | fi
79 | ;;
80 | refs/tags/*,delete)
81 | # delete tag
82 | if [ "$allowdeletetag" != "true" ]; then
83 | echo "*** Deleting a tag is not allowed in this repository" >&2
84 | exit 1
85 | fi
86 | ;;
87 | refs/tags/*,tag)
88 | # annotated tag
89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
90 | then
91 | echo "*** Tag '$refname' already exists." >&2
92 | echo "*** Modifying a tag is not allowed in this repository." >&2
93 | exit 1
94 | fi
95 | ;;
96 | refs/heads/*,commit)
97 | # branch
98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
99 | echo "*** Creating a branch is not allowed in this repository" >&2
100 | exit 1
101 | fi
102 | ;;
103 | refs/heads/*,delete)
104 | # delete branch
105 | if [ "$allowdeletebranch" != "true" ]; then
106 | echo "*** Deleting a branch is not allowed in this repository" >&2
107 | exit 1
108 | fi
109 | ;;
110 | refs/remotes/*,commit)
111 | # tracking branch
112 | ;;
113 | refs/remotes/*,delete)
114 | # delete tracking branch
115 | if [ "$allowdeletebranch" != "true" ]; then
116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2
117 | exit 1
118 | fi
119 | ;;
120 | *)
121 | # Anything else (is there anything else?)
122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
123 | exit 1
124 | ;;
125 | esac
126 |
127 | # --- Finished
128 | exit 0
129 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/25/c55c716f1f18bb91aafa55f98a02315f59afe6:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/25/c55c716f1f18bb91aafa55f98a02315f59afe6
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/2c/499787328348f09ae1e8f03757c6483b9a938a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/2c/499787328348f09ae1e8f03757c6483b9a938a
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/6f/59e5e770be445518775b22bbe25e89339b778b:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/6f/59e5e770be445518775b22bbe25e89339b778b
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/d3/0b6cdff6d118d97095f39b2982d4fa237d33d1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/d3/0b6cdff6d118d97095f39b2982d4fa237d33d1
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/e6/f123d7d0aa2025ce61d28e2d34f94f3a6b5218:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/e6/f123d7d0aa2025ce61d28e2d34f94f3a6b5218
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo-with-merge-commit/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/packed-refs:
--------------------------------------------------------------------------------
1 | # pack-refs with: peeled fully-peeled sorted
2 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/refs/heads/master:
--------------------------------------------------------------------------------
1 | e6f123d7d0aa2025ce61d28e2d34f94f3a6b5218
2 |
--------------------------------------------------------------------------------
/testdata/init-repo-with-merge-commit/refs/tags/v0.0.1:
--------------------------------------------------------------------------------
1 | e6f123d7d0aa2025ce61d28e2d34f94f3a6b5218
2 |
--------------------------------------------------------------------------------
/testdata/init-repo/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/master
2 |
--------------------------------------------------------------------------------
/testdata/init-repo/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = true
5 |
--------------------------------------------------------------------------------
/testdata/init-repo/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/applypatch-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message taken by
4 | # applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit. The hook is
8 | # allowed to edit the commit message file.
9 | #
10 | # To enable this hook, rename this file to "applypatch-msg".
11 |
12 | . git-sh-setup
13 | commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
14 | test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
15 | :
16 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to check the commit log message.
4 | # Called by "git commit" with one argument, the name of the file
5 | # that has the commit message. The hook should exit with non-zero
6 | # status after issuing an appropriate message if it wants to stop the
7 | # commit. The hook is allowed to edit the commit message file.
8 | #
9 | # To enable this hook, rename this file to "commit-msg".
10 |
11 | # Uncomment the below to add a Signed-off-by line to the message.
12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg
13 | # hook is more suited to it.
14 | #
15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
17 |
18 | # This example catches duplicate Signed-off-by lines.
19 |
20 | test "" = "$(grep '^Signed-off-by: ' "$1" |
21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
22 | echo >&2 Duplicate Signed-off-by lines.
23 | exit 1
24 | }
25 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/fsmonitor-watchman.sample:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use IPC::Open2;
6 |
7 | # An example hook script to integrate Watchman
8 | # (https://facebook.github.io/watchman/) with git to speed up detecting
9 | # new and modified files.
10 | #
11 | # The hook is passed a version (currently 1) and a time in nanoseconds
12 | # formatted as a string and outputs to stdout all files that have been
13 | # modified since the given time. Paths must be relative to the root of
14 | # the working tree and separated by a single NUL.
15 | #
16 | # To enable this hook, rename this file to "query-watchman" and set
17 | # 'git config core.fsmonitor .git/hooks/query-watchman'
18 | #
19 | my ($version, $time) = @ARGV;
20 |
21 | # Check the hook interface version
22 |
23 | if ($version == 1) {
24 | # convert nanoseconds to seconds
25 | $time = int $time / 1000000000;
26 | } else {
27 | die "Unsupported query-fsmonitor hook version '$version'.\n" .
28 | "Falling back to scanning...\n";
29 | }
30 |
31 | my $git_work_tree;
32 | if ($^O =~ 'msys' || $^O =~ 'cygwin') {
33 | $git_work_tree = Win32::GetCwd();
34 | $git_work_tree =~ tr/\\/\//;
35 | } else {
36 | require Cwd;
37 | $git_work_tree = Cwd::cwd();
38 | }
39 |
40 | my $retry = 1;
41 |
42 | launch_watchman();
43 |
44 | sub launch_watchman {
45 |
46 | my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
47 | or die "open2() failed: $!\n" .
48 | "Falling back to scanning...\n";
49 |
50 | # In the query expression below we're asking for names of files that
51 | # changed since $time but were not transient (ie created after
52 | # $time but no longer exist).
53 | #
54 | # To accomplish this, we're using the "since" generator to use the
55 | # recency index to select candidate nodes and "fields" to limit the
56 | # output to file names only. Then we're using the "expression" term to
57 | # further constrain the results.
58 | #
59 | # The category of transient files that we want to ignore will have a
60 | # creation clock (cclock) newer than $time_t value and will also not
61 | # currently exist.
62 |
63 | my $query = <<" END";
64 | ["query", "$git_work_tree", {
65 | "since": $time,
66 | "fields": ["name"],
67 | "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
68 | }]
69 | END
70 |
71 | print CHLD_IN $query;
72 | close CHLD_IN;
73 | my $response = do {local $/; };
74 |
75 | die "Watchman: command returned no output.\n" .
76 | "Falling back to scanning...\n" if $response eq "";
77 | die "Watchman: command returned invalid output: $response\n" .
78 | "Falling back to scanning...\n" unless $response =~ /^\{/;
79 |
80 | my $json_pkg;
81 | eval {
82 | require JSON::XS;
83 | $json_pkg = "JSON::XS";
84 | 1;
85 | } or do {
86 | require JSON::PP;
87 | $json_pkg = "JSON::PP";
88 | };
89 |
90 | my $o = $json_pkg->new->utf8->decode($response);
91 |
92 | if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
93 | print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
94 | $retry--;
95 | qx/watchman watch "$git_work_tree"/;
96 | die "Failed to make watchman watch '$git_work_tree'.\n" .
97 | "Falling back to scanning...\n" if $? != 0;
98 |
99 | # Watchman will always return all files on the first query so
100 | # return the fast "everything is dirty" flag to git and do the
101 | # Watchman query just to get it over with now so we won't pay
102 | # the cost in git to look up each individual file.
103 | print "/\0";
104 | eval { launch_watchman() };
105 | exit 0;
106 | }
107 |
108 | die "Watchman: $o->{error}.\n" .
109 | "Falling back to scanning...\n" if $o->{error};
110 |
111 | binmode STDOUT, ":utf8";
112 | local $, = "\0";
113 | print @{$o->{files}};
114 | }
115 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/post-update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare a packed repository for use over
4 | # dumb transports.
5 | #
6 | # To enable this hook, rename this file to "post-update".
7 |
8 | exec git update-server-info
9 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/pre-applypatch.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed
4 | # by applypatch from an e-mail message.
5 | #
6 | # The hook should exit with non-zero status after issuing an
7 | # appropriate message if it wants to stop the commit.
8 | #
9 | # To enable this hook, rename this file to "pre-applypatch".
10 |
11 | . git-sh-setup
12 | precommit="$(git rev-parse --git-path hooks/pre-commit)"
13 | test -x "$precommit" && exec "$precommit" ${1+"$@"}
14 | :
15 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/pre-commit.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to verify what is about to be committed.
4 | # Called by "git commit" with no arguments. The hook should
5 | # exit with non-zero status after issuing an appropriate message if
6 | # it wants to stop the commit.
7 | #
8 | # To enable this hook, rename this file to "pre-commit".
9 |
10 | if git rev-parse --verify HEAD >/dev/null 2>&1
11 | then
12 | against=HEAD
13 | else
14 | # Initial commit: diff against an empty tree object
15 | against=$(git hash-object -t tree /dev/null)
16 | fi
17 |
18 | # If you want to allow non-ASCII filenames set this variable to true.
19 | allownonascii=$(git config --bool hooks.allownonascii)
20 |
21 | # Redirect output to stderr.
22 | exec 1>&2
23 |
24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent
25 | # them from being added to the repository. We exploit the fact that the
26 | # printable range starts at the space character and ends with tilde.
27 | if [ "$allownonascii" != "true" ] &&
28 | # Note that the use of brackets around a tr range is ok here, (it's
29 | # even required, for portability to Solaris 10's /usr/bin/tr), since
30 | # the square bracket bytes happen to fall in the designated range.
31 | test $(git diff --cached --name-only --diff-filter=A -z $against |
32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
33 | then
34 | cat <<\EOF
35 | Error: Attempt to add a non-ASCII file name.
36 |
37 | This can cause problems if you want to work with people on other platforms.
38 |
39 | To be portable it is advisable to rename the file.
40 |
41 | If you know what you are doing you can disable this check using:
42 |
43 | git config hooks.allownonascii true
44 | EOF
45 | exit 1
46 | fi
47 |
48 | # If there are whitespace errors, print the offending file names and fail.
49 | exec git diff-index --check --cached $against --
50 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/pre-push.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # An example hook script to verify what is about to be pushed. Called by "git
4 | # push" after it has checked the remote status, but before anything has been
5 | # pushed. If this script exits with a non-zero status nothing will be pushed.
6 | #
7 | # This hook is called with the following parameters:
8 | #
9 | # $1 -- Name of the remote to which the push is being done
10 | # $2 -- URL to which the push is being done
11 | #
12 | # If pushing without using a named remote those arguments will be equal.
13 | #
14 | # Information about the commits which are being pushed is supplied as lines to
15 | # the standard input in the form:
16 | #
17 | #
18 | #
19 | # This sample shows how to prevent push of commits where the log message starts
20 | # with "WIP" (work in progress).
21 |
22 | remote="$1"
23 | url="$2"
24 |
25 | z40=0000000000000000000000000000000000000000
26 |
27 | while read local_ref local_sha remote_ref remote_sha
28 | do
29 | if [ "$local_sha" = $z40 ]
30 | then
31 | # Handle delete
32 | :
33 | else
34 | if [ "$remote_sha" = $z40 ]
35 | then
36 | # New branch, examine all commits
37 | range="$local_sha"
38 | else
39 | # Update to existing branch, examine new commits
40 | range="$remote_sha..$local_sha"
41 | fi
42 |
43 | # Check for WIP commit
44 | commit=`git rev-list -n 1 --grep '^WIP' "$range"`
45 | if [ -n "$commit" ]
46 | then
47 | echo >&2 "Found WIP commit in $local_ref, not pushing"
48 | exit 1
49 | fi
50 | fi
51 | done
52 |
53 | exit 0
54 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/pre-rebase.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Copyright (c) 2006, 2008 Junio C Hamano
4 | #
5 | # The "pre-rebase" hook is run just before "git rebase" starts doing
6 | # its job, and can prevent the command from running by exiting with
7 | # non-zero status.
8 | #
9 | # The hook is called with the following parameters:
10 | #
11 | # $1 -- the upstream the series was forked from.
12 | # $2 -- the branch being rebased (or empty when rebasing the current branch).
13 | #
14 | # This sample shows how to prevent topic branches that are already
15 | # merged to 'next' branch from getting rebased, because allowing it
16 | # would result in rebasing already published history.
17 |
18 | publish=next
19 | basebranch="$1"
20 | if test "$#" = 2
21 | then
22 | topic="refs/heads/$2"
23 | else
24 | topic=`git symbolic-ref HEAD` ||
25 | exit 0 ;# we do not interrupt rebasing detached HEAD
26 | fi
27 |
28 | case "$topic" in
29 | refs/heads/??/*)
30 | ;;
31 | *)
32 | exit 0 ;# we do not interrupt others.
33 | ;;
34 | esac
35 |
36 | # Now we are dealing with a topic branch being rebased
37 | # on top of master. Is it OK to rebase it?
38 |
39 | # Does the topic really exist?
40 | git show-ref -q "$topic" || {
41 | echo >&2 "No such branch $topic"
42 | exit 1
43 | }
44 |
45 | # Is topic fully merged to master?
46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
47 | if test -z "$not_in_master"
48 | then
49 | echo >&2 "$topic is fully merged to master; better remove it."
50 | exit 1 ;# we could allow it, but there is no point.
51 | fi
52 |
53 | # Is topic ever merged to next? If so you should not be rebasing it.
54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
55 | only_next_2=`git rev-list ^master ${publish} | sort`
56 | if test "$only_next_1" = "$only_next_2"
57 | then
58 | not_in_topic=`git rev-list "^$topic" master`
59 | if test -z "$not_in_topic"
60 | then
61 | echo >&2 "$topic is already up to date with master"
62 | exit 1 ;# we could allow it, but there is no point.
63 | else
64 | exit 0
65 | fi
66 | else
67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
68 | /usr/bin/perl -e '
69 | my $topic = $ARGV[0];
70 | my $msg = "* $topic has commits already merged to public branch:\n";
71 | my (%not_in_next) = map {
72 | /^([0-9a-f]+) /;
73 | ($1 => 1);
74 | } split(/\n/, $ARGV[1]);
75 | for my $elem (map {
76 | /^([0-9a-f]+) (.*)$/;
77 | [$1 => $2];
78 | } split(/\n/, $ARGV[2])) {
79 | if (!exists $not_in_next{$elem->[0]}) {
80 | if ($msg) {
81 | print STDERR $msg;
82 | undef $msg;
83 | }
84 | print STDERR " $elem->[1]\n";
85 | }
86 | }
87 | ' "$topic" "$not_in_next" "$not_in_master"
88 | exit 1
89 | fi
90 |
91 | <<\DOC_END
92 |
93 | This sample hook safeguards topic branches that have been
94 | published from being rewound.
95 |
96 | The workflow assumed here is:
97 |
98 | * Once a topic branch forks from "master", "master" is never
99 | merged into it again (either directly or indirectly).
100 |
101 | * Once a topic branch is fully cooked and merged into "master",
102 | it is deleted. If you need to build on top of it to correct
103 | earlier mistakes, a new topic branch is created by forking at
104 | the tip of the "master". This is not strictly necessary, but
105 | it makes it easier to keep your history simple.
106 |
107 | * Whenever you need to test or publish your changes to topic
108 | branches, merge them into "next" branch.
109 |
110 | The script, being an example, hardcodes the publish branch name
111 | to be "next", but it is trivial to make it configurable via
112 | $GIT_DIR/config mechanism.
113 |
114 | With this workflow, you would want to know:
115 |
116 | (1) ... if a topic branch has ever been merged to "next". Young
117 | topic branches can have stupid mistakes you would rather
118 | clean up before publishing, and things that have not been
119 | merged into other branches can be easily rebased without
120 | affecting other people. But once it is published, you would
121 | not want to rewind it.
122 |
123 | (2) ... if a topic branch has been fully merged to "master".
124 | Then you can delete it. More importantly, you should not
125 | build on top of it -- other people may already want to
126 | change things related to the topic as patches against your
127 | "master", so if you need further changes, it is better to
128 | fork the topic (perhaps with the same name) afresh from the
129 | tip of "master".
130 |
131 | Let's look at this example:
132 |
133 | o---o---o---o---o---o---o---o---o---o "next"
134 | / / / /
135 | / a---a---b A / /
136 | / / / /
137 | / / c---c---c---c B /
138 | / / / \ /
139 | / / / b---b C \ /
140 | / / / / \ /
141 | ---o---o---o---o---o---o---o---o---o---o---o "master"
142 |
143 |
144 | A, B and C are topic branches.
145 |
146 | * A has one fix since it was merged up to "next".
147 |
148 | * B has finished. It has been fully merged up to "master" and "next",
149 | and is ready to be deleted.
150 |
151 | * C has not merged to "next" at all.
152 |
153 | We would want to allow C to be rebased, refuse A, and encourage
154 | B to be deleted.
155 |
156 | To compute (1):
157 |
158 | git rev-list ^master ^topic next
159 | git rev-list ^master next
160 |
161 | if these match, topic has not merged in next at all.
162 |
163 | To compute (2):
164 |
165 | git rev-list master..topic
166 |
167 | if this is empty, it is fully merged to "master".
168 |
169 | DOC_END
170 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/pre-receive.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to make use of push options.
4 | # The example simply echoes all push options that start with 'echoback='
5 | # and rejects all pushes when the "reject" push option is used.
6 | #
7 | # To enable this hook, rename this file to "pre-receive".
8 |
9 | if test -n "$GIT_PUSH_OPTION_COUNT"
10 | then
11 | i=0
12 | while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
13 | do
14 | eval "value=\$GIT_PUSH_OPTION_$i"
15 | case "$value" in
16 | echoback=*)
17 | echo "echo from the pre-receive-hook: ${value#*=}" >&2
18 | ;;
19 | reject)
20 | exit 1
21 | esac
22 | i=$((i + 1))
23 | done
24 | fi
25 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/prepare-commit-msg.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to prepare the commit log message.
4 | # Called by "git commit" with the name of the file that has the
5 | # commit message, followed by the description of the commit
6 | # message's source. The hook's purpose is to edit the commit
7 | # message file. If the hook fails with a non-zero status,
8 | # the commit is aborted.
9 | #
10 | # To enable this hook, rename this file to "prepare-commit-msg".
11 |
12 | # This hook includes three examples. The first one removes the
13 | # "# Please enter the commit message..." help message.
14 | #
15 | # The second includes the output of "git diff --name-status -r"
16 | # into the message, just before the "git status" output. It is
17 | # commented because it doesn't cope with --amend or with squashed
18 | # commits.
19 | #
20 | # The third example adds a Signed-off-by line to the message, that can
21 | # still be edited. This is rarely a good idea.
22 |
23 | COMMIT_MSG_FILE=$1
24 | COMMIT_SOURCE=$2
25 | SHA1=$3
26 |
27 | /usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
28 |
29 | # case "$COMMIT_SOURCE,$SHA1" in
30 | # ,|template,)
31 | # /usr/bin/perl -i.bak -pe '
32 | # print "\n" . `git diff --cached --name-status -r`
33 | # if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
34 | # *) ;;
35 | # esac
36 |
37 | # SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
38 | # git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
39 | # if test -z "$COMMIT_SOURCE"
40 | # then
41 | # /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
42 | # fi
43 |
--------------------------------------------------------------------------------
/testdata/init-repo/hooks/update.sample:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # An example hook script to block unannotated tags from entering.
4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
5 | #
6 | # To enable this hook, rename this file to "update".
7 | #
8 | # Config
9 | # ------
10 | # hooks.allowunannotated
11 | # This boolean sets whether unannotated tags will be allowed into the
12 | # repository. By default they won't be.
13 | # hooks.allowdeletetag
14 | # This boolean sets whether deleting tags will be allowed in the
15 | # repository. By default they won't be.
16 | # hooks.allowmodifytag
17 | # This boolean sets whether a tag may be modified after creation. By default
18 | # it won't be.
19 | # hooks.allowdeletebranch
20 | # This boolean sets whether deleting branches will be allowed in the
21 | # repository. By default they won't be.
22 | # hooks.denycreatebranch
23 | # This boolean sets whether remotely creating branches will be denied
24 | # in the repository. By default this is allowed.
25 | #
26 |
27 | # --- Command line
28 | refname="$1"
29 | oldrev="$2"
30 | newrev="$3"
31 |
32 | # --- Safety check
33 | if [ -z "$GIT_DIR" ]; then
34 | echo "Don't run this script from the command line." >&2
35 | echo " (if you want, you could supply GIT_DIR then run" >&2
36 | echo " $0 ][ )" >&2
37 | exit 1
38 | fi
39 |
40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
41 | echo "usage: $0 ][ " >&2
42 | exit 1
43 | fi
44 |
45 | # --- Config
46 | allowunannotated=$(git config --bool hooks.allowunannotated)
47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
48 | denycreatebranch=$(git config --bool hooks.denycreatebranch)
49 | allowdeletetag=$(git config --bool hooks.allowdeletetag)
50 | allowmodifytag=$(git config --bool hooks.allowmodifytag)
51 |
52 | # check for no description
53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description")
54 | case "$projectdesc" in
55 | "Unnamed repository"* | "")
56 | echo "*** Project description file hasn't been set" >&2
57 | exit 1
58 | ;;
59 | esac
60 |
61 | # --- Check types
62 | # if $newrev is 0000...0000, it's a commit to delete a ref.
63 | zero="0000000000000000000000000000000000000000"
64 | if [ "$newrev" = "$zero" ]; then
65 | newrev_type=delete
66 | else
67 | newrev_type=$(git cat-file -t $newrev)
68 | fi
69 |
70 | case "$refname","$newrev_type" in
71 | refs/tags/*,commit)
72 | # un-annotated tag
73 | short_refname=${refname##refs/tags/}
74 | if [ "$allowunannotated" != "true" ]; then
75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
77 | exit 1
78 | fi
79 | ;;
80 | refs/tags/*,delete)
81 | # delete tag
82 | if [ "$allowdeletetag" != "true" ]; then
83 | echo "*** Deleting a tag is not allowed in this repository" >&2
84 | exit 1
85 | fi
86 | ;;
87 | refs/tags/*,tag)
88 | # annotated tag
89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
90 | then
91 | echo "*** Tag '$refname' already exists." >&2
92 | echo "*** Modifying a tag is not allowed in this repository." >&2
93 | exit 1
94 | fi
95 | ;;
96 | refs/heads/*,commit)
97 | # branch
98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
99 | echo "*** Creating a branch is not allowed in this repository" >&2
100 | exit 1
101 | fi
102 | ;;
103 | refs/heads/*,delete)
104 | # delete branch
105 | if [ "$allowdeletebranch" != "true" ]; then
106 | echo "*** Deleting a branch is not allowed in this repository" >&2
107 | exit 1
108 | fi
109 | ;;
110 | refs/remotes/*,commit)
111 | # tracking branch
112 | ;;
113 | refs/remotes/*,delete)
114 | # delete tracking branch
115 | if [ "$allowdeletebranch" != "true" ]; then
116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2
117 | exit 1
118 | fi
119 | ;;
120 | *)
121 | # Anything else (is there anything else?)
122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
123 | exit 1
124 | ;;
125 | esac
126 |
127 | # --- Finished
128 | exit 0
129 |
--------------------------------------------------------------------------------
/testdata/init-repo/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/init-repo/objects/2c/499787328348f09ae1e8f03757c6483b9a938a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/2c/499787328348f09ae1e8f03757c6483b9a938a
--------------------------------------------------------------------------------
/testdata/init-repo/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/2c/c00abc77d401a541d18c26e5c7fbef1effd3ed
--------------------------------------------------------------------------------
/testdata/init-repo/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/3e/c1e9a60d07cc060cee727c97ffc8aac5713943
--------------------------------------------------------------------------------
/testdata/init-repo/objects/6f/59e5e770be445518775b22bbe25e89339b778b:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/6f/59e5e770be445518775b22bbe25e89339b778b
--------------------------------------------------------------------------------
/testdata/init-repo/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/ab/515204e62e6fd2b468736de7aadcaca4d9dffd
--------------------------------------------------------------------------------
/testdata/init-repo/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
--------------------------------------------------------------------------------
/testdata/init-repo/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goreleaser/chglog/b46d97bd57b12f8c0dc317dcd0568dff5db5b396/testdata/init-repo/objects/ea/2b12e15f99419047f49d5fc5dc844073899da8
--------------------------------------------------------------------------------
/testdata/init-repo/refs/heads/master:
--------------------------------------------------------------------------------
1 | 2c499787328348f09ae1e8f03757c6483b9a938a
2 |
--------------------------------------------------------------------------------
/testdata/init-repo/refs/tags/v0.0.1:
--------------------------------------------------------------------------------
1 | 2c499787328348f09ae1e8f03757c6483b9a938a
2 |
--------------------------------------------------------------------------------
/types.go:
--------------------------------------------------------------------------------
1 | // Package chglog contains the public API for working with a changlog.yml file
2 | package chglog
3 |
4 | import (
5 | "time"
6 |
7 | "github.com/Masterminds/semver/v3"
8 | conventional_commit "gitlab.com/digitalxero/go-conventional-commit"
9 | )
10 |
11 | // ChangeLogEntries list of ChangeLog entries.
12 | type ChangeLogEntries []*ChangeLog
13 |
14 | // Len returns the length of a collection. The number of Version instances
15 | // on the slice.
16 | func (c ChangeLogEntries) Len() int {
17 | return len(c)
18 | }
19 |
20 | // Less is needed for the sort interface to compare two Version objects on the
21 | // slice. If checks if one is less than the other.
22 | func (c ChangeLogEntries) Less(i, j int) bool {
23 | v1, err := semver.NewVersion(c[i].Semver)
24 | if err != nil {
25 | return true
26 | }
27 | v2, err := semver.NewVersion(c[j].Semver)
28 | if err != nil {
29 | return false
30 | }
31 |
32 | return v1.LessThan(v2)
33 | }
34 |
35 | // Swap is needed for the sort interface to replace the Version objects
36 | // at two different positions in the slice.
37 | func (c ChangeLogEntries) Swap(i, j int) {
38 | c[i], c[j] = c[j], c[i]
39 | }
40 |
41 | // PackageChangeLog used for the formatting API.
42 | type PackageChangeLog struct {
43 | Name string `yaml:"name"`
44 | Entries ChangeLogEntries `yaml:"entries"`
45 | }
46 |
47 | // ChangeLog a single changelog entry.
48 | type ChangeLog struct {
49 | ChangeLogOverridables `yaml:",inline"`
50 | Semver string `yaml:"semver"`
51 | Date time.Time `yaml:"date"`
52 | Packager string `yaml:"packager"`
53 | Notes *ChangeLogNotes `yaml:"notes,omitempty"`
54 | Changes ChangeLogChanges `yaml:"changes,omitempty"`
55 | }
56 |
57 | // ChangeLogOverridables contains potential format specific fields.
58 | type ChangeLogOverridables struct {
59 | Deb *ChangelogDeb `yaml:"deb,omitempty"`
60 | }
61 |
62 | // ChangelogDeb contains fields specific to the debian changelog format
63 | // https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog
64 | type ChangelogDeb struct {
65 | Urgency string `yaml:"urgency"`
66 | Distributions []string `yaml:"distributions"`
67 | }
68 |
69 | // ChangeLogNotes contains a potential header/footer string for output formatting.
70 | type ChangeLogNotes struct {
71 | Header *string `yaml:"header,omitempty"`
72 | Footer *string `yaml:"footer,omitempty"`
73 | }
74 |
75 | // ChangeLogChanges list of individual changes.
76 | type ChangeLogChanges []*ChangeLogChange
77 |
78 | // ChangeLogChange an individual change.
79 | type ChangeLogChange struct {
80 | Commit string `yaml:"commit"`
81 | Note string `yaml:"note"`
82 | // Author is the original author of the commit.
83 | Author *User `yaml:"author,omitempty"`
84 | // Committer is the one performing the commit, might be different from
85 | // Author.
86 | Committer *User `yaml:"committer,omitempty"`
87 | ConventionalCommit *conventional_commit.ConventionalCommit `yaml:"conventional_commit,omitempty"`
88 | }
89 |
90 | // User is used to identify who created a commit or tag.
91 | type User struct {
92 | // Name represents a person name. It is an arbitrary string.
93 | Name string `yaml:"name"`
94 | // Email is an email, but it cannot be assumed to be well-formed.
95 | Email string `yaml:"email"`
96 | }
97 |
--------------------------------------------------------------------------------
]