55 "fmt"
66 "io"
77 "net/http"
8+ "os"
9+ "path"
810 "time"
911
1012 "github.com/AlecAivazis/survey/v2"
@@ -39,7 +41,8 @@ type ViewOptions struct {
3941
4042 Prompt bool
4143
42- Now func () time.Time
44+ Now func () time.Time
45+ CreateFile func (string ) (io.Writer , error )
4346}
4447
4548func NewCmdView (f * cmdutil.Factory , runF func (* ViewOptions ) error ) * cobra.Command {
@@ -48,6 +51,9 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
4851 HttpClient : f .HttpClient ,
4952 Now : time .Now ,
5053 Browser : f .Browser ,
54+ CreateFile : func (fullPath string ) (io.Writer , error ) {
55+ return os .Create (fullPath )
56+ },
5157 }
5258 cmd := & cobra.Command {
5359 Use : "view [<run-id>]" ,
@@ -196,6 +202,10 @@ func runView(opts *ViewOptions) error {
196202 opts .IO .StartProgressIndicator ()
197203
198204 if opts .Log && selectedJob != nil {
205+ if selectedJob .Status != shared .Completed {
206+ return fmt .Errorf ("job %d is still in progress; logs will be available when it is complete" , selectedJob .ID )
207+ }
208+
199209 r , err := jobLog (httpClient , repo , selectedJob .ID )
200210 if err != nil {
201211 return err
@@ -219,7 +229,40 @@ func runView(opts *ViewOptions) error {
219229 return nil
220230 }
221231
222- // TODO support --log without selectedJob
232+ if opts .Log {
233+ if run .Status != shared .Completed {
234+ return fmt .Errorf ("run %d is still in progress; logs will be available when it is complete" , run .ID )
235+ }
236+
237+ filename := fmt .Sprintf ("gh-run-log-%d.zip" , run .ID )
238+ dir := os .TempDir ()
239+ fullpath := path .Join (dir , filename )
240+ f , err := opts .CreateFile (fullpath )
241+ if err != nil {
242+ return fmt .Errorf ("failed to open %s: %w" , fullpath , err )
243+ }
244+
245+ r , err := runLog (httpClient , repo , run .ID )
246+ if err != nil {
247+ return fmt .Errorf ("failed to get run log: %w" , err )
248+ }
249+
250+ if _ , err := io .Copy (f , r ); err != nil {
251+ return fmt .Errorf ("failed to download log: %w" , err )
252+ }
253+
254+ opts .IO .StopProgressIndicator ()
255+ if opts .IO .IsStdoutTTY () {
256+ cs := opts .IO .ColorScheme ()
257+ fmt .Fprintf (opts .IO .Out , "%s Downloaded logs to %s\n " , cs .SuccessIcon (), fullpath )
258+ }
259+
260+ if opts .ExitStatus && shared .IsFailureState (run .Conclusion ) {
261+ return cmdutil .SilentError
262+ }
263+
264+ return nil
265+ }
223266
224267 if selectedJob == nil && len (jobs ) == 0 {
225268 jobs , err = shared .GetJobs (client , repo , * run )
@@ -324,10 +367,8 @@ func getJob(client *api.Client, repo ghrepo.Interface, jobID string) (*shared.Jo
324367 return & result , nil
325368}
326369
327- func jobLog (httpClient * http.Client , repo ghrepo.Interface , jobID int ) (io.ReadCloser , error ) {
328- url := fmt .Sprintf ("%srepos/%s/actions/jobs/%d/logs" ,
329- ghinstance .RESTPrefix (repo .RepoHost ()), ghrepo .FullName (repo ), jobID )
330- req , err := http .NewRequest ("GET" , url , nil )
370+ func getLog (httpClient * http.Client , logURL string ) (io.ReadCloser , error ) {
371+ req , err := http .NewRequest ("GET" , logURL , nil )
331372 if err != nil {
332373 return nil , err
333374 }
@@ -338,14 +379,26 @@ func jobLog(httpClient *http.Client, repo ghrepo.Interface, jobID int) (io.ReadC
338379 }
339380
340381 if resp .StatusCode == 404 {
341- return nil , errors .New ("job not found" )
382+ return nil , errors .New ("log not found" )
342383 } else if resp .StatusCode != 200 {
343384 return nil , api .HandleHTTPError (resp )
344385 }
345386
346387 return resp .Body , nil
347388}
348389
390+ func runLog (httpClient * http.Client , repo ghrepo.Interface , runID int ) (io.ReadCloser , error ) {
391+ logURL := fmt .Sprintf ("%srepos/%s/actions/runs/%d/logs" ,
392+ ghinstance .RESTPrefix (repo .RepoHost ()), ghrepo .FullName (repo ), runID )
393+ return getLog (httpClient , logURL )
394+ }
395+
396+ func jobLog (httpClient * http.Client , repo ghrepo.Interface , jobID int ) (io.ReadCloser , error ) {
397+ logURL := fmt .Sprintf ("%srepos/%s/actions/jobs/%d/logs" ,
398+ ghinstance .RESTPrefix (repo .RepoHost ()), ghrepo .FullName (repo ), jobID )
399+ return getLog (httpClient , logURL )
400+ }
401+
349402func promptForJob (cs * iostreams.ColorScheme , jobs []shared.Job ) (* shared.Job , error ) {
350403 candidates := []string {"View all jobs in this run" }
351404 for _ , job := range jobs {
0 commit comments