Merge pull request #3933 from cli/extensions-upgrade

Skip trying to upgrade local extensions
This commit is contained in:
Sam 2021-07-19 10:55:16 -07:00 committed by GitHub
commit 97a52f74cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 12 deletions

View file

@ -1,6 +1,8 @@
package extensions
import (
"errors"
"os"
"path/filepath"
"strings"
)
@ -21,3 +23,20 @@ func (e *Extension) Path() string {
func (e *Extension) URL() string {
return e.url
}
func (e *Extension) IsLocal() bool {
dir := filepath.Dir(e.path)
fileInfo, err := os.Lstat(dir)
if err != nil {
return false
}
// Check if extension is a symlink
if fileInfo.Mode()&os.ModeSymlink != 0 {
return true
}
// Check if extension does not have a git directory
if _, err = os.Stat(filepath.Join(dir, ".git")); errors.Is(err, os.ErrNotExist) {
return true
}
return false
}

View file

@ -136,6 +136,8 @@ func (m *Manager) Install(cloneURL string, stdout, stderr io.Writer) error {
return externalCmd.Run()
}
var localExtensionUpgradeError = errors.New("local extensions can not be upgraded")
func (m *Manager) Upgrade(name string, stdout, stderr io.Writer) error {
exe, err := m.lookPath("git")
if err != nil {
@ -154,6 +156,16 @@ func (m *Manager) Upgrade(name string, stdout, stderr io.Writer) error {
} else if f.Name() != name {
continue
}
if f.IsLocal() {
if name == "" {
fmt.Fprintf(stdout, "%s\n", localExtensionUpgradeError)
} else {
err = localExtensionUpgradeError
}
continue
}
dir := filepath.Dir(f.Path())
externalCmd := m.newCommand(exe, "-C", dir, "--git-dir="+filepath.Join(dir, ".git"), "pull", "--ff-only")
externalCmd.Stdout = stdout

View file

@ -44,8 +44,8 @@ func newTestManager(dir string) *Manager {
func TestManager_List(t *testing.T) {
tempDir := t.TempDir()
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
m := newTestManager(tempDir)
exts := m.List()
@ -57,7 +57,7 @@ func TestManager_List(t *testing.T) {
func TestManager_Dispatch(t *testing.T) {
tempDir := t.TempDir()
extPath := filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")
assert.NoError(t, stubExecutable(extPath))
assert.NoError(t, stubExtension(extPath))
m := newTestManager(tempDir)
@ -77,8 +77,8 @@ func TestManager_Dispatch(t *testing.T) {
func TestManager_Remove(t *testing.T) {
tempDir := t.TempDir()
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
m := newTestManager(tempDir)
err := m.Remove("hello")
@ -90,10 +90,11 @@ func TestManager_Remove(t *testing.T) {
assert.Equal(t, "gh-two", items[0].Name())
}
func TestManager_Upgrade(t *testing.T) {
func TestManager_Upgrade_AllExtensions(t *testing.T) {
tempDir := t.TempDir()
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExecutable(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-hello", "gh-hello")))
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-two", "gh-two")))
assert.NoError(t, stubLocalExtension(filepath.Join(tempDir, "extensions", "gh-local", "gh-local")))
m := newTestManager(tempDir)
@ -105,6 +106,7 @@ func TestManager_Upgrade(t *testing.T) {
assert.Equal(t, heredoc.Docf(
`
[hello]: [git -C %s --git-dir=%s pull --ff-only]
[local]: local extensions can not be upgraded
[two]: [git -C %s --git-dir=%s pull --ff-only]
`,
filepath.Join(tempDir, "extensions", "gh-hello"),
@ -115,6 +117,53 @@ func TestManager_Upgrade(t *testing.T) {
assert.Equal(t, "", stderr.String())
}
func TestManager_Upgrade_RemoteExtension(t *testing.T) {
tempDir := t.TempDir()
assert.NoError(t, stubExtension(filepath.Join(tempDir, "extensions", "gh-remote", "gh-remote")))
m := newTestManager(tempDir)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
err := m.Upgrade("remote", stdout, stderr)
assert.NoError(t, err)
assert.Equal(t, heredoc.Docf(
`
[git -C %s --git-dir=%s pull --ff-only]
`,
filepath.Join(tempDir, "extensions", "gh-remote"),
filepath.Join(tempDir, "extensions", "gh-remote", ".git"),
), stdout.String())
assert.Equal(t, "", stderr.String())
}
func TestManager_Upgrade_LocalExtension(t *testing.T) {
tempDir := t.TempDir()
assert.NoError(t, stubLocalExtension(filepath.Join(tempDir, "extensions", "gh-local", "gh-local")))
m := newTestManager(tempDir)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
err := m.Upgrade("local", stdout, stderr)
assert.EqualError(t, err, "local extensions can not be upgraded")
assert.Equal(t, "", stdout.String())
assert.Equal(t, "", stderr.String())
}
func TestManager_Upgrade_NoExtensions(t *testing.T) {
tempDir := t.TempDir()
m := newTestManager(tempDir)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
err := m.Upgrade("", stdout, stderr)
assert.EqualError(t, err, "no extensions installed")
assert.Equal(t, "", stdout.String())
assert.Equal(t, "", stderr.String())
}
func TestManager_Install(t *testing.T) {
tempDir := t.TempDir()
m := newTestManager(tempDir)
@ -127,7 +176,23 @@ func TestManager_Install(t *testing.T) {
assert.Equal(t, "", stderr.String())
}
func stubExecutable(path string) error {
func stubExtension(path string) error {
dir := filepath.Dir(path)
gitDir := filepath.Join(dir, ".git")
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
if err := os.Mkdir(gitDir, 0755); err != nil {
return err
}
f, err := os.OpenFile(path, os.O_CREATE, 0755)
if err != nil {
return err
}
return f.Close()
}
func stubLocalExtension(path string) error {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}

View file

@ -9,6 +9,7 @@ type Extension interface {
Name() string
Path() string
URL() string
IsLocal() bool
}
//go:generate moq -out manager_mock.go . ExtensionManager

View file

@ -17,6 +17,9 @@ var _ Extension = &ExtensionMock{}
//
// // make and configure a mocked Extension
// mockedExtension := &ExtensionMock{
// IsLocalFunc: func() bool {
// panic("mock out the IsLocal method")
// },
// NameFunc: func() string {
// panic("mock out the Name method")
// },
@ -33,6 +36,9 @@ var _ Extension = &ExtensionMock{}
//
// }
type ExtensionMock struct {
// IsLocalFunc mocks the IsLocal method.
IsLocalFunc func() bool
// NameFunc mocks the Name method.
NameFunc func() string
@ -44,6 +50,9 @@ type ExtensionMock struct {
// calls tracks calls to the methods.
calls struct {
// IsLocal holds details about calls to the IsLocal method.
IsLocal []struct {
}
// Name holds details about calls to the Name method.
Name []struct {
}
@ -54,9 +63,36 @@ type ExtensionMock struct {
URL []struct {
}
}
lockName sync.RWMutex
lockPath sync.RWMutex
lockURL sync.RWMutex
lockIsLocal sync.RWMutex
lockName sync.RWMutex
lockPath sync.RWMutex
lockURL sync.RWMutex
}
// IsLocal calls IsLocalFunc.
func (mock *ExtensionMock) IsLocal() bool {
if mock.IsLocalFunc == nil {
panic("ExtensionMock.IsLocalFunc: method is nil but Extension.IsLocal was just called")
}
callInfo := struct {
}{}
mock.lockIsLocal.Lock()
mock.calls.IsLocal = append(mock.calls.IsLocal, callInfo)
mock.lockIsLocal.Unlock()
return mock.IsLocalFunc()
}
// IsLocalCalls gets all the calls that were made to IsLocal.
// Check the length with:
// len(mockedExtension.IsLocalCalls())
func (mock *ExtensionMock) IsLocalCalls() []struct {
} {
var calls []struct {
}
mock.lockIsLocal.RLock()
calls = mock.calls.IsLocal
mock.lockIsLocal.RUnlock()
return calls
}
// Name calls NameFunc.