github.com/google/go-github/v69@v69.2.0/github/actions_workflow_runs_test.go (about) 1 // Copyright 2020 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "net/http" 13 "net/url" 14 "strings" 15 "testing" 16 "time" 17 18 "github.com/google/go-cmp/cmp" 19 ) 20 21 func TestActionsService_ListWorkflowRunsByID(t *testing.T) { 22 t.Parallel() 23 client, mux, _ := setup(t) 24 25 mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) { 26 testMethod(t, r, "GET") 27 testFormValues(t, r, values{"per_page": "2", "page": "2"}) 28 fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`) 29 }) 30 31 opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}} 32 ctx := context.Background() 33 runs, _, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts) 34 if err != nil { 35 t.Errorf("Actions.ListWorkFlowRunsByID returned error: %v", err) 36 } 37 38 want := &WorkflowRuns{ 39 TotalCount: Ptr(4), 40 WorkflowRuns: []*WorkflowRun{ 41 {ID: Ptr(int64(399444496)), RunNumber: Ptr(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}}, 42 {ID: Ptr(int64(399444497)), RunNumber: Ptr(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}}, 43 }, 44 } 45 if !cmp.Equal(runs, want) { 46 t.Errorf("Actions.ListWorkflowRunsByID returned %+v, want %+v", runs, want) 47 } 48 49 const methodName = "ListWorkflowRunsByID" 50 testBadOptions(t, methodName, func() (err error) { 51 _, _, err = client.Actions.ListWorkflowRunsByID(ctx, "\n", "\n", 29679449, opts) 52 return err 53 }) 54 55 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 56 got, resp, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts) 57 if got != nil { 58 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 59 } 60 return resp, err 61 }) 62 } 63 64 func TestActionsService_ListWorkflowRunsFileName(t *testing.T) { 65 t.Parallel() 66 client, mux, _ := setup(t) 67 68 mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) { 69 testMethod(t, r, "GET") 70 testFormValues(t, r, values{"per_page": "2", "page": "2"}) 71 fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`) 72 }) 73 74 opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}} 75 ctx := context.Background() 76 runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts) 77 if err != nil { 78 t.Errorf("Actions.ListWorkFlowRunsByFileName returned error: %v", err) 79 } 80 81 want := &WorkflowRuns{ 82 TotalCount: Ptr(4), 83 WorkflowRuns: []*WorkflowRun{ 84 {ID: Ptr(int64(399444496)), RunNumber: Ptr(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}}, 85 {ID: Ptr(int64(399444497)), RunNumber: Ptr(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}}, 86 }, 87 } 88 if !cmp.Equal(runs, want) { 89 t.Errorf("Actions.ListWorkflowRunsByFileName returned %+v, want %+v", runs, want) 90 } 91 92 const methodName = "ListWorkflowRunsByFileName" 93 testBadOptions(t, methodName, func() (err error) { 94 _, _, err = client.Actions.ListWorkflowRunsByFileName(ctx, "\n", "\n", "29679449", opts) 95 return err 96 }) 97 98 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 99 got, resp, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts) 100 if got != nil { 101 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 102 } 103 return resp, err 104 }) 105 } 106 107 func TestActionsService_GetWorkflowRunByID(t *testing.T) { 108 t.Parallel() 109 client, mux, _ := setup(t) 110 111 mux.HandleFunc("/repos/o/r/actions/runs/29679449", func(w http.ResponseWriter, r *http.Request) { 112 testMethod(t, r, "GET") 113 fmt.Fprint(w, `{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}}`) 114 }) 115 116 ctx := context.Background() 117 runs, _, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449) 118 if err != nil { 119 t.Errorf("Actions.GetWorkflowRunByID returned error: %v", err) 120 } 121 122 want := &WorkflowRun{ 123 ID: Ptr(int64(399444496)), 124 RunNumber: Ptr(296), 125 CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, 126 UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}, 127 } 128 129 if !cmp.Equal(runs, want) { 130 t.Errorf("Actions.GetWorkflowRunByID returned %+v, want %+v", runs, want) 131 } 132 133 const methodName = "GetWorkflowRunByID" 134 testBadOptions(t, methodName, func() (err error) { 135 _, _, err = client.Actions.GetWorkflowRunByID(ctx, "\n", "\n", 29679449) 136 return err 137 }) 138 139 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 140 got, resp, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449) 141 if got != nil { 142 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 143 } 144 return resp, err 145 }) 146 } 147 148 func TestActionsService_GetWorkflowRunAttempt(t *testing.T) { 149 t.Parallel() 150 client, mux, _ := setup(t) 151 152 mux.HandleFunc("/repos/o/r/actions/runs/29679449/attempts/3", func(w http.ResponseWriter, r *http.Request) { 153 testMethod(t, r, "GET") 154 testFormValues(t, r, values{"exclude_pull_requests": "true"}) 155 fmt.Fprint(w, `{"id":399444496,"run_number":296,"run_attempt":3,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}}`) 156 }) 157 158 opts := &WorkflowRunAttemptOptions{ExcludePullRequests: Ptr(true)} 159 ctx := context.Background() 160 runs, _, err := client.Actions.GetWorkflowRunAttempt(ctx, "o", "r", 29679449, 3, opts) 161 if err != nil { 162 t.Errorf("Actions.GetWorkflowRunAttempt returned error: %v", err) 163 } 164 165 want := &WorkflowRun{ 166 ID: Ptr(int64(399444496)), 167 RunNumber: Ptr(296), 168 RunAttempt: Ptr(3), 169 CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, 170 UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}, 171 } 172 173 if !cmp.Equal(runs, want) { 174 t.Errorf("Actions.GetWorkflowRunAttempt returned %+v, want %+v", runs, want) 175 } 176 177 const methodName = "GetWorkflowRunAttempt" 178 testBadOptions(t, methodName, func() (err error) { 179 _, _, err = client.Actions.GetWorkflowRunAttempt(ctx, "\n", "\n", 29679449, 3, opts) 180 return err 181 }) 182 183 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 184 got, resp, err := client.Actions.GetWorkflowRunAttempt(ctx, "o", "r", 29679449, 3, opts) 185 if got != nil { 186 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 187 } 188 return resp, err 189 }) 190 } 191 192 func TestActionsService_GetWorkflowRunAttemptLogs(t *testing.T) { 193 t.Parallel() 194 tcs := []struct { 195 name string 196 respectRateLimits bool 197 }{ 198 { 199 name: "withoutRateLimits", 200 respectRateLimits: false, 201 }, 202 { 203 name: "withRateLimits", 204 respectRateLimits: true, 205 }, 206 } 207 208 for _, tc := range tcs { 209 tc := tc 210 t.Run(tc.name, func(t *testing.T) { 211 t.Parallel() 212 client, mux, _ := setup(t) 213 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 214 215 mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) { 216 testMethod(t, r, "GET") 217 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 218 }) 219 220 ctx := context.Background() 221 url, resp, err := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 1) 222 if err != nil { 223 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned error: %v", err) 224 } 225 if resp.StatusCode != http.StatusFound { 226 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound) 227 } 228 want := "http://github.com/a" 229 if url.String() != want { 230 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned %+v, want %+v", url.String(), want) 231 } 232 233 const methodName = "GetWorkflowRunAttemptLogs" 234 testBadOptions(t, methodName, func() (err error) { 235 _, _, err = client.Actions.GetWorkflowRunAttemptLogs(ctx, "\n", "\n", 399444496, 2, 1) 236 return err 237 }) 238 }) 239 } 240 } 241 242 func TestActionsService_GetWorkflowRunAttemptLogs_StatusMovedPermanently_dontFollowRedirects(t *testing.T) { 243 t.Parallel() 244 tcs := []struct { 245 name string 246 respectRateLimits bool 247 }{ 248 { 249 name: "withoutRateLimits", 250 respectRateLimits: false, 251 }, 252 { 253 name: "withRateLimits", 254 respectRateLimits: true, 255 }, 256 } 257 258 for _, tc := range tcs { 259 tc := tc 260 t.Run(tc.name, func(t *testing.T) { 261 t.Parallel() 262 client, mux, _ := setup(t) 263 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 264 265 mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) { 266 testMethod(t, r, "GET") 267 http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently) 268 }) 269 270 ctx := context.Background() 271 _, resp, _ := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 0) 272 if resp.StatusCode != http.StatusMovedPermanently { 273 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently) 274 } 275 }) 276 } 277 } 278 279 func TestActionsService_GetWorkflowRunAttemptLogs_StatusMovedPermanently_followRedirects(t *testing.T) { 280 t.Parallel() 281 tcs := []struct { 282 name string 283 respectRateLimits bool 284 }{ 285 { 286 name: "withoutRateLimits", 287 respectRateLimits: false, 288 }, 289 { 290 name: "withRateLimits", 291 respectRateLimits: true, 292 }, 293 } 294 295 for _, tc := range tcs { 296 tc := tc 297 t.Run(tc.name, func(t *testing.T) { 298 t.Parallel() 299 client, mux, serverURL := setup(t) 300 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 301 302 // Mock a redirect link, which leads to an archive link 303 mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) { 304 testMethod(t, r, "GET") 305 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 306 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 307 }) 308 309 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 310 testMethod(t, r, "GET") 311 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 312 }) 313 314 ctx := context.Background() 315 url, resp, err := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 1) 316 if err != nil { 317 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned error: %v", err) 318 } 319 320 if resp.StatusCode != http.StatusFound { 321 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound) 322 } 323 324 want := "http://github.com/a" 325 if url.String() != want { 326 t.Errorf("Actions.GetWorkflowRunAttemptLogs returned %+v, want %+v", url.String(), want) 327 } 328 329 const methodName = "GetWorkflowRunAttemptLogs" 330 testBadOptions(t, methodName, func() (err error) { 331 _, _, err = client.Actions.GetWorkflowRunAttemptLogs(ctx, "\n", "\n", 399444496, 2, 1) 332 return err 333 }) 334 }) 335 } 336 } 337 338 func TestActionsService_GetWorkflowRunAttemptLogs_unexpectedCode(t *testing.T) { 339 t.Parallel() 340 tcs := []struct { 341 name string 342 respectRateLimits bool 343 }{ 344 { 345 name: "withoutRateLimits", 346 respectRateLimits: false, 347 }, 348 { 349 name: "withRateLimits", 350 respectRateLimits: true, 351 }, 352 } 353 354 for _, tc := range tcs { 355 tc := tc 356 t.Run(tc.name, func(t *testing.T) { 357 t.Parallel() 358 client, mux, serverURL := setup(t) 359 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 360 361 // Mock a redirect link, which leads to an archive link 362 mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) { 363 testMethod(t, r, "GET") 364 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 365 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 366 }) 367 368 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 369 testMethod(t, r, "GET") 370 w.WriteHeader(http.StatusNoContent) 371 }) 372 373 ctx := context.Background() 374 url, resp, err := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 1) 375 if err == nil { 376 t.Fatalf("Actions.GetWorkflowRunAttemptLogs should return error on unexpected code") 377 } 378 if !strings.Contains(err.Error(), "unexpected status code") { 379 t.Error("Actions.GetWorkflowRunAttemptLogs should return unexpected status code") 380 } 381 if got, want := resp.Response.StatusCode, http.StatusNoContent; got != want { 382 t.Errorf("Actions.GetWorkflowRunAttemptLogs return status %d, want %d", got, want) 383 } 384 if url != nil { 385 t.Errorf("Actions.GetWorkflowRunAttemptLogs return %+v, want nil", url) 386 } 387 }) 388 } 389 } 390 391 func TestActionsService_RerunWorkflowRunByID(t *testing.T) { 392 t.Parallel() 393 client, mux, _ := setup(t) 394 395 mux.HandleFunc("/repos/o/r/actions/runs/3434/rerun", func(w http.ResponseWriter, r *http.Request) { 396 testMethod(t, r, "POST") 397 w.WriteHeader(http.StatusCreated) 398 }) 399 400 ctx := context.Background() 401 resp, err := client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434) 402 if err != nil { 403 t.Errorf("Actions.RerunWorkflowByID returned error: %v", err) 404 } 405 if resp.StatusCode != http.StatusCreated { 406 t.Errorf("Actions.RerunWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated) 407 } 408 409 const methodName = "RerunWorkflowByID" 410 testBadOptions(t, methodName, func() (err error) { 411 _, err = client.Actions.RerunWorkflowByID(ctx, "\n", "\n", 3434) 412 return err 413 }) 414 415 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 416 return client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434) 417 }) 418 } 419 420 func TestActionsService_RerunFailedJobsByID(t *testing.T) { 421 t.Parallel() 422 client, mux, _ := setup(t) 423 424 mux.HandleFunc("/repos/o/r/actions/runs/3434/rerun-failed-jobs", func(w http.ResponseWriter, r *http.Request) { 425 testMethod(t, r, "POST") 426 w.WriteHeader(http.StatusCreated) 427 }) 428 429 ctx := context.Background() 430 resp, err := client.Actions.RerunFailedJobsByID(ctx, "o", "r", 3434) 431 if err != nil { 432 t.Errorf("Actions.RerunFailedJobsByID returned error: %v", err) 433 } 434 if resp.StatusCode != http.StatusCreated { 435 t.Errorf("Actions.RerunFailedJobsByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated) 436 } 437 438 const methodName = "RerunFailedJobsByID" 439 testBadOptions(t, methodName, func() (err error) { 440 _, err = client.Actions.RerunFailedJobsByID(ctx, "\n", "\n", 3434) 441 return err 442 }) 443 444 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 445 return client.Actions.RerunFailedJobsByID(ctx, "o", "r", 3434) 446 }) 447 } 448 449 func TestActionsService_RerunJobByID(t *testing.T) { 450 t.Parallel() 451 client, mux, _ := setup(t) 452 453 mux.HandleFunc("/repos/o/r/actions/jobs/3434/rerun", func(w http.ResponseWriter, r *http.Request) { 454 testMethod(t, r, "POST") 455 w.WriteHeader(http.StatusCreated) 456 }) 457 458 ctx := context.Background() 459 resp, err := client.Actions.RerunJobByID(ctx, "o", "r", 3434) 460 if err != nil { 461 t.Errorf("Actions.RerunJobByID returned error: %v", err) 462 } 463 if resp.StatusCode != http.StatusCreated { 464 t.Errorf("Actions.RerunJobByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated) 465 } 466 467 const methodName = "RerunJobByID" 468 testBadOptions(t, methodName, func() (err error) { 469 _, err = client.Actions.RerunJobByID(ctx, "\n", "\n", 3434) 470 return err 471 }) 472 473 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 474 return client.Actions.RerunJobByID(ctx, "o", "r", 3434) 475 }) 476 } 477 478 func TestActionsService_CancelWorkflowRunByID(t *testing.T) { 479 t.Parallel() 480 client, mux, _ := setup(t) 481 482 mux.HandleFunc("/repos/o/r/actions/runs/3434/cancel", func(w http.ResponseWriter, r *http.Request) { 483 testMethod(t, r, "POST") 484 w.WriteHeader(http.StatusAccepted) 485 }) 486 487 ctx := context.Background() 488 resp, err := client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434) 489 if _, ok := err.(*AcceptedError); !ok { 490 t.Errorf("Actions.CancelWorkflowRunByID returned error: %v (want AcceptedError)", err) 491 } 492 if resp.StatusCode != http.StatusAccepted { 493 t.Errorf("Actions.CancelWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusAccepted) 494 } 495 496 const methodName = "CancelWorkflowRunByID" 497 testBadOptions(t, methodName, func() (err error) { 498 _, err = client.Actions.CancelWorkflowRunByID(ctx, "\n", "\n", 3434) 499 return err 500 }) 501 502 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 503 return client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434) 504 }) 505 } 506 507 func TestActionsService_GetWorkflowRunLogs(t *testing.T) { 508 t.Parallel() 509 tcs := []struct { 510 name string 511 respectRateLimits bool 512 }{ 513 { 514 name: "withoutRateLimits", 515 respectRateLimits: false, 516 }, 517 { 518 name: "withRateLimits", 519 respectRateLimits: true, 520 }, 521 } 522 523 for _, tc := range tcs { 524 tc := tc 525 t.Run(tc.name, func(t *testing.T) { 526 t.Parallel() 527 client, mux, _ := setup(t) 528 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 529 530 mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) { 531 testMethod(t, r, "GET") 532 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 533 }) 534 535 ctx := context.Background() 536 url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 1) 537 if err != nil { 538 t.Errorf("Actions.GetWorkflowRunLogs returned error: %v", err) 539 } 540 if resp.StatusCode != http.StatusFound { 541 t.Errorf("Actions.GetWorkflowRunLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound) 542 } 543 want := "http://github.com/a" 544 if url.String() != want { 545 t.Errorf("Actions.GetWorkflowRunLogs returned %+v, want %+v", url.String(), want) 546 } 547 548 const methodName = "GetWorkflowRunLogs" 549 testBadOptions(t, methodName, func() (err error) { 550 _, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, 1) 551 return err 552 }) 553 }) 554 } 555 } 556 557 func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_dontFollowRedirects(t *testing.T) { 558 t.Parallel() 559 tcs := []struct { 560 name string 561 respectRateLimits bool 562 }{ 563 { 564 name: "withoutRateLimits", 565 respectRateLimits: false, 566 }, 567 { 568 name: "withRateLimits", 569 respectRateLimits: true, 570 }, 571 } 572 573 for _, tc := range tcs { 574 tc := tc 575 t.Run(tc.name, func(t *testing.T) { 576 t.Parallel() 577 client, mux, _ := setup(t) 578 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 579 580 mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) { 581 testMethod(t, r, "GET") 582 http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently) 583 }) 584 585 ctx := context.Background() 586 _, resp, _ := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 0) 587 if resp.StatusCode != http.StatusMovedPermanently { 588 t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently) 589 } 590 }) 591 } 592 } 593 594 func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_followRedirects(t *testing.T) { 595 t.Parallel() 596 tcs := []struct { 597 name string 598 respectRateLimits bool 599 }{ 600 { 601 name: "withoutRateLimits", 602 respectRateLimits: false, 603 }, 604 { 605 name: "withRateLimits", 606 respectRateLimits: true, 607 }, 608 } 609 610 for _, tc := range tcs { 611 tc := tc 612 t.Run(tc.name, func(t *testing.T) { 613 t.Parallel() 614 client, mux, serverURL := setup(t) 615 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 616 617 // Mock a redirect link, which leads to an archive link 618 mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) { 619 testMethod(t, r, "GET") 620 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 621 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 622 }) 623 624 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 625 testMethod(t, r, "GET") 626 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 627 }) 628 629 ctx := context.Background() 630 url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 1) 631 if err != nil { 632 t.Errorf("Actions.GetWorkflowJobLogs returned error: %v", err) 633 } 634 635 if resp.StatusCode != http.StatusFound { 636 t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound) 637 } 638 639 want := "http://github.com/a" 640 if url.String() != want { 641 t.Errorf("Actions.GetWorkflowJobLogs returned %+v, want %+v", url.String(), want) 642 } 643 644 const methodName = "GetWorkflowRunLogs" 645 testBadOptions(t, methodName, func() (err error) { 646 _, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, 1) 647 return err 648 }) 649 }) 650 } 651 } 652 653 func TestActionsService_GetWorkflowRunLogs_unexpectedCode(t *testing.T) { 654 t.Parallel() 655 tcs := []struct { 656 name string 657 respectRateLimits bool 658 }{ 659 { 660 name: "withoutRateLimits", 661 respectRateLimits: false, 662 }, 663 { 664 name: "withRateLimits", 665 respectRateLimits: true, 666 }, 667 } 668 669 for _, tc := range tcs { 670 tc := tc 671 t.Run(tc.name, func(t *testing.T) { 672 t.Parallel() 673 client, mux, serverURL := setup(t) 674 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 675 676 // Mock a redirect link, which leads to an archive link 677 mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) { 678 testMethod(t, r, "GET") 679 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 680 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 681 }) 682 683 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 684 testMethod(t, r, "GET") 685 w.WriteHeader(http.StatusNoContent) 686 }) 687 688 ctx := context.Background() 689 url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 1) 690 if err == nil { 691 t.Fatalf("Actions.GetWorkflowRunLogs should return error on unexpected code") 692 } 693 if !strings.Contains(err.Error(), "unexpected status code") { 694 t.Error("Actions.GetWorkflowRunLogs should return unexpected status code") 695 } 696 if got, want := resp.Response.StatusCode, http.StatusNoContent; got != want { 697 t.Errorf("Actions.GetWorkflowRunLogs return status %d, want %d", got, want) 698 } 699 if url != nil { 700 t.Errorf("Actions.GetWorkflowRunLogs return %+v, want nil", url) 701 } 702 }) 703 } 704 } 705 706 func TestActionService_ListRepositoryWorkflowRuns(t *testing.T) { 707 t.Parallel() 708 client, mux, _ := setup(t) 709 710 mux.HandleFunc("/repos/o/r/actions/runs", func(w http.ResponseWriter, r *http.Request) { 711 testMethod(t, r, "GET") 712 testFormValues(t, r, values{"per_page": "2", "page": "2"}) 713 fmt.Fprint(w, `{"total_count":2, 714 "workflow_runs":[ 715 {"id":298499444,"run_number":301,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"}, 716 {"id":298499445,"run_number":302,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"}]}`) 717 }) 718 719 opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}} 720 ctx := context.Background() 721 runs, _, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts) 722 if err != nil { 723 t.Errorf("Actions.ListRepositoryWorkflowRuns returned error: %v", err) 724 } 725 726 expected := &WorkflowRuns{ 727 TotalCount: Ptr(2), 728 WorkflowRuns: []*WorkflowRun{ 729 {ID: Ptr(int64(298499444)), RunNumber: Ptr(301), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}}, 730 {ID: Ptr(int64(298499445)), RunNumber: Ptr(302), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}}, 731 }, 732 } 733 734 if !cmp.Equal(runs, expected) { 735 t.Errorf("Actions.ListRepositoryWorkflowRuns returned %+v, want %+v", runs, expected) 736 } 737 738 const methodName = "ListRepositoryWorkflowRuns" 739 testBadOptions(t, methodName, func() (err error) { 740 _, _, err = client.Actions.ListRepositoryWorkflowRuns(ctx, "\n", "\n", opts) 741 742 return err 743 }) 744 745 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 746 got, resp, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts) 747 748 if got != nil { 749 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 750 } 751 return resp, err 752 }) 753 } 754 755 func TestActionService_DeleteWorkflowRun(t *testing.T) { 756 t.Parallel() 757 client, mux, _ := setup(t) 758 759 mux.HandleFunc("/repos/o/r/actions/runs/399444496", func(w http.ResponseWriter, r *http.Request) { 760 testMethod(t, r, "DELETE") 761 762 w.WriteHeader(http.StatusNoContent) 763 }) 764 765 ctx := context.Background() 766 if _, err := client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496); err != nil { 767 t.Errorf("DeleteWorkflowRun returned error: %v", err) 768 } 769 770 const methodName = "DeleteWorkflowRun" 771 testBadOptions(t, methodName, func() (err error) { 772 _, err = client.Actions.DeleteWorkflowRun(ctx, "\n", "\n", 399444496) 773 return err 774 }) 775 776 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 777 return client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496) 778 }) 779 } 780 781 func TestActionService_DeleteWorkflowRunLogs(t *testing.T) { 782 t.Parallel() 783 client, mux, _ := setup(t) 784 785 mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) { 786 testMethod(t, r, "DELETE") 787 788 w.WriteHeader(http.StatusNoContent) 789 }) 790 791 ctx := context.Background() 792 if _, err := client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496); err != nil { 793 t.Errorf("DeleteWorkflowRunLogs returned error: %v", err) 794 } 795 796 const methodName = "DeleteWorkflowRunLogs" 797 testBadOptions(t, methodName, func() (err error) { 798 _, err = client.Actions.DeleteWorkflowRunLogs(ctx, "\n", "\n", 399444496) 799 return err 800 }) 801 802 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 803 return client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496) 804 }) 805 } 806 807 func TestPendingDeployment_Marshal(t *testing.T) { 808 t.Parallel() 809 testJSONMarshal(t, &PendingDeployment{}, "{}") 810 811 u := &PendingDeployment{ 812 Environment: &PendingDeploymentEnvironment{ 813 ID: Ptr(int64(1)), 814 NodeID: Ptr("nid"), 815 Name: Ptr("n"), 816 URL: Ptr("u"), 817 HTMLURL: Ptr("hu"), 818 }, 819 WaitTimer: Ptr(int64(100)), 820 WaitTimerStartedAt: &Timestamp{referenceTime}, 821 CurrentUserCanApprove: Ptr(false), 822 Reviewers: []*RequiredReviewer{ 823 { 824 Type: Ptr("User"), 825 Reviewer: &User{ 826 Login: Ptr("l"), 827 }, 828 }, 829 { 830 Type: Ptr("Team"), 831 Reviewer: &Team{ 832 Name: Ptr("n"), 833 }, 834 }, 835 }, 836 } 837 want := `{ 838 "environment": { 839 "id": 1, 840 "node_id": "nid", 841 "name": "n", 842 "url": "u", 843 "html_url": "hu" 844 }, 845 "wait_timer": 100, 846 "wait_timer_started_at": ` + referenceTimeStr + `, 847 "current_user_can_approve": false, 848 "reviewers": [ 849 { 850 "type": "User", 851 "reviewer": { 852 "login": "l" 853 } 854 }, 855 { 856 "type": "Team", 857 "reviewer": { 858 "name": "n" 859 } 860 } 861 ] 862 }` 863 testJSONMarshal(t, u, want) 864 } 865 866 func TestActionsService_ReviewCustomDeploymentProtectionRule(t *testing.T) { 867 t.Parallel() 868 client, mux, _ := setup(t) 869 870 mux.HandleFunc("/repos/o/r/actions/runs/9444496/deployment_protection_rule", func(w http.ResponseWriter, r *http.Request) { 871 testMethod(t, r, "POST") 872 873 w.WriteHeader(http.StatusNoContent) 874 }) 875 876 request := ReviewCustomDeploymentProtectionRuleRequest{ 877 EnvironmentName: "production", 878 State: "approved", 879 Comment: "Approve deployment", 880 } 881 882 ctx := context.Background() 883 if _, err := client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request); err != nil { 884 t.Errorf("ReviewCustomDeploymentProtectionRule returned error: %v", err) 885 } 886 887 const methodName = "ReviewCustomDeploymentProtectionRule" 888 testBadOptions(t, methodName, func() (err error) { 889 _, err = client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "\n", "\n", 9444496, &request) 890 return err 891 }) 892 893 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 894 return client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request) 895 }) 896 } 897 898 func TestReviewCustomDeploymentProtectionRuleRequest_Marshal(t *testing.T) { 899 t.Parallel() 900 testJSONMarshal(t, &ReviewCustomDeploymentProtectionRuleRequest{}, "{}") 901 902 r := &ReviewCustomDeploymentProtectionRuleRequest{ 903 EnvironmentName: "e", 904 State: "rejected", 905 Comment: "c", 906 } 907 want := `{ 908 "environment_name": "e", 909 "state": "rejected", 910 "comment": "c" 911 }` 912 testJSONMarshal(t, r, want) 913 } 914 915 func TestActionsService_GetWorkflowRunUsageByID(t *testing.T) { 916 t.Parallel() 917 client, mux, _ := setup(t) 918 919 mux.HandleFunc("/repos/o/r/actions/runs/29679449/timing", func(w http.ResponseWriter, r *http.Request) { 920 testMethod(t, r, "GET") 921 fmt.Fprint(w, `{"billable":{"UBUNTU":{"total_ms":180000,"jobs":1,"job_runs":[{"job_id":1,"duration_ms":60000}]},"MACOS":{"total_ms":240000,"jobs":2,"job_runs":[{"job_id":2,"duration_ms":30000},{"job_id":3,"duration_ms":10000}]},"WINDOWS":{"total_ms":300000,"jobs":2}},"run_duration_ms":500000}`) 922 }) 923 924 ctx := context.Background() 925 workflowRunUsage, _, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449) 926 if err != nil { 927 t.Errorf("Actions.GetWorkflowRunUsageByID returned error: %v", err) 928 } 929 930 want := &WorkflowRunUsage{ 931 Billable: &WorkflowRunBillMap{ 932 "UBUNTU": &WorkflowRunBill{ 933 TotalMS: Ptr(int64(180000)), 934 Jobs: Ptr(1), 935 JobRuns: []*WorkflowRunJobRun{ 936 { 937 JobID: Ptr(1), 938 DurationMS: Ptr(int64(60000)), 939 }, 940 }, 941 }, 942 "MACOS": &WorkflowRunBill{ 943 TotalMS: Ptr(int64(240000)), 944 Jobs: Ptr(2), 945 JobRuns: []*WorkflowRunJobRun{ 946 { 947 JobID: Ptr(2), 948 DurationMS: Ptr(int64(30000)), 949 }, 950 { 951 JobID: Ptr(3), 952 DurationMS: Ptr(int64(10000)), 953 }, 954 }, 955 }, 956 "WINDOWS": &WorkflowRunBill{ 957 TotalMS: Ptr(int64(300000)), 958 Jobs: Ptr(2), 959 }, 960 }, 961 RunDurationMS: Ptr(int64(500000)), 962 } 963 964 if !cmp.Equal(workflowRunUsage, want) { 965 t.Errorf("Actions.GetWorkflowRunUsageByID returned %+v, want %+v", workflowRunUsage, want) 966 } 967 968 const methodName = "GetWorkflowRunUsageByID" 969 testBadOptions(t, methodName, func() (err error) { 970 _, _, err = client.Actions.GetWorkflowRunUsageByID(ctx, "\n", "\n", 29679449) 971 return err 972 }) 973 974 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 975 got, resp, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449) 976 if got != nil { 977 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 978 } 979 return resp, err 980 }) 981 } 982 983 func TestWorkflowRun_Marshal(t *testing.T) { 984 t.Parallel() 985 testJSONMarshal(t, &WorkflowRun{}, "{}") 986 987 u := &WorkflowRun{ 988 ID: Ptr(int64(1)), 989 Name: Ptr("n"), 990 NodeID: Ptr("nid"), 991 HeadBranch: Ptr("hb"), 992 HeadSHA: Ptr("hs"), 993 Path: Ptr("p"), 994 RunNumber: Ptr(1), 995 RunAttempt: Ptr(1), 996 Event: Ptr("e"), 997 Status: Ptr("s"), 998 Conclusion: Ptr("c"), 999 WorkflowID: Ptr(int64(1)), 1000 URL: Ptr("u"), 1001 HTMLURL: Ptr("h"), 1002 PullRequests: []*PullRequest{ 1003 { 1004 URL: Ptr("u"), 1005 ID: Ptr(int64(1)), 1006 Number: Ptr(1), 1007 Head: &PullRequestBranch{ 1008 Ref: Ptr("r"), 1009 SHA: Ptr("s"), 1010 Repo: &Repository{ 1011 ID: Ptr(int64(1)), 1012 URL: Ptr("s"), 1013 Name: Ptr("n"), 1014 }, 1015 }, 1016 Base: &PullRequestBranch{ 1017 Ref: Ptr("r"), 1018 SHA: Ptr("s"), 1019 Repo: &Repository{ 1020 ID: Ptr(int64(1)), 1021 URL: Ptr("u"), 1022 Name: Ptr("n"), 1023 }, 1024 }, 1025 }, 1026 }, 1027 CreatedAt: &Timestamp{referenceTime}, 1028 UpdatedAt: &Timestamp{referenceTime}, 1029 RunStartedAt: &Timestamp{referenceTime}, 1030 JobsURL: Ptr("j"), 1031 LogsURL: Ptr("l"), 1032 CheckSuiteURL: Ptr("c"), 1033 ArtifactsURL: Ptr("a"), 1034 CancelURL: Ptr("c"), 1035 RerunURL: Ptr("r"), 1036 PreviousAttemptURL: Ptr("p"), 1037 HeadCommit: &HeadCommit{ 1038 Message: Ptr("m"), 1039 Author: &CommitAuthor{ 1040 Name: Ptr("n"), 1041 Email: Ptr("e"), 1042 Login: Ptr("l"), 1043 }, 1044 URL: Ptr("u"), 1045 Distinct: Ptr(false), 1046 SHA: Ptr("s"), 1047 ID: Ptr("i"), 1048 TreeID: Ptr("tid"), 1049 Timestamp: &Timestamp{referenceTime}, 1050 Committer: &CommitAuthor{ 1051 Name: Ptr("n"), 1052 Email: Ptr("e"), 1053 Login: Ptr("l"), 1054 }, 1055 }, 1056 WorkflowURL: Ptr("w"), 1057 Repository: &Repository{ 1058 ID: Ptr(int64(1)), 1059 URL: Ptr("u"), 1060 Name: Ptr("n"), 1061 }, 1062 HeadRepository: &Repository{ 1063 ID: Ptr(int64(1)), 1064 URL: Ptr("u"), 1065 Name: Ptr("n"), 1066 }, 1067 Actor: &User{ 1068 Login: Ptr("l"), 1069 ID: Ptr(int64(1)), 1070 AvatarURL: Ptr("a"), 1071 GravatarID: Ptr("g"), 1072 Name: Ptr("n"), 1073 Company: Ptr("c"), 1074 Blog: Ptr("b"), 1075 Location: Ptr("l"), 1076 Email: Ptr("e"), 1077 Hireable: Ptr(true), 1078 Bio: Ptr("b"), 1079 TwitterUsername: Ptr("t"), 1080 PublicRepos: Ptr(1), 1081 Followers: Ptr(1), 1082 Following: Ptr(1), 1083 CreatedAt: &Timestamp{referenceTime}, 1084 SuspendedAt: &Timestamp{referenceTime}, 1085 URL: Ptr("u"), 1086 }, 1087 TriggeringActor: &User{ 1088 Login: Ptr("l2"), 1089 ID: Ptr(int64(2)), 1090 AvatarURL: Ptr("a2"), 1091 GravatarID: Ptr("g2"), 1092 Name: Ptr("n2"), 1093 Company: Ptr("c2"), 1094 Blog: Ptr("b2"), 1095 Location: Ptr("l2"), 1096 Email: Ptr("e2"), 1097 Hireable: Ptr(false), 1098 Bio: Ptr("b2"), 1099 TwitterUsername: Ptr("t2"), 1100 PublicRepos: Ptr(2), 1101 Followers: Ptr(2), 1102 Following: Ptr(2), 1103 CreatedAt: &Timestamp{referenceTime}, 1104 SuspendedAt: &Timestamp{referenceTime}, 1105 URL: Ptr("u2"), 1106 }, 1107 ReferencedWorkflows: []*ReferencedWorkflow{ 1108 { 1109 Path: Ptr("rwfp"), 1110 SHA: Ptr("rwfsha"), 1111 Ref: Ptr("rwfref"), 1112 }, 1113 }, 1114 } 1115 1116 want := `{ 1117 "id": 1, 1118 "name": "n", 1119 "node_id": "nid", 1120 "head_branch": "hb", 1121 "head_sha": "hs", 1122 "path": "p", 1123 "run_number": 1, 1124 "run_attempt": 1, 1125 "event": "e", 1126 "status": "s", 1127 "conclusion": "c", 1128 "workflow_id": 1, 1129 "url": "u", 1130 "html_url": "h", 1131 "pull_requests": [ 1132 { 1133 "id":1, 1134 "number":1, 1135 "url":"u", 1136 "head":{ 1137 "ref":"r", 1138 "sha":"s", 1139 "repo": { 1140 "id":1, 1141 "name":"n", 1142 "url":"s" 1143 } 1144 }, 1145 "base": { 1146 "ref":"r", 1147 "sha":"s", 1148 "repo": { 1149 "id":1, 1150 "name":"n", 1151 "url":"u" 1152 } 1153 } 1154 } 1155 ], 1156 "created_at": ` + referenceTimeStr + `, 1157 "updated_at": ` + referenceTimeStr + `, 1158 "run_started_at": ` + referenceTimeStr + `, 1159 "jobs_url": "j", 1160 "logs_url": "l", 1161 "check_suite_url": "c", 1162 "artifacts_url": "a", 1163 "cancel_url": "c", 1164 "rerun_url": "r", 1165 "previous_attempt_url": "p", 1166 "head_commit": { 1167 "message": "m", 1168 "author": { 1169 "name": "n", 1170 "email": "e", 1171 "username": "l" 1172 }, 1173 "url": "u", 1174 "distinct": false, 1175 "sha": "s", 1176 "id": "i", 1177 "tree_id": "tid", 1178 "timestamp": ` + referenceTimeStr + `, 1179 "committer": { 1180 "name": "n", 1181 "email": "e", 1182 "username": "l" 1183 } 1184 }, 1185 "workflow_url": "w", 1186 "repository": { 1187 "id": 1, 1188 "url": "u", 1189 "name": "n" 1190 }, 1191 "head_repository": { 1192 "id": 1, 1193 "url": "u", 1194 "name": "n" 1195 }, 1196 "actor": { 1197 "login": "l", 1198 "id": 1, 1199 "avatar_url": "a", 1200 "gravatar_id": "g", 1201 "name": "n", 1202 "company": "c", 1203 "blog": "b", 1204 "location": "l", 1205 "email": "e", 1206 "hireable": true, 1207 "bio": "b", 1208 "twitter_username": "t", 1209 "public_repos": 1, 1210 "followers": 1, 1211 "following": 1, 1212 "created_at": ` + referenceTimeStr + `, 1213 "suspended_at": ` + referenceTimeStr + `, 1214 "url": "u" 1215 }, 1216 "triggering_actor": { 1217 "login": "l2", 1218 "id": 2, 1219 "avatar_url": "a2", 1220 "gravatar_id": "g2", 1221 "name": "n2", 1222 "company": "c2", 1223 "blog": "b2", 1224 "location": "l2", 1225 "email": "e2", 1226 "hireable": false, 1227 "bio": "b2", 1228 "twitter_username": "t2", 1229 "public_repos": 2, 1230 "followers": 2, 1231 "following": 2, 1232 "created_at": ` + referenceTimeStr + `, 1233 "suspended_at": ` + referenceTimeStr + `, 1234 "url": "u2" 1235 }, 1236 "referenced_workflows": [ 1237 { 1238 "path": "rwfp", 1239 "sha": "rwfsha", 1240 "ref": "rwfref" 1241 } 1242 ] 1243 }` 1244 1245 testJSONMarshal(t, u, want) 1246 } 1247 1248 func TestWorkflowRuns_Marshal(t *testing.T) { 1249 t.Parallel() 1250 testJSONMarshal(t, &WorkflowRuns{}, "{}") 1251 1252 u := &WorkflowRuns{ 1253 TotalCount: Ptr(1), 1254 WorkflowRuns: []*WorkflowRun{ 1255 { 1256 ID: Ptr(int64(1)), 1257 Name: Ptr("n"), 1258 NodeID: Ptr("nid"), 1259 HeadBranch: Ptr("hb"), 1260 HeadSHA: Ptr("hs"), 1261 RunNumber: Ptr(1), 1262 RunAttempt: Ptr(1), 1263 Event: Ptr("e"), 1264 Status: Ptr("s"), 1265 Conclusion: Ptr("c"), 1266 WorkflowID: Ptr(int64(1)), 1267 URL: Ptr("u"), 1268 HTMLURL: Ptr("h"), 1269 PullRequests: []*PullRequest{ 1270 { 1271 URL: Ptr("u"), 1272 ID: Ptr(int64(1)), 1273 Number: Ptr(1), 1274 Head: &PullRequestBranch{ 1275 Ref: Ptr("r"), 1276 SHA: Ptr("s"), 1277 Repo: &Repository{ 1278 ID: Ptr(int64(1)), 1279 URL: Ptr("s"), 1280 Name: Ptr("n"), 1281 }, 1282 }, 1283 Base: &PullRequestBranch{ 1284 Ref: Ptr("r"), 1285 SHA: Ptr("s"), 1286 Repo: &Repository{ 1287 ID: Ptr(int64(1)), 1288 URL: Ptr("u"), 1289 Name: Ptr("n"), 1290 }, 1291 }, 1292 }, 1293 }, 1294 CreatedAt: &Timestamp{referenceTime}, 1295 UpdatedAt: &Timestamp{referenceTime}, 1296 RunStartedAt: &Timestamp{referenceTime}, 1297 JobsURL: Ptr("j"), 1298 LogsURL: Ptr("l"), 1299 CheckSuiteURL: Ptr("c"), 1300 ArtifactsURL: Ptr("a"), 1301 CancelURL: Ptr("c"), 1302 RerunURL: Ptr("r"), 1303 PreviousAttemptURL: Ptr("p"), 1304 HeadCommit: &HeadCommit{ 1305 Message: Ptr("m"), 1306 Author: &CommitAuthor{ 1307 Name: Ptr("n"), 1308 Email: Ptr("e"), 1309 Login: Ptr("l"), 1310 }, 1311 URL: Ptr("u"), 1312 Distinct: Ptr(false), 1313 SHA: Ptr("s"), 1314 ID: Ptr("i"), 1315 TreeID: Ptr("tid"), 1316 Timestamp: &Timestamp{referenceTime}, 1317 Committer: &CommitAuthor{ 1318 Name: Ptr("n"), 1319 Email: Ptr("e"), 1320 Login: Ptr("l"), 1321 }, 1322 }, 1323 WorkflowURL: Ptr("w"), 1324 Repository: &Repository{ 1325 ID: Ptr(int64(1)), 1326 URL: Ptr("u"), 1327 Name: Ptr("n"), 1328 }, 1329 HeadRepository: &Repository{ 1330 ID: Ptr(int64(1)), 1331 URL: Ptr("u"), 1332 Name: Ptr("n"), 1333 }, 1334 Actor: &User{ 1335 Login: Ptr("l"), 1336 ID: Ptr(int64(1)), 1337 AvatarURL: Ptr("a"), 1338 GravatarID: Ptr("g"), 1339 Name: Ptr("n"), 1340 Company: Ptr("c"), 1341 Blog: Ptr("b"), 1342 Location: Ptr("l"), 1343 Email: Ptr("e"), 1344 Hireable: Ptr(true), 1345 Bio: Ptr("b"), 1346 TwitterUsername: Ptr("t"), 1347 PublicRepos: Ptr(1), 1348 Followers: Ptr(1), 1349 Following: Ptr(1), 1350 CreatedAt: &Timestamp{referenceTime}, 1351 SuspendedAt: &Timestamp{referenceTime}, 1352 URL: Ptr("u"), 1353 }, 1354 TriggeringActor: &User{ 1355 Login: Ptr("l2"), 1356 ID: Ptr(int64(2)), 1357 AvatarURL: Ptr("a2"), 1358 GravatarID: Ptr("g2"), 1359 Name: Ptr("n2"), 1360 Company: Ptr("c2"), 1361 Blog: Ptr("b2"), 1362 Location: Ptr("l2"), 1363 Email: Ptr("e2"), 1364 Hireable: Ptr(false), 1365 Bio: Ptr("b2"), 1366 TwitterUsername: Ptr("t2"), 1367 PublicRepos: Ptr(2), 1368 Followers: Ptr(2), 1369 Following: Ptr(2), 1370 CreatedAt: &Timestamp{referenceTime}, 1371 SuspendedAt: &Timestamp{referenceTime}, 1372 URL: Ptr("u2"), 1373 }, 1374 }, 1375 }, 1376 } 1377 1378 want := `{ 1379 "total_count": 1, 1380 "workflow_runs": [ 1381 { 1382 "id": 1, 1383 "name": "n", 1384 "node_id": "nid", 1385 "head_branch": "hb", 1386 "head_sha": "hs", 1387 "run_number": 1, 1388 "run_attempt": 1, 1389 "event": "e", 1390 "status": "s", 1391 "conclusion": "c", 1392 "workflow_id": 1, 1393 "url": "u", 1394 "html_url": "h", 1395 "pull_requests": [ 1396 { 1397 "id":1, 1398 "number":1, 1399 "url":"u", 1400 "head":{ 1401 "ref":"r", 1402 "sha":"s", 1403 "repo": { 1404 "id":1, 1405 "name":"n", 1406 "url":"s" 1407 } 1408 }, 1409 "base": { 1410 "ref":"r", 1411 "sha":"s", 1412 "repo": { 1413 "id":1, 1414 "name":"n", 1415 "url":"u" 1416 } 1417 } 1418 } 1419 ], 1420 "created_at": ` + referenceTimeStr + `, 1421 "updated_at": ` + referenceTimeStr + `, 1422 "run_started_at": ` + referenceTimeStr + `, 1423 "jobs_url": "j", 1424 "logs_url": "l", 1425 "check_suite_url": "c", 1426 "artifacts_url": "a", 1427 "cancel_url": "c", 1428 "rerun_url": "r", 1429 "previous_attempt_url": "p", 1430 "head_commit": { 1431 "message": "m", 1432 "author": { 1433 "name": "n", 1434 "email": "e", 1435 "username": "l" 1436 }, 1437 "url": "u", 1438 "distinct": false, 1439 "sha": "s", 1440 "id": "i", 1441 "tree_id": "tid", 1442 "timestamp": ` + referenceTimeStr + `, 1443 "committer": { 1444 "name": "n", 1445 "email": "e", 1446 "username": "l" 1447 } 1448 }, 1449 "workflow_url": "w", 1450 "repository": { 1451 "id": 1, 1452 "url": "u", 1453 "name": "n" 1454 }, 1455 "head_repository": { 1456 "id": 1, 1457 "url": "u", 1458 "name": "n" 1459 }, 1460 "actor": { 1461 "login": "l", 1462 "id": 1, 1463 "avatar_url": "a", 1464 "gravatar_id": "g", 1465 "name": "n", 1466 "company": "c", 1467 "blog": "b", 1468 "location": "l", 1469 "email": "e", 1470 "hireable": true, 1471 "bio": "b", 1472 "twitter_username": "t", 1473 "public_repos": 1, 1474 "followers": 1, 1475 "following": 1, 1476 "created_at": ` + referenceTimeStr + `, 1477 "suspended_at": ` + referenceTimeStr + `, 1478 "url": "u" 1479 }, 1480 "triggering_actor": { 1481 "login": "l2", 1482 "id": 2, 1483 "avatar_url": "a2", 1484 "gravatar_id": "g2", 1485 "name": "n2", 1486 "company": "c2", 1487 "blog": "b2", 1488 "location": "l2", 1489 "email": "e2", 1490 "hireable": false, 1491 "bio": "b2", 1492 "twitter_username": "t2", 1493 "public_repos": 2, 1494 "followers": 2, 1495 "following": 2, 1496 "created_at": ` + referenceTimeStr + `, 1497 "suspended_at": ` + referenceTimeStr + `, 1498 "url": "u2" 1499 } 1500 } 1501 ] 1502 }` 1503 1504 testJSONMarshal(t, u, want) 1505 } 1506 1507 func TestWorkflowRunBill_Marshal(t *testing.T) { 1508 t.Parallel() 1509 testJSONMarshal(t, &WorkflowRunBill{}, "{}") 1510 1511 u := &WorkflowRunBill{ 1512 TotalMS: Ptr(int64(1)), 1513 Jobs: Ptr(1), 1514 } 1515 1516 want := `{ 1517 "total_ms": 1, 1518 "jobs": 1 1519 }` 1520 1521 testJSONMarshal(t, u, want) 1522 } 1523 1524 func TestWorkflowRunBillMap_Marshal(t *testing.T) { 1525 t.Parallel() 1526 testJSONMarshal(t, &WorkflowRunBillMap{}, "{}") 1527 1528 u := &WorkflowRunBillMap{ 1529 "UBUNTU": &WorkflowRunBill{ 1530 TotalMS: Ptr(int64(1)), 1531 Jobs: Ptr(1), 1532 }, 1533 "MACOS": &WorkflowRunBill{ 1534 TotalMS: Ptr(int64(1)), 1535 Jobs: Ptr(1), 1536 }, 1537 "WINDOWS": &WorkflowRunBill{ 1538 TotalMS: Ptr(int64(1)), 1539 Jobs: Ptr(1), 1540 }, 1541 } 1542 1543 want := `{ 1544 "UBUNTU": { 1545 "total_ms": 1, 1546 "jobs": 1 1547 }, 1548 "MACOS": { 1549 "total_ms": 1, 1550 "jobs": 1 1551 }, 1552 "WINDOWS": { 1553 "total_ms": 1, 1554 "jobs": 1 1555 } 1556 }` 1557 1558 testJSONMarshal(t, u, want) 1559 } 1560 1561 func TestWorkflowRunUsage_Marshal(t *testing.T) { 1562 t.Parallel() 1563 testJSONMarshal(t, &WorkflowRunUsage{}, "{}") 1564 1565 u := &WorkflowRunUsage{ 1566 Billable: &WorkflowRunBillMap{ 1567 "UBUNTU": &WorkflowRunBill{ 1568 TotalMS: Ptr(int64(1)), 1569 Jobs: Ptr(1), 1570 }, 1571 "MACOS": &WorkflowRunBill{ 1572 TotalMS: Ptr(int64(1)), 1573 Jobs: Ptr(1), 1574 }, 1575 "WINDOWS": &WorkflowRunBill{ 1576 TotalMS: Ptr(int64(1)), 1577 Jobs: Ptr(1), 1578 }, 1579 }, 1580 RunDurationMS: Ptr(int64(1)), 1581 } 1582 1583 want := `{ 1584 "billable": { 1585 "UBUNTU": { 1586 "total_ms": 1, 1587 "jobs": 1 1588 }, 1589 "MACOS": { 1590 "total_ms": 1, 1591 "jobs": 1 1592 }, 1593 "WINDOWS": { 1594 "total_ms": 1, 1595 "jobs": 1 1596 } 1597 }, 1598 "run_duration_ms": 1 1599 }` 1600 1601 testJSONMarshal(t, u, want) 1602 } 1603 1604 func TestActionService_PendingDeployments(t *testing.T) { 1605 t.Parallel() 1606 client, mux, _ := setup(t) 1607 1608 input := &PendingDeploymentsRequest{EnvironmentIDs: []int64{3, 4}, State: "approved", Comment: ""} 1609 1610 mux.HandleFunc("/repos/o/r/actions/runs/399444496/pending_deployments", func(w http.ResponseWriter, r *http.Request) { 1611 v := new(PendingDeploymentsRequest) 1612 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1613 1614 testMethod(t, r, "POST") 1615 if !cmp.Equal(v, input) { 1616 t.Errorf("Request body = %+v, want %+v", v, input) 1617 } 1618 1619 fmt.Fprint(w, `[{"id":1}, {"id":2}]`) 1620 }) 1621 1622 ctx := context.Background() 1623 deployments, _, err := client.Actions.PendingDeployments(ctx, "o", "r", 399444496, input) 1624 if err != nil { 1625 t.Errorf("Actions.PendingDeployments returned error: %v", err) 1626 } 1627 1628 want := []*Deployment{{ID: Ptr(int64(1))}, {ID: Ptr(int64(2))}} 1629 if !cmp.Equal(deployments, want) { 1630 t.Errorf("Actions.PendingDeployments returned %+v, want %+v", deployments, want) 1631 } 1632 1633 const methodName = "PendingDeployments" 1634 testBadOptions(t, methodName, func() (err error) { 1635 _, _, err = client.Actions.PendingDeployments(ctx, "\n", "\n", 399444496, input) 1636 return err 1637 }) 1638 1639 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1640 got, resp, err := client.Actions.PendingDeployments(ctx, "o", "r", 399444496, input) 1641 if got != nil { 1642 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1643 } 1644 return resp, err 1645 }) 1646 } 1647 1648 func TestActionService_GetPendingDeployments(t *testing.T) { 1649 t.Parallel() 1650 client, mux, _ := setup(t) 1651 1652 mux.HandleFunc("/repos/o/r/actions/runs/399444496/pending_deployments", func(w http.ResponseWriter, r *http.Request) { 1653 testMethod(t, r, "GET") 1654 fmt.Fprint(w, `[ 1655 { 1656 "environment": { 1657 "id": 1, 1658 "node_id": "nid", 1659 "name": "n", 1660 "url": "u", 1661 "html_url": "hu" 1662 }, 1663 "wait_timer": 0, 1664 "wait_timer_started_at": `+referenceTimeStr+`, 1665 "current_user_can_approve": false, 1666 "reviewers": [] 1667 }, 1668 { 1669 "environment": { 1670 "id": 2, 1671 "node_id": "nid", 1672 "name": "n", 1673 "url": "u", 1674 "html_url": "hu" 1675 }, 1676 "wait_timer": 13, 1677 "wait_timer_started_at": `+referenceTimeStr+`, 1678 "current_user_can_approve": true, 1679 "reviewers": [ 1680 { 1681 "type": "User", 1682 "reviewer": { 1683 "login": "l" 1684 } 1685 }, 1686 { 1687 "type": "Team", 1688 "reviewer": { 1689 "name": "t", 1690 "slug": "s" 1691 } 1692 } 1693 ] 1694 } 1695 ]`) 1696 }) 1697 1698 ctx := context.Background() 1699 deployments, _, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496) 1700 if err != nil { 1701 t.Errorf("Actions.GetPendingDeployments returned error: %v", err) 1702 } 1703 1704 want := []*PendingDeployment{ 1705 { 1706 Environment: &PendingDeploymentEnvironment{ 1707 ID: Ptr(int64(1)), 1708 NodeID: Ptr("nid"), 1709 Name: Ptr("n"), 1710 URL: Ptr("u"), 1711 HTMLURL: Ptr("hu"), 1712 }, 1713 WaitTimer: Ptr(int64(0)), 1714 WaitTimerStartedAt: &Timestamp{referenceTime}, 1715 CurrentUserCanApprove: Ptr(false), 1716 Reviewers: []*RequiredReviewer{}, 1717 }, 1718 { 1719 Environment: &PendingDeploymentEnvironment{ 1720 ID: Ptr(int64(2)), 1721 NodeID: Ptr("nid"), 1722 Name: Ptr("n"), 1723 URL: Ptr("u"), 1724 HTMLURL: Ptr("hu"), 1725 }, 1726 WaitTimer: Ptr(int64(13)), 1727 WaitTimerStartedAt: &Timestamp{referenceTime}, 1728 CurrentUserCanApprove: Ptr(true), 1729 Reviewers: []*RequiredReviewer{ 1730 { 1731 Type: Ptr("User"), 1732 Reviewer: &User{ 1733 Login: Ptr("l"), 1734 }, 1735 }, 1736 { 1737 Type: Ptr("Team"), 1738 Reviewer: &Team{ 1739 Name: Ptr("t"), 1740 Slug: Ptr("s"), 1741 }, 1742 }, 1743 }, 1744 }, 1745 } 1746 1747 if !cmp.Equal(deployments, want) { 1748 t.Errorf("Actions.GetPendingDeployments returned %+v, want %+v", deployments, want) 1749 } 1750 1751 const methodName = "GetPendingDeployments" 1752 testBadOptions(t, methodName, func() (err error) { 1753 _, _, err = client.Actions.GetPendingDeployments(ctx, "\n", "\n", 399444496) 1754 return err 1755 }) 1756 1757 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1758 got, resp, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496) 1759 if got != nil { 1760 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1761 } 1762 return resp, err 1763 }) 1764 }