Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix gh run download <run-id> not getting > 100 artifacts #5799

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

faubion-hbo
Copy link

@faubion-hbo faubion-hbo commented Jun 14, 2022

Fixes #5790

Testing

Used this workflow file to create 201 individual artifact uploads to the run, and was able to reproduce the bug not getting all of them when running gh run download <run-id>.

---
name: upload a bunch of run artifacts
on:
  workflow_dispatch:
jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - name: generate a bunch of files
        run: |
          for i in {0..201}; do
            echo $i > file-number-$i.txt
          done
      - uses: actions/upload-artifact@v3
        with:
          name: file-number-0
          path: file-number-0.txt
      - uses: actions/upload-artifact@v3
        with:
          name: file-number-1
          path: file-number-1.txt
#     - uses: actions/upload-artifact@v3
#       with:
#         name: file-number-<n>
#         path: file-number-<n>.txt

Compiled change, and then tested which was then able to get all 201 artifacts

@faubion-hbo faubion-hbo requested a review from as a code owner Jun 14, 2022
@faubion-hbo faubion-hbo requested review from mislav (assigned from cli/code-reviewers) and removed request for Jun 14, 2022
@cliAutomation cliAutomation added the external label Jun 14, 2022
@cliAutomation cliAutomation added this to Needs review 🤔 in The GitHub CLI Jun 14, 2022
var linkRE = regexp.MustCompile(`<([^>]+)>;\s*rel="([^"]+)"`)

return response.Artifacts, nil
func findNextPage(resp *http.Response) string {
for _, m := range linkRE.FindAllStringSubmatch(resp.Header.Get("Link"), -1) {
if len(m) > 2 && m[2] == "next" {
return m[1]
}
}
return ""
}
Copy link
Author

@faubion-hbo faubion-hbo Jun 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, I copied this code from elsewhere in the repository, and I would like to be able to reuse that instead of copying. I wasn't able to get import/referencing to work; I would try:

import (
...
  cmdApi "github.com/cli/cli/v2/pkg/cmd/api"
)
...
cmdApi.findNextPage()

but that would fail with findNextPage() is undefined in api package...

Copy link
Member

@mislav mislav Jun 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's perfectly fine to copy the function over. Lowercase functions in Go (e.g. findNextPage vs. FindNextPage) are private to a package and cannot be used from other packages, like you have found out when trying to invoke cmdApi.findNextPage().

@faubion-hbo
Copy link
Author

@faubion-hbo faubion-hbo commented Jun 14, 2022

would also appreciate advice or PR for testing the change. any pointers welcomed; new to golang

Copy link
Member

@mislav mislav left a comment

This is looking good, but the code has inconsistent indentation. You can tell Go to format your code by saying go fmt ./pkg/cmd/run/shared. You can also configure your text editor to always format your Go code on file save (it's what I do).

As for testing, you can create a mock http.Client like this:

reg := &httpmock.Registry{}
defer reg.Verify(t)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/check-runs/123456/annotations"),
httpmock.StatusStringResponse(404, "not found"))
httpClient := &http.Client{Transport: reg}

You can then pass that client to ListArtifacts and use the registry to stub responses, like so

firstRes = httpmock.WithHeader(firstRes, "Link", `<https://api.github.com/search/repositories?page=2&per_page=100&q=org%3Agithub>; rel="next"`)

var linkRE = regexp.MustCompile(`<([^>]+)>;\s*rel="([^"]+)"`)

return response.Artifacts, nil
func findNextPage(resp *http.Response) string {
for _, m := range linkRE.FindAllStringSubmatch(resp.Header.Get("Link"), -1) {
if len(m) > 2 && m[2] == "next" {
return m[1]
}
}
return ""
}
Copy link
Member

@mislav mislav Jun 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's perfectly fine to copy the function over. Lowercase functions in Go (e.g. findNextPage vs. FindNextPage) are private to a package and cannot be used from other packages, like you have found out when trying to invoke cmdApi.findNextPage().

}
path := fmt.Sprintf("repos/%s/%s/actions/", repo.RepoOwner(), repo.RepoName())
if runID == "" {
path += "artifacts"
Copy link
Member

@mislav mislav Jun 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of concatenating path together piece by piece like this, just set the whole path and also set a whole path in an if block for when runID is provided, like in the old code. It will be more readable (at the cost of a tiny bit of duplication)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external
Projects
The GitHub CLI
  
Needs review 🤔
Development

Successfully merging this pull request may close these issues.

3 participants