github.com/google/go-github/v69@v69.2.0/github/actions_artifacts.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 "fmt" 11 "net/http" 12 "net/url" 13 ) 14 15 // ArtifactWorkflowRun represents a GitHub artifact's workflow run. 16 // 17 // GitHub API docs: https://docs.github.com/rest/actions/artifacts 18 type ArtifactWorkflowRun struct { 19 ID *int64 `json:"id,omitempty"` 20 RepositoryID *int64 `json:"repository_id,omitempty"` 21 HeadRepositoryID *int64 `json:"head_repository_id,omitempty"` 22 HeadBranch *string `json:"head_branch,omitempty"` 23 HeadSHA *string `json:"head_sha,omitempty"` 24 } 25 26 // Artifact represents a GitHub artifact. Artifacts allow sharing 27 // data between jobs in a workflow and provide storage for data 28 // once a workflow is complete. 29 // 30 // GitHub API docs: https://docs.github.com/rest/actions/artifacts 31 type Artifact struct { 32 ID *int64 `json:"id,omitempty"` 33 NodeID *string `json:"node_id,omitempty"` 34 Name *string `json:"name,omitempty"` 35 SizeInBytes *int64 `json:"size_in_bytes,omitempty"` 36 URL *string `json:"url,omitempty"` 37 ArchiveDownloadURL *string `json:"archive_download_url,omitempty"` 38 Expired *bool `json:"expired,omitempty"` 39 CreatedAt *Timestamp `json:"created_at,omitempty"` 40 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 41 ExpiresAt *Timestamp `json:"expires_at,omitempty"` 42 WorkflowRun *ArtifactWorkflowRun `json:"workflow_run,omitempty"` 43 } 44 45 // ArtifactList represents a list of GitHub artifacts. 46 // 47 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#artifacts 48 type ArtifactList struct { 49 TotalCount *int64 `json:"total_count,omitempty"` 50 Artifacts []*Artifact `json:"artifacts,omitempty"` 51 } 52 53 // ListArtifactsOptions specifies the optional parameters to the 54 // ActionsService.ListArtifacts method. 55 type ListArtifactsOptions struct { 56 // Name represents the name field of an artifact. 57 // When specified, only artifacts with this name will be returned. 58 Name *string `url:"name,omitempty"` 59 60 ListOptions 61 } 62 63 // ListArtifacts lists all artifacts that belong to a repository. 64 // 65 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#list-artifacts-for-a-repository 66 // 67 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts 68 func (s *ActionsService) ListArtifacts(ctx context.Context, owner, repo string, opts *ListArtifactsOptions) (*ArtifactList, *Response, error) { 69 u := fmt.Sprintf("repos/%v/%v/actions/artifacts", owner, repo) 70 u, err := addOptions(u, opts) 71 if err != nil { 72 return nil, nil, err 73 } 74 75 req, err := s.client.NewRequest("GET", u, nil) 76 if err != nil { 77 return nil, nil, err 78 } 79 80 artifactList := new(ArtifactList) 81 resp, err := s.client.Do(ctx, req, artifactList) 82 if err != nil { 83 return nil, resp, err 84 } 85 86 return artifactList, resp, nil 87 } 88 89 // ListWorkflowRunArtifacts lists all artifacts that belong to a workflow run. 90 // 91 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#list-workflow-run-artifacts 92 // 93 //meta:operation GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts 94 func (s *ActionsService) ListWorkflowRunArtifacts(ctx context.Context, owner, repo string, runID int64, opts *ListOptions) (*ArtifactList, *Response, error) { 95 u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/artifacts", owner, repo, runID) 96 u, err := addOptions(u, opts) 97 if err != nil { 98 return nil, nil, err 99 } 100 101 req, err := s.client.NewRequest("GET", u, nil) 102 if err != nil { 103 return nil, nil, err 104 } 105 106 artifactList := new(ArtifactList) 107 resp, err := s.client.Do(ctx, req, artifactList) 108 if err != nil { 109 return nil, resp, err 110 } 111 112 return artifactList, resp, nil 113 } 114 115 // GetArtifact gets a specific artifact for a workflow run. 116 // 117 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#get-an-artifact 118 // 119 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id} 120 func (s *ActionsService) GetArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Artifact, *Response, error) { 121 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) 122 123 req, err := s.client.NewRequest("GET", u, nil) 124 if err != nil { 125 return nil, nil, err 126 } 127 128 artifact := new(Artifact) 129 resp, err := s.client.Do(ctx, req, artifact) 130 if err != nil { 131 return nil, resp, err 132 } 133 134 return artifact, resp, nil 135 } 136 137 // DownloadArtifact gets a redirect URL to download an archive for a repository. 138 // 139 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#download-an-artifact 140 // 141 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format} 142 func (s *ActionsService) DownloadArtifact(ctx context.Context, owner, repo string, artifactID int64, maxRedirects int) (*url.URL, *Response, error) { 143 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v/zip", owner, repo, artifactID) 144 145 if s.client.RateLimitRedirectionalEndpoints { 146 return s.downloadArtifactWithRateLimit(ctx, u, maxRedirects) 147 } 148 149 return s.downloadArtifactWithoutRateLimit(ctx, u, maxRedirects) 150 } 151 152 func (s *ActionsService) downloadArtifactWithoutRateLimit(ctx context.Context, u string, maxRedirects int) (*url.URL, *Response, error) { 153 resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, maxRedirects) 154 if err != nil { 155 return nil, nil, err 156 } 157 defer resp.Body.Close() 158 159 if resp.StatusCode != http.StatusFound { 160 return nil, newResponse(resp), fmt.Errorf("unexpected status code: %v", resp.Status) 161 } 162 163 parsedURL, err := url.Parse(resp.Header.Get("Location")) 164 if err != nil { 165 return nil, newResponse(resp), err 166 } 167 168 return parsedURL, newResponse(resp), nil 169 } 170 171 func (s *ActionsService) downloadArtifactWithRateLimit(ctx context.Context, u string, maxRedirects int) (*url.URL, *Response, error) { 172 req, err := s.client.NewRequest("GET", u, nil) 173 if err != nil { 174 return nil, nil, err 175 } 176 177 url, resp, err := s.client.bareDoUntilFound(ctx, req, maxRedirects) 178 if err != nil { 179 return nil, resp, err 180 } 181 defer resp.Body.Close() 182 183 // If we didn't receive a valid Location in a 302 response 184 if url == nil { 185 return nil, resp, fmt.Errorf("unexpected status code: %v", resp.Status) 186 } 187 188 return url, resp, nil 189 } 190 191 // DeleteArtifact deletes a workflow run artifact. 192 // 193 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#delete-an-artifact 194 // 195 //meta:operation DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id} 196 func (s *ActionsService) DeleteArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Response, error) { 197 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) 198 199 req, err := s.client.NewRequest("DELETE", u, nil) 200 if err != nil { 201 return nil, err 202 } 203 204 return s.client.Do(ctx, req, nil) 205 }