Skip to content

Commit

Permalink
new feature to create a github release
Browse files Browse the repository at this point in the history
  • Loading branch information
fabien-marty committed Oct 31, 2024
1 parent 4f7fbd7 commit 563a2ae
Show file tree
Hide file tree
Showing 18 changed files with 549 additions and 195 deletions.
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
49 changes: 49 additions & 0 deletions 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 Down Expand Up @@ -95,6 +103,47 @@ GLOBAL OPTIONS:

```

</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]
--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]
--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]
--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

0 comments on commit 563a2ae

Please sign in to comment.