feat: push branch with changelog

This commit is contained in:
Julian Tölle 2024-08-01 23:00:56 +02:00
parent 8199918903
commit c7743e0a80
10 changed files with 313 additions and 36 deletions

View file

@ -7,6 +7,9 @@ import (
"context"
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/spf13/cobra"
rp "github.com/apricote/releaser-pleaser"
@ -61,12 +64,12 @@ func run(cmd *cobra.Command, args []string) error {
})
}
changesets, err := getChangesetsFromForge(ctx, f)
changesets, tag, err := getChangesetsFromForge(ctx, f)
if err != nil {
return fmt.Errorf("failed to get changesets: %w", err)
}
err = reconcileReleasePR(ctx, f, changesets)
err = reconcileReleasePR(ctx, f, changesets, tag)
if err != nil {
return fmt.Errorf("failed to reconcile release pr: %w", err)
}
@ -74,32 +77,38 @@ func run(cmd *cobra.Command, args []string) error {
return nil
}
func getChangesetsFromForge(ctx context.Context, forge rp.Forge) ([]rp.Changeset, error) {
func getChangesetsFromForge(ctx context.Context, forge rp.Forge) ([]rp.Changeset, *rp.Tag, error) {
tag, err := forge.LatestTag(ctx)
if err != nil {
return nil, err
return nil, nil, err
}
logger.InfoContext(ctx, "Latest Tag", "tag.hash", tag.Hash, "tag.name", tag.Name)
if tag != nil {
logger.InfoContext(ctx, "found previous tag", "tag.hash", tag.Hash, "tag.name", tag.Name)
} else {
logger.InfoContext(ctx, "no previous tag found")
}
releasableCommits, err := forge.CommitsSince(ctx, tag)
if err != nil {
return nil, err
return nil, nil, err
}
logger.InfoContext(ctx, "Found releasable commits", "length", len(releasableCommits))
changesets, err := forge.Changesets(ctx, releasableCommits)
if err != nil {
return nil, err
return nil, nil, err
}
logger.InfoContext(ctx, "Found changesets", "length", len(changesets))
return changesets, nil
return changesets, tag, nil
}
func reconcileReleasePR(ctx context.Context, forge rp.Forge, changesets []rp.Changeset) error {
func reconcileReleasePR(ctx context.Context, forge rp.Forge, changesets []rp.Changeset, tag *rp.Tag) error {
rpBranch := fmt.Sprintf(RELEASER_PLEASER_BRANCH, flagBranch)
rpBranchRef := plumbing.NewBranchReferenceName(rpBranch)
// Check Forge for open PR
// Get any modifications from open PR
// Clone Repo
@ -114,12 +123,90 @@ func reconcileReleasePR(ctx context.Context, forge rp.Forge, changesets []rp.Cha
logger.InfoContext(ctx, "found existing release pull request: %d: %s", pr.ID, pr.Title)
}
releaseOverrides, err := pr.GetOverrides()
var releaseOverrides rp.ReleaseOverrides
if pr != nil {
releaseOverrides, err = pr.GetOverrides()
if err != nil {
return err
}
}
nextVersion, err := rp.NextVersion(tag, changesets, releaseOverrides.NextVersionType)
if err != nil {
return err
}
logger.InfoContext(ctx, "next version", "version", nextVersion)
logger.DebugContext(ctx, "cloning repository", "clone.url", forge.CloneURL())
repo, err := rp.CloneRepo(ctx, forge.CloneURL(), flagBranch, forge.GitAuth())
if err != nil {
return err
}
worktree, err := repo.Worktree()
if err != nil {
return err
}
// ...
if branch, _ := repo.Branch(rpBranch); branch != nil {
logger.DebugContext(ctx, "deleting previous releaser-pleaser branch locally", "branch.name", rpBranch)
if err = repo.DeleteBranch(rpBranch); err != nil {
return err
}
}
if err = worktree.Checkout(&git.CheckoutOptions{
Branch: rpBranchRef,
Create: true,
}); err != nil {
return err
}
err = rp.RunUpdater(ctx, nextVersion, worktree)
if err != nil {
return err
}
changelogEntry, err := rp.NewChangelogEntry(changesets, nextVersion, forge.ReleaseURL(nextVersion))
if err != nil {
return err
}
err = rp.UpdateChangelogFile(worktree, changelogEntry)
if err != nil {
return err
}
releaseCommitMessage := fmt.Sprintf("chore(%s): release %s", flagBranch, nextVersion)
releaseCommit, err := worktree.Commit(releaseCommitMessage, &git.CommitOptions{})
if err != nil {
return err
}
logger.InfoContext(ctx, "created release commit", "commit.hash", releaseCommit.String(), "commit.message", releaseCommitMessage)
// TODO: Check if there is a diff between forge/rpBranch..rpBranch..forge/rpBranch and only push if there are changes
// To reduce wasted CI cycles
pushRefSpec := config.RefSpec(fmt.Sprintf(
"+%s:%s",
rpBranchRef,
// This needs to be the local branch name, not the remotes/origin ref
// See https://stackoverflow.com/a/75727620
rpBranchRef,
))
logger.DebugContext(ctx, "pushing branch", "commit.hash", releaseCommit.String(), "branch.name", rpBranch, "refspec", pushRefSpec.String())
if err = repo.PushContext(ctx, &git.PushOptions{
RemoteName: rp.GitRemoteName,
RefSpecs: []config.RefSpec{pushRefSpec},
Force: true,
Auth: forge.GitAuth(),
}); err != nil {
return err
}
logger.InfoContext(ctx, "pushed branch", "commit.hash", releaseCommit.String(), "branch.name", rpBranch, "refspec", pushRefSpec.String())
// TODO Open PR
return nil
}