Compare commits

...

32 Commits

Author SHA1 Message Date
hiifong
a55e59a6ed
Merge 009a1df2e602e242c2459895d43be8767beeffd1 into 21af8150b7ba315a9f75264ab77813b0b7c697a8 2025-02-20 08:34:46 +08:00
GiteaBot
21af8150b7 [skip ci] Updated translations via Crowdin 2025-02-20 00:32:10 +00:00
ericLemanissier
40faa6dc78
git graph: don't show detached commits (#33645)
Some checks failed
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-docker-rootful (push) Has been cancelled
release-nightly / nightly-docker-rootless (push) Has been cancelled
Current git graph is not usable for mirrors of repos having a lot of
PRs, as can be seen at
https://demo.gitea.com/ericLemanissier/conan-center-index/graph

![image](https://github.com/user-attachments/assets/ace40dd2-3eea-4d69-8e19-10fb7224e326)


Manually running `git log --graph --date-order --all` on such a repo
indeed shows:
```
*   commit c4a34bd39d7977c8630177c5f88507000ea3e943
|\  Merge: a4bbd3ad6b 35a102c77c
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 08:36:41 2025 +0000
| |
| |     Merge 35a102c77cbc38d84baca0ca63466fb410336ea8 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| |
| * commit 35a102c77cbc38d84baca0ca63466fb410336ea8
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 17:36:35 2025 +0900
| |
| |     update 4.4.2
| |
| | * commit 5d610f4fd3c0428731e402a2f618fad9ce055875
| |/| Merge: a4bbd3ad6b fe916fb70a
|/| | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:30 2025 +0000
| | |
| | |     Merge fe916fb70a8bf49503cce70a5c7124bcc4314ddc into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | |
| | * commit fe916fb70a8bf49503cce70a5c7124bcc4314ddc
| | | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:18 2025 +0000
| | |
| | |     Remove parquet cmakelist patch
| | |
| | | * commit 9f6d2759d650ec3c86d01bb940e829e7e14220c2
| |_|/| Merge: a4bbd3ad6b f0963429b0
|/| | | Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
| | | | Date:   Wed Feb 19 08:03:08 2025 +0100
| | | |
| | | |     Merge f0963429b0952499da0da7e559f8d53387097307 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | | |
| | | * commit f0963429b0952499da0da7e559f8d53387097307
| |_|/  Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
|/| |   Date:   Wed Feb 19 08:01:43 2025 +0100
| | |
| | |       added cwt-cucumber 2.5
| | |
```

On the other hand, running `git log --graph --date-order --branches
--tags` returns the expected:
```
* commit a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98 (HEAD -> master)
| Author: Dan <mstr.danila@gmail.com>
| Date:   Fri Feb 14 18:46:11 2025 +0200
|
|     grpc: add version 1.69.0 (#26446)
|
|     * grpc: add version 1.69.0
|
|     * add cmake tool requires
|
|     ---------
|
|     Co-authored-by: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
|
* commit a7868807cb2e21206ebf95278cb588f29a3e2205
| Author: Guillaume Egles <gegles@users.noreply.github.com>
| Date:   Thu Feb 13 05:44:35 2025 -0800
|
|     openssl: add versions `3.0.16`, `3.1.8`, `3.2.4`, `3.3.3`, `3.4.1`, stop publishing revisions for version `3.0.15` (#26578)
|
* commit 86057d3e63ac71e2fe48c07bb301f2d54187044d
| Author: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
| Date:   Thu Feb 13 13:34:41 2025 +0000
|
|     android-ndk: dont set LD and AS variables (#26581)
|
|     * android-ndk: dont set LD and AS variables
|
|     * android-ndk: refactor test package
|
* commit 123e382fafd2f5e811e10faac02efc275c45ec2a
| Author: Nikita <root.kidik@gmail.com>
| Date:   Thu Feb 13 12:29:39 2025 +0300
|
|     libffi: fix conditionals when building on Windows (#26500)
|
|     * fix: add missing or `clang`
|
|     * fix: libffi - always require as tool `automake`
```
2025-02-19 10:35:08 -08:00
hiifong
009a1df2e6
Merge branch 'main' into agit/update 2025-01-15 09:30:43 +08:00
hiifong
59f37ce829
Merge branch 'main' into agit/update 2025-01-14 19:38:44 +08:00
hiifong
d4f237934f
Merge branch 'main' into agit/update 2025-01-13 17:47:07 +08:00
hiifong
2242557930
Merge branch 'main' into agit/update 2025-01-13 14:14:51 +08:00
hiifong
fec0b43e78
Merge branch 'main' into agit/update 2025-01-12 19:06:07 +08:00
hiifong
14c7ebe688
Merge branch 'main' into agit/update 2025-01-12 13:16:52 +08:00
hiifong
4c8ea3d767
Merge branch 'main' into agit/update 2025-01-12 13:12:58 +08:00
hiifong
56b13519e4
Remove 2025-01-12 13:09:08 +08:00
hiifong
e875cbab8c
Merge branch 'main' into agit/update 2025-01-12 08:46:01 +08:00
hiifong
3b2aef2940
Merge branch 'main' into agit/update 2025-01-12 08:18:08 +08:00
hiifong
a041057909
Fix 2025-01-11 16:03:43 +08:00
hiifong
30713a6370
Fix 2025-01-11 15:54:34 +08:00
hiifong
013d437373
Merge remote-tracking branch 'refs/remotes/origin/agit/update' into agit/update 2025-01-11 15:49:22 +08:00
hiifong
1660737ec8
Fix 2025-01-11 15:48:13 +08:00
hiifong
3e0c5302fa
Merge branch 'main' into agit/update 2025-01-11 01:00:13 +08:00
hiifong
cdea3574a8
Merge branch 'main' into agit/update 2025-01-10 14:50:42 +08:00
hiifong
930d8cbe07
Merge branch 'main' into agit/update 2025-01-10 10:46:03 +08:00
hiifong
b99fe1cf79 Update 2025-01-10 10:45:32 +08:00
hiifong
35a2b9b3a5
Update 2025-01-09 22:51:27 +08:00
hiifong
cab9bbccf2
fix 2025-01-09 22:00:16 +08:00
hiifong
06c5f30fc4
Merge branch 'main' into agit/update
# Conflicts:
#	modules/git/git.go
#	services/agit/agit.go
#	templates/repo/issue/view_content/sidebar.tmpl
2025-01-09 21:25:54 +08:00
hiifong
bd501a625c Update forReiewPattern 2025-01-09 15:06:52 +08:00
a1012112796
e371a21b95
split updateExistPull
Signed-off-by: a1012112796 <1012112796@qq.com>
2024-10-09 18:37:00 +08:00
a1012112796
125e7ae53b
Merge remote-tracking branch 'origin/main' into zzc/dev/agit_2 2024-10-09 18:20:21 +08:00
silverwind
1685a35363
Merge branch 'main' into zzc/dev/agit_2 2024-06-18 00:48:10 +02:00
silverwind
09daf03bb8
Merge branch 'main' into zzc/dev/agit_2 2024-06-07 04:37:10 +02:00
a1012112796
695bafe882
Merge remote-tracking branch 'origin/main' into zzc/dev/agit_2 2024-06-05 00:32:13 +00:00
a1012112796
a5b38fc7a9
fix lint
Signed-off-by: a1012112796 <1012112796@qq.com>
2024-06-05 00:31:22 +00:00
a1012112796
70d2872ff2
agit flow add refs/for-review/<pull index> support
Signed-off-by: a1012112796 <1012112796@qq.com>
2024-06-04 13:09:13 +00:00
12 changed files with 324 additions and 75 deletions

View File

@ -239,7 +239,8 @@ func runServ(c *cli.Context) error {
if git.DefaultFeatures().SupportProcReceive { if git.DefaultFeatures().SupportProcReceive {
// for AGit Flow // for AGit Flow
if cmd == "ssh_info" { if cmd == "ssh_info" {
fmt.Print(`{"type":"gitea","version":1}`) data := private.GetSSHInfo(ctx)
fmt.Println(data)
return nil return nil
} }
} }

View File

@ -40,35 +40,41 @@ func syncGitConfig() (err error) {
} }
// Set git some configurations - these must be set to these values for gitea to work correctly // Set git some configurations - these must be set to these values for gitea to work correctly
if err := configSet("core.quotePath", "false"); err != nil { if err = configSet("core.quotePath", "false"); err != nil {
return err return err
} }
if DefaultFeatures().CheckVersionAtLeast("2.10") { if DefaultFeatures().CheckVersionAtLeast("2.10") {
if err := configSet("receive.advertisePushOptions", "true"); err != nil { if err = configSet("receive.advertisePushOptions", "true"); err != nil {
return err return err
} }
} }
if DefaultFeatures().CheckVersionAtLeast("2.18") { if DefaultFeatures().CheckVersionAtLeast("2.18") {
if err := configSet("core.commitGraph", "true"); err != nil { if err = configSet("core.commitGraph", "true"); err != nil {
return err return err
} }
if err := configSet("gc.writeCommitGraph", "true"); err != nil { if err = configSet("gc.writeCommitGraph", "true"); err != nil {
return err return err
} }
if err := configSet("fetch.writeCommitGraph", "true"); err != nil { if err = configSet("fetch.writeCommitGraph", "true"); err != nil {
return err return err
} }
} }
if DefaultFeatures().SupportProcReceive { if DefaultFeatures().SupportProcReceive {
// set support for AGit flow // set support for AGit flow
if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { if err = configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil {
return err
}
if err = configAddNonExist("receive.procReceiveRefs", "refs/for-review"); err != nil {
return err return err
} }
} else { } else {
if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil { if err = configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil {
return err
}
if err = configUnsetAll("receive.procReceiveRefs", "refs/for-review"); err != nil {
return err return err
} }
} }

View File

@ -67,7 +67,8 @@ func (ref *Reference) RefGroup() string {
// or refs/for/<targe-branch> -o topic='<topic-branch>' // or refs/for/<targe-branch> -o topic='<topic-branch>'
const ForPrefix = "refs/for/" const ForPrefix = "refs/for/"
// TODO: /refs/for-review for suggest change interface // ForReviewPrefix special ref to update a pull request: refs/for-review/<pull index>
const ForReviewPrefix = "refs/for-review/"
// RefName represents a full git reference name // RefName represents a full git reference name
type RefName string type RefName string
@ -108,6 +109,12 @@ func (ref RefName) IsFor() bool {
return strings.HasPrefix(string(ref), ForPrefix) return strings.HasPrefix(string(ref), ForPrefix)
} }
var forReviewPattern = regexp.MustCompile(ForReviewPrefix + `[1-9]\d*$`)
func (ref RefName) IsForReview() bool {
return forReviewPattern.MatchString(string(ref))
}
func (ref RefName) nameWithoutPrefix(prefix string) string { func (ref RefName) nameWithoutPrefix(prefix string) string {
if strings.HasPrefix(string(ref), prefix) { if strings.HasPrefix(string(ref), prefix) {
return strings.TrimPrefix(string(ref), prefix) return strings.TrimPrefix(string(ref), prefix)

View File

@ -28,6 +28,18 @@ func TestRefName(t *testing.T) {
assert.Equal(t, "main", RefName("refs/for/main").ForBranchName()) assert.Equal(t, "main", RefName("refs/for/main").ForBranchName())
assert.Equal(t, "my/branch", RefName("refs/for/my/branch").ForBranchName()) assert.Equal(t, "my/branch", RefName("refs/for/my/branch").ForBranchName())
// Test for review name
assert.False(t, RefName("refs/for-review/").IsForReview())
assert.False(t, RefName("refs/for-review/-1").IsForReview())
assert.False(t, RefName("refs/for-review/0").IsForReview())
assert.False(t, RefName("refs/for-review/01").IsForReview())
assert.True(t, RefName("refs/for-review/1").IsForReview())
assert.True(t, RefName("refs/for-review/10").IsForReview())
assert.True(t, RefName("refs/for-review/10999").IsForReview())
assert.False(t, RefName("refs/for-review/a10").IsForReview())
assert.False(t, RefName("refs/for-review/10a").IsForReview())
assert.False(t, RefName("refs/for-review/abc").IsForReview())
// Test commit hashes. // Test commit hashes.
assert.Equal(t, "c0ffee", RefName("c0ffee").ShortName()) assert.Equal(t, "c0ffee", RefName("c0ffee").ShortName())
} }

View File

@ -12,6 +12,7 @@ import (
"strconv" "strconv"
"time" "time"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
) )
@ -36,6 +37,32 @@ func ReloadTemplates(ctx context.Context) ResponseExtra {
return requestJSONClientMsg(req, "Reloaded") return requestJSONClientMsg(req, "Reloaded")
} }
// Shutdown calls the internal shutdown function
func GetSSHInfo(ctx context.Context) string {
reqURL := setting.LocalURL + "ssh_info"
req := newInternalRequest(ctx, reqURL, "GET")
resp, err := req.Response()
if err != nil {
log.Error("GetSSHInfo Error: %v", err)
return ""
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Error("response status code is not OK, code: %d", resp.StatusCode)
return ""
}
content, err := io.ReadAll(resp.Body)
if err != nil {
log.Error("read body error: %v", err)
return ""
}
return string(content)
}
// FlushOptions represents the options for the flush call // FlushOptions represents the options for the flush call
type FlushOptions struct { type FlushOptions struct {
Timeout time.Duration Timeout time.Duration

View File

@ -1701,7 +1701,9 @@ issues.time_estimate_invalid=O formato da estimativa de tempo é inválido
issues.start_tracking_history=começou a trabalhar %s issues.start_tracking_history=começou a trabalhar %s
issues.tracker_auto_close=O cronómetro será parado automaticamente quando esta questão for fechada issues.tracker_auto_close=O cronómetro será parado automaticamente quando esta questão for fechada
issues.tracking_already_started=`Você já iniciou a contagem de tempo <a href="%s">noutra questão</a>!` issues.tracking_already_started=`Você já iniciou a contagem de tempo <a href="%s">noutra questão</a>!`
issues.stop_tracking=Parar cronómetro
issues.stop_tracking_history=trabalhou durante <b>%[1]s</b> %[2]s issues.stop_tracking_history=trabalhou durante <b>%[1]s</b> %[2]s
issues.cancel_tracking=Descartar
issues.cancel_tracking_history=`cancelou a contagem de tempo %s` issues.cancel_tracking_history=`cancelou a contagem de tempo %s`
issues.del_time=Eliminar este registo de tempo issues.del_time=Eliminar este registo de tempo
issues.add_time_history=adicionou <b>%[1]s</b> de tempo gasto %[2]s issues.add_time_history=adicionou <b>%[1]s</b> de tempo gasto %[2]s

View File

@ -4,9 +4,12 @@
package private package private
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"strconv"
"strings"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
@ -123,6 +126,8 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
preReceiveTag(ourCtx, refFullName) preReceiveTag(ourCtx, refFullName)
case git.DefaultFeatures().SupportProcReceive && refFullName.IsFor(): case git.DefaultFeatures().SupportProcReceive && refFullName.IsFor():
preReceiveFor(ourCtx, refFullName) preReceiveFor(ourCtx, refFullName)
case git.DefaultFeatures().SupportProcReceive && refFullName.IsForReview():
preReceiveForReview(ourCtx, refFullName)
default: default:
ourCtx.AssertCanWriteCode() ourCtx.AssertCanWriteCode()
} }
@ -468,6 +473,80 @@ func preReceiveFor(ctx *preReceiveContext, refFullName git.RefName) {
} }
} }
func canUpdateAgitPull(ctx *preReceiveContext, pull *issues_model.PullRequest) error {
if pull.Flow != issues_model.PullRequestFlowAGit {
return errors.New("Pull request that are not created through agit cannot be updated using agit")
}
if ctx.opts.UserID == pull.Issue.PosterID {
return nil
}
if !pull.AllowMaintainerEdit {
return fmt.Errorf("The author does not allow maintainers to edit this pull request")
}
if !ctx.loadPusherAndPermission() {
return fmt.Errorf("Internal Server Error (no specific error)")
}
if ctx.userPerm.CanWrite(unit.TypeCode) {
return errors.New("You have no permission to update this pull request")
}
return nil
}
func preReceiveForReview(ctx *preReceiveContext, refFullName git.RefName) {
if !ctx.AssertCreatePullRequest() {
return
}
if ctx.Repo.Repository.IsEmpty {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Can't create pull request for an empty repository.",
})
return
}
if ctx.opts.IsWiki {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Pull requests are not supported on the wiki.",
})
return
}
pullIndex, err := strconv.ParseInt(strings.TrimPrefix(string(refFullName), git.ForReviewPrefix), 10, 64)
if err != nil {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Unknow pull request index.",
})
return
}
pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex)
if err != nil {
log.Error("preReceiveForReview: GetPullRequestByIndex: err: %v", err)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Unknow pull request index.",
})
return
}
err = pull.LoadIssue(ctx)
if err != nil {
log.Error("preReceiveForReview: pull.LoadIssue: err: %v", err)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Unknow pull request.",
})
return
}
if err := canUpdateAgitPull(ctx, pull); err != nil {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: err.Error(),
})
return
}
}
func generateGitEnv(opts *private.HookOptions) (env []string) { func generateGitEnv(opts *private.HookOptions) (env []string) {
env = os.Environ() env = os.Environ()
if opts.GitAlternativeObjectDirectories != "" { if opts.GitAlternativeObjectDirectories != "" {

View File

@ -20,7 +20,7 @@ func SSHInfo(rw http.ResponseWriter, req *http.Request) {
return return
} }
rw.Header().Set("content-type", "text/json;charset=UTF-8") rw.Header().Set("content-type", "text/json;charset=UTF-8")
_, err := rw.Write([]byte(`{"type":"gitea","version":1}`)) _, err := rw.Write([]byte(`{"type":"gitea","version":2}`))
if err != nil { if err != nil {
log.Error("fail to write result: err: %v", err) log.Error("fail to write result: err: %v", err)
rw.WriteHeader(http.StatusInternalServerError) rw.WriteHeader(http.StatusInternalServerError)

View File

@ -7,6 +7,7 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
@ -20,6 +21,84 @@ import (
pull_service "code.gitea.io/gitea/services/pull" pull_service "code.gitea.io/gitea/services/pull"
) )
type updateExistPullOption struct {
ctx context.Context
pr *issues_model.PullRequest
gitRepo *git.Repository
repo *repo_model.Repository
forcePush bool
pusher *user_model.User
RefFullName git.RefName
OldCommitID string
NewCommitID string
}
func updateExistPull(opts *updateExistPullOption) (*private.HookProcReceiveRefResult, error) {
// update exist pull request
if err := opts.pr.LoadBaseRepo(opts.ctx); err != nil {
return nil, fmt.Errorf("unable to load base repository for PR[%d] Error: %w", opts.pr.ID, err)
}
oldCommitID, err := opts.gitRepo.GetRefCommitID(opts.pr.GetGitRefName())
if err != nil {
return nil, fmt.Errorf("unable to get ref commit id in base repository for PR[%d] Error: %w", opts.pr.ID, err)
}
if oldCommitID == opts.NewCommitID {
return &private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullName,
OldOID: opts.OldCommitID,
NewOID: opts.NewCommitID,
Err: "new commit is same with old commit",
}, nil
}
if !opts.forcePush {
output, _, err := git.NewCommand(opts.ctx, "rev-list", "--max-count=1").
AddDynamicArguments(oldCommitID, "^"+opts.NewCommitID).
RunStdString(&git.RunOpts{Dir: opts.repo.RepoPath(), Env: os.Environ()})
if err != nil {
return nil, fmt.Errorf("failed to detect force push: %w", err)
} else if len(output) > 0 {
return &private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullName,
OldOID: opts.OldCommitID,
NewOID: opts.NewCommitID,
Err: "request `force-push` push option",
}, nil
}
}
opts.pr.HeadCommitID = opts.NewCommitID
if err = pull_service.UpdateRef(opts.ctx, opts.pr); err != nil {
return nil, fmt.Errorf("failed to update pull ref. Error: %w", err)
}
pull_service.AddToTaskQueue(opts.ctx, opts.pr)
err = opts.pr.LoadIssue(opts.ctx)
if err != nil {
return nil, fmt.Errorf("failed to load pull issue. Error: %w", err)
}
comment, err := pull_service.CreatePushPullComment(opts.ctx, opts.pusher, opts.pr, oldCommitID, opts.NewCommitID)
if err == nil && comment != nil {
notify_service.PullRequestPushCommits(opts.ctx, opts.pusher, opts.pr, comment)
}
notify_service.PullRequestSynchronized(opts.ctx, opts.pusher, opts.pr)
isForcePush := comment != nil && comment.IsForcePush
return &private.HookProcReceiveRefResult{
OldOID: oldCommitID,
NewOID: opts.NewCommitID,
Ref: opts.pr.GetGitRefName(),
OriginalRef: opts.RefFullName,
IsForcePush: isForcePush,
IsCreatePR: false,
URL: fmt.Sprintf("%s/pulls/%d", opts.repo.HTMLURL(), opts.pr.Index),
ShouldShowMessage: setting.Git.PullRequestPushMessage && opts.repo.AllowsPulls(opts.ctx),
}, nil
}
// ProcReceive handle proc receive work // ProcReceive handle proc receive work
func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts *private.HookOptions) ([]private.HookProcReceiveRefResult, error) { func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts *private.HookOptions) ([]private.HookProcReceiveRefResult, error) {
results := make([]private.HookProcReceiveRefResult, 0, len(opts.OldCommitIDs)) results := make([]private.HookProcReceiveRefResult, 0, len(opts.OldCommitIDs))
@ -46,6 +125,49 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
continue continue
} }
if opts.RefFullNames[i].IsForReview() {
// try match refs/for-review/<pull index>
pullIndex, err := strconv.ParseInt(strings.TrimPrefix(string(opts.RefFullNames[i]), git.ForReviewPrefix), 10, 64)
if err != nil {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
NewOID: opts.NewCommitIDs[i],
Err: "Unknow pull request index",
})
continue
}
log.Trace("Pull request index: %d", pullIndex)
pull, err := issues_model.GetPullRequestByIndex(ctx, repo.ID, pullIndex)
if err != nil {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
NewOID: opts.NewCommitIDs[i],
Err: "Unknow pull request index",
})
continue
}
result, err := updateExistPull(&updateExistPullOption{
ctx: ctx,
pr: pull,
gitRepo: gitRepo,
repo: repo,
forcePush: forcePush.Value(),
pusher: pusher,
RefFullName: opts.RefFullNames[i],
OldCommitID: opts.OldCommitIDs[i],
NewCommitID: opts.NewCommitIDs[i],
})
if err != nil {
return nil, err
}
results = append(results, *result)
continue
}
if !opts.RefFullNames[i].IsFor() { if !opts.RefFullNames[i].IsFor() {
results = append(results, private.HookProcReceiveRefResult{ results = append(results, private.HookProcReceiveRefResult{
IsNotMatched: true, IsNotMatched: true,
@ -161,70 +283,21 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
continue continue
} }
// update exist pull request result, err := updateExistPull(&updateExistPullOption{
if err := pr.LoadBaseRepo(ctx); err != nil { ctx: ctx,
return nil, fmt.Errorf("unable to load base repository for PR[%d] Error: %w", pr.ID, err) pr: pr,
} gitRepo: gitRepo,
repo: repo,
oldCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName()) forcePush: forcePush.Value(),
if err != nil { pusher: pusher,
return nil, fmt.Errorf("unable to get ref commit id in base repository for PR[%d] Error: %w", pr.ID, err) RefFullName: opts.RefFullNames[i],
} OldCommitID: opts.OldCommitIDs[i],
NewCommitID: opts.NewCommitIDs[i],
if oldCommitID == opts.NewCommitIDs[i] {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
NewOID: opts.NewCommitIDs[i],
Err: "new commit is same with old commit",
})
continue
}
if !forcePush.Value() {
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").
AddDynamicArguments(oldCommitID, "^"+opts.NewCommitIDs[i]).
RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: os.Environ()})
if err != nil {
return nil, fmt.Errorf("failed to detect force push: %w", err)
} else if len(output) > 0 {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
NewOID: opts.NewCommitIDs[i],
Err: "request `force-push` push option",
})
continue
}
}
pr.HeadCommitID = opts.NewCommitIDs[i]
if err = pull_service.UpdateRef(ctx, pr); err != nil {
return nil, fmt.Errorf("failed to update pull ref. Error: %w", err)
}
pull_service.AddToTaskQueue(ctx, pr)
err = pr.LoadIssue(ctx)
if err != nil {
return nil, fmt.Errorf("failed to load pull issue. Error: %w", err)
}
comment, err := pull_service.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i])
if err == nil && comment != nil {
notify_service.PullRequestPushCommits(ctx, pusher, pr, comment)
}
notify_service.PullRequestSynchronized(ctx, pusher, pr)
isForcePush := comment != nil && comment.IsForcePush
results = append(results, private.HookProcReceiveRefResult{
OldOID: oldCommitID,
NewOID: opts.NewCommitIDs[i],
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
IsForcePush: isForcePush,
IsCreatePR: false,
URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx),
}) })
if err != nil {
return nil, err
}
results = append(results, *result)
} }
return results, nil return results, nil

View File

@ -29,7 +29,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
} }
if len(branches) == 0 { if len(branches) == 0 {
graphCmd.AddArguments("--all") graphCmd.AddArguments("--tags", "--branches")
} }
graphCmd.AddArguments("-C", "-M", "--date=iso-strict"). graphCmd.AddArguments("-C", "-M", "--date=iso-strict").

View File

@ -1,5 +1,5 @@
{{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed) .Issue.PullRequest.HeadRepo}} {{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed) .Issue.PullRequest.HeadRepo}}
{{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}} {{if or (eq .SignedUserID .Issue.PosterID) (and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo)}}
<div class="divider"></div> <div class="divider"></div>
<div class="ui checkbox loading-icon-2px" id="allow-edits-from-maintainers" <div class="ui checkbox loading-icon-2px" id="allow-edits-from-maintainers"
data-url="{{.Issue.Link}}" data-url="{{.Issue.Link}}"

View File

@ -871,6 +871,48 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
assert.False(t, prMsg.HasMerged) assert.False(t, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha) assert.Equal(t, commit, prMsg.Head.Sha)
}) })
t.Run("AddCommit3", func(t *testing.T) {
err := os.WriteFile(path.Join(dstPath, "test_file_2"), []byte("## test content \n ## test content 2"), 0o666)
if !assert.NoError(t, err) {
return
}
err = git.AddChanges(dstPath, true)
assert.NoError(t, err)
err = git.CommitChanges(dstPath, git.CommitChangesOptions{
Committer: &git.Signature{
Email: "user2@example.com",
Name: "user2",
When: time.Now(),
},
Author: &git.Signature{
Email: "user2@example.com",
Name: "user2",
When: time.Now(),
},
Message: "Testing commit 3",
})
assert.NoError(t, err)
commit, err = gitRepo.GetRefCommitID("HEAD")
assert.NoError(t, err)
})
t.Run("PushByForReview", func(t *testing.T) {
err := git.NewCommand(git.DefaultContext, "push", "origin").AddDynamicArguments(fmt.Sprintf("HEAD:refs/for-review/%d", pr1.Index)).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
if !assert.NoError(t, err) {
return
}
assert.False(t, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha)
})
t.Run("Merge", doAPIMergePullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)) t.Run("Merge", doAPIMergePullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index))
t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master")) t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master"))
} }