func()

in pkg/changelog/changelog.go [74:239]


func (c *Changelog) Run() error {
	tag, err := c.impl.TagStringToSemver(c.options.Tag)
	if err != nil {
		return errors.Wrapf(err, "parse tag %s", c.options.Tag)
	}

	// Automatically set the branch to a release branch if not provided
	branch := c.options.Branch
	if branch == "" {
		branch = fmt.Sprintf("release-%d.%d", tag.Major, tag.Minor)
	}
	logrus.Infof("Using release branch %s", branch)

	logrus.Infof("Using local repository path %s", c.options.RepoPath)
	repo, err := c.impl.OpenRepo(c.options.RepoPath)
	if err != nil {
		return errors.Wrapf(err,
			"open expected k/k repository %q", c.options.RepoPath,
		)
	}
	if currentBranch, err := c.impl.CurrentBranch(repo); err == nil {
		logrus.Infof("We're currently on branch: %s", currentBranch)
	}

	remoteBranch := git.Remotify(branch)
	head, err := c.impl.RevParseTag(repo, remoteBranch)
	if err != nil {
		return errors.Wrap(err, "get latest branch commit")
	}
	logrus.Infof("Found latest %s commit %s", remoteBranch, head)

	var markdown, jsonStr, startRev, endRev string
	if tag.Patch == 0 {
		if len(tag.Pre) == 0 {
			// Still create the downloads table
			downloadsTable := &bytes.Buffer{}
			startTag := util.SemverToTagString(semver.Version{
				Major: tag.Major, Minor: tag.Minor - 1, Patch: 0,
			})

			startRev = startTag
			endRev = head

			if err := c.impl.CreateDownloadsTable(
				downloadsTable, c.options.Bucket, c.options.Tars,
				c.options.Images, startRev, c.options.Tag,
			); err != nil {
				return errors.Wrapf(err, "create downloads table")
			}

			// New final minor versions should have remote release notes
			markdown, jsonStr, err = c.lookupRemoteReleaseNotes(branch)
			markdown = downloadsTable.String() + markdown
		} else if tag.Pre[0].String() == "alpha" && tag.Pre[1].VersionNum == 1 {
			// v1.x.0-alpha.1 releases use the previous minor as start commit.
			// Those are usually the first releases being cut on master after
			// the previous final has been released.
			startRev = util.SemverToTagString(semver.Version{
				Major: tag.Major, Minor: tag.Minor - 1, Patch: 0,
			})
			logrus.Infof("Using previous minor %s as start tag", startRev)

			// The end tag does not yet exist which means that we stick to
			// the current HEAD as end revision.
			endRev = head

			markdown, jsonStr, err = c.generateReleaseNotes(branch, startRev, endRev)
		} else {
			// New minor alpha, beta and rc releases get generated notes
			latestTags, tErr := c.impl.LatestGitHubTagsPerBranch()
			if tErr != nil {
				return errors.Wrap(tErr, "get latest GitHub tags")
			}

			if startTag, ok := latestTags[branch]; ok {
				logrus.Infof("Found start tag %s", startTag)

				// The end tag does not yet exist which means that we stick to
				// the current HEAD as end revision.
				startRev = startTag
				endRev = head

				markdown, jsonStr, err = c.generateReleaseNotes(branch, startRev, endRev)
			} else {
				return errors.Errorf(
					"no latest tag available for branch %s", branch,
				)
			}
		}
	} else {
		if c.options.CloneCVEMaps {
			cveDir, err := c.impl.CloneCVEData()
			if err != nil {
				return errors.Wrap(err, "getting cve data maps")
			}
			c.options.CVEDataDir = cveDir
		}

		// A patch version, let’s just use the previous patch
		startTag := util.SemverToTagString(semver.Version{
			Major: tag.Major, Minor: tag.Minor, Patch: tag.Patch - 1,
		})

		startRev = startTag
		endRev = head

		markdown, jsonStr, err = c.generateReleaseNotes(branch, startTag, endRev)
	}
	if err != nil {
		return errors.Wrap(err, "generate release notes")
	}

	if c.options.Dependencies {
		logrus.Info("Generating dependency changes")
		deps, err := c.impl.DependencyChanges(startRev, endRev)
		if err != nil {
			return errors.Wrap(err, "generate dependency changes")
		}
		markdown += strings.Repeat(nl, 2) + deps
	}

	logrus.Info("Generating TOC")
	toc, err := c.impl.GenerateTOC(markdown)
	if err != nil {
		return errors.Wrap(err, "generate table of contents")
	}

	// Restore the currently checked out branch
	currentBranch, err := c.impl.CurrentBranch(repo)
	if err != nil {
		return errors.Wrap(err, "get current branch")
	}
	if currentBranch != "" {
		defer func() {
			if err := c.impl.Checkout(repo, currentBranch); err != nil {
				logrus.Errorf("Restore branch %s: %v", currentBranch, err)
			}
		}()
	}

	logrus.Infof("Checking out %s branch", git.DefaultBranch)
	if err := c.impl.Checkout(repo, git.DefaultBranch); err != nil {
		return errors.Wrapf(err, "checkout %s branch", git.DefaultBranch)
	}

	logrus.Info("Writing markdown")
	if err := c.writeMarkdown(repo, toc, markdown, tag); err != nil {
		return errors.Wrap(err, "write markdown")
	}

	logrus.Info("Writing HTML")
	if err := c.writeHTML(tag, markdown); err != nil {
		return errors.Wrap(err, "write HTML")
	}

	logrus.Info("Writing JSON")
	if err := c.writeJSON(tag, jsonStr); err != nil {
		return errors.Wrap(err, "write JSON")
	}

	logrus.Info("Committing changes")
	return errors.Wrap(
		c.commitChanges(repo, branch, tag),
		"commit changes",
	)
}