Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .goreleaser.stable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,29 @@ changelog:
- title: Other
order: 999

brews:
homebrew_casks:
- name: git-rain
repository:
owner: git-fire
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
pull_request:
enabled: false
directory: Formula
commit_author:
name: goreleaserbot
email: bot@goreleaser.com
commit_msg_template: "chore: update git-rain to {{ .Tag }}"
homepage: "https://github.com/git-fire/git-rain"
description: "Sync local git repositories from their remotes — the reverse of git-fire"
license: MIT
install: bin.install "git-rain"
test: system "#{bin}/git-rain", "--version"
binaries:
- git-rain
hooks:
post:
install: |
if OS.mac?
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/git-rain"]
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Homebrew gate expects Formula

High Severity

Stable release config now publishes homebrew_casks (Cask under Casks/) instead of brews (Formula/git-rain.rb), but the release workflow still waits for Formula/git-rain.rb to update. GoReleaser can succeed while the Homebrew verify step times out and fails the release.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3983ecb. Configure here.


release:
github:
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ func fetchOnly(repoPath string, opts git.RainOptions) error {
}
cmd := exec.Command("git", fetchArgs...)
cmd.Dir = repoPath
git.PrepareNetworkGit(cmd)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%s: %w (output: %s)", strings.Join(append([]string{"git"}, fetchArgs...), " "), err, strings.TrimSpace(string(out)))
}
Expand Down
1 change: 1 addition & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ func TestFetchFailureMessage(t *testing.T) {
{"authentication", "Authentication failed for git@github.com", "could not authenticate with remote — check your credentials and try again"},
{"permission denied", "git@github.com: Permission denied (publickey)", "could not authenticate with remote — check your credentials and try again"},
{"could not read", "fatal: could not read from remote", "could not authenticate with remote — check your credentials and try again"},
{"terminal prompts disabled", "fatal: could not read Username for 'https://github.com': terminal prompts disabled", "could not authenticate with remote — check your credentials and try again"},
{"401", "fatal: HTTP 401: Unauthorized", "could not authenticate with remote — check your credentials and try again"},
{"403", "fatal: HTTP 403 forbidden", "could not authenticate with remote — check your credentials and try again"},
{"could not resolve", "fatal: unable to access ...: Could not resolve host", "could not reach remote — check your network and try again"},
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/charmbracelet/bubbles v1.0.0
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
github.com/git-fire/git-harness v0.3.1
github.com/git-fire/git-testkit v0.2.0
github.com/gofrs/flock v0.12.1
github.com/mattn/go-runewidth v0.0.19
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/git-fire/git-harness v0.3.1 h1:+fCQ9nMS3YI7r9iVGrU95oefH8N86XjxcYSqsin/1aE=
github.com/git-fire/git-harness v0.3.1/go.mod h1:cNvjYdbowpoO/KdJwtGenhySx+EkgoQJujuANJpRpj4=
github.com/git-fire/git-testkit v0.2.0 h1:IFzOxMdNTE5A4lnzbFz62h2R44+3qVy27Xj1KWyGi1Y=
github.com/git-fire/git-testkit v0.2.0/go.mod h1:YlJlkY9JfGdYTe9o9W3l+gv9BPj05FGu6HK36Z5jwVA=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
Expand Down
13 changes: 13 additions & 0 deletions internal/git/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package git

import (
"os/exec"

harnessgit "github.com/git-fire/git-harness/git"
)

// PrepareNetworkGit configures cmd for fetch/push operations that may contact
// a remote. Delegates to git-harness so credential behavior stays aligned with git-fire.
func PrepareNetworkGit(cmd *exec.Cmd) {
harnessgit.PrepareNetworkGit(cmd)
}
39 changes: 39 additions & 0 deletions internal/git/command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package git

import (
"os/exec"
"strings"
"testing"

testutil "github.com/git-fire/git-testkit"
)

func TestFetchFailureReason_TerminalPromptsDisabled(t *testing.T) {
got := fetchFailureReason([]byte("fatal: could not read Username for 'https://github.com': terminal prompts disabled"))
want := "could not authenticate with remote — check your credentials and try again"
if got != want {
t.Fatalf("fetchFailureReason() = %q, want %q", got, want)
}
}

func TestNetworkFetch_UnauthenticatedHTTPSFailsWithoutPrompt(t *testing.T) {
repo := testutil.CreateTestRepo(t, testutil.RepoOptions{
Name: "https-fetch-repo",
Remotes: map[string]string{
"origin": "https://github.com/git-rain/nonexistent-repo-auth-test.git",
},
})

cmd := exec.Command("git", "fetch", "--all")
cmd.Dir = repo
PrepareNetworkGit(cmd)
output, err := cmd.CombinedOutput()
if err == nil {
t.Fatal("expected fetch to fail without credentials")
}
msg := strings.ToLower(string(output) + " " + err.Error())
if !strings.Contains(msg, "terminal prompts disabled") &&
!strings.Contains(msg, "could not read username") {
t.Fatalf("expected non-interactive auth failure, got output=%q err=%v", strings.TrimSpace(string(output)), err)
}
}
1 change: 1 addition & 0 deletions internal/git/fetch_mainline.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ func MainlineFetchRemotes(repoPath string, opts RainOptions) (RainResult, error)
}
cmd := exec.Command("git", args...)
cmd.Dir = repoPath
PrepareNetworkGit(cmd)
if output, err := cmd.CombinedOutput(); err != nil {
failedReason[remote] = fetchFailureReason(output)
}
Expand Down
1 change: 1 addition & 0 deletions internal/git/rain.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ func RainRepository(repoPath string, opts RainOptions) (RainResult, error) {
}
cmd := exec.Command("git", fetchArgs...)
cmd.Dir = repoPath
PrepareNetworkGit(cmd)
if output, fetchErr := cmd.CombinedOutput(); fetchErr != nil {
// Freeze gracefully — could not reach remote (auth, network, etc.).
// This is not a hard failure; the repo is untouched. Try again later.
Expand Down
Loading