-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgithub.go
More file actions
123 lines (102 loc) · 3.54 KB
/
github.go
File metadata and controls
123 lines (102 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
)
const defaultBaseURL = "https://api.github.com"
// WorkflowRun represents a GitHub Actions workflow run.
type WorkflowRun struct {
WorkflowID int `json:"workflow_id"`
Name string `json:"name"`
Status string `json:"status"`
Conclusion string `json:"conclusion"`
}
type workflowRunsResponse struct {
WorkflowRuns []WorkflowRun `json:"workflow_runs"`
}
// GitHubClient fetches workflow run data from the GitHub API.
type GitHubClient struct {
HTTPClient *http.Client
Token string
BaseURL string
}
// NewGitHubClient creates a new GitHubClient with default settings.
func NewGitHubClient(token string) *GitHubClient {
return &GitHubClient{
HTTPClient: http.DefaultClient,
Token: token,
BaseURL: defaultBaseURL,
}
}
// FetchWorkflowRun fetches the most recent run of the named workflow for a repository.
func (c *GitHubClient) FetchWorkflowRun(repo, workflow string) (*WorkflowRun, error) {
url := fmt.Sprintf("%s/repos/%s/actions/runs?per_page=50", c.BaseURL, repo)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Authorization", "token "+c.Token)
req.Header.Set("Accept", "application/vnd.github.v3+json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("fetching runs for %s: %w", repo, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("GitHub API returned %d for %s", resp.StatusCode, repo)
}
var result workflowRunsResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decoding response for %s: %w", repo, err)
}
// Return the most recent run matching the workflow name.
for _, run := range result.WorkflowRuns {
if run.Name == workflow {
return &run, nil
}
}
return nil, nil
}
// FetchWorkflowRuns fetches the most recent run of each distinct workflow for a repository.
func (c *GitHubClient) FetchWorkflowRuns(repo string) ([]WorkflowRun, error) {
url := fmt.Sprintf("%s/repos/%s/actions/runs?per_page=50", c.BaseURL, repo)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Authorization", "token "+c.Token)
req.Header.Set("Accept", "application/vnd.github.v3+json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("fetching runs for %s: %w", repo, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("GitHub API returned %d for %s", resp.StatusCode, repo)
}
var result workflowRunsResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decoding response for %s: %w", repo, err)
}
// Collect the most recent run per distinct workflow.
// The API returns runs in reverse chronological order, so the first
// occurrence of each workflow_id is the most recent. Deduplicate on
// workflow_id because the same workflow can appear under different
// names (e.g. "Build" vs ".github/workflows/build.yaml").
seen := make(map[int]bool)
var runs []WorkflowRun
for _, run := range result.WorkflowRuns {
if !seen[run.WorkflowID] {
seen[run.WorkflowID] = true
run.Name = cleanWorkflowName(run.Name)
runs = append(runs, run)
}
}
return runs, nil
}
// cleanWorkflowName strips the ".github/workflows/" prefix from a workflow name.
func cleanWorkflowName(name string) string {
return strings.TrimPrefix(name, ".github/workflows/")
}