in pkg/anago/stage.go [403:546]
func (d *DefaultStage) TagRepository() error {
repo, err := d.impl.OpenRepo(gitRoot)
if err != nil {
return errors.Wrap(err, "open Kubernetes repository")
}
for _, version := range d.state.versions.Ordered() {
logrus.Infof("Preparing version %s", version)
// Ensure that the tag not already exists
if _, err := d.impl.RevParseTag(repo, version); err == nil {
return errors.Errorf("tag %s already exists", version)
}
// Usually the build version contains a commit we can reference. If
// not, because the build version is exactly a tag, then we fallback to
// that tag.
commit := d.options.BuildVersion
if len(d.state.semverBuildVersion.Build) > 0 {
commit = d.state.semverBuildVersion.Build[0]
}
if d.state.createReleaseBranch {
logrus.Infof("Creating release branch %s", d.options.ReleaseBranch)
if version == d.state.versions.Prime() {
logrus.Infof("Version %s is the prime version", version)
logrus.Infof(
"Creating release branch %s from commit %s",
d.options.ReleaseBranch, commit,
)
if err := d.impl.Checkout(
repo, "-b", d.options.ReleaseBranch, commit,
); err != nil {
return errors.Wrap(err, "create new release branch")
}
} else {
logrus.Infof(
"Version %s is not the prime, checking out %s branch",
version, git.DefaultBranch,
)
if err := d.impl.Checkout(repo, git.DefaultBranch); err != nil {
return errors.Wrapf(err, "checkout %s branch", git.DefaultBranch)
}
}
} else {
logrus.Infof("Checking out branch %s", d.options.ReleaseBranch)
if err := d.impl.Checkout(repo, d.options.ReleaseBranch); err != nil {
return errors.Wrapf(err, "checking out branch %s", d.options.ReleaseBranch)
}
}
// `branch == ""` in case we checked out a commit directly, which is
// then in detached head state.
branch, err := d.impl.CurrentBranch(repo)
if err != nil {
return errors.Wrap(err, "get current branch")
}
if branch != "" {
logrus.Infof("Current branch is %s", branch)
}
// For release branches, we create an empty release commit to avoid
// potential ambiguous 'git describe' logic between the official
// release, 'x.y.z' and the next beta of that release branch,
// 'x.y.(z+1)-beta.0'.
//
// We avoid doing this empty release commit on 'master', as:
// - there is a potential for branch conflicts as upstream/master
// moves ahead
// - we're checking out a git ref, as opposed to a branch, which
// means the tag will detached from 'upstream/master'
//
// A side-effect of the tag being detached from 'master' is the primary
// build job (ci-kubernetes-build) will build as the previous alpha,
// instead of the assumed tag. This causes the next anago run against
// 'master' to fail due to an old build version.
//
// Example: 'v1.18.0-alpha.2.663+df908c3aad70be'
// (should instead be:
// 'v1.18.0-alpha.3.<commits-since-tag>+<commit-ish>')
//
// ref:
// - https://github.com/kubernetes/release/issues/1020
// - https://github.com/kubernetes/release/pull/1030
// - https://github.com/kubernetes/release/issues/1080
// - https://github.com/kubernetes/kubernetes/pull/88074
// When tagging a release branch, always create an empty commit:
if strings.HasPrefix(branch, "release-") {
logrus.Infof("Creating empty release commit for tag %s", version)
if err := d.impl.CommitEmpty(
repo,
fmt.Sprintf("Release commit for Kubernetes %s", version),
); err != nil {
return errors.Wrap(err, "create empty release commit")
}
}
// If we are on master/main we do not create an empty commit,
// but we detach the head at the specified commit to avoid having
// commits merged between the BuildVersion commit and the tag:
if branch != "" && !strings.HasPrefix(branch, "release-") {
logrus.Infof("Detaching HEAD at commit %s to create tag %s", commit, version)
if err := d.impl.Checkout(repo, commit); err != nil {
return errors.Wrap(err, "checkout release commit")
}
}
// If a custom ref is provided, try to merge it into the release
// branch.
ref := release.GetK8sRef()
if ref != release.DefaultK8sRef {
logrus.Infof("Merging custom ref: %s", ref)
if err := d.impl.Merge(repo, git.Remotify(ref)); err != nil {
return errors.Wrap(err, "merge k8s ref")
}
}
// Tag the repository:
logrus.Infof("Tagging version %s", version)
if err := d.impl.Tag(
repo,
version,
fmt.Sprintf(
"Kubernetes %s release %s", d.options.ReleaseType, version,
),
); err != nil {
return errors.Wrap(err, "tag version")
}
// if we are working on master/main at this point, we are in
// detached HEAD state. So we checkout the branch again.
// The next stage (build) will checkout the branch it needs, but
// let's not end this step with a detached HEAD
if branch != "" && !strings.HasPrefix(branch, "release-") {
logrus.Infof("Checking out %s to reattach HEAD", d.options.ReleaseBranch)
if err := d.impl.Checkout(repo, d.options.ReleaseBranch); err != nil {
return errors.Wrapf(err, "checking out branch %s", d.options.ReleaseBranch)
}
}
}
return nil
}