-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support update default branch (#973)
- Loading branch information
1 parent
92761a1
commit 29f7812
Showing
11 changed files
with
271 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// 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:https://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 repo | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/harness/gitness/app/api/controller" | ||
"github.com/harness/gitness/app/auth" | ||
"github.com/harness/gitness/contextutil" | ||
"github.com/harness/gitness/git" | ||
"github.com/harness/gitness/types" | ||
"github.com/harness/gitness/types/enum" | ||
|
||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
type UpdateDefaultBranchInput struct { | ||
Name string `json:"name"` | ||
} | ||
|
||
// TODO: handle the racing condition between update/delete default branch requests for a repo. | ||
func (c *Controller) UpdateDefaultBranch( | ||
ctx context.Context, | ||
session *auth.Session, | ||
repoRef string, | ||
in *UpdateDefaultBranchInput, | ||
) (*types.Repository, error) { | ||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// the max time we give an update default branch to succeed | ||
const timeout = 2 * time.Minute | ||
|
||
// lock concurrent requests for updating the default branch of a repo | ||
// requests will wait for previous ones to compelete before proceed | ||
unlock, err := c.lockDefaultBranch( | ||
ctx, | ||
repo.GitUID, | ||
in.Name, // branch name only used for logging (lock is on repo) | ||
timeout+30*time.Second, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer unlock() | ||
|
||
writeParams, err := controller.CreateRPCInternalWriteParams(ctx, c.urlProvider, session, repo) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create RPC write params: %w", err) | ||
} | ||
|
||
// create new, time-restricted context to guarantee update completion, even if request is canceled. | ||
// TODO: a proper error handling solution required. | ||
ctx, cancel := context.WithTimeout( | ||
contextutil.WithNewValues(context.Background(), ctx), | ||
timeout, | ||
) | ||
defer cancel() | ||
|
||
err = c.git.UpdateDefaultBranch(ctx, &git.UpdateDefaultBranchParams{ | ||
WriteParams: writeParams, | ||
BranchName: in.Name, | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to update the repo default branch: %w", err) | ||
} | ||
|
||
repo, err = c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error { | ||
r.DefaultBranch = in.Name | ||
return nil | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to update the repo default branch on db:%w", err) | ||
} | ||
|
||
err = c.indexer.Index(ctx, repo) | ||
if err != nil { | ||
log.Ctx(ctx).Warn().Err(err).Int64("repo_id", repo.ID). | ||
Msgf("failed to index repo with the updated default branch %s", in.Name) | ||
} | ||
|
||
return repo, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// 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:https://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 repo | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/harness/gitness/contextutil" | ||
"github.com/harness/gitness/lock" | ||
"github.com/harness/gitness/logging" | ||
|
||
"github.com/rs/zerolog" | ||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
func (c *Controller) lockDefaultBranch( | ||
ctx context.Context, | ||
repoUID string, | ||
branchName string, | ||
expiry time.Duration, | ||
) (func(), error) { | ||
key := repoUID + "/defaultBranch" | ||
|
||
// annotate logs for easier debugging of lock related issues | ||
// TODO: refactor once common logging annotations are added | ||
ctx = logging.NewContext(ctx, func(zc zerolog.Context) zerolog.Context { | ||
return zc. | ||
Str("default_branch_lock", key). | ||
Str("repo_uid", repoUID) | ||
}) | ||
|
||
mutext, err := c.mtxManager.NewMutex( | ||
key, | ||
lock.WithNamespace("repo"), | ||
lock.WithExpiry(expiry), | ||
lock.WithTimeoutFactor(4/expiry.Seconds()), // 4s | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create new mutex for repo %q with default branch %s: %w", repoUID, branchName, err) | ||
} | ||
|
||
err = mutext.Lock(ctx) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to lock the mutex for repo %q with default branch %s: %w", repoUID, branchName, err) | ||
} | ||
|
||
log.Ctx(ctx).Info().Msgf("successfully locked the repo default branch (expiry: %s)", expiry) | ||
|
||
unlockFn := func() { | ||
// always unlock independent of whether source context got canceled or not | ||
ctx, cancel := context.WithTimeout( | ||
contextutil.WithNewValues(context.Background(), ctx), | ||
30*time.Second, | ||
) | ||
defer cancel() | ||
|
||
err := mutext.Unlock(ctx) | ||
if err != nil { | ||
log.Ctx(ctx).Warn().Err(err).Msg("failed to unlock repo default branch") | ||
} else { | ||
log.Ctx(ctx).Info().Msg("successfully unlocked repo default branch") | ||
} | ||
} | ||
return unlockFn, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// 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:https://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 repo | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
|
||
"github.com/harness/gitness/app/api/controller/repo" | ||
"github.com/harness/gitness/app/api/render" | ||
"github.com/harness/gitness/app/api/request" | ||
) | ||
|
||
func HandleUpdateDefaultBranch(repoCtrl *repo.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(w, err) | ||
return | ||
} | ||
|
||
in := new(repo.UpdateDefaultBranchInput) | ||
err = json.NewDecoder(r.Body).Decode(in) | ||
if err != nil { | ||
render.TranslatedUserError(w, err) | ||
return | ||
} | ||
|
||
repo, err := repoCtrl.UpdateDefaultBranch(ctx, session, repoRef, in) | ||
if err != nil { | ||
render.TranslatedUserError(w, err) | ||
return | ||
} | ||
|
||
render.JSON(w, http.StatusOK, repo) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters