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