Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a "create release" binary #14

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Create Release

on:
workflow_dispatch:
inputs:
draft:
type: choice
description: "Create the release as draft"
options:
- "yes"
- "no"
required: true
force:
type: choice
description: "Force the creation of a release (event if no PR are found)"
options:
- "yes"
- "no"
required: true

jobs:

release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # we need this because fetch-tags=true and because of a GHA bug: https://github.com/actions/checkout/issues/1471
fetch-tags: true
- uses: actions/setup-go@v4
with:
go-version: "1.21"
- name: Run build
run: |
make build
- name: Run
run: |
OPTIONS=""
if test "${{ github.event.inputs.draft }}" == "yes"; then
OPTIONS="${OPTIONS} --release-draft"
fi
if test "${{ github.event.inputs.force }}" == "yes"; then
OPTIONS="${OPTIONS} --dont-increment-if-no-pr"
fi
echo "OPTIONS=${OPTIONS}"
./cmd/github-create-next-semantic-release/github-create-next-semantic-release --log-level=DEBUG ${OPTIONS}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ go.work
go.work.sum
/coverage.out
/cmd/github-next-semantic-version/github-next-semantic-version
/cmd/github-create-next-semantic-release/github-create-next-semantic-release
/tmp
/.vscode
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FIX=1
COMMON_TEST_OPTIONS=-race
CMDS=cmd/github-next-semantic-version/github-next-semantic-version
CMDS=cmd/github-next-semantic-version/github-next-semantic-version cmd/github-create-next-semantic-release/github-create-next-semantic-release
BUILDARGS=

default: help
Expand All @@ -11,6 +11,9 @@ build: $(CMDS) ## Build Go binaries
cmd/github-next-semantic-version/github-next-semantic-version: $(shell find cmd/github-next-semantic-version internal -type f -name '*.go')
cd `dirname $@` && export CGO_ENABLED=0 && go build $(BUILDARGS) -o `basename $@` *.go

cmd/github-create-next-semantic-release/github-create-next-semantic-release: $(shell find cmd/github-create-next-semantic-release internal -type f -name '*.go')
cd `dirname $@` && export CGO_ENABLED=0 && go build $(BUILDARGS) -o `basename $@` *.go

.PHONY: gofmt
gofmt:
@if test "$(FIX)" = "1"; then \
Expand Down
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ $ # v1.10.1 is the next version
>
> *(of course, you can define your own labels to configure the logic)*

We also provide another CLI binary: `github-create-next-semantic-release` to use previous rules but to automatically create a GitHub release
with the guessed version and the corresponding release notes (made from merged PRs and a configurable template).

## Features

- support full semver specification (basic `1.2.3` but also `1.0.0-beta.2`, `0.1.9-post.24_a5256f1`...)
- can filter tags with regex (see `--tag-regex` option)
- support prefixed tags (example: `v1.2.3` but also `foo/bar/v1.2.3`...) when parsing the semantic version
- configure your own PR labels for major and minor increments
- ... (see "CLI reference" in this document)
- addon binary to automatically create GitHub releases with the guessed version and corresponding release notes

## Non-features

Expand All @@ -65,6 +69,10 @@ We provide compiled binaries for various architecture in the [release page](http

## CLI reference

<details open>

<summary>CLI reference of `github-next-semantic-version`</summary>

```console
$ github-next-semantic-version --help

Expand All @@ -87,14 +95,55 @@ GLOBAL OPTIONS:
--major-labels value Coma separated list of PR labels to consider as major (default: "major,breaking,Type: Major") [$GNSV_MAJOR_LABELS]
--minor-labels value Coma separated list of PR labels to consider as minor (default: "feature,Type: Feature,Type: Minor") [$GNSV_MINOR_LABELS]
--ignore-labels value Coma separated list of PR labels to consider as ignored PRs (default: "Type: Hidden") [$GNSV_HIDDEN_LABELS]
--dont-increment-if-no-pr Don't increment the version if no PR is found (or if only ignored PRs found) (default: false) [$GNSV_DONT_INCREMENT_IF_NO_PR]
--consider-also-non-merged-prs Consider also non-merged PRs (default: false) [$GNSV_CONSIDER_ALSO_NON_MERGED_PRS]
--minimal-delay-in-seconds value Minimal delay in seconds between a PR and a tag (if less, we consider that the tag is always AFTER the PR) (default: 5)
--tag-regex value Regex to match tags (if empty string (default) => no filtering) [$GNSV_TAG_REGEX]
--dont-increment-if-no-pr Don't increment the version if no PR is found (or if only ignored PRs found) (default: false) [$GNSV_DONT_INCREMENT_IF_NO_PR]
--help, -h show help

```

</details>

<details>

<summary>CLI reference of `github-create-next-semantic-release`</summary>

```console
$ github-create-next-semantic-release --help

NAME:
github-next-semantic-version - Compute the next semantic version with merged PRs and corresponding labels

USAGE:
github-next-semantic-version [global options] command [command options] LOCAL_GIT_REPO_PATH

COMMANDS:
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--log-level value log level (DEBUG, INFO, WARN, ERROR) (default: "INFO") [$LOG_LEVEL]
--log-format value log format (text-human, text, json, json-gcp) (default: "text-human") [$LOG_FORMAT]
--github-token value github token [$GITHUB_TOKEN]
--repo-owner value repository owner (organization); if not set, we are going to try to guess [$GNSV_REPO_OWNER]
--repo-name value repository name (without owner/organization part); if not set, we are going to try to guess [$GNSV_REPO_NAME]
--branch value Branch to filter on [$GNSV_BRANCH_NAME]
--major-labels value Coma separated list of PR labels to consider as major (default: "major,breaking,Type: Major") [$GNSV_MAJOR_LABELS]
--minor-labels value Coma separated list of PR labels to consider as minor (default: "feature,Type: Feature,Type: Minor") [$GNSV_MINOR_LABELS]
--ignore-labels value Coma separated list of PR labels to consider as ignored PRs (default: "Type: Hidden") [$GNSV_HIDDEN_LABELS]
--consider-also-non-merged-prs Consider also non-merged PRs (default: false) [$GNSV_CONSIDER_ALSO_NON_MERGED_PRS]
--minimal-delay-in-seconds value Minimal delay in seconds between a PR and a tag (if less, we consider that the tag is always AFTER the PR) (default: 5)
--tag-regex value Regex to match tags (if empty string (default) => no filtering) [$GNSV_TAG_REGEX]
--release-draft if set, the release is created in draft mode (default: false) [$GNSV_RELEASE_DRAFT]
--release-body-template value golang template to generate the release body (default: "{{ range . }}- {{.Title}} (#{{.Number}})\n{{ end }}") [$GNSV_RELEASE_BODY_TEMPLATE]
--release-body-template-path value golang template path to generate the release body (if set, release-body-template option is ignored) [$GNSV_RELEASE_BODY_TEMPLATE_PATH]
--release-force value if set, force the version bump and the creation of a release (even if there is no PR) [$GNSV_RELEASE_FORCE]
--help, -h show help

```

</details>

## DEV

This tool is fully developped in Golang 1.21+ with following libraries:
Expand Down
22 changes: 22 additions & 0 deletions README.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ $ # v1.10.1 is the next version
>
> *(of course, you can define your own labels to configure the logic)*

We also provide another CLI binary: `github-create-next-semantic-release` to use previous rules but to automatically create a GitHub release
with the guessed version and the corresponding release notes (made from merged PRs and a configurable template).

## Features

- support full semver specification (basic `1.2.3` but also `1.0.0-beta.2`, `0.1.9-post.24_a5256f1`...)
- can filter tags with regex (see `--tag-regex` option)
- support prefixed tags (example: `v1.2.3` but also `foo/bar/v1.2.3`...) when parsing the semantic version
- configure your own PR labels for major and minor increments
- ... (see "CLI reference" in this document)
- addon binary to automatically create GitHub releases with the guessed version and corresponding release notes

## Non-features

Expand All @@ -65,12 +69,30 @@ We provide compiled binaries for various architecture in the [release page](http

## CLI reference

<details open>

<summary>CLI reference of `github-next-semantic-version`</summary>

```console
$ github-next-semantic-version --help

{{ "./cmd/github-next-semantic-version/github-next-semantic-version --help"|shell() }}
```

</details>

<details>

<summary>CLI reference of `github-create-next-semantic-release`</summary>

```console
$ github-create-next-semantic-release --help

{{ "./cmd/github-create-next-semantic-release/github-create-next-semantic-release --help"|shell() }}
```

</details>

## DEV

This tool is fully developped in Golang 1.21+ with following libraries:
Expand Down
9 changes: 9 additions & 0 deletions cmd/github-create-next-semantic-release/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"github.com/fabien-marty/github-next-semantic-version/internal/infra/controllers/cli"
)

func main() {
cli.CreateReleaseMain()
}
2 changes: 1 addition & 1 deletion cmd/github-next-semantic-version/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import (
)

func main() {
cli.Main()
cli.NextVersionMain()
}
1 change: 0 additions & 1 deletion internal/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ type Config struct {
PullRequestMajorLabels []string // list of labels for considering a PR as major
PullRequestMinorLabels []string // list of labels for considering a PR as minor
PullRequestIgnoreLabels []string // list of labels for completely ignoring a PR
DontIncrementIfNoPR bool // if true, the version will not be incremented if no PR is found (or if all PRs are ignored)
MinimalDelayInSeconds int // minimal delay in seconds between a PR and a tag (if less, we consider that the tag is always AFTER the PR)
TagRegex string // regex to match tags (if empty string => no filtering)
}
Expand Down
20 changes: 14 additions & 6 deletions internal/app/git/entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Tag struct {
Name string // tag name (without modification)
Time time.Time // commit time of the tag
Semver *semver.Version // semver version read from tag name (nil if the tag name is not in the expected format)
Prefix string // Prefix read before the semver version
}

// NewTag creates a new Tag instance with the given name and date.
Expand All @@ -20,10 +21,19 @@ type Tag struct {
// if the tag name is in the form foo/v1.2.3, the prefix part ("foo/") will be removed before parsing
// If the name is not in the expected format, the Semver field of the returned Tag will be nil.
func NewTag(name string, date time.Time) *Tag {
nameWithoutPrefix := strings.TrimPrefix(name, "v")
if name == "" {
return nil
}
prefix := ""
nameWithoutPrefix := name
if strings.Contains(nameWithoutPrefix, "/") {
tmp := strings.Split(nameWithoutPrefix, "/")
nameWithoutPrefix = tmp[len(tmp)-1]
prefix = strings.Join(tmp[:len(tmp)-1], "/") + "/"
}
if nameWithoutPrefix[0] == 'v' {
prefix += "v"
nameWithoutPrefix = strings.TrimPrefix(nameWithoutPrefix, "v")
}
version, err := semver.NewVersion(nameWithoutPrefix)
if err != nil {
Expand All @@ -33,6 +43,7 @@ func NewTag(name string, date time.Time) *Tag {
Name: name,
Time: date,
Semver: version,
Prefix: prefix,
}
}

Expand All @@ -52,11 +63,8 @@ func (t1 *Tag) LessThan(t2 *Tag) bool {
}

// NewName returns the new name for the tag based on the provided new version.
// If the current tag name has a prefix "v", the new name will also have the same prefix.
// If the current tag name has a prefix ("v"...), the new name will also have the same prefix.
// Otherwise, the new name will not have any prefix.
func (t *Tag) NewName(newVersion semver.Version) string {
if strings.HasPrefix(t.Name, "v") {
return "v" + newVersion.String()
}
return newVersion.String()
return t.Prefix + newVersion.String()
}
3 changes: 3 additions & 0 deletions internal/app/git/entities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestNewTag(t *testing.T) {
assert.Equal(t, uint64(1), tag.Semver.Major())
assert.Equal(t, uint64(0), tag.Semver.Minor())
assert.Equal(t, uint64(0), tag.Semver.Patch())
assert.Equal(t, "", tag.Prefix)
}

func TestNewTagWithPrefix(t *testing.T) {
Expand All @@ -29,6 +30,7 @@ func TestNewTagWithPrefix(t *testing.T) {
assert.Equal(t, uint64(1), tag.Semver.Major())
assert.Equal(t, uint64(0), tag.Semver.Minor())
assert.Equal(t, uint64(0), tag.Semver.Patch())
assert.Equal(t, "v", tag.Prefix)
}

func TestNewTagWithPrefix2(t *testing.T) {
Expand All @@ -41,6 +43,7 @@ func TestNewTagWithPrefix2(t *testing.T) {
assert.Equal(t, uint64(1), tag.Semver.Major())
assert.Equal(t, uint64(0), tag.Semver.Minor())
assert.Equal(t, uint64(0), tag.Semver.Patch())
assert.Equal(t, "foo/bar/v", tag.Prefix)
}

func TestNewTagWithNonSemantic(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions internal/app/repo/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ type Port interface {
// If onlyMerged is true, only the merged pull requests since the given date are returned.
// If onlyMerged is false, merged pull requests since the given date are returned + (still) open pull requests.
GetPullRequestsSince(base string, t time.Time, onlyMerged bool) ([]PullRequest, error)
CreateRelease(base string, tagName string, body string, draft bool) error
}
Loading
Loading