Skip to content

Commit

Permalink
rancher#293: tag rancher release (rancher#315)
Browse files Browse the repository at this point in the history
* add rancher tag release command

* add release body generation with rancher/rancher

* add documentation

* fix import

* fix pull

* move types to top

* add tests

* remove components file

* remove unued struct run component files args

---------

Co-authored-by: Pedro Tashima <[email protected]>
  • Loading branch information
tashima42 and tashima42 committed Dec 12, 2023
1 parent 8685460 commit bc91df8
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 27 deletions.
58 changes: 48 additions & 10 deletions cmd/rancher_release/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Results are printed in MD, and can be pasted into Slack, but formatting is trick

**Examples**

```
```sh
rancher_release list-nonmirrored-rc-images --tag v2.8.0-rc1
```

Expand All @@ -31,7 +31,7 @@ Checks if there’s an available Helm Chart and Docker images for amd64, arm and

**Examples**

```
```sh
rancher_release check-rancher-image --tag v2.8.0-rc1
```

Expand All @@ -56,24 +56,24 @@ Optional flags can be automatically set if you are inside your rancher fork. ⚠

**Examples**

```
```sh
rancher_release set-kdm-branch-refs -n dev-v2.8-september-patches --create-pr --dry-run
```

```
```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release set-kdm-branch-refs -n dev-v2.8-september-patches -p -r
```

```
```sh
rancher_release set-kdm-branch-refs --fork-path $GOPATH/src/github.com/{YOUR_USERNAME}/rancher \
--base-branch release/v2.8 \
--current-kdm-branch dev-v2.8 \
--new-kdm-branch dev-v2.8-september-patches
```

```
```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release set-kdm-branch-refs -f $GOPATH/src/github.com/{YOUR_USERNAME}/rancher -b release/v2.8 -c dev-v2.8 -n dev-v2.8-september-patches -p -u {YOUR_USERNAME}
Expand All @@ -100,33 +100,71 @@ Non-required flags can be automatically set, if you are inside your rancher fork

**Examples**

```
```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release set-charts-branch-refs --new-charts-branch dev-v2.9 --create-pr --dry-run
```

```
```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release set-charts-branch-refs -n dev-v2.9 -p -r
```

```
```sh
rancher_release set-charts-branch-refs --fork-path $GOPATH/src/github.com/{YOUR_USERNAME}/rancher \
--base-branch release/v2.8 \
--current-charts-branch dev-v2.8 \
--new-charts-branch dev-v2.9

```

```
```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release set-charts-branch-refs -f $GOPATH/src/github.com/{YOUR_USERNAME}/rancher -b release/v2.8 -c dev-v2.8 -n dev-v2.9 -p -o {YOUR_USERNAME}

```

### tag-release
Tags releases in GitHub for Rancher.

When tagging a new release using the `tag-release` command, always prefer to use the default behavior of creating as a draft and verifying the release in the UI before publishing it.
If you are running this locally, you'll need to generate a GitHub Token, use the fine-grained personal access token, scoped to only the rancher repo and with the `contents read and write` scope.


| **Flag** | **Description** | **Required** |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| `github-token`, `g`, `GITHUB_TOKEN` | GitHub generated token as described above. | TRUE |
| `tag`, `t` | The tag that you want to create. | TRUE |
| `remote-branch`, `b` | The branch which you want to create the tag against. | TRUE |
| `repo-owner`, `o` | Username of the rancher repo owner. Default is `rancher`, only customize this for testing purposes. | FALSE |
| `general-availability`, `a` | By default, the release will be created as a pre-release, before setting this as true, make sure it absolutely needs to be a GA release. | FALSE |
| `ignore-draft`, `d` | By default, the release will be created as a draft, so you can verify everything is correct before publishing it. | FALSE |
| `dry-run`, `r` | The release will not be created, just logged. | FALSE |

**Examples**

```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release tag-release --tag v2.8.0-rc1 --remote-branch release/v2.8 --dry-run
```

```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release tag-release --tag v2.8.0-rc1 --remote-branch release/v2.8 --repo-owner tashima42 --dry-run
```

```sh
export GITHUB_TOKEN={YOUR_GITHUB_TOKEN}

rancher_release tag-release -t v2.8.0 -b release/v2.8 -a -r
```


### label-issues

Given a release candidate, updates each GitHub issue belonging to its milestone with the tag `[zube]: To Test` and adds a comment with the prerelease version to test.
Expand Down
1 change: 1 addition & 0 deletions cmd/rancher_release/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func main() {
setChartsBranchReferencesCommand(),
checkRancherRCDepsCommand(),
labelIssuesCommand(),
tagReleaseCommand(),
}
app.Flags = rootFlags

Expand Down
75 changes: 75 additions & 0 deletions cmd/rancher_release/tag_release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"context"

"github.com/rancher/ecm-distro-tools/release/rancher"
"github.com/rancher/ecm-distro-tools/repository"
"github.com/urfave/cli/v2"
)

func tagReleaseCommand() *cli.Command {
return &cli.Command{
Name: "tag-release",
Usage: "tag a rancher release",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "github-token",
Aliases: []string{"g"},
EnvVars: []string{"GITHUB_TOKEN"},
Required: true,
},
&cli.StringFlag{
Name: "tag",
Aliases: []string{"t"},
Usage: "release tag",
Required: true,
},
&cli.StringFlag{
Name: "remote-branch",
Aliases: []string{"b"},
Usage: "rancher remote branch",
Required: true,
},
&cli.StringFlag{
Name: "repo-owner",
Aliases: []string{"o"},
Usage: "repo owner for the rancher repo, default is rancher, this is only used for testing purposes",
Value: "rancher",
Required: false,
},
&cli.BoolFlag{
Name: "general-availability",
Aliases: []string{"a"},
Usage: "by default, the release will be created as a pre-release, make sure it absolutely needs to be a GA release before setting this",
Required: false,
},
&cli.BoolFlag{
Name: "ignore-draft",
Aliases: []string{"d"},
Usage: "by default, the release will be created as a draft, so you can verify all information is correct before publishing it",
Required: false,
},
&cli.BoolFlag{
Name: "dry-run",
Aliases: []string{"r"},
Usage: "skip all changes that have side effects, like creating a release in a remote repo.",
Required: false,
},
},
Action: tagRelease,
}
}

func tagRelease(c *cli.Context) error {
token := c.String("github-token")
tag := c.String("tag")
remoteBranch := c.String("remote-branch")
repoOwner := c.String("repo-owner")
generalAvailability := c.Bool("general-availability")
ignoreDraft := c.Bool("ignore-draft")
dryRun := c.Bool("dry-run")
ctx := context.Background()
ghClient := repository.NewGithub(ctx, token)
return rancher.TagRancherRelease(ctx, ghClient, tag, remoteBranch, repoOwner, generalAvailability, ignoreDraft, dryRun)
}
77 changes: 60 additions & 17 deletions release/rancher/rancher.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ import (
ecmHTTP "github.com/rancher/ecm-distro-tools/http"
"github.com/rancher/ecm-distro-tools/repository"
"github.com/sirupsen/logrus"
"golang.org/x/mod/semver"
"gopkg.in/yaml.v2"
)

const (
rancherOrg = "rancher"
rancherRepo = rancherOrg
rancherImagesBaseURL = "https://github.com/rancher/rancher/releases/download/"
rancherImagesFileName = "/rancher-images.txt"
rancherHelmRepositoryURL = "https://releases.rancher.com/server-charts/latest/index.yaml"

setKDMBranchReferencesScriptFileName = "set_kdm_branch_references.sh"
setChartReferencesScriptFileName = `set_chart_references.sh`
cloneCheckoutRancherScript = `#!/bin/sh
navigateCheckoutRancherScript = `#!/bin/sh
set -e
BRANCH_NAME={{ .BranchName }}
Expand Down Expand Up @@ -150,6 +153,20 @@ type HelmIndex struct {
} `yaml:"entries"`
}

type ContentLine struct {
Line int
File string
Content string
}

type Content struct {
RancherImages []ContentLine
FilesWithRC []ContentLine
MinFilesWithRC []ContentLine
ChartsWithDev []ContentLine
KDMWithDev []ContentLine
}

func ListRancherImagesRC(tag string) (string, error) {
downloadURL := rancherImagesBaseURL + tag + rancherImagesFileName
imagesFile, err := rancherImages(downloadURL)
Expand Down Expand Up @@ -257,7 +274,7 @@ func SetKDMBranchReferences(ctx context.Context, forkPath, rancherBaseBranch, ne
BranchName: branchName,
}

script := cloneCheckoutRancherScript + setKDMBranchReferencesScript + pushChangesScript
script := navigateCheckoutRancherScript + setKDMBranchReferencesScript + pushChangesScript
logrus.Info("running update files and apply updates script...")
output, err := exec.RunTemplatedScript(forkPath, setKDMBranchReferencesScriptFileName, script, data)
if err != nil {
Expand Down Expand Up @@ -291,7 +308,7 @@ func SetChartBranchReferences(ctx context.Context, forkPath, rancherBaseBranch,
DryRun: dryRun,
BranchName: branchName,
}
script := cloneCheckoutRancherScript + setChartBranchReferencesScript + pushChangesScript
script := navigateCheckoutRancherScript + setChartBranchReferencesScript + pushChangesScript
logrus.Info("running update files script")
output, err := exec.RunTemplatedScript(forkPath, setChartReferencesScriptFileName, script, data)
if err != nil {
Expand All @@ -317,6 +334,46 @@ func SetChartBranchReferences(ctx context.Context, forkPath, rancherBaseBranch,
return nil
}

func TagRancherRelease(ctx context.Context, ghClient *github.Client, tag, remoteBranch, repoOwner string, generalAvailability, ignoreDraft, dryRun bool) error {
logrus.Info("validating tag semver format")
if !semver.IsValid(tag) {
return errors.New("the tag `" + tag + "` isn't a valid semantic versioning string")
}
logrus.Info("getting remote branch information from " + repoOwner + "/" + rancherRepo)
branch, _, err := ghClient.Repositories.GetBranch(ctx, repoOwner, rancherRepo, remoteBranch, true)
if err != nil {
return err
}
logrus.Info("the latest commit on branch " + remoteBranch + " is: " + *branch.Commit.SHA)

createAsDraft := !ignoreDraft
createAsPrerelease := !generalAvailability
logrus.Info("creating release ")
ghRelease := github.RepositoryRelease{
TagName: github.String(tag),
Name: github.String(rancherReleaseName(generalAvailability, tag)),
Draft: &createAsDraft,
Prerelease: &createAsPrerelease,
GenerateReleaseNotes: github.Bool(false),
}
logrus.Infof("github release: %+v", ghRelease)
if dryRun {
logrus.Info("dry run, skipping release creation")
return nil
}
_, _, err = ghClient.Repositories.CreateRelease(ctx, repoOwner, rancherRepo, &ghRelease)
return err
}

func rancherReleaseName(generalAvailability bool, tag string) string {
releaseName := ""
if !generalAvailability {
releaseName += "Pre-release "
}
releaseName += tag
return releaseName
}

func createPRFromRancher(ctx context.Context, rancherBaseBranch, title, branchName, forkOwner string, ghClient *github.Client) error {
pull := &github.NewPullRequest{
Title: github.String(title),
Expand All @@ -329,20 +386,6 @@ func createPRFromRancher(ctx context.Context, rancherBaseBranch, title, branchNa
return err
}

type ContentLine struct {
Line int
File string
Content string
}

type Content struct {
RancherImages []ContentLine
FilesWithRC []ContentLine
MinFilesWithRC []ContentLine
ChartsWithDev []ContentLine
KDMWithDev []ContentLine
}

func CheckRancherRCDeps(ctx context.Context, local, forCi bool, org, repo, commitHash, files string) error {
var (
content Content
Expand Down
16 changes: 16 additions & 0 deletions release/rancher/rancher_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rancher

import (
"errors"
"net/http"
"net/http/httptest"
"reflect"
Expand Down Expand Up @@ -59,3 +60,18 @@ func TestRancherHelmChartVersions(t *testing.T) {
t.Errorf("expected %v, got %v", expectedVersions, versions)
}
}

func TestRancherReleaseName(t *testing.T) {
const tag = "v2.8.0"
const expectedGAReleaseName = tag
const expectedPreReleaseName = "Pre-release " + tag

gaReleaseName := rancherReleaseName(true, tag)
if expectedGAReleaseName != gaReleaseName {
t.Error(errors.New("expected GA release name to be '" + expectedGAReleaseName + "' got '" + gaReleaseName + "' instead"))
}
preReleaseName := rancherReleaseName(false, tag)
if expectedPreReleaseName != preReleaseName {
t.Error(errors.New("expected GA release name to be '" + expectedPreReleaseName + "' got '" + preReleaseName + "' instead"))
}
}

0 comments on commit bc91df8

Please sign in to comment.