github.com/google/go-github/v74@v74.0.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 // Digest is the SHA256 digest of the artifact. 43 // This field will only be populated on artifacts uploaded with upload-artifact v4 or newer. 44 // For older versions, this field will be null. 45 Digest *string `json:"digest,omitempty"` 46 WorkflowRun *ArtifactWorkflowRun `json:"workflow_run,omitempty"` 47 } 48 49 // ArtifactList represents a list of GitHub artifacts. 50 // 51 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#artifacts 52 type ArtifactList struct { 53 TotalCount *int64 `json:"total_count,omitempty"` 54 Artifacts []*Artifact `json:"artifacts,omitempty"` 55 } 56 57 // ListArtifactsOptions specifies the optional parameters to the 58 // ActionsService.ListArtifacts method. 59 type ListArtifactsOptions struct { 60 // Name represents the name field of an artifact. 61 // When specified, only artifacts with this name will be returned. 62 Name *string `url:"name,omitempty"` 63 64 ListOptions 65 } 66 67 // ListArtifacts lists all artifacts that belong to a repository. 68 // 69 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#list-artifacts-for-a-repository 70 // 71 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts 72 func (s *ActionsService) ListArtifacts(ctx context.Context, owner, repo string, opts *ListArtifactsOptions) (*ArtifactList, *Response, error) { 73 u := fmt.Sprintf("repos/%v/%v/actions/artifacts", owner, repo) 74 u, err := addOptions(u, opts) 75 if err != nil { 76 return nil, nil, err 77 } 78 79 req, err := s.client.NewRequest("GET", u, nil) 80 if err != nil { 81 return nil, nil, err 82 } 83 84 artifactList := new(ArtifactList) 85 resp, err := s.client.Do(ctx, req, artifactList) 86 if err != nil { 87 return nil, resp, err 88 } 89 90 return artifactList, resp, nil 91 } 92 93 // ListWorkflowRunArtifacts lists all artifacts that belong to a workflow run. 94 // 95 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#list-workflow-run-artifacts 96 // 97 //meta:operation GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts 98 func (s *ActionsService) ListWorkflowRunArtifacts(ctx context.Context, owner, repo string, runID int64, opts *ListOptions) (*ArtifactList, *Response, error) { 99 u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/artifacts", owner, repo, runID) 100 u, err := addOptions(u, opts) 101 if err != nil { 102 return nil, nil, err 103 } 104 105 req, err := s.client.NewRequest("GET", u, nil) 106 if err != nil { 107 return nil, nil, err 108 } 109 110 artifactList := new(ArtifactList) 111 resp, err := s.client.Do(ctx, req, artifactList) 112 if err != nil { 113 return nil, resp, err 114 } 115 116 return artifactList, resp, nil 117 } 118 119 // GetArtifact gets a specific artifact for a workflow run. 120 // 121 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#get-an-artifact 122 // 123 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id} 124 func (s *ActionsService) GetArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Artifact, *Response, error) { 125 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) 126 127 req, err := s.client.NewRequest("GET", u, nil) 128 if err != nil { 129 return nil, nil, err 130 } 131 132 artifact := new(Artifact) 133 resp, err := s.client.Do(ctx, req, artifact) 134 if err != nil { 135 return nil, resp, err 136 } 137 138 return artifact, resp, nil 139 } 140 141 // DownloadArtifact gets a redirect URL to download an archive for a repository. 142 // 143 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#download-an-artifact 144 // 145 //meta:operation GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format} 146 func (s *ActionsService) DownloadArtifact(ctx context.Context, owner, repo string, artifactID int64, maxRedirects int) (*url.URL, *Response, error) { 147 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v/zip", owner, repo, artifactID) 148 149 if s.client.RateLimitRedirectionalEndpoints { 150 return s.downloadArtifactWithRateLimit(ctx, u, maxRedirects) 151 } 152 153 return s.downloadArtifactWithoutRateLimit(ctx, u, maxRedirects) 154 } 155 156 func (s *ActionsService) downloadArtifactWithoutRateLimit(ctx context.Context, u string, maxRedirects int) (*url.URL, *Response, error) { 157 resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, maxRedirects) 158 if err != nil { 159 return nil, nil, err 160 } 161 defer resp.Body.Close() 162 163 if resp.StatusCode != http.StatusFound { 164 return nil, newResponse(resp), fmt.Errorf("unexpected status code: %v", resp.Status) 165 } 166 167 parsedURL, err := url.Parse(resp.Header.Get("Location")) 168 if err != nil { 169 return nil, newResponse(resp), err 170 } 171 172 return parsedURL, newResponse(resp), nil 173 } 174 175 func (s *ActionsService) downloadArtifactWithRateLimit(ctx context.Context, u string, maxRedirects int) (*url.URL, *Response, error) { 176 req, err := s.client.NewRequest("GET", u, nil) 177 if err != nil { 178 return nil, nil, err 179 } 180 181 url, resp, err := s.client.bareDoUntilFound(ctx, req, maxRedirects) 182 if err != nil { 183 return nil, resp, err 184 } 185 defer resp.Body.Close() 186 187 // If we didn't receive a valid Location in a 302 response 188 if url == nil { 189 return nil, resp, fmt.Errorf("unexpected status code: %v", resp.Status) 190 } 191 192 return url, resp, nil 193 } 194 195 // DeleteArtifact deletes a workflow run artifact. 196 // 197 // GitHub API docs: https://docs.github.com/rest/actions/artifacts#delete-an-artifact 198 // 199 //meta:operation DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id} 200 func (s *ActionsService) DeleteArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Response, error) { 201 u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) 202 203 req, err := s.client.NewRequest("DELETE", u, nil) 204 if err != nil { 205 return nil, err 206 } 207 208 return s.client.Do(ctx, req, nil) 209 }