From 60be374b8bd74e0081385816c61390ffc4b3652f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 15:28:25 +0200 Subject: [PATCH 01/12] refactor: move run logic outside of cli code --- cmd/rp/cmd/run.go | 316 +----------------------------------------- releaserpleaser.go | 336 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+), 312 deletions(-) create mode 100644 releaserpleaser.go diff --git a/cmd/rp/cmd/run.go b/cmd/rp/cmd/run.go index 04bf933..ea1e940 100644 --- a/cmd/rp/cmd/run.go +++ b/cmd/rp/cmd/run.go @@ -1,21 +1,11 @@ package cmd 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" ) -const ( - RELEASER_PLEASER_BRANCH = "releaser-pleaser--branches--%s" -) - // runCmd represents the run command var runCmd = &cobra.Command{ Use: "run", @@ -50,7 +40,7 @@ func run(cmd *cobra.Command, _ []string) error { "repo", flagRepo, ) - var f rp.Forge + var forge rp.Forge forgeOptions := rp.ForgeOptions{ Repository: flagRepo, @@ -62,312 +52,14 @@ func run(cmd *cobra.Command, _ []string) error { //f = rp.NewGitLab(forgeOptions) case "github": logger.DebugContext(ctx, "using forge GitHub") - f = rp.NewGitHub(logger, &rp.GitHubOptions{ + forge = rp.NewGitHub(logger, &rp.GitHubOptions{ ForgeOptions: forgeOptions, Owner: flagOwner, Repo: flagRepo, }) } - err := ensureLabels(ctx, f) - if err != nil { - return fmt.Errorf("failed to ensure all labels exist: %w", err) - } + releaserPleaser := rp.New(forge, logger, flagBranch) - err = createPendingReleases(ctx, f) - if err != nil { - return fmt.Errorf("failed to create pending releases: %w", err) - } - - changesets, releases, err := getChangesetsFromForge(ctx, f) - if err != nil { - return fmt.Errorf("failed to get changesets: %w", err) - } - - err = reconcileReleasePR(ctx, f, changesets, releases) - if err != nil { - return fmt.Errorf("failed to reconcile release pr: %w", err) - } - - return nil -} - -func ensureLabels(ctx context.Context, forge rp.Forge) error { - return forge.EnsureLabelsExist(ctx, rp.Labels) -} - -func createPendingReleases(ctx context.Context, forge rp.Forge) error { - logger.InfoContext(ctx, "checking for pending releases") - prs, err := forge.PendingReleases(ctx) - if err != nil { - return err - } - - if len(prs) == 0 { - logger.InfoContext(ctx, "No pending releases found") - return nil - } - - logger.InfoContext(ctx, "Found pending releases", "length", len(prs)) - - for _, pr := range prs { - err = createPendingRelease(ctx, forge, pr) - if err != nil { - return err - } - } - - return nil -} - -func createPendingRelease(ctx context.Context, forge rp.Forge, pr *rp.ReleasePullRequest) error { - logger := logger.With("pr.id", pr.ID, "pr.title", pr.Title) - - if pr.ReleaseCommit == nil { - return fmt.Errorf("pull request is missing the merge commit") - } - - logger.Info("Creating release", "commit.hash", pr.ReleaseCommit.Hash) - - version, err := pr.Version() - if err != nil { - return err - } - - changelog, err := pr.ChangelogText() - if err != nil { - return err - } - - // TODO: pre-release & latest - - logger.DebugContext(ctx, "Creating release on forge") - err = forge.CreateRelease(ctx, *pr.ReleaseCommit, version, changelog, false, true) - if err != nil { - return fmt.Errorf("failed to create release on forge: %w", err) - } - logger.DebugContext(ctx, "created release", "release.title", version, "release.url", forge.ReleaseURL(version)) - - logger.DebugContext(ctx, "updating pr labels") - err = forge.SetPullRequestLabels(ctx, pr, []string{rp.LabelReleasePending}, []string{rp.LabelReleaseTagged}) - if err != nil { - return err - } - logger.DebugContext(ctx, "updated pr labels") - - logger.InfoContext(ctx, "Created release", "release.title", version, "release.url", forge.ReleaseURL(version)) - - return nil -} - -func getChangesetsFromForge(ctx context.Context, forge rp.Forge) ([]rp.Changeset, rp.Releases, error) { - releases, err := forge.LatestTags(ctx) - if err != nil { - return nil, rp.Releases{}, err - } - - if releases.Latest != nil { - logger.InfoContext(ctx, "found latest tag", "tag.hash", releases.Latest.Hash, "tag.name", releases.Latest.Name) - if releases.Stable != nil && releases.Latest.Hash != releases.Stable.Hash { - logger.InfoContext(ctx, "found stable tag", "tag.hash", releases.Stable.Hash, "tag.name", releases.Stable.Name) - } - } else { - logger.InfoContext(ctx, "no latest tag found") - } - - releasableCommits, err := forge.CommitsSince(ctx, releases.Stable) - if err != nil { - return nil, rp.Releases{}, err - } - - logger.InfoContext(ctx, "Found releasable commits", "length", len(releasableCommits)) - - changesets, err := forge.Changesets(ctx, releasableCommits) - if err != nil { - return nil, rp.Releases{}, err - } - - logger.InfoContext(ctx, "Found changesets", "length", len(changesets)) - - return changesets, releases, nil -} - -func reconcileReleasePR(ctx context.Context, forge rp.Forge, changesets []rp.Changeset, releases rp.Releases) 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 - // Run Updaters + Changelog - // Upsert PR - pr, err := forge.PullRequestForBranch(ctx, fmt.Sprintf(RELEASER_PLEASER_BRANCH, flagBranch)) - if err != nil { - return err - } - - if pr != nil { - logger.InfoContext(ctx, "found existing release pull request", "pr.id", pr.ID, "pr.title", pr.Title) - } - - if len(changesets) == 0 { - if pr != nil { - logger.InfoContext(ctx, "closing existing pull requests, no changesets available", "pr.id", pr.ID, "pr.title", pr.Title) - err = forge.ClosePullRequest(ctx, pr) - if err != nil { - return err - } - } else { - logger.InfoContext(ctx, "No changesets available for release") - } - - return nil - } - - var releaseOverrides rp.ReleaseOverrides - if pr != nil { - releaseOverrides, err = pr.GetOverrides() - if err != nil { - return err - } - } - - versionBump := rp.VersionBumpFromChangesets(changesets) - nextVersion, err := rp.SemVerNextVersion(releases, versionBump, 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 fmt.Errorf("failed to clone repository: %w", 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 fmt.Errorf("failed to check out branch: %w", err) - } - - err = rp.RunUpdater(ctx, nextVersion, worktree) - if err != nil { - return fmt.Errorf("failed to update files with new version: %w", err) - } - - changelogEntry, err := rp.NewChangelogEntry(changesets, nextVersion, forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) - if err != nil { - return fmt.Errorf("failed to build changelog entry: %w", err) - } - - err = rp.UpdateChangelogFile(worktree, changelogEntry) - if err != nil { - return fmt.Errorf("failed to update changelog file: %w", err) - } - - releaseCommitMessage := fmt.Sprintf("chore(%s): release %s", flagBranch, nextVersion) - releaseCommitHash, err := worktree.Commit(releaseCommitMessage, &git.CommitOptions{ - Author: rp.GitSignature(), - Committer: rp.GitSignature(), - }) - if err != nil { - return fmt.Errorf("failed to commit changes: %w", err) - } - - logger.InfoContext(ctx, "created release commit", "commit.hash", releaseCommitHash.String(), "commit.message", releaseCommitMessage) - - newReleasePRChanges := true - - // Check if anything changed in comparison to the remote branch (if exists) - if remoteRef, err := repo.Reference(plumbing.NewRemoteReferenceName(rp.GitRemoteName, rpBranch), false); err != nil { - if err.Error() != "reference not found" { - // "reference not found" is expected and we should always push - return err - } - } else { - remoteCommit, err := repo.CommitObject(remoteRef.Hash()) - if err != nil { - return err - } - - localCommit, err := repo.CommitObject(releaseCommitHash) - if err != nil { - return err - } - - diff, err := localCommit.PatchContext(ctx, remoteCommit) - if err != nil { - return err - } - - newReleasePRChanges = len(diff.FilePatches()) > 0 - } - - if newReleasePRChanges { - 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", releaseCommitHash.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 fmt.Errorf("failed to push branch: %w", err) - } - - logger.InfoContext(ctx, "pushed branch", "commit.hash", releaseCommitHash.String(), "branch.name", rpBranch, "refspec", pushRefSpec.String()) - } else { - logger.InfoContext(ctx, "file content is already up-to-date in remote branch, skipping push") - } - - // Open/Update PR - if pr == nil { - pr, err = rp.NewReleasePullRequest(rpBranch, flagBranch, nextVersion, changelogEntry) - if err != nil { - return err - } - - err = forge.CreatePullRequest(ctx, pr) - if err != nil { - return err - } - logger.InfoContext(ctx, "opened pull request", "pr.title", pr.Title, "pr.id", pr.ID) - } else { - pr.SetTitle(flagBranch, nextVersion) - - overrides, err := pr.GetOverrides() - if err != nil { - return err - } - err = pr.SetDescription(changelogEntry, overrides) - if err != nil { - return err - } - - err = forge.UpdatePullRequest(ctx, pr) - if err != nil { - return err - } - logger.InfoContext(ctx, "updated pull request", "pr.title", pr.Title, "pr.id", pr.ID) - } - - return nil + return releaserPleaser.Run(ctx) } diff --git a/releaserpleaser.go b/releaserpleaser.go new file mode 100644 index 0000000..69a6723 --- /dev/null +++ b/releaserpleaser.go @@ -0,0 +1,336 @@ +package rp + +import ( + "context" + "fmt" + "log/slog" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" +) + +const ( + PullRequestBranchFormat = "releaser-pleaser--branches--%s" +) + +type ReleaserPleaser struct { + forge Forge + logger *slog.Logger + targetBranch string +} + +func New(forge Forge, logger *slog.Logger, targetBranch string) *ReleaserPleaser { + return &ReleaserPleaser{ + forge: forge, + logger: logger, + targetBranch: targetBranch, + } +} + +func (rp *ReleaserPleaser) EnsureLabels(ctx context.Context) error { + // TODO: Wrap Error + return rp.forge.EnsureLabelsExist(ctx, Labels) +} + +func (rp *ReleaserPleaser) Run(ctx context.Context) error { + err := rp.runOnboarding(ctx) + if err != nil { + return fmt.Errorf("failed to onboard repository: %w", err) + } + + err = rp.runCreatePendingReleases(ctx) + if err != nil { + return fmt.Errorf("failed to create pending releases: %w", err) + } + + return nil +} + +func (rp *ReleaserPleaser) runOnboarding(ctx context.Context) error { + err := rp.EnsureLabels(ctx) + if err != nil { + return fmt.Errorf("failed to ensure all labels exist: %w", err) + } + + return nil +} + +func (rp *ReleaserPleaser) runCreatePendingReleases(ctx context.Context) error { + logger := rp.logger.With("method", "runCreatePendingReleases") + + logger.InfoContext(ctx, "checking for pending releases") + prs, err := rp.forge.PendingReleases(ctx) + if err != nil { + return err + } + + if len(prs) == 0 { + logger.InfoContext(ctx, "No pending releases found") + return nil + } + + logger.InfoContext(ctx, "Found pending releases", "length", len(prs)) + + for _, pr := range prs { + err = rp.createPendingRelease(ctx, pr) + if err != nil { + return err + } + } + + return nil +} + +func (rp *ReleaserPleaser) createPendingRelease(ctx context.Context, pr *ReleasePullRequest) error { + logger := rp.logger.With( + "method", "createPendingRelease", + "pr.id", pr.ID, + "pr.title", pr.Title) + + if pr.ReleaseCommit == nil { + return fmt.Errorf("pull request is missing the merge commit") + } + + logger.Info("Creating release", "commit.hash", pr.ReleaseCommit.Hash) + + version, err := pr.Version() + if err != nil { + return err + } + + changelog, err := pr.ChangelogText() + if err != nil { + return err + } + + // TODO: pre-release & latest + + logger.DebugContext(ctx, "Creating release on forge") + err = rp.forge.CreateRelease(ctx, *pr.ReleaseCommit, version, changelog, false, true) + if err != nil { + return fmt.Errorf("failed to create release on forge: %w", err) + } + logger.DebugContext(ctx, "created release", "release.title", version, "release.url", rp.forge.ReleaseURL(version)) + + logger.DebugContext(ctx, "updating pr labels") + err = rp.forge.SetPullRequestLabels(ctx, pr, []string{LabelReleasePending}, []string{LabelReleaseTagged}) + if err != nil { + return err + } + logger.DebugContext(ctx, "updated pr labels") + + logger.InfoContext(ctx, "Created release", "release.title", version, "release.url", rp.forge.ReleaseURL(version)) + + return nil +} + +func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { + logger := rp.logger.With("method", "runReconcileReleasePR") + + releases, err := rp.forge.LatestTags(ctx) + if err != nil { + return err + } + + if releases.Latest != nil { + logger.InfoContext(ctx, "found latest tag", "tag.hash", releases.Latest.Hash, "tag.name", releases.Latest.Name) + if releases.Stable != nil && releases.Latest.Hash != releases.Stable.Hash { + logger.InfoContext(ctx, "found stable tag", "tag.hash", releases.Stable.Hash, "tag.name", releases.Stable.Name) + } + } else { + logger.InfoContext(ctx, "no latest tag found") + } + + releasableCommits, err := rp.forge.CommitsSince(ctx, releases.Stable) + if err != nil { + return err + } + + logger.InfoContext(ctx, "Found releasable commits", "length", len(releasableCommits)) + + changesets, err := rp.forge.Changesets(ctx, releasableCommits) + if err != nil { + return err + } + + logger.InfoContext(ctx, "Found changesets", "length", len(changesets)) + + rpBranch := fmt.Sprintf(PullRequestBranchFormat, rp.targetBranch) + rpBranchRef := plumbing.NewBranchReferenceName(rpBranch) + // Check Forge for open PR + // Get any modifications from open PR + // Clone Repo + // Run Updaters + Changelog + // Upsert PR + pr, err := rp.forge.PullRequestForBranch(ctx, rpBranch) + if err != nil { + return err + } + + if pr != nil { + logger.InfoContext(ctx, "found existing release pull request", "pr.id", pr.ID, "pr.title", pr.Title) + } + + if len(changesets) == 0 { + if pr != nil { + logger.InfoContext(ctx, "closing existing pull requests, no changesets available", "pr.id", pr.ID, "pr.title", pr.Title) + err = rp.forge.ClosePullRequest(ctx, pr) + if err != nil { + return err + } + } else { + logger.InfoContext(ctx, "No changesets available for release") + } + + return nil + } + + var releaseOverrides ReleaseOverrides + if pr != nil { + releaseOverrides, err = pr.GetOverrides() + if err != nil { + return err + } + } + + versionBump := VersionBumpFromChangesets(changesets) + nextVersion, err := SemVerNextVersion(releases, versionBump, releaseOverrides.NextVersionType) + if err != nil { + return err + } + logger.InfoContext(ctx, "next version", "version", nextVersion) + + logger.DebugContext(ctx, "cloning repository", "clone.url", rp.forge.CloneURL()) + repo, err := CloneRepo(ctx, rp.forge.CloneURL(), rp.targetBranch, rp.forge.GitAuth()) + if err != nil { + return fmt.Errorf("failed to clone repository: %w", 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 fmt.Errorf("failed to check out branch: %w", err) + } + + err = RunUpdater(ctx, nextVersion, worktree) + if err != nil { + return fmt.Errorf("failed to update files with new version: %w", err) + } + + changelogEntry, err := NewChangelogEntry(changesets, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) + if err != nil { + return fmt.Errorf("failed to build changelog entry: %w", err) + } + + err = UpdateChangelogFile(worktree, changelogEntry) + if err != nil { + return fmt.Errorf("failed to update changelog file: %w", err) + } + + releaseCommitMessage := fmt.Sprintf("chore(%s): release %s", rp.targetBranch, nextVersion) + releaseCommitHash, err := worktree.Commit(releaseCommitMessage, &git.CommitOptions{ + Author: GitSignature(), + Committer: GitSignature(), + }) + if err != nil { + return fmt.Errorf("failed to commit changes: %w", err) + } + + logger.InfoContext(ctx, "created release commit", "commit.hash", releaseCommitHash.String(), "commit.message", releaseCommitMessage) + + newReleasePRChanges := true + + // Check if anything changed in comparison to the remote branch (if exists) + if remoteRef, err := repo.Reference(plumbing.NewRemoteReferenceName(GitRemoteName, rpBranch), false); err != nil { + if err.Error() != "reference not found" { + // "reference not found" is expected and we should always push + return err + } + } else { + remoteCommit, err := repo.CommitObject(remoteRef.Hash()) + if err != nil { + return err + } + + localCommit, err := repo.CommitObject(releaseCommitHash) + if err != nil { + return err + } + + diff, err := localCommit.PatchContext(ctx, remoteCommit) + if err != nil { + return err + } + + newReleasePRChanges = len(diff.FilePatches()) > 0 + } + + if newReleasePRChanges { + 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", releaseCommitHash.String(), "branch.name", rpBranch, "refspec", pushRefSpec.String()) + if err = repo.PushContext(ctx, &git.PushOptions{ + RemoteName: GitRemoteName, + RefSpecs: []config.RefSpec{pushRefSpec}, + Force: true, + Auth: rp.forge.GitAuth(), + }); err != nil { + return fmt.Errorf("failed to push branch: %w", err) + } + + logger.InfoContext(ctx, "pushed branch", "commit.hash", releaseCommitHash.String(), "branch.name", rpBranch, "refspec", pushRefSpec.String()) + } else { + logger.InfoContext(ctx, "file content is already up-to-date in remote branch, skipping push") + } + + // Open/Update PR + if pr == nil { + pr, err = NewReleasePullRequest(rpBranch, rp.targetBranch, nextVersion, changelogEntry) + if err != nil { + return err + } + + err = rp.forge.CreatePullRequest(ctx, pr) + if err != nil { + return err + } + logger.InfoContext(ctx, "opened pull request", "pr.title", pr.Title, "pr.id", pr.ID) + } else { + pr.SetTitle(rp.targetBranch, nextVersion) + + overrides, err := pr.GetOverrides() + if err != nil { + return err + } + err = pr.SetDescription(changelogEntry, overrides) + if err != nil { + return err + } + + err = rp.forge.UpdatePullRequest(ctx, pr) + if err != nil { + return err + } + logger.InfoContext(ctx, "updated pull request", "pr.title", pr.Title, "pr.id", pr.ID) + } + + return nil +} From 1d1f18cc6b2d16a4f10e553b8bca32022c2c8866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 15:45:36 +0200 Subject: [PATCH 02/12] refactor: cleanup label handling --- forge.go | 53 +++++++++++++++++++++++++++++++++------------- releasepr.go | 24 +++++++++++---------- releaserpleaser.go | 6 +++--- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/forge.go b/forge.go index 99e65a3..41e7956 100644 --- a/forge.go +++ b/forge.go @@ -49,20 +49,35 @@ type Forge interface { // Changesets looks up the Pull/Merge Requests for each commit, returning its parsed metadata. Changesets(context.Context, []Commit) ([]Changeset, error) - EnsureLabelsExist(context.Context, []string) error + // EnsureLabelsExist verifies that all desired labels are available on the repository. If labels are missing, they + // are created them. + EnsureLabelsExist(context.Context, []Label) error // PullRequestForBranch returns the open pull request between the branch and ForgeOptions.BaseBranch. If no open PR // exists, it returns nil. PullRequestForBranch(context.Context, string) (*ReleasePullRequest, error) + // CreatePullRequest opens a new pull/merge request for the ReleasePullRequest. CreatePullRequest(context.Context, *ReleasePullRequest) error + + // UpdatePullRequest updates the pull/merge request identified through the ID of + // the ReleasePullRequest to the current description and title. UpdatePullRequest(context.Context, *ReleasePullRequest) error - SetPullRequestLabels(ctx context.Context, pr *ReleasePullRequest, remove, add []string) error + + // SetPullRequestLabels updates the pull/merge request identified through the ID of + // the ReleasePullRequest to the current labels. + SetPullRequestLabels(ctx context.Context, pr *ReleasePullRequest, remove, add []Label) error + + // ClosePullRequest closes the pull/merge request identified through the ID of + // the ReleasePullRequest, as it is no longer required. ClosePullRequest(context.Context, *ReleasePullRequest) error - PendingReleases(context.Context) ([]*ReleasePullRequest, error) + // PendingReleases returns a list of ReleasePullRequest. The list should contain all pull/merge requests that are + // merged and have the matching label. + PendingReleases(context.Context, Label) ([]*ReleasePullRequest, error) - CreateRelease(ctx context.Context, commit Commit, title, changelog string, prelease, latest bool) error + // CreateRelease creates a release on the Forge, pointing at the commit with the passed in details. + CreateRelease(ctx context.Context, commit Commit, title, changelog string, prerelease, latest bool) error } type ForgeOptions struct { @@ -326,7 +341,7 @@ func (g *GitHub) Changesets(ctx context.Context, commits []Commit) ([]Changeset, return changesets, nil } -func (g *GitHub) EnsureLabelsExist(ctx context.Context, labels []string) error { +func (g *GitHub) EnsureLabelsExist(ctx context.Context, labels []Label) error { existingLabels := make([]string, 0, len(labels)) page := 1 @@ -354,12 +369,12 @@ func (g *GitHub) EnsureLabelsExist(ctx context.Context, labels []string) error { } for _, label := range labels { - if !slices.Contains(existingLabels, label) { + if !slices.Contains(existingLabels, string(label)) { g.log.Info("creating label in repository", "label.name", label) _, _, err := g.client.Issues.CreateLabel( ctx, g.options.Owner, g.options.Repo, &github.Label{ - Name: &label, + Name: Pointer(string(label)), Color: Pointer(GitHubLabelColor), }, ) @@ -422,7 +437,7 @@ func (g *GitHub) CreatePullRequest(ctx context.Context, pr *ReleasePullRequest) // TODO: String ID? pr.ID = ghPR.GetNumber() - err = g.SetPullRequestLabels(ctx, pr, []string{}, pr.Labels) + err = g.SetPullRequestLabels(ctx, pr, []Label{}, pr.Labels) if err != nil { return err } @@ -445,20 +460,25 @@ func (g *GitHub) UpdatePullRequest(ctx context.Context, pr *ReleasePullRequest) return nil } -func (g *GitHub) SetPullRequestLabels(ctx context.Context, pr *ReleasePullRequest, remove, add []string) error { +func (g *GitHub) SetPullRequestLabels(ctx context.Context, pr *ReleasePullRequest, remove, add []Label) error { for _, label := range remove { _, err := g.client.Issues.RemoveLabelForIssue( ctx, g.options.Owner, g.options.Repo, - pr.ID, label, + pr.ID, string(label), ) if err != nil { return err } } + addString := make([]string, 0, len(add)) + for _, label := range add { + addString = append(addString, string(label)) + } + _, _, err := g.client.Issues.AddLabelsToIssue( ctx, g.options.Owner, g.options.Repo, - pr.ID, add, + pr.ID, addString, ) if err != nil { return err @@ -481,7 +501,7 @@ func (g *GitHub) ClosePullRequest(ctx context.Context, pr *ReleasePullRequest) e return nil } -func (g *GitHub) PendingReleases(ctx context.Context) ([]*ReleasePullRequest, error) { +func (g *GitHub) PendingReleases(ctx context.Context, pendingLabel Label) ([]*ReleasePullRequest, error) { page := 1 var prs []*ReleasePullRequest @@ -509,7 +529,7 @@ func (g *GitHub) PendingReleases(ctx context.Context) ([]*ReleasePullRequest, er for _, pr := range ghPRs { pending := slices.ContainsFunc(pr.Labels, func(l *github.Label) bool { - return l.GetName() == LabelReleasePending + return l.GetName() == string(pendingLabel) }) if !pending { continue @@ -559,9 +579,12 @@ func (g *GitHub) CreateRelease(ctx context.Context, commit Commit, title, change } func gitHubPRToReleasePullRequest(pr *github.PullRequest) *ReleasePullRequest { - labels := make([]string, 0, len(pr.Labels)) + labels := make([]Label, 0, len(pr.Labels)) for _, label := range pr.Labels { - labels = append(labels, label.GetName()) + labelName := Label(label.GetName()) + if slices.Contains(KnownLabels, Label(label.GetName())) { + labels = append(labels, labelName) + } } var releaseCommit *Commit diff --git a/releasepr.go b/releasepr.go index a0a6c0b..1e4d3a8 100644 --- a/releasepr.go +++ b/releasepr.go @@ -35,7 +35,7 @@ type ReleasePullRequest struct { ID int Title string Description string - Labels []string + Labels []Label Head string ReleaseCommit *Commit @@ -44,7 +44,7 @@ type ReleasePullRequest struct { func NewReleasePullRequest(head, branch, version, changelogEntry string) (*ReleasePullRequest, error) { rp := &ReleasePullRequest{ Head: head, - Labels: []string{LabelReleasePending}, + Labels: []Label{LabelReleasePending}, } rp.SetTitle(branch, version) @@ -89,18 +89,20 @@ func (n NextVersionType) String() string { } } -// PR Labels -const ( - LabelNextVersionTypeNormal = "rp-next-version::normal" - LabelNextVersionTypeRC = "rp-next-version::rc" - LabelNextVersionTypeBeta = "rp-next-version::beta" - LabelNextVersionTypeAlpha = "rp-next-version::alpha" +// Label is the string identifier of a pull/merge request label on the forge. +type Label string - LabelReleasePending = "rp-release::pending" - LabelReleaseTagged = "rp-release::tagged" +const ( + LabelNextVersionTypeNormal Label = "rp-next-version::normal" + LabelNextVersionTypeRC Label = "rp-next-version::rc" + LabelNextVersionTypeBeta Label = "rp-next-version::beta" + LabelNextVersionTypeAlpha Label = "rp-next-version::alpha" + + LabelReleasePending Label = "rp-release::pending" + LabelReleaseTagged Label = "rp-release::tagged" ) -var Labels = []string{ +var KnownLabels = []Label{ LabelNextVersionTypeNormal, LabelNextVersionTypeRC, LabelNextVersionTypeBeta, diff --git a/releaserpleaser.go b/releaserpleaser.go index 69a6723..400e0fb 100644 --- a/releaserpleaser.go +++ b/releaserpleaser.go @@ -30,7 +30,7 @@ func New(forge Forge, logger *slog.Logger, targetBranch string) *ReleaserPleaser func (rp *ReleaserPleaser) EnsureLabels(ctx context.Context) error { // TODO: Wrap Error - return rp.forge.EnsureLabelsExist(ctx, Labels) + return rp.forge.EnsureLabelsExist(ctx, KnownLabels) } func (rp *ReleaserPleaser) Run(ctx context.Context) error { @@ -60,7 +60,7 @@ func (rp *ReleaserPleaser) runCreatePendingReleases(ctx context.Context) error { logger := rp.logger.With("method", "runCreatePendingReleases") logger.InfoContext(ctx, "checking for pending releases") - prs, err := rp.forge.PendingReleases(ctx) + prs, err := rp.forge.PendingReleases(ctx, LabelReleasePending) if err != nil { return err } @@ -114,7 +114,7 @@ func (rp *ReleaserPleaser) createPendingRelease(ctx context.Context, pr *Release logger.DebugContext(ctx, "created release", "release.title", version, "release.url", rp.forge.ReleaseURL(version)) logger.DebugContext(ctx, "updating pr labels") - err = rp.forge.SetPullRequestLabels(ctx, pr, []string{LabelReleasePending}, []string{LabelReleaseTagged}) + err = rp.forge.SetPullRequestLabels(ctx, pr, []Label{LabelReleasePending}, []Label{LabelReleaseTagged}) if err != nil { return err } From 6b839cfc933311c3bd8d8f0bcc8435d658e4685c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 16:26:40 +0200 Subject: [PATCH 03/12] refactor: move commit analyzing out of forge --- changelog.go | 16 +++---- changelog_test.go | 38 +++++++-------- cmd/rp/cmd/run.go | 2 +- commits.go | 15 +++++- commits_test.go | 2 +- forge.go | 117 +++++++++++++++++++-------------------------- git.go | 5 -- releasepr.go | 5 +- releaserpleaser.go | 24 ++++++---- versioning.go | 28 +++++------ versioning_test.go | 88 +++++++++++----------------------- 11 files changed, 152 insertions(+), 188 deletions(-) diff --git a/changelog.go b/changelog.go index 40c65d4..016e876 100644 --- a/changelog.go +++ b/changelog.go @@ -90,18 +90,16 @@ func UpdateChangelogFile(wt *git.Worktree, newEntry string) error { return nil } -func NewChangelogEntry(changesets []Changeset, version, link, prefix, suffix string) (string, error) { +func NewChangelogEntry(commits []AnalyzedCommit, version, link, prefix, suffix string) (string, error) { features := make([]AnalyzedCommit, 0) fixes := make([]AnalyzedCommit, 0) - for _, changeset := range changesets { - for _, commit := range changeset.ChangelogEntries { - switch commit.Type { - case "feat": - features = append(features, commit) - case "fix": - fixes = append(fixes, commit) - } + for _, commit := range commits { + switch commit.Type { + case "feat": + features = append(features, commit) + case "fix": + fixes = append(fixes, commit) } } diff --git a/changelog_test.go b/changelog_test.go index 91ffc85..3d1612b 100644 --- a/changelog_test.go +++ b/changelog_test.go @@ -96,11 +96,11 @@ func TestUpdateChangelogFile(t *testing.T) { func Test_NewChangelogEntry(t *testing.T) { type args struct { - changesets []Changeset - version string - link string - prefix string - suffix string + analyzedCommits []AnalyzedCommit + version string + link string + prefix string + suffix string } tests := []struct { name string @@ -111,9 +111,9 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "empty", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{}}}, - version: "1.0.0", - link: "https://example.com/1.0.0", + analyzedCommits: []AnalyzedCommit{}, + version: "1.0.0", + link: "https://example.com/1.0.0", }, want: "## [1.0.0](https://example.com/1.0.0)", wantErr: assert.NoError, @@ -121,13 +121,13 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "single feature", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{ + analyzedCommits: []AnalyzedCommit{ { Commit: Commit{}, Type: "feat", Description: "Foobar!", }, - }}}, + }, version: "1.0.0", link: "https://example.com/1.0.0", }, @@ -137,13 +137,13 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "single fix", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{ + analyzedCommits: []AnalyzedCommit{ { Commit: Commit{}, Type: "fix", Description: "Foobar!", }, - }}}, + }, version: "1.0.0", link: "https://example.com/1.0.0", }, @@ -153,7 +153,7 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "multiple commits with scopes", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{ + analyzedCommits: []AnalyzedCommit{ { Commit: Commit{}, Type: "feat", @@ -176,7 +176,7 @@ func Test_NewChangelogEntry(t *testing.T) { Description: "So sad!", Scope: ptr("sad"), }, - }}}, + }, version: "1.0.0", link: "https://example.com/1.0.0", }, @@ -196,13 +196,13 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "prefix", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{ + analyzedCommits: []AnalyzedCommit{ { Commit: Commit{}, Type: "fix", Description: "Foobar!", }, - }}}, + }, version: "1.0.0", link: "https://example.com/1.0.0", prefix: "### Breaking Changes", @@ -219,13 +219,13 @@ func Test_NewChangelogEntry(t *testing.T) { { name: "suffix", args: args{ - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{ + analyzedCommits: []AnalyzedCommit{ { Commit: Commit{}, Type: "fix", Description: "Foobar!", }, - }}}, + }, version: "1.0.0", link: "https://example.com/1.0.0", suffix: "### Compatibility\n\nThis version is compatible with flux-compensator v2.2 - v2.9.", @@ -245,7 +245,7 @@ This version is compatible with flux-compensator v2.2 - v2.9. for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := NewChangelogEntry(tt.args.changesets, tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix) + got, err := NewChangelogEntry(tt.args.analyzedCommits, tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix) if !tt.wantErr(t, err) { return } diff --git a/cmd/rp/cmd/run.go b/cmd/rp/cmd/run.go index ea1e940..34db06f 100644 --- a/cmd/rp/cmd/run.go +++ b/cmd/rp/cmd/run.go @@ -59,7 +59,7 @@ func run(cmd *cobra.Command, _ []string) error { }) } - releaserPleaser := rp.New(forge, logger, flagBranch) + releaserPleaser := rp.New(forge, logger, flagBranch, rp.NewConventionalCommitsParser(), rp.SemVerNextVersion) return releaserPleaser.Run(ctx) } diff --git a/commits.go b/commits.go index 28f9f4a..f0c64e9 100644 --- a/commits.go +++ b/commits.go @@ -7,6 +7,19 @@ import ( "github.com/leodido/go-conventionalcommits/parser" ) +type Commit struct { + Hash string + Message string + + PullRequest *PullRequest +} + +type PullRequest struct { + ID int + Title string + Description string +} + type AnalyzedCommit struct { Commit Type string @@ -34,7 +47,7 @@ func NewConventionalCommitsParser() *ConventionalCommitsParser { } } -func (c *ConventionalCommitsParser) AnalyzeCommits(commits []Commit) ([]AnalyzedCommit, error) { +func (c *ConventionalCommitsParser) Analyze(commits []Commit) ([]AnalyzedCommit, error) { analyzedCommits := make([]AnalyzedCommit, 0, len(commits)) for _, commit := range commits { diff --git a/commits_test.go b/commits_test.go index 0725b32..e58a718 100644 --- a/commits_test.go +++ b/commits_test.go @@ -111,7 +111,7 @@ func TestAnalyzeCommits(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - analyzedCommits, err := NewConventionalCommitsParser().AnalyzeCommits(tt.commits) + analyzedCommits, err := NewConventionalCommitsParser().Analyze(tt.commits) if !tt.wantErr(t, err) { return } diff --git a/forge.go b/forge.go index 41e7956..8ce7f55 100644 --- a/forge.go +++ b/forge.go @@ -25,12 +25,6 @@ const ( GitHubLabelColor = "dedede" ) -type Changeset struct { - URL string - Identifier string - ChangelogEntries []AnalyzedCommit -} - type Forge interface { RepoURL() string CloneURL() string @@ -46,9 +40,6 @@ type Forge interface { // function should return all commits. CommitsSince(context.Context, *Tag) ([]Commit, error) - // Changesets looks up the Pull/Merge Requests for each commit, returning its parsed metadata. - Changesets(context.Context, []Commit) ([]Changeset, error) - // EnsureLabelsExist verifies that all desired labels are available on the repository. If labels are missing, they // are created them. EnsureLabelsExist(context.Context, []Label) error @@ -184,10 +175,16 @@ func (g *GitHub) CommitsSince(ctx context.Context, tag *Tag) ([]Commit, error) { var commits = make([]Commit, 0, len(repositoryCommits)) for _, ghCommit := range repositoryCommits { - commits = append(commits, Commit{ + commit := Commit{ Hash: ghCommit.GetSHA(), Message: ghCommit.GetCommit().GetMessage(), - }) + } + commit.PullRequest, err = g.prForCommit(ctx, commit) + if err != nil { + return nil, fmt.Errorf("failed to check for commit pull request: %w", err) + } + + commits = append(commits) } return commits, nil @@ -272,73 +269,49 @@ func (g *GitHub) commitsSinceInit(ctx context.Context) ([]*github.RepositoryComm return repositoryCommits, nil } -func (g *GitHub) Changesets(ctx context.Context, commits []Commit) ([]Changeset, error) { +func (g *GitHub) prForCommit(ctx context.Context, commit Commit) (*PullRequest, error) { // We naively look up the associated PR for each commit through the "List pull requests associated with a commit" // endpoint. This requires len(commits) requests. // Using the "List pull requests" endpoint might be faster, as it allows us to fetch 100 arbitrary PRs per request, // but worst case we need to look up all PRs made in the repository ever. - changesets := make([]Changeset, 0, len(commits)) + log := g.log.With("commit.hash", commit.Hash) + page := 1 + var associatedPRs []*github.PullRequest - for _, commit := range commits { - log := g.log.With("commit.hash", commit.Hash) - page := 1 - var associatedPRs []*github.PullRequest - - for { - log.Debug("fetching pull requests associated with commit", "page", page) - prs, resp, err := g.client.PullRequests.ListPullRequestsWithCommit( - ctx, g.options.Owner, g.options.Repo, - commit.Hash, &github.ListOptions{ - Page: page, - PerPage: GitHubPerPageMax, - }) - if err != nil { - return nil, err - } - - associatedPRs = append(associatedPRs, prs...) - - if page == resp.LastPage || resp.LastPage == 0 { - break - } - page = resp.NextPage - } - - var pullrequest *github.PullRequest - for _, pr := range associatedPRs { - // We only look for the PR that has this commit set as the "merge commit" => The result of squashing this branch onto main - if pr.GetMergeCommitSHA() == commit.Hash { - pullrequest = pr - break - } - } - if pullrequest == nil { - log.Warn("did not find associated pull request, not considering it for changesets") - // No pull request was found for this commit, nothing to do here - // TODO: We could also return the minimal changeset for this commit, so at least it would come up in the changelog. - continue - } - - log = log.With("pullrequest.id", pullrequest.GetID()) - - // TODO: Parse PR description for overrides - changelogEntries, err := NewConventionalCommitsParser().AnalyzeCommits([]Commit{commit}) - if err != nil { - log.Warn("unable to parse changelog entries", "error", err) - continue - } - - if len(changelogEntries) > 0 { - changesets = append(changesets, Changeset{ - URL: pullrequest.GetHTMLURL(), - Identifier: fmt.Sprintf("#%d", pullrequest.GetNumber()), - ChangelogEntries: changelogEntries, + for { + log.Debug("fetching pull requests associated with commit", "page", page) + prs, resp, err := g.client.PullRequests.ListPullRequestsWithCommit( + ctx, g.options.Owner, g.options.Repo, + commit.Hash, &github.ListOptions{ + Page: page, + PerPage: GitHubPerPageMax, }) + if err != nil { + return nil, err } + + associatedPRs = append(associatedPRs, prs...) + + if page == resp.LastPage || resp.LastPage == 0 { + break + } + page = resp.NextPage } - return changesets, nil + var pullrequest *github.PullRequest + for _, pr := range associatedPRs { + // We only look for the PR that has this commit set as the "merge commit" => The result of squashing this branch onto main + if pr.GetMergeCommitSHA() == commit.Hash { + pullrequest = pr + break + } + } + if pullrequest == nil { + return nil, nil + } + + return gitHubPRToPullRequest(pullrequest), nil } func (g *GitHub) EnsureLabelsExist(ctx context.Context, labels []Label) error { @@ -578,6 +551,14 @@ func (g *GitHub) CreateRelease(ctx context.Context, commit Commit, title, change return nil } +func gitHubPRToPullRequest(pr *github.PullRequest) *PullRequest { + return &PullRequest{ + ID: pr.GetNumber(), + Title: pr.GetTitle(), + Description: pr.GetBody(), + } +} + func gitHubPRToReleasePullRequest(pr *github.PullRequest) *ReleasePullRequest { labels := make([]Label, 0, len(pr.Labels)) for _, label := range pr.Labels { diff --git a/git.go b/git.go index 7df742c..2f0c7f2 100644 --- a/git.go +++ b/git.go @@ -17,11 +17,6 @@ const ( GitRemoteName = "origin" ) -type Commit struct { - Hash string - Message string -} - type Tag struct { Hash string Name string diff --git a/releasepr.go b/releasepr.go index 1e4d3a8..1d41325 100644 --- a/releasepr.go +++ b/releasepr.go @@ -31,6 +31,9 @@ func init() { } } +// ReleasePullRequest +// +// TODO: Reuse [PullRequest] type ReleasePullRequest struct { ID int Title string @@ -58,7 +61,7 @@ func NewReleasePullRequest(head, branch, version, changelogEntry string) (*Relea type ReleaseOverrides struct { Prefix string Suffix string - // TODO: Doing the changelog for normal releases after previews requires to know about this while fetching the changesets + // TODO: Doing the changelog for normal releases after previews requires to know about this while fetching the commits NextVersionType NextVersionType } diff --git a/releaserpleaser.go b/releaserpleaser.go index 400e0fb..035afec 100644 --- a/releaserpleaser.go +++ b/releaserpleaser.go @@ -18,13 +18,17 @@ type ReleaserPleaser struct { forge Forge logger *slog.Logger targetBranch string + commitParser CommitParser + nextVersion VersioningStrategy } -func New(forge Forge, logger *slog.Logger, targetBranch string) *ReleaserPleaser { +func New(forge Forge, logger *slog.Logger, targetBranch string, commitParser CommitParser, versioningStrategy VersioningStrategy) *ReleaserPleaser { return &ReleaserPleaser{ forge: forge, logger: logger, targetBranch: targetBranch, + commitParser: commitParser, + nextVersion: versioningStrategy, } } @@ -149,12 +153,13 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { logger.InfoContext(ctx, "Found releasable commits", "length", len(releasableCommits)) - changesets, err := rp.forge.Changesets(ctx, releasableCommits) + // TODO: Handle commit overrides + analyzedCommits, err := rp.commitParser.Analyze(releasableCommits) if err != nil { return err } - logger.InfoContext(ctx, "Found changesets", "length", len(changesets)) + logger.InfoContext(ctx, "Analyzed commits", "length", len(analyzedCommits)) rpBranch := fmt.Sprintf(PullRequestBranchFormat, rp.targetBranch) rpBranchRef := plumbing.NewBranchReferenceName(rpBranch) @@ -172,15 +177,15 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { logger.InfoContext(ctx, "found existing release pull request", "pr.id", pr.ID, "pr.title", pr.Title) } - if len(changesets) == 0 { + if len(analyzedCommits) == 0 { if pr != nil { - logger.InfoContext(ctx, "closing existing pull requests, no changesets available", "pr.id", pr.ID, "pr.title", pr.Title) + logger.InfoContext(ctx, "closing existing pull requests, no commits available", "pr.id", pr.ID, "pr.title", pr.Title) err = rp.forge.ClosePullRequest(ctx, pr) if err != nil { return err } } else { - logger.InfoContext(ctx, "No changesets available for release") + logger.InfoContext(ctx, "No commits available for release") } return nil @@ -194,8 +199,9 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { } } - versionBump := VersionBumpFromChangesets(changesets) - nextVersion, err := SemVerNextVersion(releases, versionBump, releaseOverrides.NextVersionType) + versionBump := VersionBumpFromCommits(analyzedCommits) + // TODO: Set version in release pr + nextVersion, err := rp.nextVersion(releases, versionBump, releaseOverrides.NextVersionType) if err != nil { return err } @@ -230,7 +236,7 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { return fmt.Errorf("failed to update files with new version: %w", err) } - changelogEntry, err := NewChangelogEntry(changesets, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) + changelogEntry, err := NewChangelogEntry(analyzedCommits, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) if err != nil { return fmt.Errorf("failed to build changelog entry: %w", err) } diff --git a/versioning.go b/versioning.go index 77bb96f..176a28d 100644 --- a/versioning.go +++ b/versioning.go @@ -69,24 +69,22 @@ func SemVerNextVersion(r Releases, versionBump conventionalcommits.VersionBump, return "v" + next.String(), nil } -func VersionBumpFromChangesets(changesets []Changeset) conventionalcommits.VersionBump { +func VersionBumpFromCommits(commits []AnalyzedCommit) conventionalcommits.VersionBump { bump := conventionalcommits.UnknownVersion - for _, changeset := range changesets { - for _, entry := range changeset.ChangelogEntries { - entryBump := conventionalcommits.UnknownVersion - switch { - case entry.BreakingChange: - entryBump = conventionalcommits.MajorVersion - case entry.Type == "feat": - entryBump = conventionalcommits.MinorVersion - case entry.Type == "fix": - entryBump = conventionalcommits.PatchVersion - } + for _, commit := range commits { + entryBump := conventionalcommits.UnknownVersion + switch { + case commit.BreakingChange: + entryBump = conventionalcommits.MajorVersion + case commit.Type == "feat": + entryBump = conventionalcommits.MinorVersion + case commit.Type == "fix": + entryBump = conventionalcommits.PatchVersion + } - if entryBump > bump { - bump = entryBump - } + if entryBump > bump { + bump = entryBump } } diff --git a/versioning_test.go b/versioning_test.go index d1846d8..b6a0995 100644 --- a/versioning_test.go +++ b/versioning_test.go @@ -333,86 +333,56 @@ func TestReleases_NextVersion(t *testing.T) { } } -func TestVersionBumpFromChangesets(t *testing.T) { +func TestVersionBumpFromCommits(t *testing.T) { tests := []struct { - name string - changesets []Changeset - want conventionalcommits.VersionBump + name string + analyzedCommits []AnalyzedCommit + want conventionalcommits.VersionBump }{ { - name: "no entries (unknown)", - changesets: []Changeset{}, - want: conventionalcommits.UnknownVersion, + name: "no entries (unknown)", + analyzedCommits: []AnalyzedCommit{}, + want: conventionalcommits.UnknownVersion, }, { - name: "non-release type (unknown)", - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{{Type: "docs"}}}}, - want: conventionalcommits.UnknownVersion, + name: "non-release type (unknown)", + analyzedCommits: []AnalyzedCommit{{Type: "docs"}}, + want: conventionalcommits.UnknownVersion, }, { - name: "single breaking (major)", - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{{BreakingChange: true}}}}, - want: conventionalcommits.MajorVersion, + name: "single breaking (major)", + analyzedCommits: []AnalyzedCommit{{BreakingChange: true}}, + want: conventionalcommits.MajorVersion, }, { - name: "single feat (minor)", - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{{Type: "feat"}}}}, - want: conventionalcommits.MinorVersion, + name: "single feat (minor)", + analyzedCommits: []AnalyzedCommit{{Type: "feat"}}, + want: conventionalcommits.MinorVersion, }, { - name: "single fix (patch)", - changesets: []Changeset{{ChangelogEntries: []AnalyzedCommit{{Type: "fix"}}}}, - want: conventionalcommits.PatchVersion, + name: "single fix (patch)", + analyzedCommits: []AnalyzedCommit{{Type: "fix"}}, + want: conventionalcommits.PatchVersion, }, { - name: "multiple changesets (major)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "fix"}}}, - {ChangelogEntries: []AnalyzedCommit{{BreakingChange: true}}}, - }, - want: conventionalcommits.MajorVersion, + name: "multiple entries (major)", + analyzedCommits: []AnalyzedCommit{{Type: "fix"}, {BreakingChange: true}}, + want: conventionalcommits.MajorVersion, }, { - name: "multiple changesets (minor)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "fix"}}}, - {ChangelogEntries: []AnalyzedCommit{{Type: "feat"}}}, - }, - want: conventionalcommits.MinorVersion, + name: "multiple entries (minor)", + analyzedCommits: []AnalyzedCommit{{Type: "fix"}, {Type: "feat"}}, + want: conventionalcommits.MinorVersion, }, { - name: "multiple changesets (patch)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "docs"}}}, - {ChangelogEntries: []AnalyzedCommit{{Type: "fix"}}}, - }, - want: conventionalcommits.PatchVersion, - }, - { - name: "multiple entries in one changeset (major)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "fix"}, {BreakingChange: true}}}, - }, - want: conventionalcommits.MajorVersion, - }, - { - name: "multiple entries in one changeset (minor)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "fix"}, {Type: "feat"}}}, - }, - want: conventionalcommits.MinorVersion, - }, - { - name: "multiple entries in one changeset (patch)", - changesets: []Changeset{ - {ChangelogEntries: []AnalyzedCommit{{Type: "docs"}, {Type: "fix"}}}, - }, - want: conventionalcommits.PatchVersion, + name: "multiple entries (patch)", + analyzedCommits: []AnalyzedCommit{{Type: "docs"}, {Type: "fix"}}, + want: conventionalcommits.PatchVersion, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, VersionBumpFromChangesets(tt.changesets), "VersionBumpFromChangesets(%v)", tt.changesets) + assert.Equalf(t, tt.want, VersionBumpFromCommits(tt.analyzedCommits), "VersionBumpFromCommits(%v)", tt.analyzedCommits) }) } } From 8abea51ec821e6758f242049dc920dd1c5f22f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 22:47:12 +0200 Subject: [PATCH 04/12] refactor: remove unused code --- changelog.go | 5 ++--- git.go | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/changelog.go b/changelog.go index 016e876..43568d5 100644 --- a/changelog.go +++ b/changelog.go @@ -14,9 +14,8 @@ import ( ) const ( - ChangelogFile = "CHANGELOG.md" - ChangelogFileBuffer = "CHANGELOG.md.tmp" - ChangelogHeader = "# Changelog" + ChangelogFile = "CHANGELOG.md" + ChangelogHeader = "# Changelog" ) var ( diff --git a/git.go b/git.go index 2f0c7f2..9131570 100644 --- a/git.go +++ b/git.go @@ -13,8 +13,7 @@ import ( ) const ( - CommitSearchDepth = 50 // TODO: Increase - GitRemoteName = "origin" + GitRemoteName = "origin" ) type Tag struct { From 4d435fa95280d673ba56ad914df6fb1f7fbe959b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 22:52:05 +0200 Subject: [PATCH 05/12] refactor: smaller fixes --- .../markdown/renderer/markdown/renderer.go | 20 +++++++++---------- internal/testutils/git.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/markdown/renderer/markdown/renderer.go b/internal/markdown/renderer/markdown/renderer.go index 7a369e7..e0d4ecb 100644 --- a/internal/markdown/renderer/markdown/renderer.go +++ b/internal/markdown/renderer/markdown/renderer.go @@ -149,7 +149,7 @@ func (r *Renderer) writeByte(w io.Writer, c byte) error { return nil } -// WriteString writes a string to an io.Writer, ensuring that appropriate indentation and prefices are added at the +// WriteString writes a string to an io.Writer, ensuring that appropriate indentation and prefixes are added at the // beginning of each line. func (r *Renderer) writeString(w io.Writer, s string) (int, error) { n, err := r.write(w, []byte(s)) @@ -178,7 +178,7 @@ func (r *Renderer) popPrefix() { // OpenBlock ensures that each block begins on a new line, and that blank lines are inserted before blocks as // indicated by node.HasPreviousBlankLines. -func (r *Renderer) openBlock(w util.BufWriter, source []byte, node ast.Node) error { +func (r *Renderer) openBlock(w util.BufWriter, _ []byte, node ast.Node) error { r.openBlocks = append(r.openBlocks, blockState{ node: node, fresh: true, @@ -222,7 +222,7 @@ func (r *Renderer) closeBlock(w io.Writer) error { } // RenderDocument renders an *ast.Document node to the given BufWriter. -func (r *Renderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderDocument(_ util.BufWriter, _ []byte, _ ast.Node, _ bool) (ast.WalkStatus, error) { r.listStack, r.prefixStack, r.prefix, r.atNewline = nil, nil, nil, false return ast.WalkContinue, nil } @@ -594,7 +594,7 @@ func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, node ast.Node } // RenderEmphasis renders an *ast.Emphasis node to the given BufWriter. -func (r *Renderer) renderEmphasis(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderEmphasis(w util.BufWriter, _ []byte, node ast.Node, _ bool) (ast.WalkStatus, error) { em := node.(*ast.Emphasis) if _, err := r.writeString(w, strings.Repeat("*", em.Level)); err != nil { return ast.WalkStop, fmt.Errorf(": %w", err) @@ -663,7 +663,7 @@ func (r *Renderer) renderLinkOrImage(w util.BufWriter, open string, dest, title } // RenderImage renders an *ast.Image node to the given BufWriter. -func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderImage(w util.BufWriter, _ []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { img := node.(*ast.Image) if err := r.renderLinkOrImage(w, "![", img.Destination, img.Title, enter); err != nil { return ast.WalkStop, fmt.Errorf(": %w", err) @@ -672,7 +672,7 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e } // RenderLink renders an *ast.Link node to the given BufWriter. -func (r *Renderer) renderLink(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderLink(w util.BufWriter, _ []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { link := node.(*ast.Link) if err := r.renderLinkOrImage(w, "[", link.Destination, link.Title, enter); err != nil { return ast.WalkStop, fmt.Errorf(": %w", err) @@ -724,7 +724,7 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en } // RenderString renders an *ast.String node to the given BufWriter. -func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderString(w util.BufWriter, _ []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { if !enter { return ast.WalkContinue, nil } @@ -801,7 +801,7 @@ func (r *Renderer) renderTableRow(w util.BufWriter, source []byte, node ast.Node return ast.WalkContinue, nil } -func (r *Renderer) renderTableCell(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderTableCell(w util.BufWriter, _ []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { if !enter { if node.NextSibling() != nil { if _, err := r.writeString(w, " | "); err != nil { @@ -813,14 +813,14 @@ func (r *Renderer) renderTableCell(w util.BufWriter, source []byte, node ast.Nod return ast.WalkContinue, nil } -func (r *Renderer) renderStrikethrough(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderStrikethrough(w util.BufWriter, _ []byte, _ ast.Node, _ bool) (ast.WalkStatus, error) { if _, err := r.writeString(w, "~~"); err != nil { return ast.WalkStop, fmt.Errorf(": %w", err) } return ast.WalkContinue, nil } -func (r *Renderer) renderTaskCheckBox(w util.BufWriter, source []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { +func (r *Renderer) renderTaskCheckBox(w util.BufWriter, _ []byte, node ast.Node, enter bool) (ast.WalkStatus, error) { if enter { var fill byte = ' ' if task := node.(*exast.TaskCheckBox); task.IsChecked { diff --git a/internal/testutils/git.go b/internal/testutils/git.go index 3bfd053..14737a0 100644 --- a/internal/testutils/git.go +++ b/internal/testutils/git.go @@ -61,9 +61,9 @@ func WithCommit(message string, options ...CommitOption) Commit { for _, fileInfo := range opts.files { file, err := wt.Filesystem.Create(fileInfo.path) require.NoError(t, err, "failed to create file %q", fileInfo.path) - defer file.Close() _, err = file.Write([]byte(fileInfo.content)) + file.Close() require.NoError(t, err, "failed to write content to file %q", fileInfo.path) } From 1ff67f4ec8b0d744fb03f5d36321eba3a66824c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 22:55:04 +0200 Subject: [PATCH 06/12] fixup! refactor: move commit analyzing out of forge --- forge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge.go b/forge.go index 8ce7f55..c244a0c 100644 --- a/forge.go +++ b/forge.go @@ -184,7 +184,7 @@ func (g *GitHub) CommitsSince(ctx context.Context, tag *Tag) ([]Commit, error) { return nil, fmt.Errorf("failed to check for commit pull request: %w", err) } - commits = append(commits) + commits = append(commits, commit) } return commits, nil From fd0c35d6f8f83e966f36cf9974bc4670c6ee1766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 22:55:21 +0200 Subject: [PATCH 07/12] fixup! refactor: move run logic outside of cli code --- releaserpleaser.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/releaserpleaser.go b/releaserpleaser.go index 035afec..7c3ab16 100644 --- a/releaserpleaser.go +++ b/releaserpleaser.go @@ -48,6 +48,11 @@ func (rp *ReleaserPleaser) Run(ctx context.Context) error { return fmt.Errorf("failed to create pending releases: %w", err) } + err = rp.runReconcileReleasePR(ctx) + if err != nil { + return fmt.Errorf("failed to reconcile release pull request: %w", err) + } + return nil } From 828a0884c781a9ad6ff333e84ee01ee26a25b4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 22:59:17 +0200 Subject: [PATCH 08/12] ci: codecov coverage --- .github/workflows/ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8fbca23..ab91e51 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,6 +39,10 @@ jobs: - name: Run tests run: go test -v -race -coverpkg=./... ./... + - name: Upload results to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} go-mod-tidy: runs-on: ubuntu-latest From 282c10ad5c0bbb0ed1fde692a2f7372cf31f34f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 23:01:18 +0200 Subject: [PATCH 09/12] ci: output test coverage file --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ab91e51..128439a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,7 +37,7 @@ jobs: go-version-file: go.mod - name: Run tests - run: go test -v -race -coverpkg=./... ./... + run: go test -v -race -coverpkg=./... -coverprofile=coverage.txt ./... - name: Upload results to Codecov uses: codecov/codecov-action@v4 From c00476684cbaee082872f490658b62cf4fd4d344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 23:05:20 +0200 Subject: [PATCH 10/12] chore: update dependencies --- go.mod | 18 ++++++++---------- go.sum | 46 ++++++++++++++++++++-------------------------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index e55cfa9..0d4a9d4 100644 --- a/go.mod +++ b/go.mod @@ -14,11 +14,11 @@ require ( ) require ( - dario.cat/mergo v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + dario.cat/mergo v1.0.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cloudflare/circl v1.3.9 // indirect + github.com/cyphar/filepath-securejoin v0.3.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -31,14 +31,12 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.2 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 385a5a2..c43a8f2 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -13,11 +13,11 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= +github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE= +github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -75,8 +75,8 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= +github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -97,12 +97,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -110,13 +108,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -130,15 +126,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -146,14 +142,12 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From ad69e252b923db1ba9247914beb2d1c46f463b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 23:08:58 +0200 Subject: [PATCH 11/12] chore: upgrade to go 1.23 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 0d4a9d4..3be3b4e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/apricote/releaser-pleaser -go 1.22.4 +go 1.23.0 require ( github.com/blang/semver/v4 v4.0.0 From 7b84b3cdccd47ecaf86e38170f76408a9a9eade8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sat, 17 Aug 2024 23:25:21 +0200 Subject: [PATCH 12/12] chore: update golangci-lint --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 128439a..38a1f4c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,7 +21,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v6 with: - version: v1.59.1 # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v1.60.1 # renovate: datasource=github-releases depName=golangci/golangci-lint args: --timeout 5m