From 1db8bb21f79727bf812976dd7dfbe0e65dc25ae2 Mon Sep 17 00:00:00 2001 From: Eitan Date: Fri, 10 Apr 2026 00:33:36 +0000 Subject: [PATCH 1/3] update nix flake hash commit-id:60390fba --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ea6f6059..efd0e7cb 100644 --- a/flake.nix +++ b/flake.nix @@ -23,7 +23,7 @@ src = self; - vendorHash = "sha256-byl+MF0vlfa4V/3uPrv5Qlcvh5jIozEyUkKSSwlRWhs="; + vendorHash = "sha256-VB7OJ8UkZ0WhEM5l2wR3xA1yxZcr+G+FLt3MxNY83Tg="; subPackages = [ "cmd/spr" From ae1791bd348b84130c57fb33c5eff1716c01a3e7 Mon Sep 17 00:00:00 2001 From: Eitan Date: Fri, 10 Apr 2026 18:45:21 +0000 Subject: [PATCH 2/3] add --fetch flag to git spr update command commit-id:f176bf4b --- cmd/spr/main.go | 24 ++++++++++++++++++------ spr/spr_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/cmd/spr/main.go b/cmd/spr/main.go index dece6055..1854d4a5 100644 --- a/cmd/spr/main.go +++ b/cmd/spr/main.go @@ -195,6 +195,12 @@ VERSION: fork of {{.Version}} if c.IsSet("no-rebase") { cfg.User.NoRebase = c.Bool("no-rebase") } + if c.IsSet("fetch") && c.IsSet("no-fetch") { + return fmt.Errorf("cannot use both --fetch and --no-fetch") + } + if c.IsSet("fetch") { + cfg.User.NoFetch = !c.Bool("fetch") + } if c.IsSet("no-fetch") { cfg.User.NoFetch = c.Bool("no-fetch") } @@ -229,12 +235,18 @@ VERSION: fork of {{.Version}} // layer ops so it is likely relied on as a feature by users at this point EnvVars: []string{"SPR_NOREBASE"}, }, - &cli.BoolFlag{ - Name: "no-fetch", - Aliases: []string{"nf"}, - Usage: "Disable fetch", - EnvVars: []string{"SPR_NOFETCH"}, - }, + &cli.BoolFlag{ + Name: "fetch", + Aliases: []string{"f"}, + Usage: "Enable fetch (overrides noFetch config)", + EnvVars: []string{"SPR_FETCH"}, + }, + &cli.BoolFlag{ + Name: "no-fetch", + Aliases: []string{"nf"}, + Usage: "Disable fetch", + EnvVars: []string{"SPR_NOFETCH"}, + }, }, }, { diff --git a/spr/spr_test.go b/spr/spr_test.go index 0530422c..0379ee70 100644 --- a/spr/spr_test.go +++ b/spr/spr_test.go @@ -974,6 +974,39 @@ func testAmendInvalidInput(t *testing.T, sync bool) { }) } +func TestSPRFetchOverridesNoFetchConfig(t *testing.T) { + // Test that --fetch flag overrides noFetch config (sets NoFetch back to false) + // This simulates: yaml has noFetch: true, user passes --fetch on CLI + s, gitmock, githubmock, _, output := makeTestObjects(t, true) + assert := require.New(t) + ctx := context.Background() + + // Start with NoFetch true (as if loaded from yaml config) + s.config.User.NoFetch = true + // Then override it back to false (as the --fetch flag would do) + s.config.User.NoFetch = false + + c1 := git.Commit{ + CommitID: "00000001", + CommitHash: "c100000000000000000000000000000000000000", + Subject: "test commit 1", + } + + // With NoFetch=false, fetch should run + githubmock.ExpectGetInfo() + gitmock.ExpectFetch() + gitmock.ExpectLogAndRespond([]*git.Commit{&c1}) + gitmock.ExpectPushCommits([]*git.Commit{&c1}) + githubmock.ExpectCreatePullRequest(c1, nil) + githubmock.ExpectUpdatePullRequest(c1, nil) + githubmock.ExpectGetInfo() + s.UpdatePullRequests(ctx, nil, nil) + assert.Equal("[vvvv] 1 : test commit 1\n", output.String()) + gitmock.ExpectationsMet() + githubmock.ExpectationsMet() + output.Reset() +} + func uintptr(a uint) *uint { return &a } From 292b3647a6fc21ff241f80c0e960b7a5ab116bec Mon Sep 17 00:00:00 2001 From: Eitan Date: Sat, 11 Apr 2026 06:14:03 +0000 Subject: [PATCH 3/3] fix double github actions trigger on git spr update commit-id:be3bf397 --- github/githubclient/client.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/github/githubclient/client.go b/github/githubclient/client.go index 4cbb3317..829d8baa 100644 --- a/github/githubclient/client.go +++ b/github/githubclient/client.go @@ -437,10 +437,6 @@ func (c *client) UpdatePullRequest(ctx context.Context, gitcmd git.GitInterface, info *github.GitHubInfo, pullRequests []*github.PullRequest, pr *github.PullRequest, commit git.Commit, prevCommit *git.Commit) { - if c.config.User.LogGitHubCalls { - fmt.Printf("> github update %d : %s\n", pr.Number, pr.Title) - } - baseRefName := c.config.Repo.GitHubBranch if prevCommit != nil { baseRefName = git.BranchNameFromCommit(c.config, *prevCommit) @@ -453,6 +449,26 @@ func (c *client) UpdatePullRequest(ctx context.Context, gitcmd git.GitInterface, templatizer := config_fetcher.PRTemplatizer(c.config, gitcmd) title := templatizer.Title(info, commit) body := templatizer.Body(info, commit, pr) + + // Skip the API call if nothing has actually changed. This avoids + // triggering a spurious pull_request "edited" event on GitHub which + // would cause a second (duplicate) Actions run after the force-push + // already triggered a "synchronize" event. + titleUnchanged := c.config.User.PreserveTitleAndBody || title == pr.Title + bodyUnchanged := c.config.User.PreserveTitleAndBody || body == pr.Body + baseUnchanged := pr.InQueue || baseRefName == pr.ToBranch + if titleUnchanged && bodyUnchanged && baseUnchanged { + log.Debug().Int("number", pr.Number).Msg("UpdatePullRequest: skipping, nothing changed") + if c.config.User.LogGitHubCalls { + fmt.Printf("> github update %d : %s (skipped, no changes)\n", pr.Number, pr.Title) + } + return + } + + if c.config.User.LogGitHubCalls { + fmt.Printf("> github update %d : %s\n", pr.Number, pr.Title) + } + input := genclient.UpdatePullRequestInput{ PullRequestId: pr.ID, Title: &title,