mirror of
https://github.com/harness/drone.git
synced 2025-05-05 15:32:56 +00:00
pull request import (#2121)
* bypass lint * bump golang version * using types from migrator * moving Importing to the RepositoryOutput * minor changes; improved unit tests * pr comments * pr import * pull request import
This commit is contained in:
parent
30dfa92023
commit
5427130a42
2
.github/workflows/ci-lint.yml
vendored
2
.github/workflows/ci-lint.yml
vendored
@ -35,7 +35,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22'
|
||||||
- name: get dependencies
|
- name: get dependencies
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ./web/dist
|
mkdir -p ./web/dist
|
||||||
|
@ -18,7 +18,7 @@ RUN yarn && yarn build && yarn cache clean
|
|||||||
# ---------------------------------------------------------#
|
# ---------------------------------------------------------#
|
||||||
# Build gitness image #
|
# Build gitness image #
|
||||||
# ---------------------------------------------------------#
|
# ---------------------------------------------------------#
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.20-alpine3.18 as builder
|
FROM --platform=$BUILDPLATFORM golang:1.22-alpine3.18 as builder
|
||||||
|
|
||||||
RUN apk update \
|
RUN apk update \
|
||||||
&& apk add --no-cache protoc build-base git
|
&& apk add --no-cache protoc build-base git
|
||||||
|
@ -47,6 +47,11 @@ func (c *Controller) PreReceive(
|
|||||||
return hook.Output{}, err
|
return hook.Output{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !in.Internal && repo.State != enum.RepoStateActive && repo.State != enum.RepoStateMigrateGitPush {
|
||||||
|
output.Error = ptr.String("Push not allowed in the current repository state")
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.limiter.RepoSize(ctx, in.RepoID); err != nil {
|
if err := c.limiter.RepoSize(ctx, in.RepoID); err != nil {
|
||||||
return hook.Output{}, fmt.Errorf(
|
return hook.Output{}, fmt.Errorf(
|
||||||
"resource limit exceeded: %w",
|
"resource limit exceeded: %w",
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
pullreqevents "github.com/harness/gitness/app/events/pullreq"
|
pullreqevents "github.com/harness/gitness/app/events/pullreq"
|
||||||
"github.com/harness/gitness/app/services/codecomments"
|
"github.com/harness/gitness/app/services/codecomments"
|
||||||
"github.com/harness/gitness/app/services/codeowners"
|
"github.com/harness/gitness/app/services/codeowners"
|
||||||
|
"github.com/harness/gitness/app/services/importer"
|
||||||
locker "github.com/harness/gitness/app/services/locker"
|
locker "github.com/harness/gitness/app/services/locker"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
"github.com/harness/gitness/app/services/pullreq"
|
"github.com/harness/gitness/app/services/pullreq"
|
||||||
@ -62,6 +63,7 @@ type Controller struct {
|
|||||||
sseStreamer sse.Streamer
|
sseStreamer sse.Streamer
|
||||||
codeOwners *codeowners.Service
|
codeOwners *codeowners.Service
|
||||||
locker *locker.Locker
|
locker *locker.Locker
|
||||||
|
importer *importer.PullReq
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewController(
|
func NewController(
|
||||||
@ -87,6 +89,7 @@ func NewController(
|
|||||||
sseStreamer sse.Streamer,
|
sseStreamer sse.Streamer,
|
||||||
codeowners *codeowners.Service,
|
codeowners *codeowners.Service,
|
||||||
locker *locker.Locker,
|
locker *locker.Locker,
|
||||||
|
importer *importer.PullReq,
|
||||||
) *Controller {
|
) *Controller {
|
||||||
return &Controller{
|
return &Controller{
|
||||||
tx: tx,
|
tx: tx,
|
||||||
@ -111,6 +114,7 @@ func NewController(
|
|||||||
sseStreamer: sseStreamer,
|
sseStreamer: sseStreamer,
|
||||||
codeOwners: codeowners,
|
codeOwners: codeowners,
|
||||||
locker: locker,
|
locker: locker,
|
||||||
|
importer: importer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +156,8 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||||||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.Importing {
|
if repo.State != enum.RepoStateActive {
|
||||||
return nil, usererror.BadRequest("Repository import is in progress.")
|
return nil, usererror.BadRequest("Repository is not ready to use.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
pullreqevents "github.com/harness/gitness/app/events/pullreq"
|
pullreqevents "github.com/harness/gitness/app/events/pullreq"
|
||||||
"github.com/harness/gitness/app/services/codecomments"
|
"github.com/harness/gitness/app/services/codecomments"
|
||||||
"github.com/harness/gitness/app/services/codeowners"
|
"github.com/harness/gitness/app/services/codeowners"
|
||||||
|
"github.com/harness/gitness/app/services/importer"
|
||||||
"github.com/harness/gitness/app/services/locker"
|
"github.com/harness/gitness/app/services/locker"
|
||||||
"github.com/harness/gitness/app/services/protection"
|
"github.com/harness/gitness/app/services/protection"
|
||||||
"github.com/harness/gitness/app/services/pullreq"
|
"github.com/harness/gitness/app/services/pullreq"
|
||||||
@ -45,7 +46,7 @@ func ProvideController(tx dbtx.Transactor, urlProvider url.Provider, authorizer
|
|||||||
checkStore store.CheckStore,
|
checkStore store.CheckStore,
|
||||||
rpcClient git.Interface, eventReporter *pullreqevents.Reporter, codeCommentMigrator *codecomments.Migrator,
|
rpcClient git.Interface, eventReporter *pullreqevents.Reporter, codeCommentMigrator *codecomments.Migrator,
|
||||||
pullreqService *pullreq.Service, ruleManager *protection.Manager, sseStreamer sse.Streamer,
|
pullreqService *pullreq.Service, ruleManager *protection.Manager, sseStreamer sse.Streamer,
|
||||||
codeOwners *codeowners.Service, locker *locker.Locker,
|
codeOwners *codeowners.Service, locker *locker.Locker, importer *importer.PullReq,
|
||||||
) *Controller {
|
) *Controller {
|
||||||
return NewController(tx, urlProvider, authorizer,
|
return NewController(tx, urlProvider, authorizer,
|
||||||
pullReqStore, pullReqActivityStore,
|
pullReqStore, pullReqActivityStore,
|
||||||
@ -56,5 +57,5 @@ func ProvideController(tx dbtx.Transactor, urlProvider url.Provider, authorizer
|
|||||||
checkStore,
|
checkStore,
|
||||||
rpcClient, eventReporter,
|
rpcClient, eventReporter,
|
||||||
codeCommentMigrator,
|
codeCommentMigrator,
|
||||||
pullreqService, ruleManager, sseStreamer, codeOwners, locker)
|
pullreqService, ruleManager, sseStreamer, codeOwners, locker, importer)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,8 @@ var errPublicRepoCreationDisabled = usererror.BadRequestf("Public repository cre
|
|||||||
|
|
||||||
type RepositoryOutput struct {
|
type RepositoryOutput struct {
|
||||||
types.Repository
|
types.Repository
|
||||||
IsPublic bool `json:"is_public" yaml:"is_public"`
|
IsPublic bool `json:"is_public" yaml:"is_public"`
|
||||||
|
Importing bool `json:"importing" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [CODE-1363]: remove after identifier migration.
|
// TODO [CODE-1363]: remove after identifier migration.
|
||||||
@ -156,6 +157,7 @@ func (c *Controller) getRepo(
|
|||||||
ctx,
|
ctx,
|
||||||
c.repoStore,
|
c.repoStore,
|
||||||
repoRef,
|
repoRef,
|
||||||
|
ActiveRepoStates,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +176,26 @@ func (c *Controller) getRepoCheckAccess(
|
|||||||
session,
|
session,
|
||||||
repoRef,
|
repoRef,
|
||||||
reqPermission,
|
reqPermission,
|
||||||
|
ActiveRepoStates,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRepoCheckAccessForGit fetches a repo
|
||||||
|
// and checks if the current user has permission to access it.
|
||||||
|
func (c *Controller) getRepoCheckAccessForGit(
|
||||||
|
ctx context.Context,
|
||||||
|
session *auth.Session,
|
||||||
|
repoRef string,
|
||||||
|
reqPermission enum.Permission,
|
||||||
|
) (*types.Repository, error) {
|
||||||
|
return GetRepoCheckAccess(
|
||||||
|
ctx,
|
||||||
|
c.repoStore,
|
||||||
|
c.authorizer,
|
||||||
|
session,
|
||||||
|
repoRef,
|
||||||
|
reqPermission,
|
||||||
|
nil, // Any state allowed - we'll block in the pre-receive hook.
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,10 +149,7 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||||
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
|
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
|
||||||
|
|
||||||
repoOutput := &RepositoryOutput{
|
repoOutput := GetRepoOutputWithAccess(ctx, in.IsPublic, repo)
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: in.IsPublic,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.auditService.Log(ctx,
|
err = c.auditService.Log(ctx,
|
||||||
session.Principal,
|
session.Principal,
|
||||||
|
@ -33,7 +33,7 @@ func (c *Controller) GitInfoRefs(
|
|||||||
gitProtocol string,
|
gitProtocol string,
|
||||||
w io.Writer,
|
w io.Writer,
|
||||||
) error {
|
) error {
|
||||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
repo, err := c.getRepoCheckAccessForGit(ctx, session, repoRef, enum.PermissionRepoView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to verify repo access: %w", err)
|
return fmt.Errorf("failed to verify repo access: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (c *Controller) GitServicePack(
|
|||||||
permission = enum.PermissionRepoPush
|
permission = enum.PermissionRepoPush
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, permission)
|
repo, err := c.getRepoCheckAccessForGit(ctx, session, repoRef, permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to verify repo access: %w", err)
|
return fmt.Errorf("failed to verify repo access: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,18 @@ import (
|
|||||||
"github.com/harness/gitness/app/store"
|
"github.com/harness/gitness/app/store"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRepo fetches an active repo (not one that is currently being imported).
|
var ActiveRepoStates = []enum.RepoState{enum.RepoStateActive}
|
||||||
|
|
||||||
|
// GetRepo fetches an repository.
|
||||||
func GetRepo(
|
func GetRepo(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
repoStore store.RepoStore,
|
repoStore store.RepoStore,
|
||||||
repoRef string,
|
repoRef string,
|
||||||
|
allowedStates []enum.RepoState,
|
||||||
) (*types.Repository, error) {
|
) (*types.Repository, error) {
|
||||||
if repoRef == "" {
|
if repoRef == "" {
|
||||||
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
||||||
@ -43,8 +48,8 @@ func GetRepo(
|
|||||||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.Importing {
|
if len(allowedStates) > 0 && !slices.Contains(allowedStates, repo.State) {
|
||||||
return nil, usererror.BadRequest("Repository import is in progress.")
|
return nil, usererror.BadRequest("Repository is not ready to use.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo, nil
|
return repo, nil
|
||||||
@ -59,8 +64,9 @@ func GetRepoCheckAccess(
|
|||||||
session *auth.Session,
|
session *auth.Session,
|
||||||
repoRef string,
|
repoRef string,
|
||||||
reqPermission enum.Permission,
|
reqPermission enum.Permission,
|
||||||
|
allowedStates []enum.RepoState,
|
||||||
) (*types.Repository, error) {
|
) (*types.Repository, error) {
|
||||||
repo, err := GetRepo(ctx, repoStore, repoRef)
|
repo, err := GetRepo(ctx, repoStore, repoRef, allowedStates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to find repo: %w", err)
|
return nil, fmt.Errorf("failed to find repo: %w", err)
|
||||||
}
|
}
|
||||||
@ -85,5 +91,18 @@ func GetRepoOutput(
|
|||||||
return &RepositoryOutput{
|
return &RepositoryOutput{
|
||||||
Repository: *repo,
|
Repository: *repo,
|
||||||
IsPublic: isPublic,
|
IsPublic: isPublic,
|
||||||
|
Importing: repo.State != enum.RepoStateActive,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRepoOutputWithAccess(
|
||||||
|
_ context.Context,
|
||||||
|
isPublic bool,
|
||||||
|
repo *types.Repository,
|
||||||
|
) *RepositoryOutput {
|
||||||
|
return &RepositoryOutput{
|
||||||
|
Repository: *repo,
|
||||||
|
IsPublic: isPublic,
|
||||||
|
Importing: repo.State != enum.RepoStateActive,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -114,10 +114,7 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||||||
log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err)
|
log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RepositoryOutput{
|
return GetRepoOutputWithAccess(ctx, false, repo), nil
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: false,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) sanitizeImportInput(in *ImportInput) error {
|
func (c *Controller) sanitizeImportInput(in *ImportInput) error {
|
||||||
|
@ -58,8 +58,8 @@ func (c *Controller) Move(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.Importing {
|
if repo.State != enum.RepoStateActive {
|
||||||
return nil, usererror.BadRequest("can't move a repo that is being imported")
|
return nil, usererror.BadRequest("Can't move a repo that isn't ready to use.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit); err != nil {
|
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit); err != nil {
|
||||||
|
@ -64,7 +64,7 @@ func (c *Controller) PurgeNoAuth(
|
|||||||
session *auth.Session,
|
session *auth.Session,
|
||||||
repo *types.Repository,
|
repo *types.Repository,
|
||||||
) error {
|
) error {
|
||||||
if repo.Importing {
|
if repo.State == enum.RepoStateGitImport {
|
||||||
log.Ctx(ctx).Info().Msg("repository is importing. cancelling the import job.")
|
log.Ctx(ctx).Info().Msg("repository is importing. cancelling the import job.")
|
||||||
err := c.importer.Cancel(ctx, repo)
|
err := c.importer.Cancel(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -94,8 +94,5 @@ func (c *Controller) RestoreNoAuth(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Repos restored as private since public access data has been deleted upon deletion.
|
// Repos restored as private since public access data has been deleted upon deletion.
|
||||||
return &RepositoryOutput{
|
return GetRepoOutputWithAccess(ctx, false, repo), nil
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: false,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ func (c *Controller) SoftDeleteNoAuth(
|
|||||||
return fmt.Errorf("failed to delete public access for repo: %w", err)
|
return fmt.Errorf("failed to delete public access for repo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.Importing {
|
if repo.State != enum.RepoStateActive {
|
||||||
return c.PurgeNoAuth(ctx, session, repo)
|
return c.PurgeNoAuth(ctx, session, repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,7 @@ func (c *Controller) UpdatePublicAccess(ctx context.Context,
|
|||||||
|
|
||||||
// no op
|
// no op
|
||||||
if isPublic == in.IsPublic {
|
if isPublic == in.IsPublic {
|
||||||
return &RepositoryOutput{
|
return GetRepoOutputWithAccess(ctx, isPublic, repo), nil
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: isPublic,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, in.IsPublic); err != nil {
|
if err = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, in.IsPublic); err != nil {
|
||||||
@ -95,8 +92,5 @@ func (c *Controller) UpdatePublicAccess(ctx context.Context,
|
|||||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update repository operation: %s", err)
|
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update repository operation: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RepositoryOutput{
|
return GetRepoOutputWithAccess(ctx, in.IsPublic, repo), nil
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: in.IsPublic,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,6 @@ func (c *Controller) getRepoCheckAccess(
|
|||||||
session,
|
session,
|
||||||
repoRef,
|
repoRef,
|
||||||
reqPermission,
|
reqPermission,
|
||||||
|
repo.ActiveRepoStates,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
apiauth "github.com/harness/gitness/app/api/auth"
|
apiauth "github.com/harness/gitness/app/api/auth"
|
||||||
"github.com/harness/gitness/app/api/controller/limiter"
|
"github.com/harness/gitness/app/api/controller/limiter"
|
||||||
repoCtrl "github.com/harness/gitness/app/api/controller/repo"
|
repoctrl "github.com/harness/gitness/app/api/controller/repo"
|
||||||
"github.com/harness/gitness/app/api/usererror"
|
"github.com/harness/gitness/app/api/usererror"
|
||||||
"github.com/harness/gitness/app/auth"
|
"github.com/harness/gitness/app/auth"
|
||||||
"github.com/harness/gitness/app/paths"
|
"github.com/harness/gitness/app/paths"
|
||||||
@ -39,8 +39,8 @@ type ImportRepositoriesInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ImportRepositoriesOutput struct {
|
type ImportRepositoriesOutput struct {
|
||||||
ImportingRepos []*repoCtrl.RepositoryOutput `json:"importing_repos"`
|
ImportingRepos []*repoctrl.RepositoryOutput `json:"importing_repos"`
|
||||||
DuplicateRepos []*repoCtrl.RepositoryOutput `json:"duplicate_repos"` // repos which already exist in the space.
|
DuplicateRepos []*repoctrl.RepositoryOutput `json:"duplicate_repos"` // repos which already exist in the space.
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSpaceCheckAuthRepoCreation checks whether the user has permissions to create repos
|
// getSpaceCheckAuthRepoCreation checks whether the user has permissions to create repos
|
||||||
@ -165,12 +165,9 @@ func (c *Controller) ImportRepositories(
|
|||||||
return ImportRepositoriesOutput{}, err
|
return ImportRepositoriesOutput{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reposOut := make([]*repoCtrl.RepositoryOutput, len(repos))
|
reposOut := make([]*repoctrl.RepositoryOutput, len(repos))
|
||||||
for i, repo := range repos {
|
for i, repo := range repos {
|
||||||
reposOut[i] = &repoCtrl.RepositoryOutput{
|
reposOut[i] = repoctrl.GetRepoOutputWithAccess(ctx, false, repo)
|
||||||
Repository: *repo,
|
|
||||||
IsPublic: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.auditService.Log(ctx,
|
err = c.auditService.Log(ctx,
|
||||||
session.Principal,
|
session.Principal,
|
||||||
@ -187,12 +184,9 @@ func (c *Controller) ImportRepositories(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicateReposOut := make([]*repoCtrl.RepositoryOutput, len(duplicateRepos))
|
duplicateReposOut := make([]*repoctrl.RepositoryOutput, len(duplicateRepos))
|
||||||
for i, dupRepo := range duplicateRepos {
|
for i, dupRepo := range duplicateRepos {
|
||||||
duplicateReposOut[i] = &repoCtrl.RepositoryOutput{
|
duplicateReposOut[i] = repoctrl.GetRepoOutputWithAccess(ctx, false, dupRepo)
|
||||||
Repository: *dupRepo,
|
|
||||||
IsPublic: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImportRepositoriesOutput{ImportingRepos: reposOut, DuplicateRepos: duplicateReposOut}, nil
|
return ImportRepositoriesOutput{ImportingRepos: reposOut, DuplicateRepos: duplicateReposOut}, nil
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/api/usererror"
|
"github.com/harness/gitness/app/api/usererror"
|
||||||
"github.com/harness/gitness/app/paths"
|
"github.com/harness/gitness/app/paths"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
"github.com/drone/go-scm/scm"
|
"github.com/drone/go-scm/scm"
|
||||||
"github.com/drone/go-scm/scm/driver/azure"
|
"github.com/drone/go-scm/scm/driver/azure"
|
||||||
@ -100,7 +101,7 @@ func (r *RepositoryInfo) ToRepo(
|
|||||||
Updated: now,
|
Updated: now,
|
||||||
ForkID: 0,
|
ForkID: 0,
|
||||||
DefaultBranch: r.DefaultBranch,
|
DefaultBranch: r.DefaultBranch,
|
||||||
Importing: true,
|
State: enum.RepoStateGitImport,
|
||||||
Path: paths.Concatenate(spacePath, identifier),
|
Path: paths.Concatenate(spacePath, identifier),
|
||||||
}, r.IsPublic
|
}, r.IsPublic
|
||||||
}
|
}
|
||||||
|
538
app/services/importer/pullreq.go
Normal file
538
app/services/importer/pullreq.go
Normal file
@ -0,0 +1,538 @@
|
|||||||
|
// 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 importer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/app/store"
|
||||||
|
"github.com/harness/gitness/app/url"
|
||||||
|
"github.com/harness/gitness/errors"
|
||||||
|
"github.com/harness/gitness/git"
|
||||||
|
"github.com/harness/gitness/git/parser"
|
||||||
|
"github.com/harness/gitness/store/database/dbtx"
|
||||||
|
"github.com/harness/gitness/types"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PullReq is pull request importer.
|
||||||
|
type PullReq struct {
|
||||||
|
urlProvider url.Provider
|
||||||
|
git git.Interface
|
||||||
|
principalStore store.PrincipalStore
|
||||||
|
repoStore store.RepoStore
|
||||||
|
pullReqStore store.PullReqStore
|
||||||
|
pullReqActStore store.PullReqActivityStore
|
||||||
|
tx dbtx.Transactor
|
||||||
|
}
|
||||||
|
|
||||||
|
type repoImportState struct {
|
||||||
|
git git.Interface
|
||||||
|
readParams git.ReadParams
|
||||||
|
principalStore store.PrincipalStore
|
||||||
|
pullReqActivityStore store.PullReqActivityStore
|
||||||
|
branchCheck map[string]*git.Branch
|
||||||
|
principals map[string]*types.Principal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import load provided pull requests in go-scm format and imports them.
|
||||||
|
//
|
||||||
|
//nolint:gocognit
|
||||||
|
func (importer PullReq) Import(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *types.Repository,
|
||||||
|
extPullReqs []*ExternalPullRequest,
|
||||||
|
) ([]*types.PullReq, error) {
|
||||||
|
if repo.State != enum.RepoStateMigrateDataImport {
|
||||||
|
return nil, errors.PreconditionFailed("Repository data can't be imported at this point")
|
||||||
|
}
|
||||||
|
|
||||||
|
readParams := git.ReadParams{RepoUID: repo.GitUID}
|
||||||
|
|
||||||
|
repoState := repoImportState{
|
||||||
|
git: importer.git,
|
||||||
|
readParams: readParams,
|
||||||
|
principalStore: importer.principalStore,
|
||||||
|
pullReqActivityStore: importer.pullReqActStore,
|
||||||
|
branchCheck: map[string]*git.Branch{},
|
||||||
|
principals: map[string]*types.Principal{},
|
||||||
|
}
|
||||||
|
|
||||||
|
pullReqUnique := map[int]struct{}{}
|
||||||
|
pullReqComments := map[*types.PullReq][]ExternalComment{}
|
||||||
|
|
||||||
|
pullReqs := make([]*types.PullReq, 0, len(extPullReqs))
|
||||||
|
// create the PR objects, one by one. Each pull request will mutate the repository object (to update the counters).
|
||||||
|
for _, extPullReqData := range extPullReqs {
|
||||||
|
extPullReq := &extPullReqData.PullRequest
|
||||||
|
|
||||||
|
if _, exists := pullReqUnique[extPullReq.Number]; exists {
|
||||||
|
return nil, errors.Conflict("duplicate pull request number %d", extPullReq.Number)
|
||||||
|
}
|
||||||
|
pullReqUnique[extPullReq.Number] = struct{}{}
|
||||||
|
|
||||||
|
pr, err := repoState.convertPullReq(ctx, repo, extPullReqData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to import pull request %d: %w", extPullReq.Number, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pullReqs = append(pullReqs, pr)
|
||||||
|
pullReqComments[pr] = extPullReqData.Comments
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pullReqs) == 0 { // nothing to do: exit early to avoid accessing the database
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := importer.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
var deltaOpen, deltaClosed, deltaMerged int
|
||||||
|
var maxNumber int64
|
||||||
|
|
||||||
|
// Store the pull request objects and the comments.
|
||||||
|
for _, pullReq := range pullReqs {
|
||||||
|
if err := importer.pullReqStore.Create(ctx, pullReq); err != nil {
|
||||||
|
return fmt.Errorf("failed to import the pull request %d: %w", pullReq.Number, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pullReq.State {
|
||||||
|
case enum.PullReqStateOpen:
|
||||||
|
deltaOpen++
|
||||||
|
case enum.PullReqStateClosed:
|
||||||
|
deltaClosed++
|
||||||
|
case enum.PullReqStateMerged:
|
||||||
|
deltaMerged++
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxNumber < pullReq.Number {
|
||||||
|
maxNumber = pullReq.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
comments, err := repoState.createComments(ctx, repo, pullReq, pullReqComments[pullReq])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to import pull request comments: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(comments) == 0 { // no need to update the pull request object in the DB if there are no comments.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := importer.pullReqStore.Update(ctx, pullReq); err != nil {
|
||||||
|
return fmt.Errorf("failed to update pull request after importing of the comments: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the repository
|
||||||
|
|
||||||
|
repoUpdate, err := importer.repoStore.Find(ctx, repo.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch repo in pull request import: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if repoUpdate.PullReqSeq < maxNumber {
|
||||||
|
repoUpdate.PullReqSeq = maxNumber
|
||||||
|
}
|
||||||
|
repoUpdate.NumPulls += len(pullReqs)
|
||||||
|
repoUpdate.NumOpenPulls += deltaOpen
|
||||||
|
repoUpdate.NumClosedPulls += deltaClosed
|
||||||
|
repoUpdate.NumMergedPulls += deltaMerged
|
||||||
|
|
||||||
|
if err := importer.repoStore.Update(ctx, repoUpdate); err != nil {
|
||||||
|
return fmt.Errorf("failed to update repo in pull request import: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pullReqs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertPullReq analyses external pull request object and creates types.PullReq object out of it.
|
||||||
|
func (r *repoImportState) convertPullReq(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *types.Repository,
|
||||||
|
extPullReqData *ExternalPullRequest,
|
||||||
|
) (*types.PullReq, error) {
|
||||||
|
extPullReq := extPullReqData.PullRequest
|
||||||
|
|
||||||
|
log := log.Ctx(ctx).With().
|
||||||
|
Str("repo.identifier", repo.Identifier).
|
||||||
|
Int("pullreq.number", extPullReq.Number).
|
||||||
|
Logger()
|
||||||
|
|
||||||
|
author, err := r.getPrincipalByEmail(ctx, extPullReq.Author.Email)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get pull request author: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UnixMilli()
|
||||||
|
createdAt := timestampMillis(extPullReq.Created, now)
|
||||||
|
updatedAt := timestampMillis(extPullReq.Updated, now)
|
||||||
|
|
||||||
|
pr := &types.PullReq{
|
||||||
|
ID: 0, // the ID will be populated in the data layer
|
||||||
|
Version: 0,
|
||||||
|
Number: int64(extPullReq.Number),
|
||||||
|
CreatedBy: author.ID,
|
||||||
|
Created: createdAt,
|
||||||
|
Updated: updatedAt,
|
||||||
|
Edited: updatedAt,
|
||||||
|
Closed: nil,
|
||||||
|
State: enum.PullReqStateOpen,
|
||||||
|
IsDraft: false,
|
||||||
|
CommentCount: 0,
|
||||||
|
UnresolvedCount: 0,
|
||||||
|
Title: extPullReq.Title,
|
||||||
|
Description: extPullReq.Body,
|
||||||
|
SourceRepoID: repo.ID,
|
||||||
|
SourceBranch: extPullReq.Head.Name,
|
||||||
|
SourceSHA: extPullReq.Head.SHA,
|
||||||
|
TargetRepoID: repo.ID,
|
||||||
|
TargetBranch: extPullReq.Base.Name,
|
||||||
|
ActivitySeq: 0,
|
||||||
|
// Merge related fields are all left unset and will be set depending on the PR state
|
||||||
|
}
|
||||||
|
|
||||||
|
params := git.ReadParams{RepoUID: repo.GitUID}
|
||||||
|
|
||||||
|
// Set the state of the PR
|
||||||
|
switch {
|
||||||
|
case extPullReq.Merged:
|
||||||
|
pr.State = enum.PullReqStateMerged
|
||||||
|
case extPullReq.Closed:
|
||||||
|
pr.State = enum.PullReqStateClosed
|
||||||
|
default:
|
||||||
|
pr.State = enum.PullReqStateOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the PR depending on its state
|
||||||
|
switch pr.State {
|
||||||
|
case enum.PullReqStateMerged:
|
||||||
|
// For merged PR's assume the Head.Sha and Base.Sha point to commits at the time of merging.
|
||||||
|
|
||||||
|
pr.Merged = &pr.Edited
|
||||||
|
pr.MergedBy = &author.ID // Don't have real info for this - use the author.
|
||||||
|
mergeMethod := enum.MergeMethodMerge // Don't know
|
||||||
|
pr.MergeMethod = &mergeMethod
|
||||||
|
|
||||||
|
pr.MergeCheckStatus = enum.MergeCheckStatusMergeable
|
||||||
|
pr.SourceSHA = extPullReq.Head.SHA
|
||||||
|
pr.MergeTargetSHA = &extPullReq.Base.SHA
|
||||||
|
pr.MergeBaseSHA = extPullReq.Head.SHA // Don't have the real value. Set the value to SourceSHA.
|
||||||
|
pr.MergeSHA = nil // Don't have this.
|
||||||
|
pr.MergeConflicts = nil
|
||||||
|
|
||||||
|
case enum.PullReqStateClosed:
|
||||||
|
// For closed PR's it's not important to verify existence of branches and commits.
|
||||||
|
// If these don't exist the PR will be impossible to open.
|
||||||
|
|
||||||
|
pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked
|
||||||
|
pr.MergeSHA = nil
|
||||||
|
pr.MergeConflicts = nil
|
||||||
|
pr.MergeTargetSHA = nil
|
||||||
|
pr.Closed = &pr.Edited
|
||||||
|
|
||||||
|
case enum.PullReqStateOpen:
|
||||||
|
// For open PR we need to verify existence of branches and find to merge base.
|
||||||
|
|
||||||
|
sourceBranch, err := r.git.GetBranch(ctx, &git.GetBranchParams{
|
||||||
|
ReadParams: params,
|
||||||
|
BranchName: extPullReq.Head.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch source branch of an open pull request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Cache this in the repoImportState - it's very likely that it will be the same for other PRs
|
||||||
|
targetBranch, err := r.git.GetBranch(ctx, &git.GetBranchParams{
|
||||||
|
ReadParams: params,
|
||||||
|
BranchName: extPullReq.Base.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch target branch of an open pull request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeBase, err := r.git.MergeBase(ctx, git.MergeBaseParams{
|
||||||
|
ReadParams: params,
|
||||||
|
Ref1: sourceBranch.Branch.SHA.String(),
|
||||||
|
Ref2: targetBranch.Branch.SHA.String(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find merge base an open pull request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSHA := sourceBranch.Branch.SHA.String()
|
||||||
|
targetSHA := targetBranch.Branch.SHA.String()
|
||||||
|
pr.SourceSHA = sourceSHA
|
||||||
|
pr.MergeTargetSHA = &targetSHA
|
||||||
|
pr.MergeBaseSHA = mergeBase.MergeBaseSHA.String()
|
||||||
|
pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Str("pullreq.state", string(pr.State)).Msg("importing pull request")
|
||||||
|
|
||||||
|
return pr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createComments analyses external pull request comment objects and stores types.PullReqActivity object to the DB.
|
||||||
|
// It will mutate the pull request object to update counter fields.
|
||||||
|
func (r *repoImportState) createComments(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *types.Repository,
|
||||||
|
pullReq *types.PullReq,
|
||||||
|
extComments []ExternalComment,
|
||||||
|
) ([]*types.PullReqActivity, error) {
|
||||||
|
log := log.Ctx(ctx).With().
|
||||||
|
Str("repo.id", repo.Identifier).
|
||||||
|
Int("pullreq.number", int(pullReq.Number)).
|
||||||
|
Logger()
|
||||||
|
|
||||||
|
extThreads := generateThreads(extComments)
|
||||||
|
|
||||||
|
comments := make([]*types.PullReqActivity, 0, len(extComments))
|
||||||
|
for idxTopLevel, extThread := range extThreads {
|
||||||
|
order := idxTopLevel + 1
|
||||||
|
|
||||||
|
// Create the top level comment with the correct value of Order, SubOrder and ReplySeq.
|
||||||
|
commentTopLevel, err := r.createComment(ctx, repo, pullReq, nil,
|
||||||
|
order, 0, len(extThread.Replies), &extThread.TopLevel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create top level comment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
comments = append(comments, commentTopLevel)
|
||||||
|
|
||||||
|
for idxReply, extReply := range extThread.Replies {
|
||||||
|
subOrder := idxReply + 1
|
||||||
|
|
||||||
|
// Create the reply comment with the correct value of Order, SubOrder and ReplySeq.
|
||||||
|
//nolint:gosec
|
||||||
|
commentReply, err := r.createComment(ctx, repo, pullReq, &commentTopLevel.ID,
|
||||||
|
order, subOrder, 0, &extReply)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create reply comment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
comments = append(comments, commentReply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Int("count", len(comments)).Msg("imported pull request comments")
|
||||||
|
|
||||||
|
return comments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createComment analyses an external pull request comment object and creates types.PullReqActivity object out of it.
|
||||||
|
// It will mutate the pull request object to update counter fields.
|
||||||
|
func (r *repoImportState) createComment(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *types.Repository,
|
||||||
|
pullReq *types.PullReq,
|
||||||
|
parentID *int64,
|
||||||
|
order, subOrder, replySeq int,
|
||||||
|
extComment *ExternalComment,
|
||||||
|
) (*types.PullReqActivity, error) {
|
||||||
|
commenter, err := r.getPrincipalByEmail(ctx, extComment.Author.Email)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get comment ID=%d author: %w", extComment.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commentedAt := extComment.Created.UnixMilli()
|
||||||
|
|
||||||
|
// Mark comments as resolved if the PR is merged, otherwise they are unresolved.
|
||||||
|
var resolved, resolvedBy *int64
|
||||||
|
if pullReq.State == enum.PullReqStateMerged {
|
||||||
|
resolved = &commentedAt
|
||||||
|
resolvedBy = &commenter.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := &types.PullReqActivity{
|
||||||
|
CreatedBy: commenter.ID,
|
||||||
|
Created: commentedAt,
|
||||||
|
Updated: commentedAt,
|
||||||
|
Edited: commentedAt,
|
||||||
|
Deleted: nil,
|
||||||
|
ParentID: parentID,
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PullReqID: pullReq.ID,
|
||||||
|
Order: int64(order),
|
||||||
|
SubOrder: int64(subOrder),
|
||||||
|
ReplySeq: int64(replySeq),
|
||||||
|
Type: enum.PullReqActivityTypeComment,
|
||||||
|
Kind: enum.PullReqActivityKindComment,
|
||||||
|
Text: extComment.Body,
|
||||||
|
PayloadRaw: json.RawMessage("{}"),
|
||||||
|
Metadata: nil,
|
||||||
|
ResolvedBy: resolvedBy,
|
||||||
|
Resolved: resolved,
|
||||||
|
CodeComment: nil,
|
||||||
|
Mentions: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc := extComment.CodeComment; cc != nil && cc.HunkHeader != "" && extComment.ParentID == 0 {
|
||||||
|
// a code comment must have a valid HunkHeader and must not be a reply
|
||||||
|
hunkHeader, ok := parser.ParseDiffHunkHeader(cc.HunkHeader)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.InvalidArgument("Invalid hunk header for code comment: %s", cc.HunkHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.Kind = enum.PullReqActivityKindChangeComment
|
||||||
|
comment.Type = enum.PullReqActivityTypeCodeComment
|
||||||
|
|
||||||
|
comment.CodeComment = &types.CodeCommentFields{
|
||||||
|
Outdated: cc.SourceSHA != pullReq.SourceSHA,
|
||||||
|
MergeBaseSHA: cc.MergeBaseSHA,
|
||||||
|
SourceSHA: cc.SourceSHA,
|
||||||
|
Path: cc.Path,
|
||||||
|
LineNew: hunkHeader.NewLine,
|
||||||
|
SpanNew: hunkHeader.NewSpan,
|
||||||
|
LineOld: hunkHeader.OldLine,
|
||||||
|
SpanOld: hunkHeader.OldSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
sideNew := !strings.EqualFold(cc.Side, "OLD") // cc.Side can be either OLD or NEW
|
||||||
|
_ = comment.SetPayload(&types.PullRequestActivityPayloadCodeComment{
|
||||||
|
Title: cc.CodeSnippet.Header,
|
||||||
|
Lines: cc.CodeSnippet.Lines,
|
||||||
|
LineStartNew: sideNew,
|
||||||
|
LineEndNew: sideNew,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the comment
|
||||||
|
|
||||||
|
if err := r.pullReqActivityStore.Create(ctx, comment); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to store the external comment ID=%d author: %w", extComment.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the pull request's counter fields
|
||||||
|
|
||||||
|
pullReq.CommentCount++
|
||||||
|
if comment.IsBlocking() {
|
||||||
|
pullReq.UnresolvedCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if pullReq.ActivitySeq < comment.Order {
|
||||||
|
pullReq.ActivitySeq = comment.Order
|
||||||
|
}
|
||||||
|
|
||||||
|
return comment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repoImportState) getPrincipalByEmail(ctx context.Context, emailAddress string) (*types.Principal, error) {
|
||||||
|
if principal, exists := r.principals[emailAddress]; exists {
|
||||||
|
return principal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
principal, err := r.principalStore.FindByEmail(ctx, emailAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load principal by email: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return principal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func timestampMillis(t time.Time, def int64) int64 {
|
||||||
|
if t.IsZero() {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateThreads(extComments []ExternalComment) []*externalCommentThread {
|
||||||
|
extCommentParents := make(map[int]int, len(extComments))
|
||||||
|
extCommentMap := make(map[int]ExternalComment, len(extComments))
|
||||||
|
for _, extComment := range extComments {
|
||||||
|
extCommentParents[extComment.ID] = extComment.ParentID
|
||||||
|
extCommentMap[extComment.ID] = extComment
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make flat list of reply comment IDs: create map[topLevelCommentID]->[]commentID
|
||||||
|
extCommentIDReplyMap := make(map[int][]int)
|
||||||
|
for _, extComment := range extComments {
|
||||||
|
topLevelParentID := getTopLevelParentID(extComment.ID, extCommentParents)
|
||||||
|
if topLevelParentID < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if topLevelParentID == extComment.ID {
|
||||||
|
// Make sure the item with topLevelParentID exist in the map, at least as a nil entry.
|
||||||
|
extCommentIDReplyMap[topLevelParentID] = extCommentIDReplyMap[topLevelParentID] //nolint:staticcheck
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
extCommentIDReplyMap[topLevelParentID] = append(extCommentIDReplyMap[topLevelParentID], extComment.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
countTopLevel := len(extCommentIDReplyMap)
|
||||||
|
if countTopLevel == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
extCommentThreads := make([]*externalCommentThread, 0, countTopLevel)
|
||||||
|
for topLevelID, replyIDs := range extCommentIDReplyMap {
|
||||||
|
expReplyComments := make([]ExternalComment, len(replyIDs))
|
||||||
|
for i, replyID := range replyIDs {
|
||||||
|
expReplyComments[i] = extCommentMap[replyID]
|
||||||
|
}
|
||||||
|
thread := &externalCommentThread{
|
||||||
|
TopLevel: extCommentMap[topLevelID],
|
||||||
|
Replies: expReplyComments,
|
||||||
|
}
|
||||||
|
extCommentThreads = append(extCommentThreads, thread)
|
||||||
|
}
|
||||||
|
|
||||||
|
// order top level comments
|
||||||
|
|
||||||
|
sort.Slice(extCommentThreads, func(i, j int) bool {
|
||||||
|
created1 := extCommentThreads[i].TopLevel.Created
|
||||||
|
created2 := extCommentThreads[j].TopLevel.Created
|
||||||
|
return created1.Before(created2)
|
||||||
|
})
|
||||||
|
|
||||||
|
// order reply comments
|
||||||
|
|
||||||
|
for _, thread := range extCommentThreads {
|
||||||
|
sort.Slice(thread.Replies, func(i, j int) bool {
|
||||||
|
created1 := thread.Replies[i].Created
|
||||||
|
created2 := thread.Replies[j].Created
|
||||||
|
return created1.Before(created2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return extCommentThreads
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTopLevelParentID(id int, tree map[int]int) int {
|
||||||
|
const maxDepth = 20
|
||||||
|
for currID, depth := id, 0; depth < maxDepth; depth++ {
|
||||||
|
parentID := tree[currID]
|
||||||
|
if parentID == 0 {
|
||||||
|
return currID
|
||||||
|
}
|
||||||
|
|
||||||
|
currID = parentID
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
72
app/services/importer/pullreq_test.go
Normal file
72
app/services/importer/pullreq_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// 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 importer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateThreads(t *testing.T) {
|
||||||
|
// comments with treelike structure
|
||||||
|
t0 := time.Now()
|
||||||
|
comments := []ExternalComment{
|
||||||
|
/* 0 */ {ID: 1, Body: "A", ParentID: 0},
|
||||||
|
/* 1 */ {ID: 2, Body: "B", ParentID: 0},
|
||||||
|
/* 2 */ {ID: 3, Body: "A1", ParentID: 1},
|
||||||
|
/* 3 */ {ID: 4, Body: "B1", ParentID: 2},
|
||||||
|
/* 4 */ {ID: 5, Body: "A2", ParentID: 1},
|
||||||
|
/* 5 */ {ID: 6, Body: "A2X", ParentID: 5},
|
||||||
|
/* 6 */ {ID: 7, Body: "A1X", ParentID: 3},
|
||||||
|
/* 7 */ {ID: 8, Body: "B1X", ParentID: 4},
|
||||||
|
/* 8 */ {ID: 9, Body: "C", ParentID: 0},
|
||||||
|
/* 9 */ {ID: 10, Body: "D1", ParentID: 11}, // Wrong order - a reply before its parent
|
||||||
|
/* 10 */ {ID: 11, Body: "D", ParentID: 0},
|
||||||
|
{ID: 20, Body: "Self-parent", ParentID: 20}, // Invalid
|
||||||
|
{ID: 30, Body: "Crosslinked-X", ParentID: 31}, // Invalid
|
||||||
|
{ID: 31, Body: "Crosslinked-Y", ParentID: 30}, // Invalid
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range comments {
|
||||||
|
comments[i].Created = t0.Add(time.Duration(i) * time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flattened threads with top level comments and a list of replies to each of them
|
||||||
|
wantThreads := []*externalCommentThread{
|
||||||
|
{
|
||||||
|
TopLevel: comments[0], // A
|
||||||
|
Replies: []ExternalComment{comments[2], comments[4], comments[5], comments[6]}, // A1, A2, A2X, A1X
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TopLevel: comments[1], // B
|
||||||
|
Replies: []ExternalComment{comments[3], comments[7]}, // B1, B1X
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TopLevel: comments[8], // C
|
||||||
|
Replies: []ExternalComment{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TopLevel: comments[10], // D
|
||||||
|
Replies: []ExternalComment{comments[9]}, // D1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gotThreads := generateThreads(comments)
|
||||||
|
if diff := cmp.Diff(gotThreads, wantThreads); diff != "" {
|
||||||
|
t.Errorf(diff)
|
||||||
|
}
|
||||||
|
}
|
27
app/services/importer/pullreq_types.go
Normal file
27
app/services/importer/pullreq_types.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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 importer
|
||||||
|
|
||||||
|
import (
|
||||||
|
migratetypes "github.com/harness/harness-migrate/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExternalPullRequest = migratetypes.PullRequestData
|
||||||
|
type ExternalComment = migratetypes.Comment
|
||||||
|
|
||||||
|
type externalCommentThread struct {
|
||||||
|
TopLevel ExternalComment
|
||||||
|
Replies []ExternalComment
|
||||||
|
}
|
@ -238,7 +238,7 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
|
|||||||
return "", fmt.Errorf("failed to find repo by id: %w", err)
|
return "", fmt.Errorf("failed to find repo by id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !repo.Importing {
|
if repo.State != enum.RepoStateGitImport {
|
||||||
return "", fmt.Errorf("repository %s is not being imported", repo.Identifier)
|
return "", fmt.Errorf("repository %s is not being imported", repo.Identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
|
|||||||
|
|
||||||
err = func() error {
|
err = func() error {
|
||||||
repo, err = r.repoStore.UpdateOptLock(ctx, repo, func(repo *types.Repository) error {
|
repo, err = r.repoStore.UpdateOptLock(ctx, repo, func(repo *types.Repository) error {
|
||||||
if !repo.Importing {
|
if repo.State != enum.RepoStateGitImport {
|
||||||
return errors.New("repository has already finished importing")
|
return errors.New("repository has already finished importing")
|
||||||
}
|
}
|
||||||
repo.GitUID = gitUID
|
repo.GitUID = gitUID
|
||||||
@ -328,13 +328,13 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
|
|||||||
log.Info().Msg("update repo in DB")
|
log.Info().Msg("update repo in DB")
|
||||||
|
|
||||||
repo, err = r.repoStore.UpdateOptLock(ctx, repo, func(repo *types.Repository) error {
|
repo, err = r.repoStore.UpdateOptLock(ctx, repo, func(repo *types.Repository) error {
|
||||||
if !repo.Importing {
|
if repo.State != enum.RepoStateGitImport {
|
||||||
return errors.New("repository has already finished importing")
|
return errors.New("repository has already finished importing")
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.GitUID = gitUID
|
repo.GitUID = gitUID
|
||||||
repo.DefaultBranch = defaultBranch
|
repo.DefaultBranch = defaultBranch
|
||||||
repo.Importing = false
|
repo.State = enum.RepoStateActive
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -385,7 +385,7 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
|
|||||||
func (r *Repository) GetProgress(ctx context.Context, repo *types.Repository) (job.Progress, error) {
|
func (r *Repository) GetProgress(ctx context.Context, repo *types.Repository) (job.Progress, error) {
|
||||||
progress, err := r.scheduler.GetJobProgress(ctx, JobIDFromRepoID(repo.ID))
|
progress, err := r.scheduler.GetJobProgress(ctx, JobIDFromRepoID(repo.ID))
|
||||||
if errors.Is(err, gitness_store.ErrResourceNotFound) {
|
if errors.Is(err, gitness_store.ErrResourceNotFound) {
|
||||||
if repo.Importing {
|
if repo.State == enum.RepoStateGitImport {
|
||||||
// if the job is not found but repo is marked as importing, return state=failed
|
// if the job is not found but repo is marked as importing, return state=failed
|
||||||
return job.FailProgress(), nil
|
return job.FailProgress(), nil
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ func (r *Repository) GetProgress(ctx context.Context, repo *types.Repository) (j
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Cancel(ctx context.Context, repo *types.Repository) error {
|
func (r *Repository) Cancel(ctx context.Context, repo *types.Repository) error {
|
||||||
if !repo.Importing {
|
if repo.State != enum.RepoStateGitImport {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
|
|
||||||
var WireSet = wire.NewSet(
|
var WireSet = wire.NewSet(
|
||||||
ProvideRepoImporter,
|
ProvideRepoImporter,
|
||||||
|
ProvidePullReqImporter,
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideRepoImporter(
|
func ProvideRepoImporter(
|
||||||
@ -73,3 +74,25 @@ func ProvideRepoImporter(
|
|||||||
|
|
||||||
return importer, nil
|
return importer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProvidePullReqImporter(
|
||||||
|
urlProvider url.Provider,
|
||||||
|
git git.Interface,
|
||||||
|
principalStore store.PrincipalStore,
|
||||||
|
repoStore store.RepoStore,
|
||||||
|
pullReqStore store.PullReqStore,
|
||||||
|
pullReqActStore store.PullReqActivityStore,
|
||||||
|
tx dbtx.Transactor,
|
||||||
|
) *PullReq {
|
||||||
|
importer := &PullReq{
|
||||||
|
urlProvider: urlProvider,
|
||||||
|
git: git,
|
||||||
|
principalStore: principalStore,
|
||||||
|
repoStore: repoStore,
|
||||||
|
pullReqStore: pullReqStore,
|
||||||
|
pullReqActStore: pullReqActStore,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
|
||||||
|
return importer
|
||||||
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE repositories
|
||||||
|
ADD COLUMN repo_importing BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
|
UPDATE repositories SET repo_importing = TRUE WHERE repo_state = 1;
|
||||||
|
|
||||||
|
ALTER TABLE repositories
|
||||||
|
DROP COLUMN repo_state;
|
@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE repositories
|
||||||
|
ADD COLUMN repo_state INTEGER DEFAULT 0;
|
||||||
|
|
||||||
|
UPDATE repositories SET repo_state = 1 WHERE repo_importing = TRUE;
|
||||||
|
|
||||||
|
ALTER TABLE repositories
|
||||||
|
DROP COLUMN repo_importing;
|
@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE repositories
|
||||||
|
ADD COLUMN repo_importing BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
|
UPDATE repositories SET repo_importing = TRUE WHERE repo_state = 1;
|
||||||
|
|
||||||
|
ALTER TABLE repositories
|
||||||
|
DROP COLUMN repo_state;
|
@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE repositories
|
||||||
|
ADD COLUMN repo_state INTEGER DEFAULT 0;
|
||||||
|
|
||||||
|
UPDATE repositories SET repo_state = 1 WHERE repo_importing = TRUE;
|
||||||
|
|
||||||
|
ALTER TABLE repositories
|
||||||
|
DROP COLUMN repo_importing;
|
@ -86,8 +86,8 @@ type repository struct {
|
|||||||
NumOpenPulls int `db:"repo_num_open_pulls"`
|
NumOpenPulls int `db:"repo_num_open_pulls"`
|
||||||
NumMergedPulls int `db:"repo_num_merged_pulls"`
|
NumMergedPulls int `db:"repo_num_merged_pulls"`
|
||||||
|
|
||||||
Importing bool `db:"repo_importing"`
|
State enum.RepoState `db:"repo_state"`
|
||||||
IsEmpty bool `db:"repo_is_empty"`
|
IsEmpty bool `db:"repo_is_empty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -112,7 +112,7 @@ const (
|
|||||||
,repo_num_closed_pulls
|
,repo_num_closed_pulls
|
||||||
,repo_num_open_pulls
|
,repo_num_open_pulls
|
||||||
,repo_num_merged_pulls
|
,repo_num_merged_pulls
|
||||||
,repo_importing
|
,repo_state
|
||||||
,repo_is_empty`
|
,repo_is_empty`
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
|
|||||||
,repo_num_closed_pulls
|
,repo_num_closed_pulls
|
||||||
,repo_num_open_pulls
|
,repo_num_open_pulls
|
||||||
,repo_num_merged_pulls
|
,repo_num_merged_pulls
|
||||||
,repo_importing
|
,repo_state
|
||||||
,repo_is_empty
|
,repo_is_empty
|
||||||
) values (
|
) values (
|
||||||
:repo_version
|
:repo_version
|
||||||
@ -258,7 +258,7 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
|
|||||||
,:repo_num_closed_pulls
|
,:repo_num_closed_pulls
|
||||||
,:repo_num_open_pulls
|
,:repo_num_open_pulls
|
||||||
,:repo_num_merged_pulls
|
,:repo_num_merged_pulls
|
||||||
,:repo_importing
|
,:repo_state
|
||||||
,:repo_is_empty
|
,:repo_is_empty
|
||||||
) RETURNING repo_id`
|
) RETURNING repo_id`
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ func (s *RepoStore) Update(ctx context.Context, repo *types.Repository) error {
|
|||||||
,repo_num_closed_pulls = :repo_num_closed_pulls
|
,repo_num_closed_pulls = :repo_num_closed_pulls
|
||||||
,repo_num_open_pulls = :repo_num_open_pulls
|
,repo_num_open_pulls = :repo_num_open_pulls
|
||||||
,repo_num_merged_pulls = :repo_num_merged_pulls
|
,repo_num_merged_pulls = :repo_num_merged_pulls
|
||||||
,repo_importing = :repo_importing
|
,repo_state = :repo_state
|
||||||
,repo_is_empty = :repo_is_empty
|
,repo_is_empty = :repo_is_empty
|
||||||
WHERE repo_id = :repo_id AND repo_version = :repo_version - 1`
|
WHERE repo_id = :repo_id AND repo_version = :repo_version - 1`
|
||||||
|
|
||||||
@ -744,7 +744,7 @@ func (s *RepoStore) mapToRepo(
|
|||||||
NumClosedPulls: in.NumClosedPulls,
|
NumClosedPulls: in.NumClosedPulls,
|
||||||
NumOpenPulls: in.NumOpenPulls,
|
NumOpenPulls: in.NumOpenPulls,
|
||||||
NumMergedPulls: in.NumMergedPulls,
|
NumMergedPulls: in.NumMergedPulls,
|
||||||
Importing: in.Importing,
|
State: in.State,
|
||||||
IsEmpty: in.IsEmpty,
|
IsEmpty: in.IsEmpty,
|
||||||
// Path: is set below
|
// Path: is set below
|
||||||
}
|
}
|
||||||
@ -827,7 +827,7 @@ func mapToInternalRepo(in *types.Repository) *repository {
|
|||||||
NumClosedPulls: in.NumClosedPulls,
|
NumClosedPulls: in.NumClosedPulls,
|
||||||
NumOpenPulls: in.NumOpenPulls,
|
NumOpenPulls: in.NumOpenPulls,
|
||||||
NumMergedPulls: in.NumMergedPulls,
|
NumMergedPulls: in.NumMergedPulls,
|
||||||
Importing: in.Importing,
|
State: in.State,
|
||||||
IsEmpty: in.IsEmpty,
|
IsEmpty: in.IsEmpty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -857,7 +857,7 @@ func applySortFilter(stmt squirrel.SelectBuilder, filter *types.RepoFilter) squi
|
|||||||
// NOTE: string concatenation is safe because the
|
// NOTE: string concatenation is safe because the
|
||||||
// order attribute is an enum and is not user-defined,
|
// order attribute is an enum and is not user-defined,
|
||||||
// and is therefore not subject to injection attacks.
|
// and is therefore not subject to injection attacks.
|
||||||
stmt = stmt.OrderBy("repo_importing desc, repo_uid " + filter.Order.String())
|
stmt = stmt.OrderBy("repo_state desc, repo_uid " + filter.Order.String())
|
||||||
case enum.RepoAttrCreated:
|
case enum.RepoAttrCreated:
|
||||||
stmt = stmt.OrderBy("repo_created " + filter.Order.String())
|
stmt = stmt.OrderBy("repo_created " + filter.Order.String())
|
||||||
case enum.RepoAttrUpdated:
|
case enum.RepoAttrUpdated:
|
||||||
|
@ -266,7 +266,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, eventsReporter, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker)
|
pullReq := importer.ProvidePullReqImporter(provider, gitInterface, principalStore, repoStore, pullReqStore, pullReqActivityStore, transactor)
|
||||||
|
pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, eventsReporter, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq)
|
||||||
webhookConfig := server.ProvideWebhookConfig(config)
|
webhookConfig := server.ProvideWebhookConfig(config)
|
||||||
webhookStore := database.ProvideWebhookStore(db)
|
webhookStore := database.ProvideWebhookStore(db)
|
||||||
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
|
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
|
||||||
|
8
go.mod
8
go.mod
@ -1,6 +1,6 @@
|
|||||||
module github.com/harness/gitness
|
module github.com/harness/gitness
|
||||||
|
|
||||||
go 1.20
|
go 1.22
|
||||||
|
|
||||||
replace github.com/docker/docker => github.com/docker/engine v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
replace github.com/docker/docker => github.com/docker/engine v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
||||||
|
|
||||||
@ -12,6 +12,8 @@ require (
|
|||||||
github.com/bmatcuk/doublestar/v4 v4.6.0
|
github.com/bmatcuk/doublestar/v4 v4.6.0
|
||||||
github.com/coreos/go-semver v0.3.0
|
github.com/coreos/go-semver v0.3.0
|
||||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
|
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
|
||||||
|
github.com/docker/docker v23.0.3+incompatible
|
||||||
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/drone-runners/drone-runner-docker v1.8.4-0.20240109154718-47375e234554
|
github.com/drone-runners/drone-runner-docker v1.8.4-0.20240109154718-47375e234554
|
||||||
github.com/drone/drone-go v1.7.1
|
github.com/drone/drone-go v1.7.1
|
||||||
github.com/drone/drone-yaml v1.2.3
|
github.com/drone/drone-yaml v1.2.3
|
||||||
@ -36,7 +38,7 @@ require (
|
|||||||
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
|
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
|
||||||
github.com/gotidy/ptr v1.4.0
|
github.com/gotidy/ptr v1.4.0
|
||||||
github.com/guregu/null v4.0.0+incompatible
|
github.com/guregu/null v4.0.0+incompatible
|
||||||
github.com/harness/harness-migrate v0.21.1-0.20240624210736-65c7e9fbe930
|
github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/jmoiron/sqlx v1.3.3
|
github.com/jmoiron/sqlx v1.3.3
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
@ -88,8 +90,6 @@ require (
|
|||||||
github.com/containerd/containerd v1.7.6 // indirect
|
github.com/containerd/containerd v1.7.6 // indirect
|
||||||
github.com/distribution/reference v0.5.0 // indirect
|
github.com/distribution/reference v0.5.0 // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/docker v23.0.3+incompatible // indirect
|
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/drone/envsubst v1.0.3 // indirect
|
github.com/drone/envsubst v1.0.3 // indirect
|
||||||
github.com/fatih/semgroup v1.2.0 // indirect
|
github.com/fatih/semgroup v1.2.0 // indirect
|
||||||
|
22
go.sum
22
go.sum
@ -56,6 +56,7 @@ github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d/go.mod h1:3
|
|||||||
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
|
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
|
||||||
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
|
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g=
|
github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g=
|
||||||
github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE=
|
github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
@ -81,6 +82,7 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
|
|||||||
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs=
|
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs=
|
||||||
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
@ -111,7 +113,9 @@ github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9
|
|||||||
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||||
github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0=
|
github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0=
|
||||||
|
github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
|
||||||
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
|
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
|
||||||
|
github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
|
||||||
github.com/buildkite/yaml v2.1.0+incompatible h1:xirI+ql5GzfikVNDmt+yeiXpf/v1Gt03qXTtT5WXdr8=
|
github.com/buildkite/yaml v2.1.0+incompatible h1:xirI+ql5GzfikVNDmt+yeiXpf/v1Gt03qXTtT5WXdr8=
|
||||||
github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeLBgQQIjL/H7Y6KwikUrI=
|
github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeLBgQQIjL/H7Y6KwikUrI=
|
||||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
@ -268,6 +272,7 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
|||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@ -298,6 +303,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -346,6 +352,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
|
|||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||||
|
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
@ -402,9 +409,11 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
|||||||
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||||
github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
|
github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
|
||||||
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
||||||
|
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
github.com/harness/harness-migrate v0.21.1-0.20240624210736-65c7e9fbe930 h1:NboKpEf78oc/8bOmh7Gk8uILbIYrD5nswyX9+K6iuKg=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/harness/harness-migrate v0.21.1-0.20240624210736-65c7e9fbe930/go.mod h1:HiUX39ZfhBGY+OkEEN6JpglbodNJlbzayOt/l3nkk6w=
|
github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8 h1:X0/Nk9aCkIKoF3kavxZcr9EtfARSBqnJK33c59m+xmw=
|
||||||
|
github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8/go.mod h1:HiUX39ZfhBGY+OkEEN6JpglbodNJlbzayOt/l3nkk6w=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
@ -437,6 +446,7 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
|||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||||
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
|
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
|
||||||
|
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
@ -531,6 +541,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
|||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
@ -607,6 +618,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk=
|
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk=
|
||||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||||
@ -733,6 +745,7 @@ github.com/sercand/kuberesolver/v5 v5.1.0 h1:YLqreB1vUFbZHSidcqI5ChMp+RIRmop0brQ
|
|||||||
github.com/sercand/kuberesolver/v5 v5.1.0/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ=
|
github.com/sercand/kuberesolver/v5 v5.1.0/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
@ -785,6 +798,7 @@ github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKN
|
|||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw=
|
github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw=
|
||||||
|
github.com/swaggest/assertjson v1.7.0/go.mod h1:vxMJMehbSVJd+dDWFCKv3QRZKNTpy/ktZKTz9LOEDng=
|
||||||
github.com/swaggest/jsonschema-go v0.3.40 h1:9EqQ9RvtdW69xfYODmyEKWOSZ12x5eiK+wGD2EVh/L4=
|
github.com/swaggest/jsonschema-go v0.3.40 h1:9EqQ9RvtdW69xfYODmyEKWOSZ12x5eiK+wGD2EVh/L4=
|
||||||
github.com/swaggest/jsonschema-go v0.3.40/go.mod h1:ipIOmoFP64QyRUgyPyU/P9tayq2m2TlvUhyZHrhe3S4=
|
github.com/swaggest/jsonschema-go v0.3.40/go.mod h1:ipIOmoFP64QyRUgyPyU/P9tayq2m2TlvUhyZHrhe3S4=
|
||||||
github.com/swaggest/openapi-go v0.2.23 h1:DYUezSTyw180z1bL51wUnalYYbTMwHBjp1Itvji8/rs=
|
github.com/swaggest/openapi-go v0.2.23 h1:DYUezSTyw180z1bL51wUnalYYbTMwHBjp1Itvji8/rs=
|
||||||
@ -805,7 +819,9 @@ github.com/vearutop/statigz v1.4.0/go.mod h1:LYTolBLiz9oJISwiVKnOQoIwhO1LWX1A7OE
|
|||||||
github.com/vinzenz/yaml v0.0.0-20170920082545-91409cdd725d/go.mod h1:mb5taDqMnJiZNRQ3+02W2IFG+oEz1+dTuCXkp4jpkfo=
|
github.com/vinzenz/yaml v0.0.0-20170920082545-91409cdd725d/go.mod h1:mb5taDqMnJiZNRQ3+02W2IFG+oEz1+dTuCXkp4jpkfo=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||||
|
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||||
|
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
@ -1307,6 +1323,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
@ -1335,6 +1352,7 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -18,10 +18,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Defines repo attributes that can be used for sorting and filtering.
|
// RepoAttr defines repo attributes that can be used for sorting and filtering.
|
||||||
type RepoAttr int
|
type RepoAttr int
|
||||||
|
|
||||||
// Order enumeration.
|
// RepoAttr enumeration.
|
||||||
const (
|
const (
|
||||||
RepoAttrNone RepoAttr = iota
|
RepoAttrNone RepoAttr = iota
|
||||||
// TODO [CODE-1363]: remove after identifier migration.
|
// TODO [CODE-1363]: remove after identifier migration.
|
||||||
@ -72,3 +72,30 @@ func (a RepoAttr) String() string {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepoState defines repo state.
|
||||||
|
type RepoState int
|
||||||
|
|
||||||
|
// RepoState enumeration.
|
||||||
|
const (
|
||||||
|
RepoStateActive RepoState = iota
|
||||||
|
RepoStateGitImport
|
||||||
|
RepoStateMigrateGitPush
|
||||||
|
RepoStateMigrateDataImport
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns the string representation of the RepoState.
|
||||||
|
func (state RepoState) String() string {
|
||||||
|
switch state {
|
||||||
|
case RepoStateActive:
|
||||||
|
return "active"
|
||||||
|
case RepoStateGitImport:
|
||||||
|
return "git-import"
|
||||||
|
case RepoStateMigrateGitPush:
|
||||||
|
return "migrate-git-push"
|
||||||
|
case RepoStateMigrateDataImport:
|
||||||
|
return "migrate-data-import"
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -48,8 +48,8 @@ type Repository struct {
|
|||||||
NumOpenPulls int `json:"num_open_pulls" yaml:"num_open_pulls"`
|
NumOpenPulls int `json:"num_open_pulls" yaml:"num_open_pulls"`
|
||||||
NumMergedPulls int `json:"num_merged_pulls" yaml:"num_merged_pulls"`
|
NumMergedPulls int `json:"num_merged_pulls" yaml:"num_merged_pulls"`
|
||||||
|
|
||||||
Importing bool `json:"importing" yaml:"-"`
|
State enum.RepoState `json:"state" yaml:"-"`
|
||||||
IsEmpty bool `json:"is_empty,omitempty" yaml:"is_empty"`
|
IsEmpty bool `json:"is_empty,omitempty" yaml:"is_empty"`
|
||||||
|
|
||||||
// git urls
|
// git urls
|
||||||
GitURL string `json:"git_url" yaml:"-"`
|
GitURL string `json:"git_url" yaml:"-"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user