55package pull
66
77import (
8- "bufio"
9- "bytes"
108 "context"
119 "fmt"
1210 "io"
11+ "os"
1312 "regexp"
1413 "strings"
15- "time"
1614
1715 "code.gitea.io/gitea/models"
1816 "code.gitea.io/gitea/models/db"
@@ -30,6 +28,7 @@ import (
3028 repo_module "code.gitea.io/gitea/modules/repository"
3129 "code.gitea.io/gitea/modules/setting"
3230 "code.gitea.io/gitea/modules/sync"
31+ "code.gitea.io/gitea/modules/util"
3332 issue_service "code.gitea.io/gitea/services/issue"
3433)
3534
@@ -352,69 +351,56 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
352351// checkIfPRContentChanged checks if diff to target branch has changed by push
353352// A commit can be considered to leave the PR untouched if the patch/diff with its merge base is unchanged
354353func checkIfPRContentChanged (ctx context.Context , pr * issues_model.PullRequest , oldCommitID , newCommitID string ) (hasChanged bool , err error ) {
355- if err = pr .LoadHeadRepoCtx (ctx ); err != nil {
356- return false , fmt .Errorf ("LoadHeadRepo: %w" , err )
357- } else if pr .HeadRepo == nil {
358- // corrupt data assumed changed
359- return true , nil
360- }
361-
362- if err = pr .LoadBaseRepoCtx (ctx ); err != nil {
363- return false , fmt .Errorf ("LoadBaseRepo: %w" , err )
364- }
365-
366- headGitRepo , err := git .OpenRepository (ctx , pr .HeadRepo .RepoPath ())
354+ tmpBasePath , err := createTemporaryRepo (ctx , pr )
367355 if err != nil {
368- return false , fmt .Errorf ("OpenRepository: %w" , err )
369- }
370- defer headGitRepo .Close ()
371-
372- // Add a temporary remote.
373- tmpRemote := "checkIfPRContentChanged-" + fmt .Sprint (time .Now ().UnixNano ())
374- if err = headGitRepo .AddRemote (tmpRemote , pr .BaseRepo .RepoPath (), true ); err != nil {
375- return false , fmt .Errorf ("AddRemote: %s/%s-%s: %w" , pr .HeadRepo .OwnerName , pr .HeadRepo .Name , tmpRemote , err )
356+ log .Error ("CreateTemporaryRepo: %v" , err )
357+ return false , err
376358 }
377359 defer func () {
378- if err := headGitRepo . RemoveRemote ( tmpRemote ); err != nil {
379- log .Error ("checkIfPRContentChanged: RemoveRemote : %s/%s-%s: %v" , pr . HeadRepo . OwnerName , pr . HeadRepo . Name , tmpRemote , err )
360+ if err := repo_module . RemoveTemporaryPath ( tmpBasePath ); err != nil {
361+ log .Error ("checkIfPRContentChanged: RemoveTemporaryPath : %s" , err )
380362 }
381363 }()
382- // To synchronize repo and get a base ref
383- _ , base , err := headGitRepo . GetMergeBase ( tmpRemote , pr . BaseBranch , pr . HeadBranch )
364+
365+ tmpRepo , err := git . OpenRepository ( ctx , tmpBasePath )
384366 if err != nil {
385- return false , fmt .Errorf ("GetMergeBase : %w" , err )
367+ return false , fmt .Errorf ("OpenRepository : %w" , err )
386368 }
369+ defer tmpRepo .Close ()
387370
388- diffBefore := & bytes.Buffer {}
389- diffAfter := & bytes.Buffer {}
390- if err := headGitRepo .GetDiffFromMergeBase (base , oldCommitID , diffBefore ); err != nil {
391- // If old commit not found, assume changed.
392- log .Debug ("GetDiffFromMergeBase: %v" , err )
393- return true , nil
394- }
395- if err := headGitRepo .GetDiffFromMergeBase (base , newCommitID , diffAfter ); err != nil {
396- // New commit should be found
397- return false , fmt .Errorf ("GetDiffFromMergeBase: %w" , err )
371+ // Find the merge-base
372+ _ , base , err := tmpRepo .GetMergeBase ("" , "base" , "tracking" )
373+ if err != nil {
374+ return false , fmt .Errorf ("GetMergeBase: %w" , err )
398375 }
399376
400- diffBeforeLines := bufio .NewScanner (diffBefore )
401- diffAfterLines := bufio .NewScanner (diffAfter )
402-
403- for diffBeforeLines .Scan () && diffAfterLines .Scan () {
404- if strings .HasPrefix (diffBeforeLines .Text (), "index" ) && strings .HasPrefix (diffAfterLines .Text (), "index" ) {
405- // file hashes can change without the diff changing
406- continue
407- } else if strings .HasPrefix (diffBeforeLines .Text (), "@@" ) && strings .HasPrefix (diffAfterLines .Text (), "@@" ) {
408- // the location of the difference may change
409- continue
410- } else if ! bytes .Equal (diffBeforeLines .Bytes (), diffAfterLines .Bytes ()) {
377+ cmd := git .NewCommand (ctx , "diff" , "--name-only" , "-z" ).AddDynamicArguments (newCommitID , oldCommitID , base )
378+ stdoutReader , stdoutWriter , err := os .Pipe ()
379+ if err != nil {
380+ return false , fmt .Errorf ("unable to open pipe for to run diff: %w" , err )
381+ }
382+
383+ if err := cmd .Run (& git.RunOpts {
384+ Dir : tmpBasePath ,
385+ Stdout : stdoutWriter ,
386+ PipelineFunc : func (ctx context.Context , cancel context.CancelFunc ) error {
387+ _ = stdoutWriter .Close ()
388+ defer func () {
389+ _ = stdoutReader .Close ()
390+ }()
391+ return util .IsEmptyReader (stdoutReader )
392+ },
393+ }); err != nil {
394+ if err == util .ErrNotEmpty {
411395 return true , nil
412396 }
413- }
414397
415- if diffBeforeLines .Scan () || diffAfterLines .Scan () {
416- // Diffs not of equal length
417- return true , nil
398+ log .Error ("Unable to run diff on %s %s %s in tempRepo for PR[%d]%s/%s...%s/%s: Error: %v" ,
399+ newCommitID , oldCommitID , base ,
400+ pr .ID , pr .BaseRepo .FullName (), pr .BaseBranch , pr .HeadRepo .FullName (), pr .HeadBranch ,
401+ err )
402+
403+ return false , fmt .Errorf ("Unable to run git diff --name-only -z %s %s %s: %w" , newCommitID , oldCommitID , base , err )
418404 }
419405
420406 return false , nil
0 commit comments