mirror of https://github.com/harness/drone.git
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 APICODE-2402
parent
327c5ed284
commit
93b642b2ba
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"})
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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"`
|
||||
|
|
Loading…
Reference in New Issue