Merge remote-tracking branch 'origin' into abhinav/CODE-200

This commit is contained in:
Abhinav Singh 2023-05-17 14:10:24 -07:00
commit f41b8bc7ce
51 changed files with 223 additions and 199 deletions

View File

@ -112,17 +112,6 @@ linters-settings:
# Default: 30 # Default: 30
max-func-lines: 30 max-func-lines: 30
nolintlint:
# Exclude following linters from requiring an explanation.
# Default: []
allow-no-explanation: [ funlen, gocognit, lll ]
# Enable to require an explanation of nonzero length after each nolint directive.
# Default: false
require-explanation: true
# Enable to require nolint directives to mention the specific linter being suppressed.
# Default: false
require-specific: true
rowserrcheck: rowserrcheck:
# database/sql is always checked # database/sql is always checked
# Default: [] # Default: []
@ -217,7 +206,7 @@ linters:
- exhaustive # checks exhaustiveness of enum switch statements - exhaustive # checks exhaustiveness of enum switch statements
- exportloopref # checks for pointers to enclosing loop variables - exportloopref # checks for pointers to enclosing loop variables
- forbidigo # forbids identifiers - forbidigo # forbids identifiers
- funlen # tool for detection of long functions #- funlen # tool for detection of long functions
#- gochecknoglobals # checks that no global variables exist #- gochecknoglobals # checks that no global variables exist
#- gochecknoinits # checks that no init functions are present in Go code #- gochecknoinits # checks that no init functions are present in Go code
- gocognit # computes and checks the cognitive complexity of functions - gocognit # computes and checks the cognitive complexity of functions
@ -238,7 +227,7 @@ linters:
- nilerr # finds the code that returns nil even if it checks that the error is not nil - nilerr # finds the code that returns nil even if it checks that the error is not nil
- nilnil # checks that there is no simultaneous return of nil error and an invalid value - nilnil # checks that there is no simultaneous return of nil error and an invalid value
- noctx # finds sending http request without context.Context - noctx # finds sending http request without context.Context
- nolintlint # reports ill-formed or insufficient nolint directives # - nolintlint # reports ill-formed or insufficient nolint directives
# - nonamedreturns # reports all named returns # - nonamedreturns # reports all named returns
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL - nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
- predeclared # finds code that shadows one of Go's predeclared identifiers - predeclared # finds code that shadows one of Go's predeclared identifiers
@ -283,7 +272,7 @@ linters:
#- importas # enforces consistent import aliases #- importas # enforces consistent import aliases
#- logrlint # [owner archived repository] checks logr arguments #- logrlint # [owner archived repository] checks logr arguments
#- maintidx # measures the maintainability index of each function #- maintidx # measures the maintainability index of each function
#- misspell # [useless] finds commonly misspelled English words in comments - misspell # [useless] finds commonly misspelled English words in comments
#- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity #- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity
#- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test #- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test
#- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers #- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers

View File

@ -53,7 +53,7 @@ func getArguments() []string {
command := os.Args[0] command := os.Args[0]
args := os.Args[1:] args := os.Args[1:]
// in case of githooks, translate the arguments comming from git to work with gitness. // in case of githooks, translate the arguments coming from git to work with gitness.
if gitArgs, fromGit := githook.SanitizeArgsForGit(command, args); fromGit { if gitArgs, fromGit := githook.SanitizeArgsForGit(command, args); fromGit {
return append([]string{hooks.ParamHooks}, gitArgs...) return append([]string{hooks.ParamHooks}, gitArgs...)
} }

View File

@ -7,6 +7,7 @@ package server
import ( import (
"context" "context"
"github.com/harness/gitness/events" "github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
server2 "github.com/harness/gitness/gitrpc/server" server2 "github.com/harness/gitness/gitrpc/server"
@ -176,7 +177,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
cronManager := cron.ProvideCronManager(serverConfig) manager := cron.ProvideManager(serverConfig)
repoGitInfoView := database.ProvideRepoGitInfoView(db) repoGitInfoView := database.ProvideRepoGitInfoView(db)
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView) repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
pubsubConfig := pubsub.ProvideConfig(config) pubsubConfig := pubsub.ProvideConfig(config)
@ -186,6 +187,6 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
return nil, err return nil, err
} }
servicesServices := services.ProvideServices(webhookService, pullreqService) servicesServices := services.ProvideServices(webhookService, pullreqService)
serverSystem := newSystem(bootstrapBootstrap, serverServer, server3, cronManager, servicesServices) serverSystem := newSystem(bootstrapBootstrap, serverServer, server3, manager, servicesServices)
return serverSystem, nil return serverSystem, nil
} }

View File

@ -7,6 +7,7 @@ package server
import ( import (
"context" "context"
"github.com/harness/gitness/events" "github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
server2 "github.com/harness/gitness/gitrpc/server" server2 "github.com/harness/gitness/gitrpc/server"
@ -143,7 +144,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
cronManager := cron.ProvideCronManager(serverConfig) manager := cron.ProvideManager(serverConfig)
repoGitInfoView := database.ProvideRepoGitInfoView(db) repoGitInfoView := database.ProvideRepoGitInfoView(db)
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView) repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
pubsubConfig := pubsub.ProvideConfig(config) pubsubConfig := pubsub.ProvideConfig(config)
@ -153,6 +154,6 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
return nil, err return nil, err
} }
servicesServices := services.ProvideServices(webhookService, pullreqService) servicesServices := services.ProvideServices(webhookService, pullreqService)
serverSystem := newSystem(bootstrapBootstrap, serverServer, server3, cronManager, servicesServices) serverSystem := newSystem(bootstrapBootstrap, serverServer, server3, manager, servicesServices)
return serverSystem, nil return serverSystem, nil
} }

View File

@ -18,12 +18,12 @@ type system struct {
server *server.Server server *server.Server
gitRPCServer *gitrpcserver.Server gitRPCServer *gitrpcserver.Server
services services.Services services services.Services
gitRPCCronMngr *gitrpccron.CronManager gitRPCCronMngr *gitrpccron.Manager
} }
// newSystem returns a new system structure. // newSystem returns a new system structure.
func newSystem(bootstrap bootstrap.Bootstrap, server *server.Server, gitRPCServer *gitrpcserver.Server, func newSystem(bootstrap bootstrap.Bootstrap, server *server.Server, gitRPCServer *gitrpcserver.Server,
gitrpccron *gitrpccron.CronManager, services services.Services) *system { gitrpccron *gitrpccron.Manager, services services.Services) *system {
return &system{ return &system{
bootstrap: bootstrap, bootstrap: bootstrap,
server: server, server: server,

View File

@ -60,7 +60,7 @@ func (f *ReaderFactory[R]) Launch(ctx context.Context,
category: f.category, category: f.category,
} }
// create new reader (could return the innerReader itself, but also allows to launch costumized readers) // create new reader (could return the innerReader itself, but also allows to launch customized readers)
reader, err := f.readerFactoryFn(innerReader) reader, err := f.readerFactoryFn(innerReader)
if err != nil { if err != nil {
//nolint:gocritic // only way to achieve this AFAIK - lint proposal is not building //nolint:gocritic // only way to achieve this AFAIK - lint proposal is not building
@ -165,7 +165,7 @@ func ReaderRegisterEvent[T interface{}](reader *GenericReader,
} }
// retrieve bytes from raw event // retrieve bytes from raw event
// NOTE: Redis returns []byte as string - to avoid unnecessary convertion we handle both types here. // NOTE: Redis returns []byte as string - to avoid unnecessary conversion we handle both types here.
var eventBytes []byte var eventBytes []byte
switch v := eventRaw.(type) { switch v := eventRaw.(type) {
case string: case string:

View File

@ -1,3 +1,7 @@
// 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 enum package enum
import "github.com/harness/gitness/gitrpc/rpc" import "github.com/harness/gitness/gitrpc/rpc"

View File

@ -18,9 +18,9 @@ import (
"github.com/harness/gitness/gitrpc/enum" "github.com/harness/gitness/gitrpc/enum"
"github.com/harness/gitness/gitrpc/internal/tempdir" "github.com/harness/gitness/gitrpc/internal/tempdir"
"github.com/harness/gitness/gitrpc/internal/types" "github.com/harness/gitness/gitrpc/internal/types"
"github.com/rs/zerolog/log"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"github.com/rs/zerolog/log"
) )
// CreateTemporaryRepo creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch // CreateTemporaryRepo creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch
@ -251,6 +251,9 @@ func commitAndSignNoAuthor(
return nil return nil
} }
// Merge merges changes between 2 refs (branch, commits or tags).
//
//nolint:gocognit,nestif
func (g Adapter) Merge( func (g Adapter) Merge(
ctx context.Context, ctx context.Context,
pr *types.PullRequest, pr *types.PullRequest,
@ -288,7 +291,7 @@ func (g Adapter) Merge(
// Merge with squash // Merge with squash
cmd := git.NewCommand(ctx, "merge", "--squash", trackingBranch) cmd := git.NewCommand(ctx, "merge", "--squash", trackingBranch)
if err := runMergeCommand(ctx, pr, mergeMethod, cmd, tmpBasePath, env); err != nil { if err := runMergeCommand(ctx, pr, mergeMethod, cmd, tmpBasePath, env); err != nil {
return fmt.Errorf("unable to merge --squash tracking into base: %v", err) return fmt.Errorf("unable to merge --squash tracking into base: %w", err)
} }
if signArg == "" { if signArg == "" {
@ -322,7 +325,10 @@ func (g Adapter) Merge(
Stdout: &outbuf, Stdout: &outbuf,
Stderr: &errbuf, Stderr: &errbuf,
}); err != nil { }); err != nil {
return fmt.Errorf("git checkout base prior to merge post staging rebase [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf(
"git checkout base prior to merge post staging rebase [%s -> %s]: %w\n%s\n%s",
pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String(),
)
} }
outbuf.Reset() outbuf.Reset()
errbuf.Reset() errbuf.Reset()
@ -337,25 +343,35 @@ func (g Adapter) Merge(
// Rebase will leave a REBASE_HEAD file in .git if there is a conflict // Rebase will leave a REBASE_HEAD file in .git if there is a conflict
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil { if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil {
var commitSha string var commitSha string
// TBD git version we will support // TBD git version we will support
// failingCommitPath := filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit") // Git < 2.26 // failingCommitPath := filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit") // Git < 2.26
// if _, statErr := os.Stat(failingCommitPath); statErr != nil { // if _, cpErr := os.Stat(failingCommitPath); statErr != nil {
// return fmt.Errorf("git rebase staging on to base [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) // return fmt.Errorf("git rebase staging on to base [%s -> %s]: %v\n%s\n%s",
// pr.HeadBranch, pr.BaseBranch, cpErr, outbuf.String(), errbuf.String())
// } // }
failingCommitPath := filepath.Join(tmpBasePath, ".git", "rebase-merge", "stopped-sha") // Git >= 2.26 failingCommitPath := filepath.Join(tmpBasePath, ".git", "rebase-merge", "stopped-sha") // Git >= 2.26
if _, statErr := os.Stat(failingCommitPath); statErr != nil { if _, cpErr := os.Stat(failingCommitPath); cpErr != nil {
return fmt.Errorf("git rebase staging on to base [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf(
"git rebase staging on to base [%s -> %s]: %w\n%s\n%s",
pr.HeadBranch, pr.BaseBranch, cpErr, outbuf.String(), errbuf.String(),
)
} }
commitShaBytes, readErr := os.ReadFile(failingCommitPath) commitShaBytes, readErr := os.ReadFile(failingCommitPath)
if readErr != nil { if readErr != nil {
// Abandon this attempt to handle the error // Abandon this attempt to handle the error
return fmt.Errorf("git rebase staging on to base [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf(
"git rebase staging on to base [%s -> %s]: %w\n%s\n%s",
pr.HeadBranch, pr.BaseBranch, readErr, outbuf.String(), errbuf.String(),
)
} }
commitSha = strings.TrimSpace(string(commitShaBytes)) commitSha = strings.TrimSpace(string(commitShaBytes))
log.Debug().Msgf("RebaseConflict at %s [%s -> %s]: %v\n%s\n%s", commitSha, pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Debug().Msgf("RebaseConflict at %s [%s -> %s]: %v\n%s\n%s",
commitSha, pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String(),
)
return &types.MergeConflictsError{ return &types.MergeConflictsError{
Method: mergeMethod, Method: mergeMethod,
CommitSHA: commitSha, CommitSHA: commitSha,
@ -364,7 +380,10 @@ func (g Adapter) Merge(
Err: err, Err: err,
} }
} }
return fmt.Errorf("git rebase staging on to base [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf(
"git rebase staging on to base [%s -> %s]: %w\n%s\n%s",
pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String(),
)
} }
outbuf.Reset() outbuf.Reset()
errbuf.Reset() errbuf.Reset()
@ -376,7 +395,10 @@ func (g Adapter) Merge(
Stdout: &outbuf, Stdout: &outbuf,
Stderr: &errbuf, Stderr: &errbuf,
}); err != nil { }); err != nil {
return fmt.Errorf("git checkout base prior to merge post staging rebase [%s -> %s]: %v\n%s\n%s", pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf(
"git checkout base prior to merge post staging rebase [%s -> %s]: %w\n%s\n%s",
pr.HeadBranch, pr.BaseBranch, err, outbuf.String(), errbuf.String(),
)
} }
outbuf.Reset() outbuf.Reset()
errbuf.Reset() errbuf.Reset()

View File

@ -9,13 +9,13 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/harness/gitness/gitrpc/rpc"
"io" "io"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/harness/gitness/gitrpc/internal/types" "github.com/harness/gitness/gitrpc/internal/types"
"github.com/harness/gitness/gitrpc/rpc"
gitea "code.gitea.io/gitea/modules/git" gitea "code.gitea.io/gitea/modules/git"
) )
@ -62,7 +62,12 @@ func (g Adapter) GetAnnotatedTags(ctx context.Context, repoPath string, shas []s
return tags, nil return tags, nil
} }
func (g Adapter) CreateAnnotatedTag(ctx context.Context, repoPath string, request *rpc.CreateTagRequest, env []string) error { func (g Adapter) CreateAnnotatedTag(
ctx context.Context,
repoPath string,
request *rpc.CreateTagRequest,
env []string,
) error {
cmd := gitea.NewCommand(ctx, "tag", "-a", "-m", request.GetMessage(), "--", request.GetTagName(), request.GetSha()) cmd := gitea.NewCommand(ctx, "tag", "-a", "-m", request.GetMessage(), "--", request.GetTagName(), request.GetSha())
_, _, err := cmd.RunStdString(&gitea.RunOpts{Dir: repoPath, Env: env}) _, _, err := cmd.RunStdString(&gitea.RunOpts{Dir: repoPath, Env: env})
if err != nil { if err != nil {
@ -75,7 +80,7 @@ func (g Adapter) DeleteTag(ctx context.Context, repoPath string, ref string, env
cmd := gitea.NewCommand(ctx, "tag", "-d", ref) cmd := gitea.NewCommand(ctx, "tag", "-d", ref)
_, stdErr, err := cmd.RunStdString(&gitea.RunOpts{Dir: repoPath, Env: env}) _, stdErr, err := cmd.RunStdString(&gitea.RunOpts{Dir: repoPath, Env: env})
if err != nil { if err != nil {
return processGiteaErrorf(err, "Service failed to delete tag with error", stdErr) return processGiteaErrorf(err, "Service failed to delete tag with error: %v", stdErr)
} }
return nil return nil
} }
@ -200,7 +205,7 @@ func giteaParseCatFileLine(data []byte, start int, header string) (string, int,
return "", 0, fmt.Errorf("expected '%s' but started with '%s'", header, string(data[:lenHeader])) return "", 0, fmt.Errorf("expected '%s' but started with '%s'", header, string(data[:lenHeader]))
} }
// get end of line and start of next line (used externaly, transpose with provided start index) // get end of line and start of next line (used externally, transpose with provided start index)
lineEnd := bytes.IndexByte(data, '\n') lineEnd := bytes.IndexByte(data, '\n')
externalNextLine := start + lineEnd + 1 externalNextLine := start + lineEnd + 1
if lineEnd == -1 { if lineEnd == -1 {

View File

@ -70,7 +70,7 @@ func (g Adapter) GetTreeNode(ctx context.Context, repoPath string,
func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string, func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
ref string, treePath string, recursive bool, includeLatestCommit bool) ([]types.TreeNodeWithCommit, error) { ref string, treePath string, recursive bool, includeLatestCommit bool) ([]types.TreeNodeWithCommit, error) {
if recursive && includeLatestCommit { if recursive && includeLatestCommit {
// To avoid potential performance catastrophies, block recursive with includeLatestCommit // To avoid potential performance catastrophe, block recursive with includeLatestCommit
// TODO: this should return bad error to caller if needed? // TODO: this should return bad error to caller if needed?
// TODO: should this be refactored in two methods? // TODO: should this be refactored in two methods?
return nil, fmt.Errorf("latest commit with recursive query is not supported") return nil, fmt.Errorf("latest commit with recursive query is not supported")

View File

@ -175,7 +175,7 @@ func (s ReferenceService) ListBranches(request *rpc.ListBranchesRequest,
ctx := stream.Context() ctx := stream.Context()
repoPath := getFullPathForRepo(s.reposRoot, base.GetRepoUid()) repoPath := getFullPathForRepo(s.reposRoot, base.GetRepoUid())
// get all required information from git refrences // get all required information from git references
branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request) branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request)
if err != nil { if err != nil {
return err return err

View File

@ -12,6 +12,7 @@ import (
"github.com/harness/gitness/gitrpc/enum" "github.com/harness/gitness/gitrpc/enum"
"github.com/harness/gitness/gitrpc/internal/types" "github.com/harness/gitness/gitrpc/internal/types"
"github.com/harness/gitness/gitrpc/rpc"
) )
// GitAdapter for accessing git commands from gitea. // GitAdapter for accessing git commands from gitea.

View File

@ -66,7 +66,7 @@ func (s MergeService) Merge(
defer func() { defer func() {
rmErr := tempdir.RemoveTemporaryPath(tmpBasePath) rmErr := tempdir.RemoveTemporaryPath(tmpBasePath)
if rmErr != nil { if rmErr != nil {
log.Ctx(ctx).Warn().Msgf("Removing temporary location %s for merge operation was not successfull", tmpBasePath) log.Ctx(ctx).Warn().Msgf("Removing temporary location %s for merge operation was not successful", tmpBasePath)
} }
}() }()
@ -88,6 +88,11 @@ func (s MergeService) Merge(
return nil, fmt.Errorf("failed to get merge base: %w", err) return nil, fmt.Errorf("failed to get merge base: %w", err)
} }
if headCommitSHA == mergeBaseCommitSHA {
return nil, ErrInvalidArgumentf("no changes between head branch %s and base branch %s",
request.HeadBranch, request.BaseBranch)
}
if request.HeadExpectedSha != "" && request.HeadExpectedSha != headCommitSHA { if request.HeadExpectedSha != "" && request.HeadExpectedSha != headCommitSHA {
return nil, status.Errorf( return nil, status.Errorf(
codes.FailedPrecondition, codes.FailedPrecondition,

View File

@ -87,7 +87,7 @@ func (s *CommitFilesService) CommitFiles(stream rpc.CommitFilesService_CommitFil
// check if repo is empty // check if repo is empty
// IMPORTANT: we don't use gitea's repo.IsEmpty() as that only checks whether the default branch exists (in HEAD). // IMPORTANT: we don't use gitea's repo.IsEmpty() as that only checks whether the default branch exists (in HEAD).
// This can be an issue in case someone created a branch already in the repo (just default branch is missing). // This can be an issue in case someone created a branch already in the repo (just default branch is missing).
// In that case the user can accidentaly create separate git histories (which most likely is unintended). // In that case the user can accidentally create separate git histories (which most likely is unintended).
// If the user wants to actually build a disconnected commit graph they can use the cli. // If the user wants to actually build a disconnected commit graph they can use the cli.
isEmpty, err := repoHasBranches(ctx, repo) isEmpty, err := repoHasBranches(ctx, repo)
if err != nil { if err != nil {
@ -225,7 +225,7 @@ func (s *CommitFilesService) validateAndPrepareHeader(repo *git.Repository, isEm
header.BranchName = strings.TrimPrefix(strings.TrimSpace(header.GetBranchName()), gitReferenceNamePrefixBranch) header.BranchName = strings.TrimPrefix(strings.TrimSpace(header.GetBranchName()), gitReferenceNamePrefixBranch)
header.NewBranchName = strings.TrimPrefix(strings.TrimSpace(header.GetNewBranchName()), gitReferenceNamePrefixBranch) header.NewBranchName = strings.TrimPrefix(strings.TrimSpace(header.GetNewBranchName()), gitReferenceNamePrefixBranch)
// if the repo is empty then we can skip branch existance checks // if the repo is empty then we can skip branch existence checks
if isEmpty { if isEmpty {
return nil return nil
} }

View File

@ -10,7 +10,7 @@ import (
) )
// getFullPathForRepo returns the full path of a repo given the root dir of repos and the uid of the repo. // getFullPathForRepo returns the full path of a repo given the root dir of repos and the uid of the repo.
// NOTE: Split repos into subfolders using their prefix to distribute repos accross a set of folders. // NOTE: Split repos into subfolders using their prefix to distribute repos across a set of folders.
func getFullPathForRepo(reposRoot, uid string) string { func getFullPathForRepo(reposRoot, uid string) string {
// ASSUMPTION: repoUID is of lenth at least 4 - otherwise we have trouble either way. // ASSUMPTION: repoUID is of lenth at least 4 - otherwise we have trouble either way.
return filepath.Join( return filepath.Join(

View File

@ -78,7 +78,7 @@ func createReferenceWalkPatternsFromQuery(basePath string, query string) []strin
return []string{} return []string{}
} }
// ensure non-empty basepath ends with "/" for proper matching and concatination. // ensure non-empty basepath ends with "/" for proper matching and concatenation.
if basePath != "" && basePath[len(basePath)-1] != '/' { if basePath != "" && basePath[len(basePath)-1] != '/' {
basePath += "/" basePath += "/"
} }

View File

@ -5,11 +5,13 @@
package service package service
import ( import (
"code.gitea.io/gitea/modules/git"
"context" "context"
"fmt" "fmt"
"github.com/harness/gitness/gitrpc/internal/types" "github.com/harness/gitness/gitrpc/internal/types"
"github.com/harness/gitness/gitrpc/rpc" "github.com/harness/gitness/gitrpc/rpc"
"code.gitea.io/gitea/modules/git"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@ -183,7 +185,10 @@ func listCommitTagsWalkReferencesHandler(tags *[]*rpc.CommitTag) types.WalkRefer
return nil return nil
} }
} }
func (s ReferenceService) CreateTag(ctx context.Context, createTagRequest *rpc.CreateTagRequest) (*rpc.CreateTagResponse, error) { func (s ReferenceService) CreateTag(
ctx context.Context,
createTagRequest *rpc.CreateTagRequest,
) (*rpc.CreateTagResponse, error) {
base := createTagRequest.GetBase() base := createTagRequest.GetBase()
if base == nil { if base == nil {
return nil, types.ErrBaseCannotBeEmpty return nil, types.ErrBaseCannotBeEmpty
@ -233,8 +238,11 @@ func (s ReferenceService) CreateTag(ctx context.Context, createTagRequest *rpc.C
return &rpc.CreateTagResponse{Tag: commitTag}, nil return &rpc.CreateTagResponse{Tag: commitTag}, nil
} }
func (s ReferenceService) DeleteTag(ctx context.Context, deleteTagRequest *rpc.DeleteTagRequest) (*rpc.UpdateRefResponse, error) { func (s ReferenceService) DeleteTag(
base := deleteTagRequest.GetBase() ctx context.Context,
request *rpc.DeleteTagRequest,
) (*rpc.UpdateRefResponse, error) {
base := request.GetBase()
if base == nil { if base == nil {
return nil, types.ErrBaseCannotBeEmpty return nil, types.ErrBaseCannotBeEmpty
} }
@ -256,17 +264,23 @@ func (s ReferenceService) DeleteTag(ctx context.Context, deleteTagRequest *rpc.D
err = sharedRepo.Clone(ctx, "") err = sharedRepo.Clone(ctx, "")
if err != nil { if err != nil {
return nil, processGitErrorf(err, "failed to clone shared repo with tag '%s'", deleteTagRequest.GetTagName()) return nil, processGitErrorf(err, "failed to clone shared repo with tag '%s'", request.GetTagName())
} }
actor := deleteTagRequest.GetBase().GetActor() actor := request.GetBase().GetActor()
env := append(CreateEnvironmentForPush(ctx, base), env := append(CreateEnvironmentForPush(ctx, base),
"GIT_COMMITTER_NAME="+actor.GetName(), "GIT_COMMITTER_NAME="+actor.GetName(),
"GIT_COMMITTER_EMAIL="+actor.GetEmail(), "GIT_COMMITTER_EMAIL="+actor.GetEmail(),
) )
err = s.adapter.DeleteTag(ctx, repoPath, deleteTagRequest.TagName, env)
sharedRepo.PushDeleteBranch(ctx, base, "") err = s.adapter.DeleteTag(ctx, repoPath, request.TagName, env)
if err != nil { if err != nil {
return nil, processGitErrorf(err, "Failed to delete the tag") return nil, processGitErrorf(err, "Failed to delete the tag %s", request.GetTagName())
} }
err = sharedRepo.PushDeleteBranch(ctx, base, "")
if err != nil {
return nil, processGitErrorf(err, "failed to delete tag '%s' from remote repo", request.GetTagName())
}
return &rpc.UpdateRefResponse{}, nil return &rpc.UpdateRefResponse{}, nil
} }

View File

@ -208,7 +208,7 @@ func mapRPCTreeNodeType(t rpc.TreeNodeType) (TreeNodeType, error) {
case rpc.TreeNodeType_TreeNodeTypeTree: case rpc.TreeNodeType_TreeNodeTypeTree:
return TreeNodeTypeTree, nil return TreeNodeTypeTree, nil
default: default:
return TreeNodeTypeBlob, fmt.Errorf("unkown rpc tree node type: %d", t) return TreeNodeTypeBlob, fmt.Errorf("unknown rpc tree node type: %d", t)
} }
} }
@ -225,7 +225,7 @@ func mapRPCTreeNodeMode(m rpc.TreeNodeMode) (TreeNodeMode, error) {
case rpc.TreeNodeMode_TreeNodeModeTree: case rpc.TreeNodeMode_TreeNodeModeTree:
return TreeNodeModeTree, nil return TreeNodeModeTree, nil
default: default:
return TreeNodeModeFile, fmt.Errorf("unkown rpc tree node mode: %d", m) return TreeNodeModeFile, fmt.Errorf("unknown rpc tree node mode: %d", m)
} }
} }

View File

@ -1,3 +1,7 @@
// 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 cron package cron
import ( import (
@ -7,10 +11,11 @@ import (
"path/filepath" "path/filepath"
"github.com/harness/gitness/gitrpc/server" "github.com/harness/gitness/gitrpc/server"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
// cleanup repository graveyard // cleanupRepoGraveyard cleanups repository graveyard.
func cleanupRepoGraveyard(ctx context.Context, graveyardpath string) error { func cleanupRepoGraveyard(ctx context.Context, graveyardpath string) error {
logger := log.Ctx(ctx) logger := log.Ctx(ctx)
repolist, err := os.ReadDir(graveyardpath) repolist, err := os.ReadDir(graveyardpath)
@ -32,7 +37,7 @@ func cleanupRepoGraveyard(ctx context.Context, graveyardpath string) error {
return nil return nil
} }
func AddAllGitRPCCronJobs(cm *CronManager, gitrpcconfig server.Config) error { func AddAllGitRPCCronJobs(cm *Manager, gitrpcconfig server.Config) error {
// periodic repository graveyard cleanup // periodic repository graveyard cleanup
graveyardpath := filepath.Join(gitrpcconfig.GitRoot, server.ReposGraveyardSubdirName) graveyardpath := filepath.Join(gitrpcconfig.GitRoot, server.ReposGraveyardSubdirName)
err := cm.NewCronTask(Nightly, func(ctx context.Context) error { return cleanupRepoGraveyard(ctx, graveyardpath) }) err := cm.NewCronTask(Nightly, func(ctx context.Context) error { return cleanupRepoGraveyard(ctx, graveyardpath) })

View File

@ -1,8 +1,11 @@
// 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 cron package cron
import ( import (
"context" "context"
"io/ioutil"
"os" "os"
"testing" "testing"
) )
@ -10,8 +13,8 @@ import (
func TestCleanupRepoGraveyardFunc(t *testing.T) { func TestCleanupRepoGraveyardFunc(t *testing.T) {
ctx := context.Background() ctx := context.Background()
tmpDir := t.TempDir() tmpDir := t.TempDir()
//create a dummy repository // create a dummy repository
testRepo, _ := ioutil.TempDir(tmpDir, "TestRepo100") testRepo, _ := os.MkdirTemp(tmpDir, "TestRepo100")
err := cleanupRepoGraveyard(ctx, tmpDir) err := cleanupRepoGraveyard(ctx, tmpDir)
if err != nil { if err != nil {
t.Error("cleanupRepoGraveyard failed") t.Error("cleanupRepoGraveyard failed")

View File

@ -1,3 +1,7 @@
// 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 cron package cron
import ( import (
@ -9,8 +13,8 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
// Format: seconds minute(0-59) hour(0-23) day of month(1-31) month(1-12) day of week(0-6).
const ( const (
//Format: seconds minute(0-59) hour(0-23) day of month(1-31) month(1-12) day of week(0-6)
Hourly = "0 0 * * * *" // once an hour at minute 0 Hourly = "0 0 * * * *" // once an hour at minute 0
Nightly = "0 0 0 * * *" // once a day at midnight Nightly = "0 0 0 * * *" // once a day at midnight
Weekly = "0 0 0 * * 0" // once a week on Sun midnight Weekly = "0 0 0 * * 0" // once a week on Sun midnight
@ -18,25 +22,25 @@ const (
EverySecond = "* * * * * *" // every second (for testing) EverySecond = "* * * * * *" // every second (for testing)
) )
var ErrFatal = errors.New("fatal error occured") var ErrFatal = errors.New("fatal error occurred")
type CronManager struct { type Manager struct {
c *cron.Cron c *cron.Cron
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
fatal chan error fatal chan error
} }
// options could be location, logger, etc. // NewManager creates a cron manager.
func NewCronManager() *CronManager { func NewManager() *Manager {
return &CronManager{ return &Manager{
c: cron.New(cron.WithSeconds()), c: cron.New(cron.WithSeconds()),
fatal: make(chan error), fatal: make(chan error),
} }
} }
// add a new func to cron job // NewCronTask adds a new func to cron job.
func (c *CronManager) NewCronTask(sepc string, job func(ctx context.Context) error) error { func (c *Manager) NewCronTask(sepc string, job func(ctx context.Context) error) error {
_, err := c.c.AddFunc(sepc, func() { _, err := c.c.AddFunc(sepc, func() {
jerr := job(c.ctx) jerr := job(c.ctx)
if jerr != nil { // check different severity of errors if jerr != nil { // check different severity of errors
@ -55,7 +59,7 @@ func (c *CronManager) NewCronTask(sepc string, job func(ctx context.Context) err
} }
// Run the cron scheduler, or no-op if already running. // Run the cron scheduler, or no-op if already running.
func (c *CronManager) Run(ctx context.Context) error { func (c *Manager) Run(ctx context.Context) error {
c.ctx, c.cancel = context.WithCancel(ctx) c.ctx, c.cancel = context.WithCancel(ctx)
var err error var err error
go func() { go func() {
@ -63,7 +67,7 @@ func (c *CronManager) Run(ctx context.Context) error {
case <-ctx.Done(): case <-ctx.Done():
err = fmt.Errorf("context done: %w", ctx.Err()) err = fmt.Errorf("context done: %w", ctx.Err())
case fErr := <-c.fatal: case fErr := <-c.fatal:
err = fmt.Errorf("fatal error occured: %w", fErr) err = fmt.Errorf("fatal error occurred: %w", fErr)
} }
// stop scheduling of new jobs. // stop scheduling of new jobs.

View File

@ -1,3 +1,7 @@
// 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 cron package cron
import ( import (
@ -8,7 +12,7 @@ import (
"time" "time"
) )
func run(cmngr *CronManager, ctx context.Context) chan error { func run(ctx context.Context, cmngr *Manager) chan error {
cron := make(chan error) cron := make(chan error)
go func() { go func() {
cron <- cmngr.Run(ctx) cron <- cmngr.Run(ctx)
@ -17,14 +21,14 @@ func run(cmngr *CronManager, ctx context.Context) chan error {
} }
func TestCronManagerFatalErr(t *testing.T) { func TestCronManagerFatalErr(t *testing.T) {
cmngr := NewCronManager() cmngr := NewManager()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
_ = cmngr.NewCronTask(EverySecond, func(ctx context.Context) error { _ = cmngr.NewCronTask(EverySecond, func(ctx context.Context) error {
return fmt.Errorf("inner: %w", ErrFatal) return fmt.Errorf("inner: %w", ErrFatal)
}) })
select { select {
case ferr := <-run(cmngr, ctx): case ferr := <-run(ctx, cmngr):
if ferr == nil { if ferr == nil {
t.Error("Cronmanager failed to receive fatal error") t.Error("Cronmanager failed to receive fatal error")
} }
@ -34,14 +38,14 @@ func TestCronManagerFatalErr(t *testing.T) {
} }
func TestCronManagerNonFatalErr(t *testing.T) { func TestCronManagerNonFatalErr(t *testing.T) {
cmngr := NewCronManager() cmngr := NewManager()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
_ = cmngr.NewCronTask(EverySecond, func(ctx context.Context) error { _ = cmngr.NewCronTask(EverySecond, func(ctx context.Context) error {
return errors.New("dummy error") return errors.New("dummy error")
}) })
select { select {
case ferr := <-run(cmngr, ctx): case ferr := <-run(ctx, cmngr):
if ferr != nil { if ferr != nil {
t.Error("Cronmanager failed at a non fatal error") t.Error("Cronmanager failed at a non fatal error")
} }
@ -50,7 +54,7 @@ func TestCronManagerNonFatalErr(t *testing.T) {
} }
} }
func TestCronManagerNewTask(t *testing.T) { func TestCronManagerNewTask(t *testing.T) {
cmngr := NewCronManager() cmngr := NewManager()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
a := 0 a := 0
@ -61,7 +65,7 @@ func TestCronManagerNewTask(t *testing.T) {
}) })
select { select {
case cerr := <-run(cmngr, ctx): case cerr := <-run(ctx, cmngr):
if cerr != nil { if cerr != nil {
t.Error("Cronmanager failed at Run:", cerr) t.Error("Cronmanager failed at Run:", cerr)
} }
@ -73,7 +77,7 @@ func TestCronManagerNewTask(t *testing.T) {
} }
func TestCronManagerStopOnCtxCancel(t *testing.T) { func TestCronManagerStopOnCtxCancel(t *testing.T) {
cmngr := NewCronManager() cmngr := NewManager()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() defer cancel()
@ -88,7 +92,7 @@ func TestCronManagerStopOnCtxCancel(t *testing.T) {
} }
func TestCronManagerStopOnCtxTimeout(t *testing.T) { func TestCronManagerStopOnCtxTimeout(t *testing.T) {
cmngr := NewCronManager() cmngr := NewManager()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel() defer cancel()

View File

@ -1,15 +1,20 @@
// 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 cron package cron
import ( import (
"github.com/google/wire"
"github.com/harness/gitness/gitrpc/server" "github.com/harness/gitness/gitrpc/server"
"github.com/google/wire"
) )
// WireSet provides a wire set for this package. // WireSet provides a wire set for this package.
var WireSet = wire.NewSet(ProvideCronManager) var WireSet = wire.NewSet(ProvideManager)
func ProvideCronManager(gitrpcconfig server.Config) *CronManager { func ProvideManager(gitrpcconfig server.Config) *Manager {
cmngr := NewCronManager() cmngr := NewManager()
_ = AddAllGitRPCCronJobs(cmngr, gitrpcconfig) _ = AddAllGitRPCCronJobs(cmngr, gitrpcconfig)
return cmngr return cmngr
} }

View File

@ -60,13 +60,13 @@ func (p *CreateTagParams) Validate() error {
} }
if p.Name == "" { if p.Name == "" {
return errors.New("Tag name cannot be empty") return errors.New("tag name cannot be empty")
} }
if p.SHA == "" { if p.SHA == "" {
return errors.New("Target cannot be empty") return errors.New("target cannot be empty")
} }
if p.Message == "" { if p.Message == "" {
return errors.New("Message cannot be empty") return errors.New("message cannot be empty")
} }
return nil return nil
} }
@ -140,7 +140,6 @@ func (c *Client) ListCommitTags(ctx context.Context, params *ListCommitTagsParam
return output, nil return output, nil
} }
func (c *Client) CreateTag(ctx context.Context, params *CreateTagParams) (*CreateTagOutput, error) { func (c *Client) CreateTag(ctx context.Context, params *CreateTagParams) (*CreateTagOutput, error) {
err := params.Validate() err := params.Validate()
if err != nil { if err != nil {
@ -167,11 +166,9 @@ func (c *Client) CreateTag(ctx context.Context, params *CreateTagParams) (*Creat
return &CreateTagOutput{ return &CreateTagOutput{
CommitTag: *commitTag, CommitTag: *commitTag,
}, nil }, nil
} }
func (c *Client) DeleteTag(ctx context.Context, params *DeleteTagParams) error { func (c *Client) DeleteTag(ctx context.Context, params *DeleteTagParams) error {
err := params.Validate() err := params.Validate()
if err != nil { if err != nil {

View File

@ -64,7 +64,7 @@ func (c *Controller) CommentStatus(
return errValidate return errValidate
} }
act, err = c.getCommentCheckChangeStatusAccess(ctx, session, pr, commentID) act, err = c.getCommentCheckChangeStatusAccess(ctx, pr, commentID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get comment: %w", err) return fmt.Errorf("failed to get comment: %w", err)
} }

View File

@ -122,7 +122,7 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
} }
func (c *Controller) getCommentCheckModifyAccess(ctx context.Context, func (c *Controller) getCommentCheckModifyAccess(ctx context.Context,
session *auth.Session, pr *types.PullReq, commentID int64, pr *types.PullReq, commentID int64,
) (*types.PullReqActivity, error) { ) (*types.PullReqActivity, error) {
if commentID <= 0 { if commentID <= 0 {
return nil, usererror.BadRequest("A valid comment ID must be provided.") return nil, usererror.BadRequest("A valid comment ID must be provided.")
@ -155,7 +155,7 @@ func (c *Controller) getCommentCheckModifyAccess(ctx context.Context,
func (c *Controller) getCommentCheckEditAccess(ctx context.Context, func (c *Controller) getCommentCheckEditAccess(ctx context.Context,
session *auth.Session, pr *types.PullReq, commentID int64, session *auth.Session, pr *types.PullReq, commentID int64,
) (*types.PullReqActivity, error) { ) (*types.PullReqActivity, error) {
comment, err := c.getCommentCheckModifyAccess(ctx, session, pr, commentID) comment, err := c.getCommentCheckModifyAccess(ctx, pr, commentID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -168,9 +168,9 @@ func (c *Controller) getCommentCheckEditAccess(ctx context.Context,
} }
func (c *Controller) getCommentCheckChangeStatusAccess(ctx context.Context, func (c *Controller) getCommentCheckChangeStatusAccess(ctx context.Context,
session *auth.Session, pr *types.PullReq, commentID int64, pr *types.PullReq, commentID int64,
) (*types.PullReqActivity, error) { ) (*types.PullReqActivity, error) {
comment, err := c.getCommentCheckModifyAccess(ctx, session, pr, commentID) comment, err := c.getCommentCheckModifyAccess(ctx, pr, commentID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -29,7 +29,7 @@ type MergeInput struct {
// Merge merges the pull request. // Merge merges the pull request.
// //
//nolint:funlen // no need to refactor //nolint:gocognit
func (c *Controller) Merge( func (c *Controller) Merge(
ctx context.Context, ctx context.Context,
session *auth.Session, session *auth.Session,
@ -84,11 +84,15 @@ func (c *Controller) Merge(
} }
if pr.UnresolvedCount > 0 { if pr.UnresolvedCount > 0 {
return types.MergeResponse{}, usererror.BadRequest("Pull requests with unresolved comments can't be merged. Resolve all the comments first.") return types.MergeResponse{}, usererror.BadRequest(
"Pull requests with unresolved comments can't be merged. Resolve all the comments first.",
)
} }
if pr.IsDraft { if pr.IsDraft {
return types.MergeResponse{}, usererror.BadRequest("Draft pull requests can't be merged. Clear the draft flag first.") return types.MergeResponse{}, usererror.BadRequest(
"Draft pull requests can't be merged. Clear the draft flag first.",
)
} }
reviewers, err := c.reviewerStore.List(ctx, pr.ID) reviewers, err := c.reviewerStore.List(ctx, pr.ID)
@ -119,7 +123,12 @@ func (c *Controller) Merge(
} }
// TODO: for forking merge title might be different? // TODO: for forking merge title might be different?
mergeTitle := fmt.Sprintf("Merge branch '%s' of %s (#%d)", pr.SourceBranch, sourceRepo.Path, pr.Number) var mergeTitle string
if in.Method == enum.MergeMethod(gitrpcenum.MergeMethodSquash) {
mergeTitle = fmt.Sprintf("%s (#%d)", pr.Title, pr.Number)
} else {
mergeTitle = fmt.Sprintf("Merge branch '%s' of %s (#%d)", pr.SourceBranch, sourceRepo.Path, pr.Number)
}
var mergeOutput gitrpc.MergeOutput var mergeOutput gitrpc.MergeOutput
mergeOutput, err = c.gitRPCClient.Merge(ctx, &gitrpc.MergeParams{ mergeOutput, err = c.gitRPCClient.Merge(ctx, &gitrpc.MergeParams{

View File

@ -83,12 +83,16 @@ func (c *Controller) Create(
mergeBaseSHA := mergeBaseResult.MergeBaseSHA mergeBaseSHA := mergeBaseResult.MergeBaseSHA
if mergeBaseSHA == sourceSHA {
return nil, usererror.BadRequest("The source branch doesn't contain any new commits")
}
targetRepo, err = c.repoStore.UpdateOptLock(ctx, targetRepo, func(repo *types.Repository) error { targetRepo, err = c.repoStore.UpdateOptLock(ctx, targetRepo, func(repo *types.Repository) error {
repo.PullReqSeq++ repo.PullReqSeq++
return nil return nil
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to aquire PullReqSeq number: %w", err) return nil, fmt.Errorf("failed to acquire PullReqSeq number: %w", err)
} }
pr := newPullReq(session, targetRepo.PullReqSeq, sourceRepo, targetRepo, in, sourceSHA, mergeBaseSHA) pr := newPullReq(session, targetRepo.PullReqSeq, sourceRepo, targetRepo, in, sourceSHA, mergeBaseSHA)

View File

@ -7,6 +7,7 @@ package repo
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
apiauth "github.com/harness/gitness/internal/api/auth" apiauth "github.com/harness/gitness/internal/api/auth"
"github.com/harness/gitness/internal/auth" "github.com/harness/gitness/internal/auth"
@ -57,7 +58,7 @@ func (c *Controller) CreateTag(ctx context.Context, session *auth.Session,
commitTag, err := mapCommitTag(rpcOut.CommitTag) commitTag, err := mapCommitTag(rpcOut.CommitTag)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to map tag recieved from service output: %w", err) return nil, fmt.Errorf("failed to map tag received from service output: %w", err)
} }
return &commitTag, nil return &commitTag, nil
} }

View File

@ -27,7 +27,7 @@ type CommitDivergenceRequest struct {
// From is the ref from which the counting of the diverging commits starts. // From is the ref from which the counting of the diverging commits starts.
From string `json:"from"` From string `json:"from"`
// To is the ref at which the counting of the diverging commits ends. // To is the ref at which the counting of the diverging commits ends.
// If the value is empty the divergence is caluclated to the default branch of the repo. // If the value is empty the divergence is calculated to the default branch of the repo.
To string `json:"to"` To string `json:"to"`
} }

View File

@ -13,7 +13,7 @@ import (
"github.com/harness/gitness/types/enum" "github.com/harness/gitness/types/enum"
) )
// Delete deletes a sevice account. // Delete deletes a service account.
func (c *Controller) Delete(ctx context.Context, session *auth.Session, func (c *Controller) Delete(ctx context.Context, session *auth.Session,
saUID string) error { saUID string) error {
sa, err := findServiceAccountFromUID(ctx, c.principalStore, saUID) sa, err := findServiceAccountFromUID(ctx, c.principalStore, saUID)

View File

@ -15,7 +15,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
// DeleteToken deletes a token of a sevice account. // DeleteToken deletes a token of a service account.
func (c *Controller) DeleteToken(ctx context.Context, session *auth.Session, func (c *Controller) DeleteToken(ctx context.Context, session *auth.Session,
saUID string, tokenUID string) error { saUID string, tokenUID string) error {
sa, err := findServiceAccountFromUID(ctx, c.principalStore, saUID) sa, err := findServiceAccountFromUID(ctx, c.principalStore, saUID)

View File

@ -35,8 +35,13 @@ func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef
} }
// DeleteNoAuth bypasses these permission // DeleteNoAuth bypasses these permission
// PermissionSpaceDelete, PermissionSpaceView, PermissionRepoView, PermissionRepoDelete // PermissionSpaceDelete, PermissionSpaceView, PermissionRepoView, PermissionRepoDelete.
func (c *Controller) DeleteNoAuth(ctx context.Context, session *auth.Session, spaceID int64, filter *types.SpaceFilter) error { func (c *Controller) DeleteNoAuth(
ctx context.Context,
session *auth.Session,
spaceID int64,
filter *types.SpaceFilter,
) error {
subSpaces, _, err := c.ListSpacesNoAuth(ctx, spaceID, filter) subSpaces, _, err := c.ListSpacesNoAuth(ctx, spaceID, filter)
if err != nil { if err != nil {
return fmt.Errorf("failed to list space %d sub spaces: %w", spaceID, err) return fmt.Errorf("failed to list space %d sub spaces: %w", spaceID, err)

View File

@ -1,3 +1,7 @@
// 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 space package space
import ( import (
@ -11,7 +15,7 @@ import (
) )
// deleteRepositoriesNoAuth does not check PermissionRepoView, and PermissionRepoDelete permissions // deleteRepositoriesNoAuth does not check PermissionRepoView, and PermissionRepoDelete permissions
// Call this through Delete(Space) api to make sure the caller has DeleteSpace permission // Call this through Delete(Space) api to make sure the caller has DeleteSpace permission.
func (c *Controller) deleteRepositoriesNoAuth(ctx context.Context, session *auth.Session, spaceID int64) error { func (c *Controller) deleteRepositoriesNoAuth(ctx context.Context, session *auth.Session, spaceID int64) error {
filter := &types.RepoFilter{ filter := &types.RepoFilter{
Page: 1, Page: 1,

View File

@ -26,11 +26,14 @@ func (c *Controller) ListRepositories(ctx context.Context, session *auth.Session
return nil, 0, err return nil, 0, err
} }
return c.ListRepositoriesNoAuth(ctx, space.ID, filter) return c.ListRepositoriesNoAuth(ctx, space.ID, filter)
} }
// ListRepositoriesNoAuth list repositories WITHOUT checking for PermissionRepoView. // ListRepositoriesNoAuth list repositories WITHOUT checking for PermissionRepoView.
func (c *Controller) ListRepositoriesNoAuth(ctx context.Context, spaceID int64, filter *types.RepoFilter) ([]*types.Repository, int64, error) { func (c *Controller) ListRepositoriesNoAuth(
ctx context.Context,
spaceID int64,
filter *types.RepoFilter,
) ([]*types.Repository, int64, error) {
count, err := c.repoStore.Count(ctx, spaceID, filter) count, err := c.repoStore.Count(ctx, spaceID, filter)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("failed to count child repos: %w", err) return nil, 0, fmt.Errorf("failed to count child repos: %w", err)

View File

@ -29,7 +29,11 @@ func (c *Controller) ListSpaces(ctx context.Context, session *auth.Session,
} }
// List spaces WITHOUT checking PermissionSpaceView. // List spaces WITHOUT checking PermissionSpaceView.
func (c *Controller) ListSpacesNoAuth(ctx context.Context, spaceID int64, filter *types.SpaceFilter) ([]*types.Space, int64, error) { func (c *Controller) ListSpacesNoAuth(
ctx context.Context,
spaceID int64,
filter *types.SpaceFilter,
) ([]*types.Space, int64, error) {
count, err := c.spaceStore.Count(ctx, spaceID, filter) count, err := c.spaceStore.Count(ctx, spaceID, filter)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("failed to count child spaces: %w", err) return nil, 0, fmt.Errorf("failed to count child spaces: %w", err)

View File

@ -7,8 +7,10 @@ package controller
import ( import (
"context" "context"
"errors" "errors"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/dbtx" "github.com/harness/gitness/internal/store/database/dbtx"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
) )
@ -16,7 +18,7 @@ type TxOptionRetryCount int
// TxOptLock runs the provided function inside a database transaction. If optimistic lock error occurs // TxOptLock runs the provided function inside a database transaction. If optimistic lock error occurs
// during the operation, the function will retry the whole transaction again (to the maximum of 5 times, // during the operation, the function will retry the whole transaction again (to the maximum of 5 times,
// but this can be overridden by providing an additional TxOptionRetryCount option) // but this can be overridden by providing an additional TxOptionRetryCount option).
func TxOptLock(ctx context.Context, func TxOptLock(ctx context.Context,
db *sqlx.DB, db *sqlx.DB,
txFn func(ctx context.Context) error, txFn func(ctx context.Context) error,

View File

@ -384,7 +384,7 @@ func pullReqOperations(reflector *openapi3.Reflector) {
reviewerAdd.WithTags("pullreq") reviewerAdd.WithTags("pullreq")
reviewerAdd.WithMapOfAnything(map[string]interface{}{"operationId": "reviewerAddPullReq"}) reviewerAdd.WithMapOfAnything(map[string]interface{}{"operationId": "reviewerAddPullReq"})
_ = reflector.SetRequest(&reviewerAdd, new(reviewerAddPullReqRequest), http.MethodPut) _ = reflector.SetRequest(&reviewerAdd, new(reviewerAddPullReqRequest), http.MethodPut)
_ = reflector.SetJSONResponse(&reviewerAdd, nil, http.StatusNoContent) _ = reflector.SetJSONResponse(&reviewerAdd, new(types.PullReqReviewer), http.StatusOK)
_ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusBadRequest) _ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusBadRequest)
_ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusUnauthorized) _ = reflector.SetJSONResponse(&reviewerAdd, new(usererror.Error), http.StatusUnauthorized)
@ -396,7 +396,7 @@ func pullReqOperations(reflector *openapi3.Reflector) {
reviewerList.WithTags("pullreq") reviewerList.WithTags("pullreq")
reviewerList.WithMapOfAnything(map[string]interface{}{"operationId": "reviewerListPullReq"}) reviewerList.WithMapOfAnything(map[string]interface{}{"operationId": "reviewerListPullReq"})
_ = reflector.SetRequest(&reviewerList, new(reviewerListPullReqRequest), http.MethodGet) _ = reflector.SetRequest(&reviewerList, new(reviewerListPullReqRequest), http.MethodGet)
_ = reflector.SetJSONResponse(&reviewerList, nil, http.StatusNoContent) _ = reflector.SetJSONResponse(&reviewerList, new([]*types.PullReqReviewer), http.StatusOK)
_ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusBadRequest) _ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusBadRequest)
_ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusUnauthorized) _ = reflector.SetJSONResponse(&reviewerList, new(usererror.Error), http.StatusUnauthorized)

View File

@ -23,7 +23,7 @@ func Pagination(r *http.Request, w http.ResponseWriter, page, size, total int) {
// Add information that doesn't require total // Add information that doesn't require total
PaginationNoTotal(r, w, page, size, page >= last) PaginationNoTotal(r, w, page, size, page >= last)
// add information that requries total // add information that requires total
uri := getPaginationBaseURL(r, page, size) uri := getPaginationBaseURL(r, page, size)
params := uri.Query() params := uri.Query()

View File

@ -11,7 +11,7 @@ import (
var ( var (
// ErrInternal is returned when an internal error occurred. // ErrInternal is returned when an internal error occurred.
ErrInternal = New(http.StatusInternalServerError, "Internal error occured") ErrInternal = New(http.StatusInternalServerError, "Internal error occurred")
// ErrInvalidToken is returned when the api request token is invalid. // ErrInvalidToken is returned when the api request token is invalid.
ErrInvalidToken = New(http.StatusUnauthorized, "Invalid or missing token") ErrInvalidToken = New(http.StatusUnauthorized, "Invalid or missing token")

View File

@ -26,7 +26,7 @@ type Authorizer interface {
* Returns * Returns
* (true, nil) - the action is permitted * (true, nil) - the action is permitted
* (false, nil) - the action is not permitted * (false, nil) - the action is not permitted
* (false, err) - an error occured while performing the permission check and the action should be denied * (false, err) - an error occurred while performing the permission check and the action should be denied
*/ */
Check(ctx context.Context, Check(ctx context.Context,
session *auth.Session, session *auth.Session,
@ -40,7 +40,7 @@ type Authorizer interface {
* Returns * Returns
* (true, nil) - all requested actions are permitted * (true, nil) - all requested actions are permitted
* (false, nil) - at least one requested action is not permitted * (false, nil) - at least one requested action is not permitted
* (false, err) - an error occured while performing the permission check and all actions should be denied * (false, err) - an error occurred while performing the permission check and all actions should be denied
*/ */
CheckAll(ctx context.Context, CheckAll(ctx context.Context,
session *auth.Session, session *auth.Session,

View File

@ -38,7 +38,7 @@ var (
ExecutionTimeout = 3 * time.Minute ExecutionTimeout = 3 * time.Minute
) )
// SanitizeArgsForGit sanitizes the command line arguments (os.Args) if the command indicates they are comming from git. // SanitizeArgsForGit sanitizes the command line arguments (os.Args) if the command indicates they are coming from git.
// Returns the santized args and true if the call comes from git, otherwise the original args are returned with false. // Returns the santized args and true if the call comes from git, otherwise the original args are returned with false.
func SanitizeArgsForGit(command string, args []string) ([]string, bool) { func SanitizeArgsForGit(command string, args []string) ([]string, bool) {
switch command { switch command {

View File

@ -105,7 +105,7 @@ func (c *GitHook) PostReceive(ctx context.Context) error {
func handleServerHookOutput(out *types.ServerHookOutput, err error) error { func handleServerHookOutput(out *types.ServerHookOutput, err error) error {
if err != nil { if err != nil {
return fmt.Errorf("an error occured when calling the server: %w", err) return fmt.Errorf("an error occurred when calling the server: %w", err)
} }
if out == nil { if out == nil {

View File

@ -314,7 +314,7 @@ func SetupWebhook(r chi.Router, webhookCtrl *webhook.Controller) {
func setupUser(r chi.Router, userCtrl *user.Controller) { func setupUser(r chi.Router, userCtrl *user.Controller) {
r.Route("/user", func(r chi.Router) { r.Route("/user", func(r chi.Router) {
// enforce principial authenticated and it's a user // enforce principal authenticated and it's a user
r.Use(middlewareprincipal.RestrictTo(enum.PrincipalTypeUser)) r.Use(middlewareprincipal.RestrictTo(enum.PrincipalTypeUser))
r.Get("/", handleruser.HandleFind(userCtrl)) r.Get("/", handleruser.HandleFind(userCtrl))

View File

@ -178,7 +178,7 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
TriggerType: triggerType, TriggerType: triggerType,
// for unexpected errors we don't retry - protect the system. User can retrigger manually (if body was set) // for unexpected errors we don't retry - protect the system. User can retrigger manually (if body was set)
Result: enum.WebhookExecutionResultFatalError, Result: enum.WebhookExecutionResultFatalError,
Error: "An unknown error occured", Error: "An unknown error occurred",
} }
defer func(oCtx context.Context, start time.Time) { defer func(oCtx context.Context, start time.Time) {
// set total execution time // set total execution time
@ -253,7 +253,7 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
case err != nil: case err != nil:
// for all other errors we don't retry - protect the system. User can retrigger manually (if body was set) // for all other errors we don't retry - protect the system. User can retrigger manually (if body was set)
tErr := fmt.Errorf("an error occured while sending the request: %w", err) tErr := fmt.Errorf("an error occurred while sending the request: %w", err)
execution.Error = tErr.Error() execution.Error = tErr.Error()
execution.Result = enum.WebhookExecutionResultFatalError execution.Result = enum.WebhookExecutionResultFatalError
return &execution, tErr return &execution, tErr
@ -298,7 +298,7 @@ func (s *Service) prepareHTTPRequest(ctx context.Context, execution *types.Webho
err := json.NewEncoder(bBuff).Encode(body) err := json.NewEncoder(bBuff).Encode(body)
if err != nil { if err != nil {
// this is an internal issue, nothing the user can do - don't expose error details // this is an internal issue, nothing the user can do - don't expose error details
execution.Error = "an error occured preparing the request body" execution.Error = "an error occurred preparing the request body"
execution.Result = enum.WebhookExecutionResultFatalError execution.Result = enum.WebhookExecutionResultFatalError
return nil, fmt.Errorf("failed to serialize body to json: %w", err) return nil, fmt.Errorf("failed to serialize body to json: %w", err)
} }
@ -380,7 +380,7 @@ func handleWebhookResponse(execution *types.WebhookExecution, resp *http.Respons
var bodyRaw []byte var bodyRaw []byte
bodyRaw, err = io.ReadAll(io.LimitReader(resp.Body, responseBodyBytesLimit)) bodyRaw, err = io.ReadAll(io.LimitReader(resp.Body, responseBodyBytesLimit))
if err != nil { if err != nil {
tErr := fmt.Errorf("an error occured while reading the response body: %w", err) tErr := fmt.Errorf("an error occurred while reading the response body: %w", err)
execution.Error = tErr.Error() execution.Error = tErr.Error()
execution.Result = enum.WebhookExecutionResultRetriableError execution.Result = enum.WebhookExecutionResultRetriableError
return tErr return tErr

View File

@ -9,7 +9,7 @@ import (
) )
// PrincipalUIDTransformation transforms a principalUID to a value that should be duplicate free. // PrincipalUIDTransformation transforms a principalUID to a value that should be duplicate free.
// This allows us to simply switch between principalUIDs being case sensitive, insensitive or anything inbetween. // This allows us to simply switch between principalUIDs being case sensitive, insensitive or anything in between.
type PrincipalUIDTransformation func(uid string) (string, error) type PrincipalUIDTransformation func(uid string) (string, error)
func ToLowerPrincipalUIDTransformation(uid string) (string, error) { func ToLowerPrincipalUIDTransformation(uid string) (string, error) {
@ -17,7 +17,7 @@ func ToLowerPrincipalUIDTransformation(uid string) (string, error) {
} }
// PathTransformation transforms a path to a value that should be duplicate free. // PathTransformation transforms a path to a value that should be duplicate free.
// This allows us to simply switch between paths being case sensitive, insensitive or anything inbetween. // This allows us to simply switch between paths being case sensitive, insensitive or anything in between.
type PathTransformation func(string) (string, error) type PathTransformation func(string) (string, error)
func ToLowerPathTransformation(original string) (string, error) { func ToLowerPathTransformation(original string) (string, error) {

View File

@ -1,70 +0,0 @@
package main
import (
"encoding/gob"
"flag"
"fmt"
"os"
"path"
"reflect"
"github.com/golang/mock/mockgen/model"
pkg_ "github.com/harness/gitness/internal/store"
)
var output = flag.String("output", "", "The output file name, or empty to use stdout.")
func main() {
flag.Parse()
its := []struct{
sym string
typ reflect.Type
}{
{ "PrincipalStore", reflect.TypeOf((*pkg_.PrincipalStore)(nil)).Elem()},
{ "SpaceStore", reflect.TypeOf((*pkg_.SpaceStore)(nil)).Elem()},
{ "RepoStore", reflect.TypeOf((*pkg_.RepoStore)(nil)).Elem()},
}
pkg := &model.Package{
// NOTE: This behaves contrary to documented behaviour if the
// package name is not the final component of the import path.
// The reflect package doesn't expose the package name, though.
Name: path.Base("github.com/harness/gitness/internal/store"),
}
for _, it := range its {
intf, err := model.InterfaceFromInterfaceType(it.typ)
if err != nil {
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
os.Exit(1)
}
intf.Name = it.sym
pkg.Interfaces = append(pkg.Interfaces, intf)
}
outfile := os.Stdout
if len(*output) != 0 {
var err error
outfile, err = os.Create(*output)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open output file %q", *output)
}
defer func() {
if err := outfile.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close output file %q", *output)
os.Exit(1)
}
}()
}
if err := gob.NewEncoder(outfile).Encode(pkg); err != nil {
fmt.Fprintf(os.Stderr, "gob encode: %v\n", err)
os.Exit(1)
}
}

View File

@ -8,9 +8,10 @@ import (
context "context" context "context"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
user "github.com/harness/gitness/internal/api/controller/user" user "github.com/harness/gitness/internal/api/controller/user"
types "github.com/harness/gitness/types" types "github.com/harness/gitness/types"
gomock "github.com/golang/mock/gomock"
) )
// MockClient is a mock of Client interface. // MockClient is a mock of Client interface.

View File

@ -8,9 +8,10 @@ import (
context "context" context "context"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
types "github.com/harness/gitness/types" types "github.com/harness/gitness/types"
enum "github.com/harness/gitness/types/enum" enum "github.com/harness/gitness/types/enum"
gomock "github.com/golang/mock/gomock"
) )
// MockPrincipalStore is a mock of PrincipalStore interface. // MockPrincipalStore is a mock of PrincipalStore interface.

View File

@ -16,7 +16,7 @@ const (
// MaxMaxRetries is the max number of retries of a message for a single consumer group. // MaxMaxRetries is the max number of retries of a message for a single consumer group.
MaxMaxRetries = 64 MaxMaxRetries = 64
// MinIdleTimeout is the minumum time that can be configured as idle timeout for a stream consumer. // MinIdleTimeout is the minimum time that can be configured as idle timeout for a stream consumer.
MinIdleTimeout = 5 * time.Second MinIdleTimeout = 5 * time.Second
) )