-
Notifications
You must be signed in to change notification settings - Fork 7.8k
fix(gist): add support for editing & viewing large files #11761
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
Conversation
* Added `RawURL` to store the raw URL of the gist file. * Added `Truncated` to indicate if the content is truncated.
* Implements a new function to fetch the raw content of a gist using its `rawURL`. * Handles HTTP requests and responses, including error management for non-200 status codes.
* Added logic to fetch the full content of a gist file if it is marked as truncated. * Utilizes the `GetRawGistFile` function to obtain the complete content from the provided `RawURL`.
* Added logic to fetch full content for truncated files when updating a gist. * Utilizes `shared.GetRawGistFile` to retrieve the complete content based on the `RawURL`.
- Implemented unit tests for various scenarios in `GetRawGistFile`. - Covered cases including successful requests, error handling, and different content types. - Ensured proper verification of HTTP responses and error messages.
* Implement tests for editing gists that contain truncated files. * Ensure that both single and multiple truncated files are handled correctly. * Mock responses for retrieving full content from raw URLs for truncated files.
* Added test cases for viewing truncated files with and without the raw flag. * Included scenarios for multiple files with truncation behavior. * Ensured correct output is returned for truncated files when accessed via raw URLs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements support for editing and viewing large files in GitHub gists by automatically fetching the full content from raw URLs when files are marked as truncated.
- Adds automatic retrieval of full content for truncated gist files
- Implements a new
GetRawGistFilefunction to fetch content from raw URLs - Extends the
GistFilestruct to includeRawURLandTruncatedfields
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cmd/gist/shared/shared.go | Adds new fields to GistFile struct and implements GetRawGistFile function |
| pkg/cmd/gist/view/view.go | Modifies view logic to fetch full content for truncated files |
| pkg/cmd/gist/edit/edit.go | Updates edit logic to handle truncated files before editing |
| pkg/cmd/gist/shared/shared_test.go | Adds comprehensive tests for the new GetRawGistFile function |
| pkg/cmd/gist/view/view_test.go | Adds test cases for viewing truncated files |
| pkg/cmd/gist/edit/edit_test.go | Adds test cases for editing truncated files |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
BagToad
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @luxass 👋 Thanks for your patience!
I've been reviewing this with @babakks and it's pretty good, but we're concerned about fetching the full gist content of each file attached to a gist even when the user hasn't selected to edit it.
We think it would be better to fetch only the raw content of a particular gist when the user has selected to edit a gist where truncated is true. If the user doesn't select a gist where truncated is true, we don't need to fetch the full raw file content.
As we investigated and reviewed further, I realized that we're also sending the full list of files to the API anytime we post an update, even though some are unchanged 🤔 I believe this to be part of the underlying cause of the data loss reported in #11739 since any file that is truncated will be updated with the truncated contents instead of the full contents:
Files from the previous version of the gist that aren't explicitly changed during an edit are unchanged.
I believe this documentation point means we could omit gist files from the upload payload that the user doesn't change. Doing so in conjunction with only fetching raw gist content when needed by the user seems like the ideal experience.
I think we need to do some testing to ensure I'm interpreting the API documentation correctly, and then if so, change our approach to:
- only fetch raw gist content when needed
- only include files that have changed in the gist update request
Let me know if that makes sense and if you're interested in helping out with this still 🙏
|
Hi @BagToad That makes total sense 👍🏻 I will continue work on this PR. |
This change makes it only fetch the raw content, when we wanna edit the specific file.
There was some issues when sending the full list of files, some of them would be truncated.
|
The only thing I'm missing is some more tests - otherwise i think it is ready to go. 🙂 I've verified that the behavior
is correct and working 👍🏻 |
|
Thank you very much @luxass! ✨ And great work!
I took a stab at filling in the gaps on the tests, feel free to commit if you think they look good: Show Diff
diff --git a/pkg/cmd/gist/edit/edit_test.go b/pkg/cmd/gist/edit/edit_test.go
index 296ae3261..ac1555f5c 100644
--- a/pkg/cmd/gist/edit/edit_test.go
+++ b/pkg/cmd/gist/edit/edit_test.go
@@ -237,6 +237,33 @@ func Test_editRun(t *testing.T) {
},
},
},
+ {
+ name: "single file edit flag sends only edited file",
+ opts: &EditOptions{
+ Selector: "1234",
+ EditFilename: "unix.md",
+ },
+ mockGist: &shared.Gist{
+ ID: "1234",
+ Files: map[string]*shared.GistFile{
+ "cicada.txt": {Filename: "cicada.txt", Content: "bwhiizzzbwhuiiizzzz", Type: "text/plain"},
+ "unix.md": {Filename: "unix.md", Content: "meow", Type: "text/markdown"},
+ },
+ Owner: &shared.GistOwner{Login: "octocat"},
+ },
+ httpStubs: func(reg *httpmock.Registry) {
+ reg.Register(httpmock.REST("POST", "gists/1234"), httpmock.StatusStringResponse(201, "{}"))
+ },
+ wantLastRequestParameters: map[string]interface{}{
+ "description": "",
+ "files": map[string]interface{}{
+ "unix.md": map[string]interface{}{
+ "content": "new file content",
+ "filename": "unix.md",
+ },
+ },
+ },
+ },
{
name: "multiple files, cancel, with TTY",
isTTY: true,
@@ -645,6 +672,48 @@ func Test_editRun(t *testing.T) {
},
},
},
+ {
+ name: "interactive truncated multi-file gist fetches only selected file raw content the first time",
+ isTTY: true,
+ opts: &EditOptions{Selector: "1234"},
+ prompterStubs: func(pm *prompter.MockPrompter) {
+ pm.RegisterSelect("Edit which file?", []string{"also-truncated.txt", "large.txt"}, func(_, _ string, opts []string) (int, error) {
+ return prompter.IndexFor(opts, "large.txt")
+ })
+ pm.RegisterSelect("What next?", editNextOptions, func(_, _ string, opts []string) (int, error) {
+ return prompter.IndexFor(opts, "Edit another file")
+ })
+ // Editing large.txt twice to ensure that fetch for the raw URL happens only once
+ pm.RegisterSelect("Edit which file?", []string{"also-truncated.txt", "large.txt"}, func(_, _ string, opts []string) (int, error) {
+ return prompter.IndexFor(opts, "large.txt")
+ })
+ pm.RegisterSelect("What next?", editNextOptions, func(_, _ string, opts []string) (int, error) {
+ return prompter.IndexFor(opts, "Submit")
+ })
+ },
+ mockGist: &shared.Gist{
+ ID: "1234",
+ Files: map[string]*shared.GistFile{
+ "large.txt": {Filename: "large.txt", Content: "This is truncated content...", Type: "text/plain", Truncated: true, RawURL: "https://gist.githubusercontent.com/user/1234/raw/large.txt"},
+ "also-truncated.txt": {Filename: "also-truncated.txt", Content: "stuff...", Type: "text/plain", Truncated: true, RawURL: "https://gist.githubusercontent.com/user/1234/raw/also-truncated.txt"},
+ },
+ Owner: &shared.GistOwner{Login: "octocat"},
+ },
+ httpStubs: func(reg *httpmock.Registry) {
+ reg.Register(httpmock.REST("POST", "gists/1234"), httpmock.StatusStringResponse(201, "{}"))
+ // Explicity exclude also-truncated.txt raw URL to ensure it is not fetched since we did not select it.
+ reg.Exclude(t, httpmock.REST("GET", "user/1234/raw/also-truncated.txt"))
+ },
+ wantLastRequestParameters: map[string]interface{}{
+ "description": "",
+ "files": map[string]interface{}{
+ "large.txt": map[string]interface{}{
+ "content": "new file content",
+ "filename": "large.txt",
+ },
+ },
+ },
+ },
}
for _, tt := range tests { |
…-file selection Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com>
|
Thanks a lot for adding those tests - I've pushed them 👍🏻 They were very close to what I had in mind, but I couldn't quite find a nice way to assert that the raw URL was only hit the first time. Your version nailed that part, so thanks 🙌🏻 |
BagToad
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright I think this looks great! Thanks much for the collaboration on this one! 🍻
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [cli/cli](https://github.com/cli/cli) | minor | `v2.82.1` -> `v2.83.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>cli/cli (cli/cli)</summary> ### [`v2.83.0`](https://github.com/cli/cli/releases/tag/v2.83.0): GitHub CLI 2.83.0 [Compare Source](cli/cli@v2.82.1...v2.83.0) #### What's Changed ##### ✨ Features - Add `isImmutable` to `release list` JSON output by [@​babakks](https://github.com/babakks) in [#​12064](cli/cli#12064) - `gh agent-task create`: support `--custom-agent`/`-a` flag by [@​BagToad](https://github.com/BagToad) in [#​12068](cli/cli#12068) - 💡 (gh repo delete) Add warning when `--yes` is ignored without a repository, Closes: [#​12033](cli/cli#12033) by [@​Shion1305](https://github.com/Shion1305) in [#​12039](cli/cli#12039) - feat: implement gh `pr revert` by [@​lucasmelin](https://github.com/lucasmelin) in [#​8826](cli/cli#8826) ##### 🐛 Fixes - fix(gist): add support for editing & viewing large files by [@​luxass](https://github.com/luxass) in [#​11761](cli/cli#11761) - Fix gh attestation verify to work when Public Good Instance of Sigstore is unavailable by [@​Copilot](https://github.com/Copilot) in [#​11989](cli/cli#11989) ##### 📚 Docs & Chores - chore: add basic linters by [@​babakks](https://github.com/babakks) in [#​12084](cli/cli#12084) - CI: Update lint govulncheck to use source mode by [@​BagToad](https://github.com/BagToad) in [#​12089](cli/cli#12089) - chore: add `workflow_dispatch` to govulncheck triggers by [@​babakks](https://github.com/babakks) in [#​12085](cli/cli#12085) - Exclude `third-party` from Golangci-lint formatting paths by [@​babakks](https://github.com/babakks) in [#​12058](cli/cli#12058) - Apply `go fix` to remove deprecated `// +build` tags by [@​babakks](https://github.com/babakks) in [#​12056](cli/cli#12056) - Bump Golangci-lint to `v2.6.0` by [@​babakks](https://github.com/babakks) in [#​12049](cli/cli#12049) - Mention `pr checks` in `run list` docs by [@​babakks](https://github.com/babakks) in [#​12050](cli/cli#12050) - Fix typo in comment for `gh issue develop` branch checkout command by [@​jonzfisher](https://github.com/jonzfisher) in [#​12042](cli/cli#12042) - Use "release" sentinel value for release attestation verification by [@​Copilot](https://github.com/Copilot) in [#​11991](cli/cli#11991) - Improve docstring for release-create by [@​bdehamer](https://github.com/bdehamer) in [#​11945](cli/cli#11945) - Improve `api` command docs around `--input` and `--field` by [@​babakks](https://github.com/babakks) in [#​12062](cli/cli#12062) - Fix `--interval` flags docs in `gh pr checks` by [@​2003Aditya](https://github.com/2003Aditya) in [#​12053](cli/cli#12053) #####Dependencies - Bump Go to 1.25.3 by [@​github-actions](https://github.com/github-actions)\[bot] in [#​11926](cli/cli#11926) - chore(deps): bump github.com/cli/go-gh/v2 from 2.12.2 to 2.13.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12095](cli/cli#12095) - Update Go toolchain version to 1.24.9 by [@​BagToad](https://github.com/BagToad) in [#​12054](cli/cli#12054) - chore(deps): bump golang.org/x/text from 0.29.0 to 0.30.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​11973](cli/cli#11973) - chore(deps): bump golang.org/x/crypto from 0.42.0 to 0.43.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​11974](cli/cli#11974) - chore(deps): bump actions/upload-artifact from 4 to 5 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12031](cli/cli#12031) - chore(deps): bump actions/download-artifact from 5 to 6 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12032](cli/cli#12032) - chore(deps): bump github.com/rivo/tview from 0.0.0-20250625164341-a4a78f1e05cb to 0.42.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12000](cli/cli#12000) - chore(deps): bump goreleaser/goreleaser-action from 6.3.0 to 6.4.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​11509](cli/cli#11509) - chore(deps): bump mislav/bump-homebrew-formula-action from 3.4 to 3.6 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​11750](cli/cli#11750) #### New Contributors - [@​lucasmelin](https://github.com/lucasmelin) made their first contribution in [#​8826](cli/cli#8826) - [@​jonzfisher](https://github.com/jonzfisher) made their first contribution in [#​12042](cli/cli#12042) - [@​2003Aditya](https://github.com/2003Aditya) made their first contribution in [#​12053](cli/cli#12053) **Full Changelog**: <cli/cli@v2.82.1...v2.83.0> </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNjkuMyIsInVwZGF0ZWRJblZlciI6IjQxLjE2OS4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
resolves #11739