From c5d92b498bc64060cf8c9432baca5c6f76fa3f04 Mon Sep 17 00:00:00 2001 From: Johannes Batzill Date: Wed, 1 Feb 2023 18:50:54 -0800 Subject: [PATCH] [API] Add GetCommit API (#291) --- gitrpc/internal/gitea/mapping.go | 2 + internal/api/controller/repo/get_commit.go | 46 +++++++++++++++++++++ internal/api/handler/repo/get_branch.go | 1 + internal/api/handler/repo/get_commit.go | 41 +++++++++++++++++++ internal/api/openapi/repo.go | 16 ++++++++ internal/api/request/git.go | 5 +++ internal/router/api.go | 5 +++ web/src/services/code/index.tsx | 25 ++++++++++++ web/src/services/code/swagger.yaml | 47 ++++++++++++++++++++++ 9 files changed, 188 insertions(+) create mode 100644 internal/api/controller/repo/get_commit.go create mode 100644 internal/api/handler/repo/get_commit.go diff --git a/gitrpc/internal/gitea/mapping.go b/gitrpc/internal/gitea/mapping.go index 484d97306..6fceb5415 100644 --- a/gitrpc/internal/gitea/mapping.go +++ b/gitrpc/internal/gitea/mapping.go @@ -33,6 +33,8 @@ func processGiteaErrorf(err error, format string, args ...interface{}) error { switch { case gitea.IsErrNotExist(err): return types.ErrNotFound + case gitea.IsErrBranchNotExist(err): + return types.ErrNotFound default: return fallbackErr } diff --git a/internal/api/controller/repo/get_commit.go b/internal/api/controller/repo/get_commit.go new file mode 100644 index 000000000..c9019deea --- /dev/null +++ b/internal/api/controller/repo/get_commit.go @@ -0,0 +1,46 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package repo + +import ( + "context" + "fmt" + + "github.com/harness/gitness/gitrpc" + apiauth "github.com/harness/gitness/internal/api/auth" + "github.com/harness/gitness/internal/api/controller" + "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +// GetCommit gets a repo commit. +func (c *Controller) GetCommit(ctx context.Context, session *auth.Session, + repoRef string, sha string) (*types.Commit, error) { + repo, err := c.repoStore.FindByRef(ctx, repoRef) + if err != nil { + return nil, fmt.Errorf("faild to find repo: %w", err) + } + + if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, false); err != nil { + return nil, fmt.Errorf("access check failed: %w", err) + } + + rpcOut, err := c.gitRPCClient.GetCommit(ctx, &gitrpc.GetCommitParams{ + ReadParams: CreateRPCReadParams(repo), + SHA: sha, + }) + if err != nil { + return nil, fmt.Errorf("failed to get commit from gitrpc: %w", err) + } + + rpcCommit := rpcOut.Commit + commit, err := controller.MapCommit(&rpcCommit) + if err != nil { + return nil, fmt.Errorf("failed to map commit: %w", err) + } + + return commit, nil +} diff --git a/internal/api/handler/repo/get_branch.go b/internal/api/handler/repo/get_branch.go index 4c789da3a..e84927120 100644 --- a/internal/api/handler/repo/get_branch.go +++ b/internal/api/handler/repo/get_branch.go @@ -33,6 +33,7 @@ func HandleGetBranch(repoCtrl *repo.Controller) http.HandlerFunc { branch, err := repoCtrl.GetBranch(ctx, session, repoRef, branchName) if err != nil { render.TranslatedUserError(w, err) + return } render.JSON(w, http.StatusOK, branch) diff --git a/internal/api/handler/repo/get_commit.go b/internal/api/handler/repo/get_commit.go new file mode 100644 index 000000000..4115e70bf --- /dev/null +++ b/internal/api/handler/repo/get_commit.go @@ -0,0 +1,41 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package repo + +import ( + "net/http" + + "github.com/harness/gitness/internal/api/controller/repo" + "github.com/harness/gitness/internal/api/render" + "github.com/harness/gitness/internal/api/request" +) + +/* + * Gets a given commit. + */ +func HandleGetCommit(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 + } + commitSHA, err := request.GetCommitSHAFromPath(r) + if err != nil { + render.TranslatedUserError(w, err) + return + } + + commit, err := repoCtrl.GetCommit(ctx, session, repoRef, commitSHA) + if err != nil { + render.TranslatedUserError(w, err) + return + } + + render.JSON(w, http.StatusOK, commit) + } +} diff --git a/internal/api/openapi/repo.go b/internal/api/openapi/repo.go index bf5ad0ae2..1e5428ca6 100644 --- a/internal/api/openapi/repo.go +++ b/internal/api/openapi/repo.go @@ -98,6 +98,11 @@ type listCommitsRequest struct { repoRequest } +type GetCommitRequest struct { + repoRequest + CommitSHA string `path:"commit_sha"` +} + type calculateCommitDivergenceRequest struct { repoRequest repo.GetCommitDivergencesInput @@ -386,6 +391,17 @@ func repoOperations(reflector *openapi3.Reflector) { _ = reflector.SetJSONResponse(&opListCommits, new(usererror.Error), http.StatusNotFound) _ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/commits", opListCommits) + opGetCommit := openapi3.Operation{} + opGetCommit.WithTags("repository") + opGetCommit.WithMapOfAnything(map[string]interface{}{"operationId": "getCommit"}) + _ = reflector.SetRequest(&opGetCommit, new(GetCommitRequest), http.MethodGet) + _ = reflector.SetJSONResponse(&opGetCommit, types.Commit{}, http.StatusOK) + _ = reflector.SetJSONResponse(&opGetCommit, new(usererror.Error), http.StatusInternalServerError) + _ = reflector.SetJSONResponse(&opGetCommit, new(usererror.Error), http.StatusUnauthorized) + _ = reflector.SetJSONResponse(&opGetCommit, new(usererror.Error), http.StatusForbidden) + _ = reflector.SetJSONResponse(&opGetCommit, new(usererror.Error), http.StatusNotFound) + _ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/commits/{commit_sha}", opGetCommit) + opCalulateCommitDivergence := openapi3.Operation{} opCalulateCommitDivergence.WithTags("repository") opCalulateCommitDivergence.WithMapOfAnything(map[string]interface{}{"operationId": "calculateCommitDivergence"}) diff --git a/internal/api/request/git.go b/internal/api/request/git.go index ed5cc1a93..ab966fc97 100644 --- a/internal/api/request/git.go +++ b/internal/api/request/git.go @@ -14,6 +14,7 @@ import ( const ( QueryParamGitRef = "git_ref" QueryParamIncludeCommit = "include_commit" + PathParamCommitSHA = "commit_sha" ) func GetGitRefFromQueryOrDefault(r *http.Request, deflt string) string { @@ -24,6 +25,10 @@ func GetIncludeCommitFromQueryOrDefault(r *http.Request, deflt bool) (bool, erro return QueryParamAsBoolOrDefault(r, QueryParamIncludeCommit, deflt) } +func GetCommitSHAFromPath(r *http.Request) (string, error) { + return PathParamOrError(r, PathParamCommitSHA) +} + // ParseSortBranch extracts the branch sort parameter from the url. func ParseSortBranch(r *http.Request) enum.BranchSortOption { return enum.ParseBranchSortOption( diff --git a/internal/router/api.go b/internal/router/api.go index ec28aced6..63bddd1b3 100644 --- a/internal/router/api.go +++ b/internal/router/api.go @@ -173,6 +173,11 @@ func setupRepos(r chi.Router, repoCtrl *repo.Controller, pullreqCtrl *pullreq.Co r.Post("/calculate-divergence", handlerrepo.HandleCalculateCommitDivergence(repoCtrl)) r.Post("/", handlerrepo.HandleCommitFiles(repoCtrl)) + + // per commit operations + r.Route(fmt.Sprintf("/{%s}", request.PathParamCommitSHA), func(r chi.Router) { + r.Get("/", handlerrepo.HandleGetCommit(repoCtrl)) + }) }) // branch operations diff --git a/web/src/services/code/index.tsx b/web/src/services/code/index.tsx index 80a0e0459..df69f4a08 100644 --- a/web/src/services/code/index.tsx +++ b/web/src/services/code/index.tsx @@ -879,6 +879,31 @@ export const useCommitFiles = ({ repo_ref, ...props }: UseCommitFilesProps) => { base: getConfig('code'), pathParams: { repo_ref }, ...props } ) +export interface GetCommitPathParams { + repo_ref: string + commit_sha: string +} + +export type GetCommitProps = Omit, 'path'> & + GetCommitPathParams + +export const GetCommit = ({ repo_ref, commit_sha, ...props }: GetCommitProps) => ( + + path={`/repos/${repo_ref}/commits/${commit_sha}`} + base={getConfig('code')} + {...props} + /> +) + +export type UseGetCommitProps = Omit, 'path'> & + GetCommitPathParams + +export const useGetCommit = ({ repo_ref, commit_sha, ...props }: UseGetCommitProps) => + useGet( + (paramsInPath: GetCommitPathParams) => `/repos/${paramsInPath.repo_ref}/commits/${paramsInPath.commit_sha}`, + { base: getConfig('code'), pathParams: { repo_ref, commit_sha }, ...props } + ) + export interface CalculateCommitDivergencePathParams { repo_ref: string } diff --git a/web/src/services/code/swagger.yaml b/web/src/services/code/swagger.yaml index 17d3f3d09..132f40b44 100644 --- a/web/src/services/code/swagger.yaml +++ b/web/src/services/code/swagger.yaml @@ -610,6 +610,53 @@ paths: description: Internal Server Error tags: - repository + /repos/{repo_ref}/commits/{commit_sha}: + get: + operationId: getCommit + parameters: + - in: path + name: repo_ref + required: true + schema: + type: string + - in: path + name: commit_sha + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TypesCommit' + description: OK + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/UsererrorError' + description: Unauthorized + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/UsererrorError' + description: Forbidden + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/UsererrorError' + description: Not Found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/UsererrorError' + description: Internal Server Error + tags: + - repository /repos/{repo_ref}/commits/calculate-divergence: post: operationId: calculateCommitDivergence