Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore(scripts): add script to promote mainline to stable#13054

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
mafredri merged 4 commits intomainfrommafredri/feat-add-promote-mainline-to-stable
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes fromall 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
1 change: 1 addition & 0 deletionsgo.mod
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -218,6 +218,7 @@ require (
github.com/benbjohnson/clock v1.3.5
github.com/coder/serpent v0.7.0
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47
github.com/google/go-github/v61 v61.0.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletionsgo.sum
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -469,6 +469,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v43 v43.0.1-0.20220414155304-00e42332e405 h1:DdHws/YnnPrSywrjNYu2lEHqYHWp/LnEx56w59esd54=
github.com/google/go-github/v43 v43.0.1-0.20220414155304-00e42332e405/go.mod h1:4RgUDSnsxP19d65zJWqvqJ/poJxBCvmna50eXmIvoR8=
github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5pNlu1go=
github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down
223 changes: 223 additions & 0 deletionsscripts/release/main.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
package main

import (
"context"
"errors"
"fmt"
"os"
"slices"
"strings"
"time"

"github.com/google/go-cmp/cmp"
"github.com/google/go-github/v61/github"
"golang.org/x/mod/semver"
"golang.org/x/xerrors"

"cdr.dev/slog"
"cdr.dev/slog/sloggers/sloghuman"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/serpent"
)

const (
owner = "coder"
repo = "coder"
)

func main() {
logger := slog.Make(sloghuman.Sink(os.Stderr)).Leveled(slog.LevelDebug)

var ghToken string
var dryRun bool

cmd := serpent.Command{
Use: "release <subcommand>",
Short: "Prepare, create and publish releases.",
Options: serpent.OptionSet{
{
Flag: "gh-token",
Description: "GitHub personal access token.",
Env: "GH_TOKEN",
Value: serpent.StringOf(&ghToken),
},
{
Flag: "dry-run",
FlagShorthand: "n",
Description: "Do not make any changes, only print what would be done.",
Value: serpent.BoolOf(&dryRun),
},
},
Children: []*serpent.Command{
{
Use: "promote <version>",
Short: "Promote version to stable.",
Handler: func(inv *serpent.Invocation) error {
ctx := inv.Context()
if len(inv.Args) == 0 {
return xerrors.New("version argument missing")
}
if !dryRun && ghToken == "" {
return xerrors.New("GitHub personal access token is required, use --gh-token or GH_TOKEN")
}

err := promoteVersionToStable(ctx, inv, logger, ghToken, dryRun, inv.Args[0])
if err != nil {
return err
}

return nil
},
},
},
}

err := cmd.Invoke().WithOS().Run()
if err != nil {
if errors.Is(err, cliui.Canceled) {
os.Exit(1)
}
logger.Error(context.Background(), "release command failed", "err", err)
os.Exit(1)
}
}

//nolint:revive // Allow dryRun control flag.
func promoteVersionToStable(ctx context.Context, inv *serpent.Invocation, logger slog.Logger, ghToken string, dryRun bool, version string) error {
client := github.NewClient(nil)
if ghToken != "" {
client = client.WithAuthToken(ghToken)
}

logger = logger.With(slog.F("dry_run", dryRun), slog.F("version", version))

logger.Info(ctx, "checking current stable release")

// Check if the version is already the latest stable release.
currentStable, _, err := client.Repositories.GetLatestRelease(ctx, "coder", "coder")
if err != nil {
return xerrors.Errorf("get latest release failed: %w", err)
}

logger = logger.With(slog.F("stable_version", currentStable.GetTagName()))
logger.Info(ctx, "found current stable release")

if currentStable.GetTagName() == version {
return xerrors.Errorf("version %q is already the latest stable release", version)
}

// Ensure the version is a valid release.
perPage := 20
latestReleases, _, err := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{
Page: 0,
PerPage: perPage,
})
if err != nil {
return xerrors.Errorf("list releases failed: %w", err)
}

var releaseVersions []string
var newStable *github.RepositoryRelease
for _, r := range latestReleases {
releaseVersions = append(releaseVersions, r.GetTagName())
if r.GetTagName() == version {
newStable = r
}
}
semver.Sort(releaseVersions)
slices.Reverse(releaseVersions)

switch {
case len(releaseVersions) == 0:
return xerrors.Errorf("no releases found")
case newStable == nil:
return xerrors.Errorf("version %q is not found in the last %d releases", version, perPage)
}

logger = logger.With(slog.F("mainline_version", releaseVersions[0]))

if version != releaseVersions[0] {
logger.Warn(ctx, "selected version is not the latest mainline release")
}

if reply, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Are you sure you want to promote this version to stable?",
Default: "no",
IsConfirm: true,
}); err != nil {
if reply == cliui.ConfirmNo {
return nil
}
return err
}

logger.Info(ctx, "promoting selected version to stable")

// Update the release to latest.
updatedNewStable := cloneRelease(newStable)

updatedBody := removeMainlineBlurb(newStable.GetBody())
updatedBody = addStableSince(time.Now().UTC(), updatedBody)
updatedNewStable.Body = github.String(updatedBody)
updatedNewStable.Prerelease = github.Bool(false)
updatedNewStable.Draft = github.Bool(false)
if !dryRun {
_, _, err = client.Repositories.EditRelease(ctx, owner, repo, newStable.GetID(), newStable)
if err != nil {
return xerrors.Errorf("edit release failed: %w", err)
}
logger.Info(ctx, "selected version promoted to stable", "url", newStable.GetHTMLURL())
} else {
logger.Info(ctx, "dry-run: release not updated", "uncommitted_changes", cmp.Diff(newStable, updatedNewStable))
}

return nil
}

func cloneRelease(r *github.RepositoryRelease) *github.RepositoryRelease {
rr := *r
return &rr
}

// addStableSince adds a stable since note to the release body.
//
// Example:
//
//> ## Stable (since April 23, 2024)
func addStableSince(date time.Time, body string) string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Nice!!

mafredri reacted with heart emoji
return fmt.Sprintf("> ## Stable (since %s)\n\n", date.Format("January 02, 2006")) + body
}

// removeMainlineBlurb removes the mainline blurb from the release body.
//
// Example:
//
//> [!NOTE]
//> This is a mainline Coder release. We advise enterprise customers without a staging environment to install our [latest stable release](https://github.com/coder/coder/releases/latest) while we refine this version. Learn more about our [Release Schedule](https://coder.com/docs/v2/latest/install/releases).
func removeMainlineBlurb(body string) string {
lines := strings.Split(body, "\n")

var newBody, clip []string
var found bool
for _, line := range lines {
if strings.HasPrefix(strings.TrimSpace(line), "> [!NOTE]") {
clip = append(clip, line)
found = true
continue
}
if found {
clip = append(clip, line)
found = strings.HasPrefix(strings.TrimSpace(line), ">")
continue
}
if !found && len(clip) > 0 {
if !strings.Contains(strings.ToLower(strings.Join(clip, "\n")), "this is a mainline coder release") {
newBody = append(newBody, clip...) // This is some other note, restore it.
}
clip = nil
}
newBody = append(newBody, line)
}

return strings.Join(newBody, "\n")
}
136 changes: 136 additions & 0 deletionsscripts/release/main_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
package main

import (
"testing"
"time"

"github.com/google/go-cmp/cmp"
)

func Test_removeMainlineBlurb(t *testing.T) {
t.Parallel()

tests := []struct {
name string
body string
want string
}{
{
name: "NoMainlineBlurb",
body: `## Changelog

### Chores

- Add support for additional Azure Instance Identity RSA Certificates (#13028) (@kylecarbs)

Compare: [` + "`" + `v2.10.1...v2.10.2` + "`" + `](https://github.com/coder/coder/compare/v2.10.1...v2.10.2)

## Container image

- ` + "`" + `docker pull ghcr.io/coder/coder:v2.10.2` + "`" + `

## Install/upgrade

Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below.
`,
want: `## Changelog

### Chores

- Add support for additional Azure Instance Identity RSA Certificates (#13028) (@kylecarbs)

Compare: [` + "`" + `v2.10.1...v2.10.2` + "`" + `](https://github.com/coder/coder/compare/v2.10.1...v2.10.2)

## Container image

- ` + "`" + `docker pull ghcr.io/coder/coder:v2.10.2` + "`" + `

## Install/upgrade

Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below.
`,
},
{
name: "WithMainlineBlurb",
body: `## Changelog

> [!NOTE]
> This is a mainline Coder release. We advise enterprise customers without a staging environment to install our [latest stable release](https://github.com/coder/coder/releases/latest) while we refine this version. Learn more about our [Release Schedule](https://coder.com/docs/v2/latest/install/releases).
Copy link
Contributor

@dannykoppingdannykoppingApr 24, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think it'd be illustrative / more complete to add a test which shows that multiple lines subsequent to[!NOTE] prefixed with> are removed; we'll likely amend this note in the future.

mafredri reacted with thumbs up emoji

### Chores

- Add support for additional Azure Instance Identity RSA Certificates (#13028) (@kylecarbs)

Compare: [` + "`" + `v2.10.1...v2.10.2` + "`" + `](https://github.com/coder/coder/compare/v2.10.1...v2.10.2)

## Container image

- ` + "`" + `docker pull ghcr.io/coder/coder:v2.10.2` + "`" + `

## Install/upgrade

Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below.
`,
want: `## Changelog

### Chores

- Add support for additional Azure Instance Identity RSA Certificates (#13028) (@kylecarbs)

Compare: [` + "`" + `v2.10.1...v2.10.2` + "`" + `](https://github.com/coder/coder/compare/v2.10.1...v2.10.2)

## Container image

- ` + "`" + `docker pull ghcr.io/coder/coder:v2.10.2` + "`" + `

## Install/upgrade

Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below.
`,
},
{
name: "EntireQuotedBlurbIsRemoved",
body: `## Changelog

> [!NOTE]
> This is a mainline Coder release. We advise enterprise customers without a staging environment to install our [latest stable release](https://github.com/coder/coder/releases/latest) while we refine this version. Learn more about our [Release Schedule](https://coder.com/docs/v2/latest/install/releases).
> This is an extended note.
> This is another extended note.

### Best release yet!

Enjoy.
`,
want: `## Changelog

### Best release yet!

Enjoy.
`,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if diff := cmp.Diff(removeMainlineBlurb(tt.body), tt.want); diff != "" {
t.Errorf("removeMainlineBlurb() mismatch (-want +got):\n%s", diff)
}
})
}
}

func Test_addStableSince(t *testing.T) {
t.Parallel()

date := time.Date(2024, time.April, 23, 0, 0, 0, 0, time.UTC)
body := "## Changelog"

expected := "> ## Stable (since April 23, 2024)\n\n## Changelog"
result := addStableSince(date, body)

if diff := cmp.Diff(expected, result); diff != "" {
t.Errorf("addStableSince() mismatch (-want +got):\n%s", diff)
}
}
10 changes: 10 additions & 0 deletionsscripts/release_promote_stable.sh
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

set -euo pipefail
# shellcheck source=scripts/lib.sh
source"$(dirname"${BASH_SOURCE[0]}")/lib.sh"

# This script is a convenience wrapper around the release promote command.
#
# Sed hack to make help text look like this script.
exec go run"${SCRIPT_DIR}/release" promote"$@"

[8]ページ先頭

©2009-2025 Movatter.jp