Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add apply-patch, basic revert and cherry-pick functionality #17902

Merged
merged 56 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
13ba415
Add apply-patch button
zeripath Jan 26, 2020
d477e5a
placate lint
zeripath Dec 4, 2021
c3326b2
update copyright years
zeripath Dec 5, 2021
f2c01fd
Merge branch 'main' into apply-patch
zeripath Dec 5, 2021
d4a4f1f
Update templates/repo/editor/patch.tmpl
zeripath Dec 6, 2021
8d9a6df
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 9, 2021
d0fc943
Merge remote-tracking branch 'zeripath/apply-patch' into apply-patch
zeripath Dec 9, 2021
ea9f569
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 10, 2021
c767f86
handle conflict
zeripath Dec 10, 2021
6ac0064
Add basic cherry-pick and revert functionality
zeripath Dec 12, 2021
8b3cdba
placate lint
zeripath Dec 12, 2021
2527d2d
slight further improvement
zeripath Dec 15, 2021
427e99c
placate lint
zeripath Dec 15, 2021
20b6b1e
Use git read-tree -m for better cherry-picking and reversion first
zeripath Dec 16, 2021
b23c35b
Improve TestPatch to use git read-tree -m
zeripath Dec 16, 2021
2f65bf9
Merge branch 'main' into update-TestPatch-to-use-read-tree
zeripath Dec 16, 2021
46bcf3e
Implement the git-merge-one-file algorithm
zeripath Dec 17, 2021
cb4e9e1
and handle empty patches too
zeripath Dec 17, 2021
507ede4
placate lint
zeripath Dec 17, 2021
7a523dd
use errConflict instead callback
zeripath Dec 17, 2021
0a38bd1
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 17, 2021
8193743
Merge remote-tracking branch 'origin/main' into update-TestPatch-to-u…
zeripath Dec 17, 2021
e02708e
Merge branch 'update-TestPatch-to-use-read-tree' into apply-patch
zeripath Dec 17, 2021
92de7bf
use the new updated merging from TestPatch
zeripath Dec 17, 2021
490ac9a
move revert and cherry-pick to drop down for operations and add creat…
zeripath Dec 17, 2021
561160f
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 19, 2021
6a47494
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 20, 2021
20c6e69
Split off other actions button
zeripath Dec 23, 2021
d707b88
remove browse-button css
zeripath Dec 23, 2021
406f525
as per review
zeripath Dec 24, 2021
1ac56a6
as per noerw
zeripath Dec 25, 2021
7244187
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Dec 25, 2021
4a4caf2
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Jan 1, 2022
5049cc9
Fix bug
zeripath Jan 1, 2022
d3bbf2e
Merge branch 'main' into apply-patch
zeripath Jan 19, 2022
b43ac20
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Jan 20, 2022
d371168
Merge branch 'main' into apply-patch
zeripath Jan 20, 2022
7170909
Merge remote-tracking branch 'origin/main' into apply-patch
zeripath Jan 20, 2022
7cf8382
fix linting and conflicts from previous prs
zeripath Jan 20, 2022
bed30e6
Merge branch 'main' into apply-patch
6543 Jan 22, 2022
6ec8527
Merge branch 'main' into apply-patch
6543 Feb 2, 2022
046da34
use git.NewCommandContext
6543 Feb 2, 2022
ac0be2d
cmd.RunWithContext do use processManager ...
6543 Feb 2, 2022
2ca39bb
use RunWithContext
6543 Feb 2, 2022
6ca8f13
Merge branch 'main' into apply-patch
zeripath Feb 3, 2022
9557783
Merge branch 'main' into apply-patch
6543 Feb 7, 2022
31fddcb
Merge branch 'master' into apply-patch
6543 Feb 7, 2022
095823d
adapt refactor
6543 Feb 7, 2022
6494e11
pass ctx down
6543 Feb 7, 2022
6fbc6e1
cherrypick use normal ctx
6543 Feb 7, 2022
1f6e6e9
use attr
zeripath Feb 7, 2022
683822b
Merge branch 'main' into apply-patch
zeripath Feb 8, 2022
63c5656
as per reviews
zeripath Feb 8, 2022
f20e9d4
Merge branch 'main' into apply-patch
6543 Feb 9, 2022
ff58993
Merge branch 'main' into apply-patch
zeripath Feb 9, 2022
c7c3c63
Merge branch 'main' into apply-patch
zeripath Feb 9, 2022
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
18 changes: 16 additions & 2 deletions modules/git/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ func GetRawDiff(ctx context.Context, repoPath, commitID string, diffType RawDiff
return GetRawDiffForFile(ctx, repoPath, "", commitID, diffType, "", writer)
}

// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
stderr := new(bytes.Buffer)
cmd := NewCommand(ctx, "show", "--pretty=format:revert %H%n", "-R", commitID)
if err := cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: writer,
Stderr: stderr,
}); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
return nil
}

// GetRawDiffForFile dumps diff results of file in given commit ID to io.Writer.
func GetRawDiffForFile(ctx context.Context, repoPath, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error {
repo, closer, err := RepositoryFromContextOrOpen(ctx, repoPath)
Expand Down Expand Up @@ -221,8 +236,7 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
}
}
}
err := scanner.Err()
if err != nil {
if err := scanner.Err(); err != nil {
return "", err
}

Expand Down
8 changes: 8 additions & 0 deletions modules/structs/repo_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ type UpdateFileOptions struct {
FromPath string `json:"from_path" binding:"MaxSize(500)"`
}

// ApplyDiffPatchFileOptions options for applying a diff patch
// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
type ApplyDiffPatchFileOptions struct {
DeleteFileOptions
// required: true
Content string `json:"content"`
}

// FileLinksResponse contains the links for a repo's file
type FileLinksResponse struct {
Self *string `json:"self"`
Expand Down
19 changes: 19 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,10 @@ editor.add_tmpl = Add '<filename>'
editor.add = Add '%s'
editor.update = Update '%s'
editor.delete = Delete '%s'
editor.patch = Apply Patch
editor.patching = Patching:
editor.fail_to_apply_patch = Unable to apply patch '%s'
editor.new_patch = New Patch
editor.commit_message_desc = Add an optional extended description…
editor.signoff_desc = Add a Signed-off-by trailer by the committer at the end of the commit log message.
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
Expand Down Expand Up @@ -1110,6 +1114,8 @@ editor.cannot_commit_to_protected_branch = Cannot commit to protected branch '%s
editor.no_commit_to_branch = Unable to commit directly to branch because:
editor.user_no_push_to_branch = User cannot push to branch
editor.require_signed_commit = Branch requires a signed commit
editor.cherry_pick = Cherry-pick %s onto:
editor.revert = Revert %s onto:

commits.desc = Browse source code change history.
commits.commits = Commits
Expand All @@ -1130,6 +1136,14 @@ commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does n
commits.gpg_key_id = GPG Key ID
commits.ssh_key_fingerprint = SSH Key Fingerprint

commit.actions = Actions
commit.revert = Revert
commit.revert-header = Revert: %s
commit.revert-content = Select branch to revert onto:
commit.cherry-pick = Cherry-pick
commit.cherry-pick-header = Cherry-pick: %s
commit.cherry-pick-content = Select branch to cherry-pick onto:

ext_issues = Access to External Issues
ext_issues.desc = Link to an external issue tracker.

Expand Down Expand Up @@ -2215,11 +2229,16 @@ branch.included_desc = This branch is part of the default branch
branch.included = Included
branch.create_new_branch = Create branch from branch:
branch.confirm_create_branch = Create branch
branch.create_branch_operation = Create branch
branch.new_branch = Create new branch
branch.new_branch_from = Create new branch from '%s'
branch.renamed = Branch %s was renamed to %s.

tag.create_tag = Create tag <strong>%s</strong>
tag.create_tag_operation = Create tag
tag.confirm_create_tag = Create tag
tag.create_tag_from = Create new tag from '%s'

tag.create_success = Tag '%s' has been created.

topic.manage_topics = Manage Topics
Expand Down
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Get("/tags/{sha}", context.RepoRefForAPI, repo.GetAnnotatedTag)
m.Get("/notes/{sha}", repo.GetNote)
}, reqRepoReader(unit.TypeCode))
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)
m.Get("/*", repo.GetContents)
Expand Down
107 changes: 107 additions & 0 deletions routers/api/v1/repo/patch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repo

import (
"net/http"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/repository/files"
)

// ApplyDiffPatch handles API call for applying a patch
func ApplyDiffPatch(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/diffpatch repository repoApplyDiffPatch
// ---
// summary: Apply diff patch to repository
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/UpdateFileOptions"
// responses:
// "200":
// "$ref": "#/responses/FileResponse"
apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions)

opts := &files.ApplyDiffPatchOptions{
Content: apiOpts.Content,
SHA: apiOpts.SHA,
Message: apiOpts.Message,
OldBranch: apiOpts.BranchName,
NewBranch: apiOpts.NewBranchName,
Committer: &files.IdentityOptions{
Name: apiOpts.Committer.Name,
Email: apiOpts.Committer.Email,
},
Author: &files.IdentityOptions{
Name: apiOpts.Author.Name,
Email: apiOpts.Author.Email,
},
Dates: &files.CommitDateOptions{
Author: apiOpts.Dates.Author,
Committer: apiOpts.Dates.Committer,
},
Signoff: apiOpts.Signoff,
}
if opts.Dates.Author.IsZero() {
opts.Dates.Author = time.Now()
}
if opts.Dates.Committer.IsZero() {
opts.Dates.Committer = time.Now()
}

if opts.Message == "" {
opts.Message = "apply-patch"
}

if !canWriteFiles(ctx.Repo) {
ctx.Error(http.StatusInternalServerError, "ApplyPatch", models.ErrUserDoesNotHaveAccessToRepo{
UserID: ctx.User.ID,
RepoName: ctx.Repo.Repository.LowerName,
})
zeripath marked this conversation as resolved.
Show resolved Hide resolved
return
}

fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.User, opts)
if err != nil {
if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) {
ctx.Error(http.StatusForbidden, "Access", err)
return
}
if models.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) ||
models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) {
ctx.Error(http.StatusUnprocessableEntity, "Invalid", err)
return
}
if models.IsErrBranchDoesNotExist(err) || git.IsErrBranchNotExist(err) {
ctx.Error(http.StatusNotFound, "BranchDoesNotExist", err)
return
}
ctx.Error(http.StatusInternalServerError, "ApplyPatch", err)
} else {
ctx.JSON(http.StatusCreated, fileResponse)
}
}
Loading