blob: d9f9a20fe0124d3daf7ab5592428cd7b05875d98 [file] [log] [blame]
package task
import (
"fmt"
"strconv"
"strings"
"golang.org/x/build/gerrit"
"golang.org/x/build/internal/workflow"
)
// VersionTasks contains tasks related to versioning the release.
type VersionTasks struct {
Gerrit GerritClient
Project string
}
type NextVersions struct {
CurrentMinor string
PreviousMinor string
Beta string
RC string
Major string
}
// GetNextVersions returns the next version for each type of release.
func (t *VersionTasks) GetNextVersions(ctx *workflow.TaskContext) (NextVersions, error) {
tags, err := t.Gerrit.ListTags(ctx, t.Project)
if err != nil {
return NextVersions{}, err
}
tagSet := map[string]bool{}
for _, tag := range tags {
tagSet[tag] = true
}
// Find the most recently released major version.
currentMajor := 0
for ; ; currentMajor++ {
if !tagSet[fmt.Sprintf("go1.%d", currentMajor+1)] {
break
}
}
var savedError error
findUnused := func(v string) string {
for {
if !tagSet[v] {
return v
}
var err error
v, err = nextVersion(v)
if err != nil {
savedError = err
return ""
}
}
}
// Find the next missing tag for each release type.
result := NextVersions{
CurrentMinor: findUnused(fmt.Sprintf("go1.%d.1", currentMajor)),
PreviousMinor: findUnused(fmt.Sprintf("go1.%d.1", currentMajor-1)),
Beta: findUnused(fmt.Sprintf("go1.%dbeta1", currentMajor+1)),
RC: findUnused(fmt.Sprintf("go1.%drc1", currentMajor+1)),
Major: fmt.Sprintf("go1.%d", currentMajor+1),
}
return result, savedError
}
func nextVersion(version string) (string, error) {
lastNonDigit := strings.LastIndexFunc(version, func(r rune) bool {
return r < '0' || r > '9'
})
if lastNonDigit == -1 || len(version) == lastNonDigit {
return "", fmt.Errorf("malformatted Go version %q", version)
}
n, err := strconv.Atoi(version[lastNonDigit+1:])
if err != nil {
return "", fmt.Errorf("malformatted Go version %q (%v)", version, err)
}
return fmt.Sprintf("%s%d", version[:lastNonDigit+1], n+1), nil
}
// CreateAutoSubmitVersionCL mails an auto-submit change to update VERSION on branch.
func (t *VersionTasks) CreateAutoSubmitVersionCL(ctx *workflow.TaskContext, branch, version string) (string, error) {
return t.Gerrit.CreateAutoSubmitChange(ctx, gerrit.ChangeInput{
Project: t.Project,
Branch: branch,
Subject: fmt.Sprintf("[%v] %v", branch, version),
}, map[string]string{
"VERSION": version,
})
}
// AwaitCL waits for the specified CL to be submitted.
func (t *VersionTasks) AwaitCL(ctx *workflow.TaskContext, changeID string) (string, error) {
ctx.Printf("Awaiting review/submit of %v", changeLink(changeID))
return t.Gerrit.AwaitSubmit(ctx, changeID)
}
// TagRelease tags commit as version.
func (t *VersionTasks) TagRelease(ctx *workflow.TaskContext, version, commit string) (string, error) {
return "", t.Gerrit.Tag(ctx, t.Project, version, commit)
}