From 5fad092b9e7f4b847a77dffe883d71e6310df416 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Sun, 5 Sep 2021 01:01:58 -0700 Subject: [PATCH 001/767] Refactor Windows Installer setup Resolves #703 along with several other issues: * Build an x64 MSI for an x64 executable. This means the binary is installed to C:\Program Files, by default, rather than C:\Program Files (x86) without the ability to redirect it to 64-bit locations. * Environment change to PATH is not system-wide, which for a per-machine install it should be so all users who can access the executable have it in their PATH. * Environment change to PATH is not cleaned up when uninstalled. * RTF conversion of LICENSE was difficult to read. A simple conversion script is checked in to facilitate regenerating RTF from root LICENSE. --- .github/workflows/releases.yml | 14 +++----- build/windows/ConvertTo-Rtf.ps1 | 24 ++++++++++++++ build/windows/LICENSE.rtf | 23 +++++++++++++ build/windows/gh.wixproj | 35 ++++++++++++++++++++ build/windows/gh.wxs | 58 +++++++++++++++++++++++++++++++++ wix.json | 32 ------------------ 6 files changed, 144 insertions(+), 42 deletions(-) create mode 100644 build/windows/ConvertTo-Rtf.ps1 create mode 100644 build/windows/LICENSE.rtf create mode 100644 build/windows/gh.wixproj create mode 100644 build/windows/gh.wxs delete mode 100644 wix.json diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 79e150113..cbba42cb9 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -123,23 +123,17 @@ jobs: unzip -o *.zip && rm -v *.zip env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - - name: Install go-msi - run: choco install -y "go-msi" - name: Prepare PATH - shell: bash - run: | - echo "$WIX\\bin" >> $GITHUB_PATH - echo "C:\\Program Files\\go-msi" >> $GITHUB_PATH + uses: microsoft/setup-msbuild@v1.0.3 - name: Build MSI id: buildmsi shell: bash env: ZIP_FILE: ${{ steps.download_exe.outputs.zip }} run: | - mkdir -p build - msi="$(basename "$ZIP_FILE" ".zip").msi" - printf "::set-output name=msi::%s\n" "$msi" - go-msi make --msi "$PWD/$msi" --out "$PWD/build" --version "${GITHUB_REF#refs/tags/}" + name="$(basename "$ZIP_FILE" ".zip")" + printf "::set-output name=msi::%s\n" "$name.msi" + msbuild .\build\windows\gh.wixproj /p:SourceDir="$PWD" /p:OutputName="$name" /p:ProductVersion="${GITHUB_REF#refs/tags/}" - name: Obtain signing cert id: obtain_cert env: diff --git a/build/windows/ConvertTo-Rtf.ps1 b/build/windows/ConvertTo-Rtf.ps1 new file mode 100644 index 000000000..401951cc8 --- /dev/null +++ b/build/windows/ConvertTo-Rtf.ps1 @@ -0,0 +1,24 @@ +[CmdletBinding()] +param ( + [Parameter(Mandatory=$true, Position=0)] + [string] $Path, + + [Parameter(Mandatory=$true, Position=1)] + [string] $OutFile, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] $FontFamily = 'Arial' +) + +$rtf = "{\rtf1\ansi\deff0{\fonttbl{\f0\fcharset0 $FontFamily;}}\pard\sa200\sl200\slmult1\fs20`n" +foreach ($line in (Get-Content $Path)) { + if (!$line) { + $rtf += "\par`n" + } else { + $rtf += "$line`n" + } +} +$rtf += '}' + +$rtf | Set-Content $OutFile \ No newline at end of file diff --git a/build/windows/LICENSE.rtf b/build/windows/LICENSE.rtf new file mode 100644 index 000000000..185063f24 --- /dev/null +++ b/build/windows/LICENSE.rtf @@ -0,0 +1,23 @@ +{\rtf1\ansi\deff0{\fonttbl{\f0\fcharset0 Arial;}}\pard\sa200\sl200\slmult1\fs20 +MIT License +\par +Copyright (c) 2019 GitHub Inc. +\par +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +\par +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +\par +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +} diff --git a/build/windows/gh.wixproj b/build/windows/gh.wixproj new file mode 100644 index 000000000..56a87fb66 --- /dev/null +++ b/build/windows/gh.wixproj @@ -0,0 +1,35 @@ + + + + Debug + x64 + 0.1.0 + $(MSBuildProjectName) + package + $(MSBuildProjectDirectory)\..\.. + $(RepoPath)\bin\$(Platform)\$(Configuration)\ + $(RepoPath)\bin\obj\$(Platform)\$(Configuration)\ + + $(DefineConstants); + ProductVersion=$(ProductVersion); + + false + $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets + + + + + + + + + + + + + + + + + + diff --git a/build/windows/gh.wxs b/build/windows/gh.wxs new file mode 100644 index 000000000..7d2f967d5 --- /dev/null +++ b/build/windows/gh.wxs @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wix.json b/wix.json deleted file mode 100644 index 6b2356ae3..000000000 --- a/wix.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "product": "GitHub CLI", - "company": "GitHub, Inc.", - "license": "LICENSE", - "upgrade-code": "7c0a5736-5b8e-4176-b350-613fa2d8a1b3", - "files": { - "guid": "6e6dcb19-3cf6-46d1-ac56-c6fb39485c9d", - "items": [ - "bin/gh.exe" - ] - }, - "env": { - "guid": "94faac3d-4478-431c-8497-fba55dcfb249", - "vars": [ - { - "name": "PATH", - "value": "[INSTALLDIR]", - "permanent": "yes", - "system": "no", - "action": "set", - "part": "last" - } - ] - }, - "shortcuts": {}, - "choco": { - "description": "Use GitHub from the CLI", - "project-url": "https://github.com/cli/cli", - "tags": "github cli git", - "license-url": "https://github.com/cli/cli/blob/trunk/LICENSE" - } -} From cb599af1a33789e2d6be93b4be6a93c428e4b4b0 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Sun, 5 Sep 2021 09:15:36 -0700 Subject: [PATCH 002/767] Make sure correct step output is set Also simplifies directories for an always-release binary. --- .github/workflows/releases.yml | 2 +- build/windows/gh.wixproj | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index cbba42cb9..3acd23acd 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -133,7 +133,7 @@ jobs: run: | name="$(basename "$ZIP_FILE" ".zip")" printf "::set-output name=msi::%s\n" "$name.msi" - msbuild .\build\windows\gh.wixproj /p:SourceDir="$PWD" /p:OutputName="$name" /p:ProductVersion="${GITHUB_REF#refs/tags/}" + msbuild .\build\windows\gh.wixproj /p:SourceDir="$PWD" /p:OutputPath="$PWD" /p:OutputName="$name" /p:ProductVersion="${GITHUB_REF#refs/tags/}" - name: Obtain signing cert id: obtain_cert env: diff --git a/build/windows/gh.wixproj b/build/windows/gh.wixproj index 56a87fb66..db5f1b0c7 100644 --- a/build/windows/gh.wixproj +++ b/build/windows/gh.wixproj @@ -1,14 +1,14 @@ - Debug + Release x64 0.1.0 $(MSBuildProjectName) package - $(MSBuildProjectDirectory)\..\.. - $(RepoPath)\bin\$(Platform)\$(Configuration)\ - $(RepoPath)\bin\obj\$(Platform)\$(Configuration)\ + $([MSBuild]::NormalizeDirectory($(MSBuildProjectDirectory)\..\..)) + $(RepoPath)bin\$(Platform)\ + $(RepoPath)bin\obj\$(Platform)\ $(DefineConstants); ProductVersion=$(ProductVersion); @@ -31,5 +31,9 @@ + + + + From 2fa3de9ba49ca28223a5a01026ce81d8c87c42d6 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Tue, 7 Sep 2021 23:02:59 -0700 Subject: [PATCH 003/767] Resolve PR feedback --- .github/workflows/releases.yml | 3 +-- build/windows/gh.wixproj | 1 + build/windows/gh.wxs | 30 +++++++++++++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 3acd23acd..63a3891e6 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -132,8 +132,7 @@ jobs: ZIP_FILE: ${{ steps.download_exe.outputs.zip }} run: | name="$(basename "$ZIP_FILE" ".zip")" - printf "::set-output name=msi::%s\n" "$name.msi" - msbuild .\build\windows\gh.wixproj /p:SourceDir="$PWD" /p:OutputPath="$PWD" /p:OutputName="$name" /p:ProductVersion="${GITHUB_REF#refs/tags/}" + msbuild .\build\windows\gh.wixproj /p:SourceDir="$PWD" /p:OutputPath="$PWD" /p:OutputName="$name" /p:ProductVersion="${GITHUB_REF#refs/tags/v}" - name: Obtain signing cert id: obtain_cert env: diff --git a/build/windows/gh.wixproj b/build/windows/gh.wixproj index db5f1b0c7..5c355955d 100644 --- a/build/windows/gh.wixproj +++ b/build/windows/gh.wixproj @@ -13,6 +13,7 @@ $(DefineConstants); ProductVersion=$(ProductVersion); + ICE39 false $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets diff --git a/build/windows/gh.wxs b/build/windows/gh.wxs index 7d2f967d5..32eb9564b 100644 --- a/build/windows/gh.wxs +++ b/build/windows/gh.wxs @@ -5,11 +5,27 @@ - + + + + + + + + + + + + + + + + + - + @@ -21,7 +37,7 @@ - + @@ -35,6 +51,7 @@ + @@ -42,8 +59,11 @@ - - + + + + + From a6c7bd832694fd5ef7baa67ddba6cf1c5c657167 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Sat, 18 Sep 2021 09:23:43 -0700 Subject: [PATCH 004/767] Resolve PR feedback * Removed license dialog * Removed RTF copy of license --- build/windows/ConvertTo-Rtf.ps1 | 24 --------------- build/windows/LICENSE.rtf | 23 -------------- build/windows/gh.wixproj | 4 +-- build/windows/gh.wxs | 5 ++- build/windows/ui.wxs | 54 +++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 53 deletions(-) delete mode 100644 build/windows/ConvertTo-Rtf.ps1 delete mode 100644 build/windows/LICENSE.rtf create mode 100644 build/windows/ui.wxs diff --git a/build/windows/ConvertTo-Rtf.ps1 b/build/windows/ConvertTo-Rtf.ps1 deleted file mode 100644 index 401951cc8..000000000 --- a/build/windows/ConvertTo-Rtf.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -[CmdletBinding()] -param ( - [Parameter(Mandatory=$true, Position=0)] - [string] $Path, - - [Parameter(Mandatory=$true, Position=1)] - [string] $OutFile, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [string] $FontFamily = 'Arial' -) - -$rtf = "{\rtf1\ansi\deff0{\fonttbl{\f0\fcharset0 $FontFamily;}}\pard\sa200\sl200\slmult1\fs20`n" -foreach ($line in (Get-Content $Path)) { - if (!$line) { - $rtf += "\par`n" - } else { - $rtf += "$line`n" - } -} -$rtf += '}' - -$rtf | Set-Content $OutFile \ No newline at end of file diff --git a/build/windows/LICENSE.rtf b/build/windows/LICENSE.rtf deleted file mode 100644 index 185063f24..000000000 --- a/build/windows/LICENSE.rtf +++ /dev/null @@ -1,23 +0,0 @@ -{\rtf1\ansi\deff0{\fonttbl{\f0\fcharset0 Arial;}}\pard\sa200\sl200\slmult1\fs20 -MIT License -\par -Copyright (c) 2019 GitHub Inc. -\par -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -\par -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -\par -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -} diff --git a/build/windows/gh.wixproj b/build/windows/gh.wixproj index 5c355955d..aa72d4da3 100644 --- a/build/windows/gh.wixproj +++ b/build/windows/gh.wixproj @@ -19,11 +19,9 @@ + - - - diff --git a/build/windows/gh.wxs b/build/windows/gh.wxs index 32eb9564b..1e91734f1 100644 --- a/build/windows/gh.wxs +++ b/build/windows/gh.wxs @@ -70,9 +70,8 @@ - + - - + diff --git a/build/windows/ui.wxs b/build/windows/ui.wxs new file mode 100644 index 000000000..8c534adc8 --- /dev/null +++ b/build/windows/ui.wxs @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + 1 + "1"]]> + + 1 + + NOT Installed + Installed AND PATCH + + 1 + 1 + NOT WIXUI_DONTVALIDATEPATH + "1"]]> + WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" + 1 + 1 + + NOT Installed + Installed AND NOT PATCH + Installed AND PATCH + + 1 + + 1 + 1 + 1 + + + + + + + \ No newline at end of file From ab668e8419f2491b41ab727d5d24abc30b112580 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 1 Nov 2021 10:28:30 +0300 Subject: [PATCH 005/767] gist edit: add way to edit files from different sources This commit adds an optional parameter to set source for editing or adding files to gist. If parameter is equal to "-" then stdin will be used. --- pkg/cmd/gist/edit/edit.go | 95 +++++++++++++++----- pkg/cmd/gist/edit/edit_test.go | 156 +++++++++++++++++++++++++++++++-- 2 files changed, 222 insertions(+), 29 deletions(-) diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index 174b326cd..b9db2fa54 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -5,8 +5,9 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" + "os" "path/filepath" "sort" "strings" @@ -32,6 +33,7 @@ type EditOptions struct { Selector string EditFilename string AddFilename string + SourceFile string } func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { @@ -49,11 +51,22 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman } cmd := &cobra.Command{ - Use: "edit { | }", + Use: "edit { | } []", Short: "Edit one of your gists", - Args: cmdutil.ExactArgs(1, "cannot edit: gist argument required"), + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return cmdutil.FlagErrorf("cannot edit: gist argument required") + } + if len(args) > 2 { + return cmdutil.FlagErrorf("too many arguments") + } + return nil + }, RunE: func(c *cobra.Command, args []string) error { opts.Selector = args[0] + if len(args) > 1 { + opts.SourceFile = args[1] + } if runF != nil { return runF(&opts) @@ -115,7 +128,36 @@ func editRun(opts *EditOptions) error { } if opts.AddFilename != "" { - files, err := getFilesToAdd(opts.AddFilename) + var input io.Reader + switch src := opts.SourceFile; { + case src == "-": + input = opts.IO.In + case src != "": + f, err := os.Open(src) + if err != nil { + return err + } + defer func() { + _ = f.Close() + }() + input = f + default: + f, err := os.Open(opts.AddFilename) + if err != nil { + return err + } + defer func() { + _ = f.Close() + }() + input = f + } + + content, err := io.ReadAll(input) + if err != nil { + return fmt.Errorf("read content: %w", err) + } + + files, err := getFilesToAdd(opts.AddFilename, content) if err != nil { return err } @@ -161,14 +203,32 @@ func editRun(opts *EditOptions) error { return fmt.Errorf("editing binary files not supported") } - editorCommand, err := cmdutil.DetermineEditor(opts.Config) - if err != nil { - return err - } - text, err := opts.Edit(editorCommand, filename, gistFile.Content, opts.IO) + var text string + if src := opts.SourceFile; src != "" { + if src == "-" { + data, err := io.ReadAll(opts.IO.In) + if err != nil { + return fmt.Errorf("read from stdin: %w", err) + } + text = string(data) + } else { + data, err := os.ReadFile(src) + if err != nil { + return fmt.Errorf("read %s: %w", src, err) + } + text = string(data) + } + } else { + editorCommand, err := cmdutil.DetermineEditor(opts.Config) + if err != nil { + return err + } - if err != nil { - return err + data, err := opts.Edit(editorCommand, filename, gistFile.Content, opts.IO) + if err != nil { + return err + } + text = data } if text != gistFile.Content { @@ -253,20 +313,11 @@ func updateGist(apiClient *api.Client, hostname string, gist *shared.Gist) error return nil } -func getFilesToAdd(file string) (map[string]*shared.GistFile, error) { - isBinary, err := shared.IsBinaryFile(file) - if err != nil { - return nil, fmt.Errorf("failed to read file %s: %w", file, err) - } - if isBinary { +func getFilesToAdd(file string, content []byte) (map[string]*shared.GistFile, error) { + if shared.IsBinaryContents(content) { return nil, fmt.Errorf("failed to upload %s: binary file not supported", file) } - content, err := ioutil.ReadFile(file) - if err != nil { - return nil, fmt.Errorf("failed to read file %s: %w", file, err) - } - if len(content) == 0 { return nil, errors.New("file contents cannot be empty") } diff --git a/pkg/cmd/gist/edit/edit_test.go b/pkg/cmd/gist/edit/edit_test.go index cac99b923..efacf87ec 100644 --- a/pkg/cmd/gist/edit/edit_test.go +++ b/pkg/cmd/gist/edit/edit_test.go @@ -20,14 +20,11 @@ import ( ) func Test_getFilesToAdd(t *testing.T) { - fileToAdd := filepath.Join(t.TempDir(), "gist-test.txt") - err := ioutil.WriteFile(fileToAdd, []byte("hello"), 0600) + filename := "gist-test.txt" + + gf, err := getFilesToAdd(filename, []byte("hello")) require.NoError(t, err) - gf, err := getFilesToAdd(fileToAdd) - require.NoError(t, err) - - filename := filepath.Base(fileToAdd) assert.Equal(t, map[string]*shared.GistFile{ filename: { Filename: filename, @@ -65,6 +62,15 @@ func TestNewCmdEdit(t *testing.T) { AddFilename: "cool.md", }, }, + { + name: "add with source", + cli: "123 --add cool.md -", + wants: EditOptions{ + Selector: "123", + AddFilename: "cool.md", + SourceFile: "-", + }, + }, } for _, tt := range tests { @@ -106,6 +112,7 @@ func Test_editRun(t *testing.T) { httpStubs func(*httpmock.Registry) askStubs func(*prompt.AskStubber) nontty bool + stdin string wantErr string wantParams map[string]interface{} }{ @@ -262,6 +269,140 @@ func Test_editRun(t *testing.T) { AddFilename: fileToAdd, }, }, + { + name: "add file to existing gist from source parameter", + gist: &shared.Gist{ + ID: "1234", + Files: map[string]*shared.GistFile{ + "sample.txt": { + Filename: "sample.txt", + Content: "bwhiizzzbwhuiiizzzz", + Type: "text/plain", + }, + }, + Owner: &shared.GistOwner{Login: "octocat"}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "gists/1234"), + httpmock.StatusStringResponse(201, "{}")) + }, + opts: &EditOptions{ + AddFilename: "from_source.txt", + SourceFile: fileToAdd, + }, + wantParams: map[string]interface{}{ + "description": "", + "updated_at": "0001-01-01T00:00:00Z", + "public": false, + "files": map[string]interface{}{ + "from_source.txt": map[string]interface{}{ + "content": "hello", + "filename": "from_source.txt", + }, + }, + }, + }, + { + name: "add file to existing gist from stdin", + gist: &shared.Gist{ + ID: "1234", + Files: map[string]*shared.GistFile{ + "sample.txt": { + Filename: "sample.txt", + Content: "bwhiizzzbwhuiiizzzz", + Type: "text/plain", + }, + }, + Owner: &shared.GistOwner{Login: "octocat"}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "gists/1234"), + httpmock.StatusStringResponse(201, "{}")) + }, + opts: &EditOptions{ + AddFilename: "from_source.txt", + SourceFile: "-", + }, + stdin: "data from stdin", + wantParams: map[string]interface{}{ + "description": "", + "updated_at": "0001-01-01T00:00:00Z", + "public": false, + "files": map[string]interface{}{ + "from_source.txt": map[string]interface{}{ + "content": "data from stdin", + "filename": "from_source.txt", + }, + }, + }, + }, + { + name: "edit gist using file from source parameter", + gist: &shared.Gist{ + ID: "1234", + Files: map[string]*shared.GistFile{ + "sample.txt": { + Filename: "sample.txt", + Content: "bwhiizzzbwhuiiizzzz", + Type: "text/plain", + }, + }, + Owner: &shared.GistOwner{Login: "octocat"}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "gists/1234"), + httpmock.StatusStringResponse(201, "{}")) + }, + opts: &EditOptions{ + SourceFile: fileToAdd, + }, + wantParams: map[string]interface{}{ + "description": "", + "updated_at": "0001-01-01T00:00:00Z", + "public": false, + "files": map[string]interface{}{ + "sample.txt": map[string]interface{}{ + "content": "hello", + "filename": "sample.txt", + "type": "text/plain", + }, + }, + }, + }, + { + name: "edit gist using stdin", + gist: &shared.Gist{ + ID: "1234", + Files: map[string]*shared.GistFile{ + "sample.txt": { + Filename: "sample.txt", + Content: "bwhiizzzbwhuiiizzzz", + Type: "text/plain", + }, + }, + Owner: &shared.GistOwner{Login: "octocat"}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "gists/1234"), + httpmock.StatusStringResponse(201, "{}")) + }, + opts: &EditOptions{ + SourceFile: "-", + }, + stdin: "data from stdin", + wantParams: map[string]interface{}{ + "description": "", + "updated_at": "0001-01-01T00:00:00Z", + "public": false, + "files": map[string]interface{}{ + "sample.txt": map[string]interface{}{ + "content": "data from stdin", + "filename": "sample.txt", + "type": "text/plain", + }, + }, + }, + }, } for _, tt := range tests { @@ -297,7 +438,8 @@ func Test_editRun(t *testing.T) { tt.opts.HttpClient = func() (*http.Client, error) { return &http.Client{Transport: reg}, nil } - io, _, stdout, stderr := iostreams.Test() + io, stdin, stdout, stderr := iostreams.Test() + stdin.WriteString(tt.stdin) io.SetStdoutTTY(!tt.nontty) io.SetStdinTTY(!tt.nontty) tt.opts.IO = io From f30e76aab8a1584bb3e78bfad691897990f76bb0 Mon Sep 17 00:00:00 2001 From: Ben Steadman Date: Tue, 16 Nov 2021 20:05:54 +0000 Subject: [PATCH 006/767] Support editing gist description Add a --desc flag to gh gist edit to support editing gist descriptions. This flag can be used in combination with the other gist editing flags to edit the description whilst also adding/editing files. Signed-off-by: Ben Steadman --- pkg/cmd/gist/edit/edit.go | 22 +++++++++++------- pkg/cmd/gist/edit/edit_test.go | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index 174b326cd..a43cf9a5b 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -32,6 +32,7 @@ type EditOptions struct { Selector string EditFilename string AddFilename string + Description string } func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { @@ -64,6 +65,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman } cmd.Flags().StringVarP(&opts.AddFilename, "add", "a", "", "Add a new file to the gist") + cmd.Flags().StringVarP(&opts.Description, "desc", "d", "", "New description for the gist") cmd.Flags().StringVarP(&opts.EditFilename, "filename", "f", "", "Select a file to edit") return cmd @@ -114,6 +116,12 @@ func editRun(opts *EditOptions) error { return fmt.Errorf("You do not own this gist.") } + shouldUpdate := false + if opts.Description != "" { + shouldUpdate = true + gist.Description = opts.Description + } + if opts.AddFilename != "" { files, err := getFilesToAdd(opts.AddFilename) if err != nil { @@ -166,7 +174,6 @@ func editRun(opts *EditOptions) error { return err } text, err := opts.Edit(editorCommand, filename, gistFile.Content, opts.IO) - if err != nil { return err } @@ -215,16 +222,15 @@ func editRun(opts *EditOptions) error { } } - if len(filesToUpdate) == 0 { + if len(filesToUpdate) > 0 { + shouldUpdate = true + } + + if !shouldUpdate { return nil } - err = updateGist(apiClient, host, gist) - if err != nil { - return err - } - - return nil + return updateGist(apiClient, host, gist) } func updateGist(apiClient *api.Client, hostname string, gist *shared.Gist) error { diff --git a/pkg/cmd/gist/edit/edit_test.go b/pkg/cmd/gist/edit/edit_test.go index cac99b923..62b6fcb25 100644 --- a/pkg/cmd/gist/edit/edit_test.go +++ b/pkg/cmd/gist/edit/edit_test.go @@ -65,6 +65,14 @@ func TestNewCmdEdit(t *testing.T) { AddFilename: "cool.md", }, }, + { + name: "description", + cli: `123 --desc "my new description"`, + wants: EditOptions{ + Selector: "123", + Description: "my new description", + }, + }, } for _, tt := range tests { @@ -262,6 +270,39 @@ func Test_editRun(t *testing.T) { AddFilename: fileToAdd, }, }, + { + name: "change description", + gist: &shared.Gist{ + ID: "1234", + Description: "my old description", + Files: map[string]*shared.GistFile{ + "sample.txt": { + Filename: "sample.txt", + Type: "text/plain", + }, + }, + Owner: &shared.GistOwner{Login: "octocat"}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "gists/1234"), + httpmock.StatusStringResponse(201, "{}")) + }, + wantParams: map[string]interface{}{ + "description": "my new description", + "updated_at": "0001-01-01T00:00:00Z", + "public": false, + "files": map[string]interface{}{ + "sample.txt": map[string]interface{}{ + "content": "new file content", + "filename": "sample.txt", + "type": "text/plain", + }, + }, + }, + opts: &EditOptions{ + Description: "my new description", + }, + }, } for _, tt := range tests { From 54d92facbf64f6acbca33f3b928688d638d9a9d9 Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Fri, 10 Dec 2021 22:59:35 +0530 Subject: [PATCH 007/767] add flag to set fork-name during repo fork. Tests WIP --- api/queries_repo.go | 32 ++++++++++++++++++ git/remote.go | 1 + pkg/cmd/repo/fork/fork.go | 10 ++++++ pkg/cmd/repo/rename/http.go | 61 ----------------------------------- pkg/cmd/repo/rename/rename.go | 7 +++- 5 files changed, 49 insertions(+), 62 deletions(-) delete mode 100644 pkg/cmd/repo/rename/http.go diff --git a/api/queries_repo.go b/api/queries_repo.go index c6159f205..22079fb39 100644 --- a/api/queries_repo.go +++ b/api/queries_repo.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/cli/cli/v2/internal/ghinstance" "io" "net/http" "sort" @@ -524,6 +525,37 @@ func ForkRepo(client *Client, repo ghrepo.Interface, org string) (*Repository, e }, nil } +// RenameRepo renames the repository on GitHub and returns the renamed repository +func RenameRepo(client *Client, repo ghrepo.Interface, newRepoName string) (*Repository, error) { + input := map[string]string{"name": newRepoName} + body := &bytes.Buffer{} + enc := json.NewEncoder(body) + if err := enc.Encode(input); err != nil { + return nil, err + } + + path := fmt.Sprintf("%srepos/%s", + ghinstance.RESTPrefix(repo.RepoHost()), + ghrepo.FullName(repo)) + + result := repositoryV3{} + err := client.REST(repo.RepoHost(), "PATCH", path, body, &result) + if err != nil { + return nil, err + } + + return &Repository{ + ID: result.NodeID, + Name: result.Name, + CreatedAt: result.CreatedAt, + Owner: RepositoryOwner{ + Login: result.Owner.Login, + }, + ViewerPermission: "WRITE", + hostname: repo.RepoHost(), + }, nil +} + // RepoFindForks finds forks of the repo that are affiliated with the viewer func RepoFindForks(client *Client, repo ghrepo.Interface, limit int) ([]*Repository, error) { result := struct { diff --git a/git/remote.go b/git/remote.go index bea81da90..7a5890cb6 100644 --- a/git/remote.go +++ b/git/remote.go @@ -153,6 +153,7 @@ func AddRemote(name, u string) (*Remote, error) { } func UpdateRemoteURL(name, u string) error { + fmt.Println(name, u, "=====================name u==============") addCmd, err := GitCommand("remote", "set-url", name, u) if err != nil { return err diff --git a/pkg/cmd/repo/fork/fork.go b/pkg/cmd/repo/fork/fork.go index 773f46641..1295482ca 100644 --- a/pkg/cmd/repo/fork/fork.go +++ b/pkg/cmd/repo/fork/fork.go @@ -39,6 +39,7 @@ type ForkOptions struct { PromptRemote bool RemoteName string Organization string + ForkName string Rename bool } @@ -115,6 +116,7 @@ Additional 'git clone' flags can be passed in by listing them after '--'.`, cmd.Flags().BoolVar(&opts.Remote, "remote", false, "Add remote for fork {true|false}") cmd.Flags().StringVar(&opts.RemoteName, "remote-name", defaultRemoteName, "Specify a name for a fork's new remote.") cmd.Flags().StringVar(&opts.Organization, "org", "", "Create the fork in an organization") + cmd.Flags().StringVar(&opts.ForkName, "fork-name", "", "Specify a name for the forked repo") return cmd } @@ -180,6 +182,14 @@ func forkRun(opts *ForkOptions) error { return fmt.Errorf("failed to fork: %w", err) } + // Rename the forked repo if ForkName is specified in opts. + if opts.ForkName != "" { + forkedRepo, err = api.RenameRepo(apiClient, forkedRepo, opts.ForkName) + if err != nil { + return err + } + } + // This is weird. There is not an efficient way to determine via the GitHub API whether or not a // given user has forked a given repo. We noticed, also, that the create fork API endpoint just // returns the fork repo data even if it already exists -- with no change in status code or diff --git a/pkg/cmd/repo/rename/http.go b/pkg/cmd/repo/rename/http.go deleted file mode 100644 index 1e5d73477..000000000 --- a/pkg/cmd/repo/rename/http.go +++ /dev/null @@ -1,61 +0,0 @@ -package rename - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/cli/cli/v2/api" - "github.com/cli/cli/v2/internal/ghinstance" - "github.com/cli/cli/v2/internal/ghrepo" -) - -func apiRename(client *http.Client, repo ghrepo.Interface, newRepoName string) (ghrepo.Interface, error) { - input := map[string]string{"name": newRepoName} - body, err := json.Marshal(input) - if err != nil { - return nil, err - } - - path := fmt.Sprintf("%srepos/%s", - ghinstance.RESTPrefix(repo.RepoHost()), - ghrepo.FullName(repo)) - - request, err := http.NewRequest("PATCH", path, bytes.NewBuffer(body)) - if err != nil { - return nil, err - } - - request.Header.Set("Content-Type", "application/json; charset=utf-8") - - resp, err := client.Do(request) - if err != nil { - return nil, err - } - - if resp.StatusCode > 299 { - return nil, api.HandleHTTPError(resp) - } - - defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - result := struct { - Name string - Owner struct { - Login string - } - }{} - if err := json.Unmarshal(b, &result); err != nil { - return nil, fmt.Errorf("error unmarshaling response: %w", err) - } - - newRepo := ghrepo.NewWithHost(result.Owner.Login, result.Name, repo.RepoHost()) - - return newRepo, nil -} diff --git a/pkg/cmd/repo/rename/rename.go b/pkg/cmd/repo/rename/rename.go index d8b0e8123..a0f6ee4bf 100644 --- a/pkg/cmd/repo/rename/rename.go +++ b/pkg/cmd/repo/rename/rename.go @@ -2,6 +2,7 @@ package rename import ( "fmt" + "github.com/cli/cli/v2/api" "net/http" "github.com/AlecAivazis/survey/v2" @@ -114,7 +115,9 @@ func renameRun(opts *RenameOptions) error { } } - newRepo, err := apiRename(httpClient, currRepo, newRepoName) + apiClient := api.NewClientFromHTTP(httpClient) + + newRepo, err := api.RenameRepo(apiClient, currRepo, newRepoName) if err != nil { return err } @@ -124,6 +127,8 @@ func renameRun(opts *RenameOptions) error { fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), ghrepo.FullName(newRepo)) } + fmt.Println(opts.HasRepoOverride, "=========erpo override=============") + if opts.HasRepoOverride { return nil } From 3fb4c481dc55885a57bd64c870822cbba1744b73 Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Sat, 11 Dec 2021 10:17:04 +0530 Subject: [PATCH 008/767] modify tests --- api/client.go | 1 + git/remote.go | 1 - pkg/cmd/repo/fork/fork_test.go | 82 ++++++++++++++++++++++++++++++ pkg/cmd/repo/rename/rename.go | 6 +-- pkg/cmd/repo/rename/rename_test.go | 10 ++-- 5 files changed, 91 insertions(+), 9 deletions(-) diff --git a/api/client.go b/api/client.go index 3fcf0d930..a3bf486ad 100644 --- a/api/client.go +++ b/api/client.go @@ -310,6 +310,7 @@ func (c Client) REST(hostname string, method string, p string, body io.Reader, d if err != nil { return err } + err = json.Unmarshal(b, &data) if err != nil { return err diff --git a/git/remote.go b/git/remote.go index 7a5890cb6..bea81da90 100644 --- a/git/remote.go +++ b/git/remote.go @@ -153,7 +153,6 @@ func AddRemote(name, u string) (*Remote, error) { } func UpdateRemoteURL(name, u string) error { - fmt.Println(name, u, "=====================name u==============") addCmd, err := GitCommand("remote", "set-url", name, u) if err != nil { return err diff --git a/pkg/cmd/repo/fork/fork_test.go b/pkg/cmd/repo/fork/fork_test.go index 775152440..4028ff929 100644 --- a/pkg/cmd/repo/fork/fork_test.go +++ b/pkg/cmd/repo/fork/fork_test.go @@ -132,6 +132,16 @@ func TestNewCmdFork(t *testing.T) { wantErr: true, errMsg: "unknown flag: --depth\nSeparate git clone flags with '--'.", }, + { + name: "with fork name", + cli: "--fork-name new-fork", + wants: ForkOptions{ + Remote: false, + RemoteName: "origin", + ForkName: "new-fork", + Rename: false, + }, + }, } for _, tt := range tests { @@ -529,6 +539,78 @@ func TestRepoFork(t *testing.T) { cs.Register(`git -C REPO remote add -f upstream https://github\.com/OWNER/REPO\.git`, 0, "") }, }, + { + name: "non tty repo arg with fork-name", + opts: &ForkOptions{ + Repository: "someone/REPO", + Clone: false, + ForkName: "NEW_REPO", + }, + tty: false, + httpStubs: func(reg *httpmock.Registry) { + forkResult := `{ + "node_id": "123", + "name": "REPO", + "clone_url": "https://github.com/OWNER/REPO.git", + "created_at": "2011-01-26T19:01:12Z", + "owner": { + "login": "OWNER" + } + }` + renameResult := `{ + "node_id": "1234", + "name": "NEW_REPO", + "clone_url": "https://github.com/OWNER/NEW_REPO.git", + "created_at": "2012-01-26T19:01:12Z", + "owner": { + "login": "OWNER" + } + }` + reg.Register( + httpmock.REST("POST", "repos/someone/REPO/forks"), + httpmock.StringResponse(forkResult)) + reg.Register( + httpmock.REST("PATCH", "repos/OWNER/REPO"), + httpmock.StringResponse(renameResult)) + }, + wantErrOut: "", + }, + { + name: "tty repo arg with fork-name", + opts: &ForkOptions{ + Repository: "someone/REPO", + Clone: false, + ForkName: "NEW_REPO", + }, + tty: true, + httpStubs: func(reg *httpmock.Registry) { + forkResult := `{ + "node_id": "123", + "name": "REPO", + "clone_url": "https://github.com/OWNER/REPO.git", + "created_at": "2011-01-26T19:01:12Z", + "owner": { + "login": "OWNER" + } + }` + renameResult := `{ + "node_id": "1234", + "name": "NEW_REPO", + "clone_url": "https://github.com/OWNER/NEW_REPO.git", + "created_at": "2012-01-26T19:01:12Z", + "owner": { + "login": "OWNER" + } + }` + reg.Register( + httpmock.REST("POST", "repos/someone/REPO/forks"), + httpmock.StringResponse(forkResult)) + reg.Register( + httpmock.REST("PATCH", "repos/OWNER/REPO"), + httpmock.StringResponse(renameResult)) + }, + wantErrOut: "✓ Created fork OWNER/NEW_REPO\n", + }, } for _, tt := range tests { diff --git a/pkg/cmd/repo/rename/rename.go b/pkg/cmd/repo/rename/rename.go index a0f6ee4bf..54747cff9 100644 --- a/pkg/cmd/repo/rename/rename.go +++ b/pkg/cmd/repo/rename/rename.go @@ -122,18 +122,18 @@ func renameRun(opts *RenameOptions) error { return err } + renamedRepo := ghrepo.New(newRepo.Owner.Login, newRepo.Name) + cs := opts.IO.ColorScheme() if opts.IO.IsStdoutTTY() { fmt.Fprintf(opts.IO.Out, "%s Renamed repository %s\n", cs.SuccessIcon(), ghrepo.FullName(newRepo)) } - fmt.Println(opts.HasRepoOverride, "=========erpo override=============") - if opts.HasRepoOverride { return nil } - remote, err := updateRemote(currRepo, newRepo, opts) + remote, err := updateRemote(currRepo, renamedRepo, opts) if err != nil { fmt.Fprintf(opts.IO.ErrOut, "%s Warning: unable to update remote %q: %v\n", cs.WarningIcon(), remote.Name, err) } else if opts.IO.IsStdoutTTY() { diff --git a/pkg/cmd/repo/rename/rename_test.go b/pkg/cmd/repo/rename/rename_test.go index 042579613..549abc731 100644 --- a/pkg/cmd/repo/rename/rename_test.go +++ b/pkg/cmd/repo/rename/rename_test.go @@ -122,7 +122,7 @@ func TestRenameRun(t *testing.T) { httpStubs: func(reg *httpmock.Registry) { reg.Register( httpmock.REST("PATCH", "repos/OWNER/REPO"), - httpmock.StatusStringResponse(204, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) + httpmock.StatusStringResponse(200, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) }, execStubs: func(cs *run.CommandStubber) { cs.Register(`git remote set-url origin https://github.com/OWNER/NEW_REPO.git`, 0, "") @@ -141,7 +141,7 @@ func TestRenameRun(t *testing.T) { httpStubs: func(reg *httpmock.Registry) { reg.Register( httpmock.REST("PATCH", "repos/OWNER/REPO"), - httpmock.StatusStringResponse(204, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) + httpmock.StatusStringResponse(200, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) }, tty: true, }, @@ -154,7 +154,7 @@ func TestRenameRun(t *testing.T) { httpStubs: func(reg *httpmock.Registry) { reg.Register( httpmock.REST("PATCH", "repos/OWNER/REPO"), - httpmock.StatusStringResponse(204, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) + httpmock.StatusStringResponse(200, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) }, execStubs: func(cs *run.CommandStubber) { cs.Register(`git remote set-url origin https://github.com/OWNER/NEW_REPO.git`, 0, "") @@ -169,7 +169,7 @@ func TestRenameRun(t *testing.T) { httpStubs: func(reg *httpmock.Registry) { reg.Register( httpmock.REST("PATCH", "repos/OWNER/REPO"), - httpmock.StatusStringResponse(204, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) + httpmock.StatusStringResponse(200, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) }, execStubs: func(cs *run.CommandStubber) { cs.Register(`git remote set-url origin https://github.com/OWNER/NEW_REPO.git`, 0, "") @@ -189,7 +189,7 @@ func TestRenameRun(t *testing.T) { httpStubs: func(reg *httpmock.Registry) { reg.Register( httpmock.REST("PATCH", "repos/OWNER/REPO"), - httpmock.StatusStringResponse(204, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) + httpmock.StatusStringResponse(200, `{"name":"NEW_REPO","owner":{"login":"OWNER"}}`)) }, execStubs: func(cs *run.CommandStubber) { cs.Register(`git remote set-url origin https://github.com/OWNER/NEW_REPO.git`, 0, "") From 354bac82b3a513a5796694de262129b40e12ece9 Mon Sep 17 00:00:00 2001 From: Andrei Jiroh Eugenio Halili Date: Fri, 24 Dec 2021 18:43:22 +0800 Subject: [PATCH 009/767] Add Alpine Linux install docs --- docs/install_linux.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/install_linux.md b/docs/install_linux.md index b11c2faa9..eda70db95 100644 --- a/docs/install_linux.md +++ b/docs/install_linux.md @@ -179,6 +179,23 @@ openSUSE Tumbleweed users can install from the [official distribution repo](http sudo zypper in gh ``` +### Alpine Linux + +Alpine Linux users can install from the [stable releases' community packaage repository](https://pkgs.alpinelinux.org/packages?name=github-cli&branch=v3.15). + +```bash +apk add github-cli +``` + +Users wanting the latest version of the CLI without waiting to be backported into their stable release they're using should use the edge release's +community repo through this method below, without mixing packages from stable and unstable repos.[^1] + +```bash +echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories +apk add github-cli@community +``` + [releases page]: https://github.com/cli/cli/releases/latest [arch linux repo]: https://www.archlinux.org/packages/community/x86_64/github-cli [arch linux aur]: https://aur.archlinux.org/packages/github-cli-git +[^1]: https://wiki.alpinelinux.org/wiki/Package_management#Repository_pinning From 0ac546a81f266f50025c1288bbc45c1c9a524599 Mon Sep 17 00:00:00 2001 From: Frank Dietrich Date: Thu, 6 Jan 2022 09:16:27 +0100 Subject: [PATCH 010/767] Amend location of GPG key file Following the Debian [documentation](https://wiki.debian.org/SecureApt) the keyring should be stored in `/etc/apt/trusted.gpg.d/. > In more recent Debian GNU/Linux versions (Wheezy, for example), the keyrings are stored in specific files all located in the `/etc/apt/trusted.gpg.d` directory. --- docs/install_linux.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install_linux.md b/docs/install_linux.md index b11c2faa9..729edf78d 100644 --- a/docs/install_linux.md +++ b/docs/install_linux.md @@ -14,8 +14,8 @@ our release schedule. Install: ```bash -curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null +curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/etc/apt/trusted.gpg.d/githubcli-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null sudo apt update sudo apt install gh ``` From 015b9f7fea68cbbeb324556f2101d57f73a544db Mon Sep 17 00:00:00 2001 From: keijun-kumagai Date: Tue, 11 Jan 2022 01:49:19 +0900 Subject: [PATCH 011/767] fix(release): discussion category with assets --- pkg/cmd/release/create/create.go | 7 ++++++- pkg/cmd/release/create/http.go | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 1b834373f..bdfdf1460 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -418,7 +418,12 @@ func createRun(opts *CreateOptions) error { } if !opts.Draft { - rel, err := publishRelease(httpClient, newRelease.APIURL) + params := map[string]interface{}{} + params["draft"] = false + if opts.DiscussionCategory != "" { + params["discussion_category_name"] = opts.DiscussionCategory + } + rel, err := publishRelease(httpClient, newRelease.APIURL, params) if err != nil { return err } diff --git a/pkg/cmd/release/create/http.go b/pkg/cmd/release/create/http.go index fb082cd79..058b38c5b 100644 --- a/pkg/cmd/release/create/http.go +++ b/pkg/cmd/release/create/http.go @@ -134,8 +134,9 @@ func createRelease(httpClient *http.Client, repo ghrepo.Interface, params map[st return &newRelease, err } -func publishRelease(httpClient *http.Client, releaseURL string) (*shared.Release, error) { - req, err := http.NewRequest("PATCH", releaseURL, bytes.NewBufferString(`{"draft":false}`)) +func publishRelease(httpClient *http.Client, releaseURL string, params map[string]interface{}) (*shared.Release, error) { + bodyBytes, err := json.Marshal(params) + req, err := http.NewRequest("PATCH", releaseURL, bytes.NewBuffer(bodyBytes)) if err != nil { return nil, err } From 562f1b3d0d18896d70427d77e60365f74f4b9268 Mon Sep 17 00:00:00 2001 From: nate smith Date: Tue, 11 Jan 2022 14:56:58 -0600 Subject: [PATCH 012/767] add GetOrDefault functionality to config --- internal/config/config_file_test.go | 18 +++++++++--------- internal/config/config_type.go | 3 +++ internal/config/config_type_test.go | 6 +++--- internal/config/from_env.go | 18 ++++++++++++++++++ internal/config/from_env_test.go | 4 ++-- internal/config/from_file.go | 21 +++++++++++++++++---- internal/config/stub.go | 18 ++++++++++++++++++ pkg/cmd/auth/gitcredential/helper.go | 6 +++--- pkg/cmd/auth/gitcredential/helper_test.go | 8 +++++++- pkg/cmd/auth/login/login.go | 2 +- pkg/cmd/auth/logout/logout.go | 2 +- pkg/cmd/auth/refresh/refresh.go | 8 ++++---- pkg/cmd/auth/shared/login_flow.go | 4 ++-- pkg/cmd/auth/shared/login_flow_test.go | 2 +- pkg/cmd/auth/status/status.go | 4 ++-- pkg/cmd/config/get/get.go | 2 +- pkg/cmd/config/get/get_test.go | 2 +- pkg/cmd/config/list/list.go | 2 +- pkg/cmd/config/set/set_test.go | 4 ++-- pkg/cmd/extension/manager.go | 2 +- pkg/cmd/factory/default.go | 6 +++--- pkg/cmd/factory/http.go | 6 +++--- pkg/cmd/factory/http_test.go | 2 +- pkg/cmd/factory/remote_resolver.go | 2 +- pkg/cmd/gist/clone/clone.go | 2 +- pkg/cmd/pr/checkout/checkout.go | 2 +- pkg/cmd/pr/create/create.go | 2 +- pkg/cmd/repo/clone/clone.go | 4 ++-- pkg/cmd/repo/create/create.go | 4 ++-- pkg/cmd/repo/fork/fork.go | 2 +- pkg/cmd/repo/rename/rename.go | 2 +- pkg/cmdutil/auth_check.go | 2 +- pkg/cmdutil/legacy.go | 2 +- 33 files changed, 116 insertions(+), 58 deletions(-) diff --git a/internal/config/config_file_test.go b/internal/config/config_file_test.go index 4c35f24f9..8ee938f31 100644 --- a/internal/config/config_file_test.go +++ b/internal/config/config_file_test.go @@ -22,10 +22,10 @@ hosts: `, "")() config, err := parseConfig("config.yml") assert.NoError(t, err) - user, err := config.Get("github.com", "user") + user, err := config.GetOrDefault("github.com", "user") assert.NoError(t, err) assert.Equal(t, "monalisa", user) - token, err := config.Get("github.com", "oauth_token") + token, err := config.GetOrDefault("github.com", "oauth_token") assert.NoError(t, err) assert.Equal(t, "OTOKEN", token) } @@ -42,10 +42,10 @@ hosts: `, "")() config, err := parseConfig("config.yml") assert.NoError(t, err) - user, err := config.Get("github.com", "user") + user, err := config.GetOrDefault("github.com", "user") assert.NoError(t, err) assert.Equal(t, "monalisa", user) - token, err := config.Get("github.com", "oauth_token") + token, err := config.GetOrDefault("github.com", "oauth_token") assert.NoError(t, err) assert.Equal(t, "OTOKEN", token) } @@ -58,10 +58,10 @@ github.com: `)() config, err := parseConfig("config.yml") assert.NoError(t, err) - user, err := config.Get("github.com", "user") + user, err := config.GetOrDefault("github.com", "user") assert.NoError(t, err) assert.Equal(t, "monalisa", user) - token, err := config.Get("github.com", "oauth_token") + token, err := config.GetOrDefault("github.com", "oauth_token") assert.NoError(t, err) assert.Equal(t, "OTOKEN", token) } @@ -80,13 +80,13 @@ example.com: `)() config, err := parseConfig("config.yml") assert.NoError(t, err) - val, err := config.Get("example.com", "git_protocol") + val, err := config.GetOrDefault("example.com", "git_protocol") assert.NoError(t, err) assert.Equal(t, "https", val) - val, err = config.Get("github.com", "git_protocol") + val, err = config.GetOrDefault("github.com", "git_protocol") assert.NoError(t, err) assert.Equal(t, "ssh", val) - val, err = config.Get("nonexistent.io", "git_protocol") + val, err = config.GetOrDefault("nonexistent.io", "git_protocol") assert.NoError(t, err) assert.Equal(t, "ssh", val) } diff --git a/internal/config/config_type.go b/internal/config/config_type.go index 92792e93f..7a71e0c96 100644 --- a/internal/config/config_type.go +++ b/internal/config/config_type.go @@ -9,7 +9,10 @@ import ( // This interface describes interacting with some persistent configuration for gh. type Config interface { Get(string, string) (string, error) + GetOrDefault(string, string) (string, error) GetWithSource(string, string) (string, string, error) + GetOrDefaultWithSource(string, string) (string, string, error) + Default(string) string Set(string, string, string) error UnsetHost(string) Hosts() ([]string, error) diff --git a/internal/config/config_type_test.go b/internal/config/config_type_test.go index bf53aabe4..dd46a7c2e 100644 --- a/internal/config/config_type_test.go +++ b/internal/config/config_type_test.go @@ -58,11 +58,11 @@ func Test_defaultConfig(t *testing.T) { assert.Equal(t, expected, mainBuf.String()) assert.Equal(t, "", hostsBuf.String()) - proto, err := cfg.Get("", "git_protocol") + proto, err := cfg.GetOrDefault("", "git_protocol") assert.NoError(t, err) assert.Equal(t, "https", proto) - editor, err := cfg.Get("", "editor") + editor, err := cfg.GetOrDefault("", "editor") assert.NoError(t, err) assert.Equal(t, "", editor) @@ -72,7 +72,7 @@ func Test_defaultConfig(t *testing.T) { expansion, _ := aliases.Get("co") assert.Equal(t, expansion, "pr checkout") - browser, err := cfg.Get("", "browser") + browser, err := cfg.GetOrDefault("", "browser") assert.NoError(t, err) assert.Equal(t, "", browser) } diff --git a/internal/config/from_env.go b/internal/config/from_env.go index ad31537f4..27cf3c54b 100644 --- a/internal/config/from_env.go +++ b/internal/config/from_env.go @@ -76,6 +76,24 @@ func (c *envConfig) GetWithSource(hostname, key string) (string, string, error) return c.Config.GetWithSource(hostname, key) } +func (c *envConfig) GetOrDefault(hostname, key string) (val string, err error) { + val, _, err = c.GetOrDefaultWithSource(hostname, key) + return +} + +func (c *envConfig) GetOrDefaultWithSource(hostname, key string) (val string, src string, err error) { + val, src, err = c.GetWithSource(hostname, key) + if err == nil && val == "" { + val = c.Default(key) + } + + return +} + +func (c *envConfig) Default(key string) string { + return c.Config.Default(key) +} + func (c *envConfig) CheckWriteable(hostname, key string) error { if hostname != "" && key == "oauth_token" { if token, env := AuthTokenFromEnv(hostname); token != "" { diff --git a/internal/config/from_env_test.go b/internal/config/from_env_test.go index bf81c7976..59856021d 100644 --- a/internal/config/from_env_test.go +++ b/internal/config/from_env_test.go @@ -301,11 +301,11 @@ func TestInheritEnv(t *testing.T) { hosts, _ := cfg.Hosts() assert.Equal(t, tt.wants.hosts, hosts) - val, source, _ := cfg.GetWithSource(tt.hostname, "oauth_token") + val, source, _ := cfg.GetOrDefaultWithSource(tt.hostname, "oauth_token") assert.Equal(t, tt.wants.token, val) assert.Regexp(t, tt.wants.source, source) - val, _ = cfg.Get(tt.hostname, "oauth_token") + val, _ = cfg.GetOrDefault(tt.hostname, "oauth_token") assert.Equal(t, tt.wants.token, val) err := cfg.CheckWriteable(tt.hostname, "oauth_token") diff --git a/internal/config/from_file.go b/internal/config/from_file.go index 080143df4..3c1cfd65b 100644 --- a/internal/config/from_file.go +++ b/internal/config/from_file.go @@ -65,13 +65,26 @@ func (c *fileConfig) GetWithSource(hostname, key string) (string, string, error) return "", defaultSource, err } - if value == "" { - return defaultFor(key), defaultSource, nil - } - return value, defaultSource, nil } +func (c *fileConfig) GetOrDefault(hostname, key string) (val string, err error) { + val, _, err = c.GetOrDefaultWithSource(hostname, key) + return +} + +func (c *fileConfig) GetOrDefaultWithSource(hostname, key string) (val string, src string, err error) { + val, src, err = c.GetWithSource(hostname, key) + if err != nil && val == "" { + val = c.Default(key) + } + return +} + +func (c *fileConfig) Default(key string) string { + return defaultFor(key) +} + func (c *fileConfig) Set(hostname, key, value string) error { if hostname == "" { return c.SetStringValue(key, value) diff --git a/internal/config/stub.go b/internal/config/stub.go index e68183d32..357458f60 100644 --- a/internal/config/stub.go +++ b/internal/config/stub.go @@ -25,6 +25,24 @@ func (c ConfigStub) GetWithSource(host, key string) (string, string, error) { return "", "", errors.New("not found") } +func (c ConfigStub) GetOrDefault(hostname, key string) (val string, err error) { + val, _, err = c.GetOrDefaultWithSource(hostname, key) + return +} + +func (c ConfigStub) GetOrDefaultWithSource(hostname, key string) (val string, src string, err error) { + val, src, err = c.GetWithSource(hostname, key) + if err == nil && val == "" { + val = c.Default(key) + } + return +} + +func (c ConfigStub) Default(key string) string { + // TODO may regret this + return defaultFor(key) +} + func (c ConfigStub) Set(host, key, value string) error { c[genKey(host, key)] = value return nil diff --git a/pkg/cmd/auth/gitcredential/helper.go b/pkg/cmd/auth/gitcredential/helper.go index 8d1ab7ff3..67c1c28c4 100644 --- a/pkg/cmd/auth/gitcredential/helper.go +++ b/pkg/cmd/auth/gitcredential/helper.go @@ -14,7 +14,7 @@ import ( const tokenUser = "x-access-token" type config interface { - GetWithSource(string, string) (string, string, error) + GetOrDefaultWithSource(string, string) (string, string, error) } type CredentialOptions struct { @@ -101,11 +101,11 @@ func helperRun(opts *CredentialOptions) error { } var gotUser string - gotToken, source, _ := cfg.GetWithSource(wants["host"], "oauth_token") + gotToken, source, _ := cfg.GetOrDefaultWithSource(wants["host"], "oauth_token") if strings.HasSuffix(source, "_TOKEN") { gotUser = tokenUser } else { - gotUser, _, _ = cfg.GetWithSource(wants["host"], "user") + gotUser, _, _ = cfg.GetOrDefaultWithSource(wants["host"], "user") } if gotUser == "" || gotToken == "" { diff --git a/pkg/cmd/auth/gitcredential/helper_test.go b/pkg/cmd/auth/gitcredential/helper_test.go index 7e30ec495..053dd8f69 100644 --- a/pkg/cmd/auth/gitcredential/helper_test.go +++ b/pkg/cmd/auth/gitcredential/helper_test.go @@ -8,12 +8,18 @@ import ( "github.com/cli/cli/v2/pkg/iostreams" ) +// why not just use the config stub argh type tinyConfig map[string]string -func (c tinyConfig) GetWithSource(host, key string) (string, string, error) { +func (c tinyConfig) GetOrDefaultWithSource(host, key string) (string, string, error) { return c[fmt.Sprintf("%s:%s", host, key)], c["_source"], nil } +func (c tinyConfig) GetOrDefault(host, key string) (val string, err error) { + val, _, err = c.GetOrDefaultWithSource(host, key) + return +} + func Test_helperRun(t *testing.T) { tests := []struct { name string diff --git a/pkg/cmd/auth/login/login.go b/pkg/cmd/auth/login/login.go index f591fcbc6..f8896de1a 100644 --- a/pkg/cmd/auth/login/login.go +++ b/pkg/cmd/auth/login/login.go @@ -165,7 +165,7 @@ func loginRun(opts *LoginOptions) error { return cfg.Write() } - existingToken, _ := cfg.Get(hostname, "oauth_token") + existingToken, _ := cfg.GetOrDefault(hostname, "oauth_token") if existingToken != "" && opts.Interactive { if err := shared.HasMinimumScopes(httpClient, hostname, existingToken); err == nil { var keepGoing bool diff --git a/pkg/cmd/auth/logout/logout.go b/pkg/cmd/auth/logout/logout.go index 3873da324..f48e59db2 100644 --- a/pkg/cmd/auth/logout/logout.go +++ b/pkg/cmd/auth/logout/logout.go @@ -127,7 +127,7 @@ func logoutRun(opts *LogoutOptions) error { if err != nil { // suppressing; the user is trying to delete this token and it might be bad. // we'll see if the username is in the config and fall back to that. - username, _ = cfg.Get(hostname, "user") + username, _ = cfg.GetOrDefault(hostname, "user") } usernameStr := "" diff --git a/pkg/cmd/auth/refresh/refresh.go b/pkg/cmd/auth/refresh/refresh.go index f2b9cbbb4..c4b15003e 100644 --- a/pkg/cmd/auth/refresh/refresh.go +++ b/pkg/cmd/auth/refresh/refresh.go @@ -132,7 +132,7 @@ func refreshRun(opts *RefreshOptions) error { } var additionalScopes []string - if oldToken, _ := cfg.Get(hostname, "oauth_token"); oldToken != "" { + if oldToken, _ := cfg.GetOrDefault(hostname, "oauth_token"); oldToken != "" { if oldScopes, err := shared.GetScopes(opts.httpClient, hostname, oldToken); err == nil { for _, s := range strings.Split(oldScopes, ",") { s = strings.TrimSpace(s) @@ -146,7 +146,7 @@ func refreshRun(opts *RefreshOptions) error { credentialFlow := &shared.GitCredentialFlow{ Executable: opts.MainExecutable, } - gitProtocol, _ := cfg.Get(hostname, "git_protocol") + gitProtocol, _ := cfg.GetOrDefault(hostname, "git_protocol") if opts.Interactive && gitProtocol == "https" { if err := credentialFlow.Prompt(hostname); err != nil { return err @@ -159,8 +159,8 @@ func refreshRun(opts *RefreshOptions) error { } if credentialFlow.ShouldSetup() { - username, _ := cfg.Get(hostname, "user") - password, _ := cfg.Get(hostname, "oauth_token") + username, _ := cfg.GetOrDefault(hostname, "user") + password, _ := cfg.GetOrDefault(hostname, "oauth_token") if err := credentialFlow.Setup(hostname, username, password); err != nil { return err } diff --git a/pkg/cmd/auth/shared/login_flow.go b/pkg/cmd/auth/shared/login_flow.go index 0bac49b35..2ba31b1a9 100644 --- a/pkg/cmd/auth/shared/login_flow.go +++ b/pkg/cmd/auth/shared/login_flow.go @@ -15,7 +15,7 @@ import ( ) type iconfig interface { - Get(string, string) (string, error) + GetOrDefault(string, string) (string, error) Set(string, string, string) error Write() error } @@ -147,7 +147,7 @@ func Login(opts *LoginOptions) error { var username string if userValidated { - username, _ = cfg.Get(hostname, "user") + username, _ = cfg.GetOrDefault(hostname, "user") } else { apiClient := api.NewClientFromHTTP(httpClient) var err error diff --git a/pkg/cmd/auth/shared/login_flow_test.go b/pkg/cmd/auth/shared/login_flow_test.go index 530e34045..1290aa176 100644 --- a/pkg/cmd/auth/shared/login_flow_test.go +++ b/pkg/cmd/auth/shared/login_flow_test.go @@ -17,7 +17,7 @@ import ( type tinyConfig map[string]string -func (c tinyConfig) Get(host, key string) (string, error) { +func (c tinyConfig) GetOrDefault(host, key string) (string, error) { return c[fmt.Sprintf("%s:%s", host, key)], nil } diff --git a/pkg/cmd/auth/status/status.go b/pkg/cmd/auth/status/status.go index f84004c87..7196d42bc 100644 --- a/pkg/cmd/auth/status/status.go +++ b/pkg/cmd/auth/status/status.go @@ -92,7 +92,7 @@ func statusRun(opts *StatusOptions) error { } isHostnameFound = true - token, tokenSource, _ := cfg.GetWithSource(hostname, "oauth_token") + token, tokenSource, _ := cfg.GetOrDefaultWithSource(hostname, "oauth_token") tokenIsWriteable := cfg.CheckWriteable(hostname, "oauth_token") == nil statusInfo[hostname] = []string{} @@ -127,7 +127,7 @@ func statusRun(opts *StatusOptions) error { addMsg("%s %s: api call failed: %s", cs.Red("X"), hostname, err) } addMsg("%s Logged in to %s as %s (%s)", cs.SuccessIcon(), hostname, cs.Bold(username), tokenSource) - proto, _ := cfg.Get(hostname, "git_protocol") + proto, _ := cfg.GetOrDefault(hostname, "git_protocol") if proto != "" { addMsg("%s Git operations for %s configured to use %s protocol.", cs.SuccessIcon(), hostname, cs.Bold(proto)) diff --git a/pkg/cmd/config/get/get.go b/pkg/cmd/config/get/get.go index 3a5634458..94694adb2 100644 --- a/pkg/cmd/config/get/get.go +++ b/pkg/cmd/config/get/get.go @@ -53,7 +53,7 @@ func NewCmdConfigGet(f *cmdutil.Factory, runF func(*GetOptions) error) *cobra.Co } func getRun(opts *GetOptions) error { - val, err := opts.Config.Get(opts.Hostname, opts.Key) + val, err := opts.Config.GetOrDefault(opts.Hostname, opts.Key) if err != nil { return err } diff --git a/pkg/cmd/config/get/get_test.go b/pkg/cmd/config/get/get_test.go index 7c5efa9be..f376c773d 100644 --- a/pkg/cmd/config/get/get_test.go +++ b/pkg/cmd/config/get/get_test.go @@ -115,7 +115,7 @@ func Test_getRun(t *testing.T) { assert.NoError(t, err) assert.Equal(t, tt.stdout, stdout.String()) assert.Equal(t, tt.stderr, stderr.String()) - _, err = tt.input.Config.Get("", "_written") + _, err = tt.input.Config.GetOrDefault("", "_written") assert.Error(t, err) }) } diff --git a/pkg/cmd/config/list/list.go b/pkg/cmd/config/list/list.go index 8b1157b1f..c2ad0397b 100644 --- a/pkg/cmd/config/list/list.go +++ b/pkg/cmd/config/list/list.go @@ -59,7 +59,7 @@ func listRun(opts *ListOptions) error { configOptions := config.ConfigOptions() for _, key := range configOptions { - val, err := cfg.Get(host, key.Key) + val, err := cfg.GetOrDefault(host, key.Key) if err != nil { return err } diff --git a/pkg/cmd/config/set/set_test.go b/pkg/cmd/config/set/set_test.go index cdd2e7c94..2beb20edc 100644 --- a/pkg/cmd/config/set/set_test.go +++ b/pkg/cmd/config/set/set_test.go @@ -145,11 +145,11 @@ func Test_setRun(t *testing.T) { assert.Equal(t, tt.stdout, stdout.String()) assert.Equal(t, tt.stderr, stderr.String()) - val, err := tt.input.Config.Get(tt.input.Hostname, tt.input.Key) + val, err := tt.input.Config.GetOrDefault(tt.input.Hostname, tt.input.Key) assert.NoError(t, err) assert.Equal(t, tt.expectedValue, val) - val, err = tt.input.Config.Get("", "_written") + val, err = tt.input.Config.GetOrDefault("", "_written") assert.NoError(t, err) assert.Equal(t, "true", val) }) diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index 691110656..5652fb564 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -337,7 +337,7 @@ func (m *Manager) Install(repo ghrepo.Interface) error { return errors.New("extension is uninstallable: missing executable") } - protocol, _ := m.config.Get(repo.RepoHost(), "git_protocol") + protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol") return m.installGit(ghrepo.FormatRemoteURL(repo, protocol), m.io.Out, m.io.ErrOut) } diff --git a/pkg/cmd/factory/default.go b/pkg/cmd/factory/default.go index 08d93c2be..8c15e0235 100644 --- a/pkg/cmd/factory/default.go +++ b/pkg/cmd/factory/default.go @@ -113,7 +113,7 @@ func browserLauncher(f *cmdutil.Factory) string { cfg, err := f.Config() if err == nil { - if cfgBrowser, _ := cfg.Get("", "browser"); cfgBrowser != "" { + if cfgBrowser, _ := cfg.GetOrDefault("", "browser"); cfgBrowser != "" { return cfgBrowser } } @@ -220,7 +220,7 @@ func ioStreams(f *cmdutil.Factory) *iostreams.IOStreams { return io } - if prompt, _ := cfg.Get("", "prompt"); prompt == "disabled" { + if prompt, _ := cfg.GetOrDefault("", "prompt"); prompt == "disabled" { io.SetNeverPrompt(true) } @@ -230,7 +230,7 @@ func ioStreams(f *cmdutil.Factory) *iostreams.IOStreams { // 3. PAGER if ghPager, ghPagerExists := os.LookupEnv("GH_PAGER"); ghPagerExists { io.SetPager(ghPager) - } else if pager, _ := cfg.Get("", "pager"); pager != "" { + } else if pager, _ := cfg.GetOrDefault("", "pager"); pager != "" { io.SetPager(pager) } diff --git a/pkg/cmd/factory/http.go b/pkg/cmd/factory/http.go index fd61f2dc7..2db083557 100644 --- a/pkg/cmd/factory/http.go +++ b/pkg/cmd/factory/http.go @@ -54,7 +54,7 @@ var timezoneNames = map[int]string{ } type configGetter interface { - Get(string, string) (string, error) + GetOrDefault(string, string) (string, error) } // generic authenticated HTTP client for commands @@ -73,7 +73,7 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg configGetter, appVersion string, // which would use that non-default behavior is right here, and it doesn't // seem worth the cognitive overhead everywhere else just to serve this one // use case. - unixSocket, err := cfg.Get("", "http_unix_socket") + unixSocket, err := cfg.GetOrDefault("", "http_unix_socket") if err != nil { return nil, err } @@ -92,7 +92,7 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg configGetter, appVersion string, api.AddHeader("User-Agent", fmt.Sprintf("GitHub CLI %s", appVersion)), api.AddHeaderFunc("Authorization", func(req *http.Request) (string, error) { hostname := ghinstance.NormalizeHostname(getHost(req)) - if token, err := cfg.Get(hostname, "oauth_token"); err == nil && token != "" { + if token, err := cfg.GetOrDefault(hostname, "oauth_token"); err == nil && token != "" { return fmt.Sprintf("token %s", token), nil } return "", nil diff --git a/pkg/cmd/factory/http_test.go b/pkg/cmd/factory/http_test.go index 1505d1b65..57613bd66 100644 --- a/pkg/cmd/factory/http_test.go +++ b/pkg/cmd/factory/http_test.go @@ -157,7 +157,7 @@ func TestNewHTTPClient(t *testing.T) { type tinyConfig map[string]string -func (c tinyConfig) Get(host, key string) (string, error) { +func (c tinyConfig) GetOrDefault(host, key string) (string, error) { return c[fmt.Sprintf("%s:%s", host, key)], nil } diff --git a/pkg/cmd/factory/remote_resolver.go b/pkg/cmd/factory/remote_resolver.go index 44cd0242d..a197c41a2 100644 --- a/pkg/cmd/factory/remote_resolver.go +++ b/pkg/cmd/factory/remote_resolver.go @@ -83,7 +83,7 @@ func (rr *remoteResolver) Resolver() func() (context.Remotes, error) { dummyHostname := "example.com" // any non-github.com hostname is fine here if config.IsHostEnv(src) { return nil, fmt.Errorf("none of the git remotes configured for this repository correspond to the %s environment variable. Try adding a matching remote or unsetting the variable.", src) - } else if v, src, _ := cfg.GetWithSource(dummyHostname, "oauth_token"); v != "" && config.IsEnterpriseEnv(src) { + } else if v, src, _ := cfg.GetOrDefaultWithSource(dummyHostname, "oauth_token"); v != "" && config.IsEnterpriseEnv(src) { return nil, errors.New("set the GH_HOST environment variable to specify which GitHub host to use") } return nil, errors.New("none of the git remotes configured for this repository point to a known GitHub host. To tell gh about a new GitHub host, please use `gh auth login`") diff --git a/pkg/cmd/gist/clone/clone.go b/pkg/cmd/gist/clone/clone.go index cbd14b324..5127dba64 100644 --- a/pkg/cmd/gist/clone/clone.go +++ b/pkg/cmd/gist/clone/clone.go @@ -79,7 +79,7 @@ func cloneRun(opts *CloneOptions) error { if err != nil { return err } - protocol, err := cfg.Get(hostname, "git_protocol") + protocol, err := cfg.GetOrDefault(hostname, "git_protocol") if err != nil { return err } diff --git a/pkg/cmd/pr/checkout/checkout.go b/pkg/cmd/pr/checkout/checkout.go index e174ccc9b..1063d9f36 100644 --- a/pkg/cmd/pr/checkout/checkout.go +++ b/pkg/cmd/pr/checkout/checkout.go @@ -85,7 +85,7 @@ func checkoutRun(opts *CheckoutOptions) error { if err != nil { return err } - protocol, _ := cfg.Get(baseRepo.RepoHost(), "git_protocol") + protocol, _ := cfg.GetOrDefault(baseRepo.RepoHost(), "git_protocol") remotes, err := opts.Remotes() if err != nil { diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index b9e450e71..9151ceabb 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -701,7 +701,7 @@ func handlePush(opts CreateOptions, ctx CreateContext) error { if err != nil { return err } - cloneProtocol, _ := cfg.Get(headRepo.RepoHost(), "git_protocol") + cloneProtocol, _ := cfg.GetOrDefault(headRepo.RepoHost(), "git_protocol") headRepoURL := ghrepo.FormatRemoteURL(headRepo, cloneProtocol) diff --git a/pkg/cmd/repo/clone/clone.go b/pkg/cmd/repo/clone/clone.go index ebfd65ec1..574159ced 100644 --- a/pkg/cmd/repo/clone/clone.go +++ b/pkg/cmd/repo/clone/clone.go @@ -121,7 +121,7 @@ func cloneRun(opts *CloneOptions) error { return err } - protocol, err = cfg.Get(repo.RepoHost(), "git_protocol") + protocol, err = cfg.GetOrDefault(repo.RepoHost(), "git_protocol") if err != nil { return err } @@ -156,7 +156,7 @@ func cloneRun(opts *CloneOptions) error { // If the repo is a fork, add the parent as an upstream if canonicalRepo.Parent != nil { - protocol, err := cfg.Get(canonicalRepo.Parent.RepoHost(), "git_protocol") + protocol, err := cfg.GetOrDefault(canonicalRepo.Parent.RepoHost(), "git_protocol") if err != nil { return err } diff --git a/pkg/cmd/repo/create/create.go b/pkg/cmd/repo/create/create.go index b8d8c764e..67ef94829 100644 --- a/pkg/cmd/repo/create/create.go +++ b/pkg/cmd/repo/create/create.go @@ -361,7 +361,7 @@ func createFromScratch(opts *CreateOptions) error { } if opts.Clone { - protocol, err := cfg.Get(repo.RepoHost(), "git_protocol") + protocol, err := cfg.GetOrDefault(repo.RepoHost(), "git_protocol") if err != nil { return err } @@ -498,7 +498,7 @@ func createFromLocal(opts *CreateOptions) error { fmt.Fprintln(stdout, repo.URL) } - protocol, err := cfg.Get(repo.RepoHost(), "git_protocol") + protocol, err := cfg.GetOrDefault(repo.RepoHost(), "git_protocol") if err != nil { return err } diff --git a/pkg/cmd/repo/fork/fork.go b/pkg/cmd/repo/fork/fork.go index 773f46641..98fc79e2f 100644 --- a/pkg/cmd/repo/fork/fork.go +++ b/pkg/cmd/repo/fork/fork.go @@ -209,7 +209,7 @@ func forkRun(opts *ForkOptions) error { if err != nil { return err } - protocol, err := cfg.Get(repoToFork.RepoHost(), "git_protocol") + protocol, err := cfg.GetOrDefault(repoToFork.RepoHost(), "git_protocol") if err != nil { return err } diff --git a/pkg/cmd/repo/rename/rename.go b/pkg/cmd/repo/rename/rename.go index d8b0e8123..8bbcc4f9a 100644 --- a/pkg/cmd/repo/rename/rename.go +++ b/pkg/cmd/repo/rename/rename.go @@ -144,7 +144,7 @@ func updateRemote(repo ghrepo.Interface, renamed ghrepo.Interface, opts *RenameO return nil, err } - protocol, err := cfg.Get(repo.RepoHost(), "git_protocol") + protocol, err := cfg.GetOrDefault(repo.RepoHost(), "git_protocol") if err != nil { return nil, err } diff --git a/pkg/cmdutil/auth_check.go b/pkg/cmdutil/auth_check.go index 3da9cfcfd..dc340dc51 100644 --- a/pkg/cmdutil/auth_check.go +++ b/pkg/cmdutil/auth_check.go @@ -24,7 +24,7 @@ func CheckAuth(cfg config.Config) bool { } for _, hostname := range hosts { - token, _ := cfg.Get(hostname, "oauth_token") + token, _ := cfg.GetOrDefault(hostname, "oauth_token") if token != "" { return true } diff --git a/pkg/cmdutil/legacy.go b/pkg/cmdutil/legacy.go index 19400f1cc..617d359b4 100644 --- a/pkg/cmdutil/legacy.go +++ b/pkg/cmdutil/legacy.go @@ -16,7 +16,7 @@ func DetermineEditor(cf func() (config.Config, error)) (string, error) { if err != nil { return "", fmt.Errorf("could not read config: %w", err) } - editorCommand, _ = cfg.Get("", "editor") + editorCommand, _ = cfg.GetOrDefault("", "editor") } return editorCommand, nil From 56522f9f14dda0866c579a9a3fe2072a1a0f60a3 Mon Sep 17 00:00:00 2001 From: nate smith Date: Tue, 11 Jan 2022 14:57:10 -0600 Subject: [PATCH 013/767] formatting --- pkg/cmd/auth/status/status.go | 2 +- pkg/cmd/factory/http_test.go | 4 ++-- pkg/cmd/repo/create/create.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/auth/status/status.go b/pkg/cmd/auth/status/status.go index 7196d42bc..a7578f1e2 100644 --- a/pkg/cmd/auth/status/status.go +++ b/pkg/cmd/auth/status/status.go @@ -35,7 +35,7 @@ func NewCmdStatus(f *cmdutil.Factory, runF func(*StatusOptions) error) *cobra.Co Args: cobra.ExactArgs(0), Short: "View authentication status", Long: heredoc.Doc(`Verifies and displays information about your authentication state. - + This command will test your authentication state for each GitHub host that gh knows about and report on any issues. `), diff --git a/pkg/cmd/factory/http_test.go b/pkg/cmd/factory/http_test.go index 57613bd66..f5e11bd1e 100644 --- a/pkg/cmd/factory/http_test.go +++ b/pkg/cmd/factory/http_test.go @@ -95,10 +95,10 @@ func TestNewHTTPClient(t *testing.T) { > Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview > Authorization: token ████████████████████ > User-Agent: GitHub CLI v1.2.3 - + < HTTP/1.1 204 No Content < Date: