feat: [CODE-2359]: PR source branch delete/restore API (#2690)

* passed 409 for open PRs for restore branch API
* addressed review comments
* fixed lint issue
* feat: [CODE-2359]: PR source branch delete/restore API
CODE-2402
Karan Saraswat 2024-09-18 12:17:21 +00:00 committed by Harness
parent 327c5ed284
commit 93b642b2ba
18 changed files with 474 additions and 53 deletions

View File

@ -20,7 +20,6 @@ import (
"fmt"
"sort"
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/app/services/protection"
"github.com/harness/gitness/types"
@ -44,14 +43,9 @@ func (c *Controller) ListChecks(
return types.PullReqChecks{}, fmt.Errorf("failed to find pull request by number: %w", err)
}
isRepoOwner, err := apiauth.IsRepoOwner(ctx, c.authorizer, session, repo)
protectionRules, isRepoOwner, err := c.fetchRules(ctx, session, repo)
if err != nil {
return types.PullReqChecks{}, fmt.Errorf("failed to determine if user is repo owner: %w", err)
}
protectionRules, err := c.protectionManager.ForRepository(ctx, repo.ID)
if err != nil {
return types.PullReqChecks{}, fmt.Errorf("failed to fetch protection rules for the repository: %w", err)
return types.PullReqChecks{}, fmt.Errorf("failed to fetch rules: %w", err)
}
reqChecks, err := protectionRules.RequiredChecks(ctx, protection.RequiredChecksInput{

View File

@ -20,7 +20,6 @@ import (
"strings"
"time"
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
@ -112,14 +111,9 @@ func (c *Controller) CommentApplySuggestions(
}
// verify branch rules
isRepoOwner, err := apiauth.IsRepoOwner(ctx, c.authorizer, session, repo)
protectionRules, isRepoOwner, err := c.fetchRules(ctx, session, repo)
if err != nil {
return CommentApplySuggestionsOutput{}, nil, fmt.Errorf("failed to determine if user is repo owner: %w", err)
}
protectionRules, err := c.protectionManager.ForRepository(ctx, repo.ID)
if err != nil {
return CommentApplySuggestionsOutput{}, nil, fmt.Errorf(
"failed to fetch protection rules for the repository: %w", err)
return CommentApplySuggestionsOutput{}, nil, fmt.Errorf("failed to fetch rules: %w", err)
}
violations, err := protectionRules.RefChangeVerify(ctx, protection.RefChangeVerifyInput{
Actor: &session.Principal,

View File

@ -199,6 +199,24 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
return repo, nil
}
func (c *Controller) fetchRules(
ctx context.Context,
session *auth.Session,
repo *types.Repository,
) (protection.Protection, bool, error) {
isRepoOwner, err := apiauth.IsRepoOwner(ctx, c.authorizer, session, repo)
if err != nil {
return nil, false, fmt.Errorf("failed to determine if user is repo owner: %w", err)
}
protectionRules, err := c.protectionManager.ForRepository(ctx, repo.ID)
if err != nil {
return nil, false, fmt.Errorf("failed to fetch protection rules for the repository: %w", err)
}
return protectionRules, isRepoOwner, nil
}
func (c *Controller) getCommentForPR(
ctx context.Context,
pr *types.PullReq,

View File

@ -0,0 +1,117 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pullreq
import (
"context"
"fmt"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/app/services/protection"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
// DeleteBranch deletes the source branch of a PR.
func (c *Controller) DeleteBranch(ctx context.Context,
session *auth.Session,
repoRef string,
pullreqNum int64,
bypassRules bool,
dryRunRules bool,
) (types.DeleteBranchOutput, []types.RuleViolations, error) {
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
if err != nil {
return types.DeleteBranchOutput{}, nil, fmt.Errorf("failed to acquire access to repo: %w", err)
}
pr, err := c.pullreqStore.FindByNumber(ctx, repo.ID, pullreqNum)
if err != nil {
return types.DeleteBranchOutput{}, nil, fmt.Errorf("failed to get pull request by number: %w", err)
}
branchName := pr.SourceBranch
// make sure user isn't deleting the default branch
if branchName == repo.DefaultBranch {
return types.DeleteBranchOutput{}, nil, usererror.ErrDefaultBranchCantBeDeleted
}
rules, isRepoOwner, err := c.fetchRules(ctx, session, repo)
if err != nil {
return types.DeleteBranchOutput{}, nil, fmt.Errorf("failed to fetch rules: %w", err)
}
violations, err := rules.RefChangeVerify(ctx, protection.RefChangeVerifyInput{
Actor: &session.Principal,
AllowBypass: bypassRules,
IsRepoOwner: isRepoOwner,
Repo: repo,
RefAction: protection.RefActionDelete,
RefType: protection.RefTypeBranch,
RefNames: []string{branchName},
})
if err != nil {
return types.DeleteBranchOutput{}, nil, fmt.Errorf("failed to verify protection rules: %w", err)
}
if dryRunRules {
return types.DeleteBranchOutput{
DryRunRulesOutput: types.DryRunRulesOutput{
DryRunRules: true,
RuleViolations: violations,
},
}, nil, nil
}
if protection.IsCritical(violations) {
return types.DeleteBranchOutput{}, violations, nil
}
writeParams, err := controller.CreateRPCInternalWriteParams(ctx, c.urlProvider, session, repo)
if err != nil {
return types.DeleteBranchOutput{}, nil, fmt.Errorf("failed to create RPC write params: %w", err)
}
err = c.git.DeleteBranch(ctx, &git.DeleteBranchParams{
WriteParams: writeParams,
BranchName: branchName,
SHA: pr.SourceSHA,
})
if err != nil {
return types.DeleteBranchOutput{}, nil, err
}
err = func() error {
if pr, err = c.pullreqStore.UpdateActivitySeq(ctx, pr); err != nil {
return fmt.Errorf("failed to update pull request activity sequence: %w", err)
}
_, err := c.activityStore.CreateWithPayload(ctx, pr, session.Principal.ID,
&types.PullRequestActivityPayloadBranchDelete{SHA: pr.SourceSHA}, nil)
return err
}()
if err != nil {
log.Ctx(ctx).Err(err).Msgf("failed to write pull request activity for successful branch delete")
}
return types.DeleteBranchOutput{
DryRunRulesOutput: types.DryRunRulesOutput{
RuleViolations: violations,
}}, nil, nil
}

View File

@ -20,7 +20,6 @@ import (
"strings"
"time"
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
@ -182,9 +181,9 @@ func (c *Controller) Merge(
}
}
isRepoOwner, err := apiauth.IsRepoOwner(ctx, c.authorizer, session, targetRepo)
protectionRules, isRepoOwner, err := c.fetchRules(ctx, session, targetRepo)
if err != nil {
return nil, nil, fmt.Errorf("failed to determine if user is repo owner: %w", err)
return nil, nil, fmt.Errorf("failed to fetch rules: %w", err)
}
checkResults, err := c.checkStore.ListResults(ctx, targetRepo.ID, pr.SourceSHA)
@ -192,11 +191,6 @@ func (c *Controller) Merge(
return nil, nil, fmt.Errorf("failed to list status checks: %w", err)
}
protectionRules, err := c.protectionManager.ForRepository(ctx, targetRepo.ID)
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch protection rules for the repository: %w", err)
}
codeOwnerWithApproval, err := c.codeOwners.Evaluate(ctx, sourceRepo, pr, reviewers)
// check for error and ignore if it is codeowners file not found else throw error
if err != nil && !errors.Is(err, codeowners.ErrNotFound) {

View File

@ -0,0 +1,136 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pullreq
import (
"context"
"fmt"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/app/services/instrument"
"github.com/harness/gitness/app/services/protection"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
// RestoreBranchInput used for branch restoration apis.
type RestoreBranchInput struct {
DryRunRules bool `json:"dry_run_rules"`
BypassRules bool `json:"bypass_rules"`
}
// RestoreBranch restores branch for the merged/closed PR.
func (c *Controller) RestoreBranch(ctx context.Context,
session *auth.Session,
repoRef string,
pullreqNum int64,
in *RestoreBranchInput,
) (types.CreateBranchOutput, []types.RuleViolations, error) {
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to acquire access to repo: %w", err)
}
pr, err := c.pullreqStore.FindByNumber(ctx, repo.ID, pullreqNum)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to get pull request by number: %w", err)
}
if pr.State == enum.PullReqStateOpen {
return types.CreateBranchOutput{}, nil, errors.Conflict("source branch %q already exists", pr.SourceBranch)
}
rules, isRepoOwner, err := c.fetchRules(ctx, session, repo)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to fetch rules: %w", err)
}
violations, err := rules.RefChangeVerify(ctx, protection.RefChangeVerifyInput{
Actor: &session.Principal,
AllowBypass: in.BypassRules,
IsRepoOwner: isRepoOwner,
Repo: repo,
RefAction: protection.RefActionCreate,
RefType: protection.RefTypeBranch,
RefNames: []string{pr.SourceBranch},
})
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to verify protection rules: %w", err)
}
if in.DryRunRules {
return types.CreateBranchOutput{
DryRunRulesOutput: types.DryRunRulesOutput{
DryRunRules: true,
RuleViolations: violations,
},
}, nil, nil
}
if protection.IsCritical(violations) {
return types.CreateBranchOutput{}, violations, nil
}
writeParams, err := controller.CreateRPCInternalWriteParams(ctx, c.urlProvider, session, repo)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to create RPC write params: %w", err)
}
rpcOut, err := c.git.CreateBranch(ctx, &git.CreateBranchParams{
WriteParams: writeParams,
BranchName: pr.SourceBranch,
Target: pr.SourceSHA,
})
if err != nil {
return types.CreateBranchOutput{}, nil, err
}
branch, err := controller.MapBranch(rpcOut.Branch)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to map branch: %w", err)
}
err = func() error {
if pr, err = c.pullreqStore.UpdateActivitySeq(ctx, pr); err != nil {
return fmt.Errorf("failed to update pull request activity sequence: %w", err)
}
_, err := c.activityStore.CreateWithPayload(ctx, pr, session.Principal.ID,
&types.PullRequestActivityPayloadBranchRestore{SHA: pr.SourceSHA}, nil)
return err
}()
if err != nil {
log.Ctx(ctx).Err(err).Msgf("failed to write pull request activity for successful branch restore")
}
err = c.instrumentation.Track(ctx, instrument.Event{
Type: instrument.EventTypeCreateBranch,
Principal: session.Principal.ToPrincipalInfo(),
Path: repo.Path,
Properties: map[instrument.Property]any{
instrument.PropertyRepositoryID: repo.ID,
instrument.PropertyRepositoryName: repo.Identifier,
},
})
if err != nil {
log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create branch operation: %s", err)
}
return types.CreateBranchOutput{
Branch: branch,
}, nil, nil
}

View File

@ -102,7 +102,7 @@ func (c *Controller) CreateBranch(ctx context.Context,
return types.CreateBranchOutput{}, nil, err
}
branch, err := mapBranch(rpcOut.Branch)
branch, err := controller.MapBranch(rpcOut.Branch)
if err != nil {
return types.CreateBranchOutput{}, nil, fmt.Errorf("failed to map branch: %w", err)
}

View File

@ -18,6 +18,7 @@ import (
"context"
"fmt"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
@ -43,7 +44,7 @@ func (c *Controller) GetBranch(ctx context.Context,
return nil, fmt.Errorf("failed to get branch: %w", err)
}
branch, err := mapBranch(rpcOut.Branch)
branch, err := controller.MapBranch(rpcOut.Branch)
if err != nil {
return nil, fmt.Errorf("failed to map branch: %w", err)
}

View File

@ -52,7 +52,7 @@ func (c *Controller) ListBranches(ctx context.Context,
branches := make([]types.Branch, len(rpcOut.Branches))
for i := range rpcOut.Branches {
branches[i], err = mapBranch(rpcOut.Branches[i])
branches[i], err = controller.MapBranch(rpcOut.Branches[i])
if err != nil {
return nil, fmt.Errorf("failed to map branch: %w", err)
}
@ -88,19 +88,3 @@ func mapToRPCSortOrder(o enum.Order) git.SortOrder {
return git.SortOrderDefault
}
}
func mapBranch(b git.Branch) (types.Branch, error) {
var commit *types.Commit
if b.Commit != nil {
var err error
commit, err = controller.MapCommit(b.Commit)
if err != nil {
return types.Branch{}, err
}
}
return types.Branch{
Name: b.Name,
SHA: b.SHA.String(),
Commit: commit,
}, nil
}

View File

@ -18,7 +18,6 @@ import (
"context"
"fmt"
apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
@ -71,14 +70,9 @@ func (c *Controller) Rebase(
return nil, nil, fmt.Errorf("failed to acquire access to repo: %w", err)
}
isRepoOwner, err := apiauth.IsRepoOwner(ctx, c.authorizer, session, repo)
protectionRules, isRepoOwner, err := c.fetchRules(ctx, session, repo)
if err != nil {
return nil, nil, fmt.Errorf("failed to determine if user is repo owner: %w", err)
}
protectionRules, err := c.protectionManager.ForRepository(ctx, repo.ID)
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch protection rules for the repository: %w", err)
return nil, nil, fmt.Errorf("failed to fetch rules: %w", err)
}
violations, err := protectionRules.RefChangeVerify(ctx, protection.RefChangeVerifyInput{

View File

@ -79,6 +79,22 @@ func CreateRPCInternalWriteParams(
return createRPCWriteParams(ctx, urlProvider, session, repo, true)
}
func MapBranch(b git.Branch) (types.Branch, error) {
var commit *types.Commit
if b.Commit != nil {
var err error
commit, err = MapCommit(b.Commit)
if err != nil {
return types.Branch{}, err
}
}
return types.Branch{
Name: b.Name,
SHA: b.SHA.String(),
Commit: commit,
}, nil
}
func MapCommit(c *git.Commit) (*types.Commit, error) {
if c == nil {
return nil, fmt.Errorf("commit is nil")

View File

@ -0,0 +1,67 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pullreq
import (
"net/http"
"github.com/harness/gitness/app/api/controller/pullreq"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
)
// HandleDeleteBranch deletes the source branch of a PR.
func HandleDeleteBranch(pullreqCtrl *pullreq.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
repoRef, err := request.GetRepoRefFromPath(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
pullreqNumber, err := request.GetPullReqNumberFromPath(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
bypassRules, err := request.ParseBypassRulesFromQuery(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
dryRunRules, err := request.ParseDryRunRulesFromQuery(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
out, violations, err := pullreqCtrl.DeleteBranch(ctx, session, repoRef, pullreqNumber, bypassRules, dryRunRules)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
if violations != nil {
render.Violations(w, violations)
return
}
render.JSON(w, http.StatusOK, out)
}
}

View File

@ -0,0 +1,63 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pullreq
import (
"encoding/json"
"net/http"
"github.com/harness/gitness/app/api/controller/pullreq"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
)
// HandleRestoreBranch writes json-encoded branch information to the http response body.
func HandleRestoreBranch(pullreqCtrl *pullreq.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
repoRef, err := request.GetRepoRefFromPath(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
pullreqNumber, err := request.GetPullReqNumberFromPath(r)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
in := new(pullreq.RestoreBranchInput)
err = json.NewDecoder(r.Body).Decode(in)
if err != nil {
render.BadRequestf(ctx, w, "Invalid request body: %s.", err)
return
}
out, violations, err := pullreqCtrl.RestoreBranch(ctx, session, repoRef, pullreqNumber, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
if violations != nil {
render.Violations(w, violations)
return
}
render.JSON(w, http.StatusCreated, out)
}
}

View File

@ -41,7 +41,7 @@ func HandleCreateBranch(repoCtrl *repo.Controller) http.HandlerFunc {
return
}
branch, violations, err := repoCtrl.CreateBranch(ctx, session, repoRef, in)
out, violations, err := repoCtrl.CreateBranch(ctx, session, repoRef, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
@ -51,6 +51,6 @@ func HandleCreateBranch(repoCtrl *repo.Controller) http.HandlerFunc {
return
}
render.JSON(w, http.StatusCreated, branch)
render.JSON(w, http.StatusCreated, out)
}
}

View File

@ -702,6 +702,34 @@ func pullReqOperations(reflector *openapi3.Reflector) {
_ = reflector.SetJSONResponse(&opMetaData, new(usererror.Error), http.StatusNotFound)
_ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/pullreq/{pullreq_number}/metadata", opMetaData)
opRestoreBranch := openapi3.Operation{}
opRestoreBranch.WithTags("pullreq")
opRestoreBranch.WithMapOfAnything(map[string]interface{}{"operationId": "restorePullReqSourceBranch"})
_ = reflector.SetRequest(&opRestoreBranch, struct {
pullReqRequest
pullreq.RestoreBranchInput
}{}, http.MethodPost)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(types.CreateBranchOutput), http.StatusCreated)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(usererror.Error), http.StatusBadRequest)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(usererror.Error), http.StatusUnauthorized)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(usererror.Error), http.StatusForbidden)
_ = reflector.SetJSONResponse(&opRestoreBranch, new(types.RulesViolations), http.StatusUnprocessableEntity)
_ = reflector.Spec.AddOperation(http.MethodPost, "/repos/{repo_ref}/pullreq/{pullreq_number}/branch", opRestoreBranch)
opDeleteBranch := openapi3.Operation{}
opDeleteBranch.WithTags("pullreq")
opDeleteBranch.WithMapOfAnything(map[string]interface{}{"operationId": "deletePullReqSourceBranch"})
opDeleteBranch.WithParameters(queryParameterBypassRules, queryParameterDryRunRules)
_ = reflector.SetRequest(&opDeleteBranch, new(pullReqRequest), http.MethodDelete)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(types.DeleteBranchOutput), http.StatusOK)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(usererror.Error), http.StatusUnauthorized)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(usererror.Error), http.StatusForbidden)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(usererror.Error), http.StatusNotFound)
_ = reflector.SetJSONResponse(&opDeleteBranch, new(types.RulesViolations), http.StatusUnprocessableEntity)
_ = reflector.Spec.AddOperation(http.MethodDelete, "/repos/{repo_ref}/pullreq/{pullreq_number}/branch", opDeleteBranch)
fileViewAdd := openapi3.Operation{}
fileViewAdd.WithTags("pullreq")
fileViewAdd.WithMapOfAnything(map[string]interface{}{"operationId": "fileViewAddPullReq"})

View File

@ -649,6 +649,10 @@ func SetupPullReq(r chi.Router, pullreqCtrl *pullreq.Controller) {
r.Post("/merge", handlerpullreq.HandleMerge(pullreqCtrl))
r.Get("/commits", handlerpullreq.HandleCommits(pullreqCtrl))
r.Get("/metadata", handlerpullreq.HandleMetadata(pullreqCtrl))
r.Route("/branch", func(r chi.Router) {
r.Post("/", handlerpullreq.HandleRestoreBranch(pullreqCtrl))
r.Delete("/", handlerpullreq.HandleDeleteBranch(pullreqCtrl))
})
r.Route("/file-views", func(r chi.Router) {
r.Put("/", handlerpullreq.HandleFileViewAdd(pullreqCtrl))

View File

@ -87,6 +87,7 @@ const (
PullReqActivityTypeReviewerDelete PullReqActivityType = "reviewer-delete"
PullReqActivityTypeBranchUpdate PullReqActivityType = "branch-update"
PullReqActivityTypeBranchDelete PullReqActivityType = "branch-delete"
PullReqActivityTypeBranchRestore PullReqActivityType = "branch-restore"
PullReqActivityTypeMerge PullReqActivityType = "merge"
PullReqActivityTypeLabelModify PullReqActivityType = "label-modify"
)
@ -100,6 +101,7 @@ var pullReqActivityTypes = sortEnum([]PullReqActivityType{
PullReqActivityTypeReviewerDelete,
PullReqActivityTypeBranchUpdate,
PullReqActivityTypeBranchDelete,
PullReqActivityTypeBranchRestore,
PullReqActivityTypeMerge,
PullReqActivityTypeLabelModify,
})

View File

@ -60,6 +60,7 @@ var allPullReqActivityPayloads = func(
func() PullReqActivityPayload { return &PullRequestActivityPayloadReviewSubmit{} },
func() PullReqActivityPayload { return &PullRequestActivityPayloadBranchUpdate{} },
func() PullReqActivityPayload { return &PullRequestActivityPayloadBranchDelete{} },
func() PullReqActivityPayload { return &PullRequestActivityPayloadBranchRestore{} },
})
// newPayloadForActivity returns a new payload instance for the requested activity type.
@ -169,6 +170,14 @@ func (a *PullRequestActivityPayloadBranchDelete) ActivityType() enum.PullReqActi
return enum.PullReqActivityTypeBranchDelete
}
type PullRequestActivityPayloadBranchRestore struct {
SHA string `json:"sha"`
}
func (a *PullRequestActivityPayloadBranchRestore) ActivityType() enum.PullReqActivityType {
return enum.PullReqActivityTypeBranchRestore
}
type PullRequestActivityLabel struct {
Label string `json:"label"`
LabelColor enum.LabelColor `json:"label_color"`