@@ -16,13 +16,23 @@ package librarian
1616
1717import (
1818 "context"
19+ "errors"
1920 "fmt"
2021 "log/slog"
2122 "regexp"
23+ "strconv"
2224 "strings"
25+ "time"
2326
2427 "github.com/googleapis/librarian/internal/cli"
2528 "github.com/googleapis/librarian/internal/config"
29+ "github.com/googleapis/librarian/internal/github"
30+ "github.com/googleapis/librarian/internal/gitrepo"
31+ )
32+
33+ const (
34+ pullRequestSegments = 5
35+ tagAndReleaseCmdName = "tag-and-release"
2636)
2737
2838var (
3242
3343// cmdTagAndRelease is the command for the `release tag-and-release` subcommand.
3444var cmdTagAndRelease = & cli.Command {
35- Short : "release tag-and-release tags and creates a GitHub release for a merged pull request." ,
45+ Short : "tag-and-release tags and creates a GitHub release for a merged pull request." ,
3646 UsageLine : "librarian release tag-and-release [arguments]" ,
3747 Long : "Tags and creates a GitHub release for a merged pull request." ,
3848 Run : func (ctx context.Context , cfg * config.Config ) error {
@@ -54,19 +64,92 @@ func init() {
5464}
5565
5666type tagAndReleaseRunner struct {
57- cfg * config.Config
67+ cfg * config.Config
68+ ghClient GitHubClient
69+ repo gitrepo.Repository
70+ state * config.LibrarianState
5871}
5972
6073func newTagAndReleaseRunner (cfg * config.Config ) (* tagAndReleaseRunner , error ) {
74+ runner , err := newCommandRunner (cfg )
75+ if err != nil {
76+ return nil , err
77+ }
6178 if cfg .GitHubToken == "" {
6279 return nil , fmt .Errorf ("`LIBRARIAN_GITHUB_TOKEN` must be set" )
6380 }
6481 return & tagAndReleaseRunner {
65- cfg : cfg ,
82+ cfg : cfg ,
83+ repo : runner .repo ,
84+ state : runner .state ,
85+ ghClient : runner .ghClient ,
6686 }, nil
6787}
6888
6989func (r * tagAndReleaseRunner ) run (ctx context.Context ) error {
90+ slog .Info ("running tag-and-release command" )
91+ prs , err := r .determinePullRequestsToProcess (ctx )
92+ if err != nil {
93+ return err
94+ }
95+ if len (prs ) == 0 {
96+ slog .Info ("no pull requests to process, exiting" )
97+ return nil
98+ }
99+
100+ var hadErrors bool
101+ for _ , p := range prs {
102+ if err := r .processPullRequest (ctx , p ); err != nil {
103+ slog .Error ("failed to process pull request" , "pr" , p .GetNumber (), "error" , err )
104+ hadErrors = true
105+ continue
106+ }
107+ slog .Info ("processed pull request" , "pr" , p .GetNumber ())
108+ }
109+ slog .Info ("finished processing all pull requests" )
110+
111+ if hadErrors {
112+ return errors .New ("failed to process some pull requests" )
113+ }
114+ return nil
115+ }
116+
117+ func (r * tagAndReleaseRunner ) determinePullRequestsToProcess (ctx context.Context ) ([]* github.PullRequest , error ) {
118+ slog .Info ("determining pull requests to process" )
119+ if r .cfg .PullRequest != "" {
120+ slog .Info ("processing a single pull request" , "pr" , r .cfg .PullRequest )
121+ ss := strings .Split (r .cfg .PullRequest , "/" )
122+ if len (ss ) != pullRequestSegments {
123+ return nil , fmt .Errorf ("invalid pull request format: %s" , r .cfg .PullRequest )
124+ }
125+ prNum , err := strconv .Atoi (ss [pullRequestSegments - 1 ])
126+ if err != nil {
127+ return nil , fmt .Errorf ("invalid pull request number: %s" , ss [pullRequestSegments - 1 ])
128+ }
129+ pr , err := r .ghClient .GetPullRequest (ctx , prNum )
130+ if err != nil {
131+ return nil , fmt .Errorf ("failed to get pull request %d: %w" , prNum , err )
132+ }
133+ return []* github.PullRequest {pr }, nil
134+ }
135+
136+ slog .Info ("searching for pull requests to tag and release" )
137+ thirtyDaysAgo := time .Now ().Add (- 30 * 24 * time .Hour ).Format (time .RFC3339 )
138+ query := fmt .Sprintf ("label:release:pending merged:>=%s" , thirtyDaysAgo )
139+ prs , err := r .ghClient .SearchPullRequests (ctx , query )
140+ if err != nil {
141+ return nil , fmt .Errorf ("failed to search pull requests: %w" , err )
142+ }
143+ return prs , nil
144+ }
145+
146+ func (r * tagAndReleaseRunner ) processPullRequest (_ context.Context , p * github.PullRequest ) error {
147+ slog .Info ("processing pull request" , "pr" , p .GetNumber ())
148+ // hack to make CI happy until we impl
149+ // TODO(https://github.com/googleapis/librarian/issues/1009)
150+ if p .GetNumber () != 0 {
151+ return fmt .Errorf ("skipping pull request %d" , p .GetNumber ())
152+ }
70153 return nil
71154}
72155
0 commit comments