diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index add97bb..ce219e9 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -28,7 +28,7 @@ jobs: testing: runs-on: ubuntu-latest - container: golang:1.24-alpine + container: golang:1.25-alpine steps: - name: Checkout repository uses: actions/checkout@v6 diff --git a/plugin.go b/plugin.go index 700af06..7a5774d 100644 --- a/plugin.go +++ b/plugin.go @@ -148,10 +148,19 @@ func (p Plugin) WriteToken() error { } // HandleRemote adds the git remote if required. +// If the remote already exists, it updates the URL instead. func (p Plugin) HandleRemote(ctx context.Context) error { if p.Config.Remote != "" { - if err := execute(repo.RemoteAdd(ctx, p.Config.RemoteName, p.Config.Remote)); err != nil { - return err + if repo.RemoteExists(ctx, p.Config.RemoteName) { + cmd := repo.RemoteSetURL(ctx, p.Config.RemoteName, p.Config.Remote) + if err := execute(cmd); err != nil { + return err + } + } else { + cmd := repo.RemoteAdd(ctx, p.Config.RemoteName, p.Config.Remote) + if err := execute(cmd); err != nil { + return err + } } } diff --git a/plugin_test.go b/plugin_test.go index fe59c0c..a6b35c9 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -2,6 +2,8 @@ package main import ( "context" + "os" + "os/exec" "testing" ) @@ -40,3 +42,63 @@ func TestPlugin_HandleRemote(t *testing.T) { }) } } + +func TestPlugin_HandleRemote_ExistingRemote(t *testing.T) { + // Create a temporary git repo + tmpDir, err := os.MkdirTemp("", "drone-git-push-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + // Save current dir and change to temp dir + origDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer func() { + _ = os.Chdir(origDir) + }() + + if err := os.Chdir(tmpDir); err != nil { + t.Fatal(err) + } + + // Initialize a git repo and add a remote + ctx := context.Background() + if out, err := exec.CommandContext( + ctx, "git", "init", + ).CombinedOutput(); err != nil { + t.Fatalf("git init failed: %s, %v", out, err) + } + if out, err := exec.CommandContext( + ctx, "git", "remote", "add", "origin", + "git@github.com:old/repo.git", + ).CombinedOutput(); err != nil { + t.Fatalf("git remote add failed: %s, %v", out, err) + } + + // HandleRemote should succeed even though "origin" already exists + p := Plugin{ + Config: Config{ + RemoteName: "origin", + Remote: "git@github.com:new/repo.git", + }, + } + if err := p.HandleRemote(ctx); err != nil { + t.Errorf("HandleRemote() with existing remote should not fail, got: %v", err) + } + + // Verify the remote URL was updated + out, err := exec.CommandContext( + ctx, "git", "remote", "get-url", "origin", + ).Output() + if err != nil { + t.Fatal(err) + } + got := string(out) + want := "git@github.com:new/repo.git\n" + if got != want { + t.Errorf("remote URL = %q, want %q", got, want) + } +} diff --git a/repo/remote.go b/repo/remote.go index caae8a6..28c6a83 100644 --- a/repo/remote.go +++ b/repo/remote.go @@ -18,6 +18,17 @@ func RemoteRemove(ctx context.Context, name string) *exec.Cmd { return cmd } +// RemoteExists checks if a named remote already exists in a git repo. +func RemoteExists(ctx context.Context, name string) bool { + cmd := exec.CommandContext( + ctx, + "git", + "remote", + "get-url", + name) + return cmd.Run() == nil +} + // RemoteAdd adds an additional remote to a git repo. func RemoteAdd(ctx context.Context, name, url string) *exec.Cmd { cmd := exec.CommandContext( @@ -31,6 +42,19 @@ func RemoteAdd(ctx context.Context, name, url string) *exec.Cmd { return cmd } +// RemoteSetURL updates the URL of an existing remote in a git repo. +func RemoteSetURL(ctx context.Context, name, url string) *exec.Cmd { + cmd := exec.CommandContext( + ctx, + "git", + "remote", + "set-url", + name, + url) + + return cmd +} + // RemotePush pushs the changes from the local head to a remote branch.. func RemotePush(ctx context.Context, remote, branch string, force, followtags bool) *exec.Cmd { return RemotePushNamedBranch(ctx, remote, "HEAD", branch, force, followtags) diff --git a/repo/remote_test.go b/repo/remote_test.go index 395de8f..dcc1c6b 100644 --- a/repo/remote_test.go +++ b/repo/remote_test.go @@ -1,6 +1,7 @@ package repo import ( + "context" "testing" ) @@ -45,3 +46,17 @@ func TestSanitizeInput(t *testing.T) { }) } } + +func TestRemoteSetURL(t *testing.T) { + cmd := RemoteSetURL(context.Background(), "origin", "git@github.com:user/repo.git") + args := cmd.Args + expected := []string{"git", "remote", "set-url", "origin", "git@github.com:user/repo.git"} + if len(args) != len(expected) { + t.Fatalf("expected %d args, got %d", len(expected), len(args)) + } + for i, arg := range args { + if arg != expected[i] { + t.Errorf("arg[%d] = %q, want %q", i, arg, expected[i]) + } + } +}