fix: [CDE-413]: Setting branch URL in all gitspace API response (#2881)

* 

fix: [CDE-413]: Adding spacePath to method.
* 

fix: [CDE-413]: Adding method to get branch url in the scm interface and using it to set the branch url in the gitspace config api responses. Removing the SCM interface as it has only 1 impl. Minor refactoring.
* 

fix: [CDE-413]: Adding method to get branch url in the scm interface and using it to set the branch url in the gitspace config api responses. Removing the SCM interface as it has only 1 impl. Minor refactoring.
This commit is contained in:
Dhruv Dhruv 2024-10-29 04:46:03 +00:00 committed by Harness
parent 178af11902
commit 6dbe85fbfd
19 changed files with 146 additions and 74 deletions

View File

@ -76,6 +76,9 @@ func (c *Controller) Action(
return nil, err return nil, err
} }
} }
gitspaceConfig.BranchURL = c.gitspaceSvc.GetBranchURL(ctx, gitspaceConfig)
// All the actions should be idempotent. // All the actions should be idempotent.
switch in.Action { switch in.Action {
case enum.GitspaceActionTypeStart: case enum.GitspaceActionTypeStart:

View File

@ -37,7 +37,7 @@ type Controller struct {
gitspaceEventStore store.GitspaceEventStore gitspaceEventStore store.GitspaceEventStore
tx dbtx.Transactor tx dbtx.Transactor
statefulLogger *logutil.StatefulLogger statefulLogger *logutil.StatefulLogger
scm scm.SCM scm *scm.SCM
repoStore store.RepoStore repoStore store.RepoStore
gitspaceSvc *gitspace.Service gitspaceSvc *gitspace.Service
gitspaceLimiter limiter.Gitspace gitspaceLimiter limiter.Gitspace
@ -52,7 +52,7 @@ func NewController(
spaceStore store.SpaceStore, spaceStore store.SpaceStore,
gitspaceEventStore store.GitspaceEventStore, gitspaceEventStore store.GitspaceEventStore,
statefulLogger *logutil.StatefulLogger, statefulLogger *logutil.StatefulLogger,
scm scm.SCM, scm *scm.SCM,
repoStore store.RepoStore, repoStore store.RepoStore,
gitspaceSvc *gitspace.Service, gitspaceSvc *gitspace.Service,
gitspaceLimiter limiter.Gitspace, gitspaceLimiter limiter.Gitspace,

View File

@ -177,6 +177,7 @@ func (c *Controller) Create(
if err != nil { if err != nil {
return nil, err return nil, err
} }
gitspaceConfig.BranchURL = c.gitspaceSvc.GetBranchURL(ctx, gitspaceConfig)
return gitspaceConfig, nil return gitspaceConfig, nil
} }

View File

@ -75,6 +75,10 @@ func (c *Controller) ListAllGitspaces( // nolint:gocognit
return nil, err return nil, err
} }
for _, gitspaceConfig := range result {
gitspaceConfig.BranchURL = c.gitspaceSvc.GetBranchURL(ctx, gitspaceConfig)
}
return result, nil return result, nil
} }

View File

@ -41,7 +41,7 @@ func ProvideController(
spaceStore store.SpaceStore, spaceStore store.SpaceStore,
eventStore store.GitspaceEventStore, eventStore store.GitspaceEventStore,
statefulLogger *logutil.StatefulLogger, statefulLogger *logutil.StatefulLogger,
scm scm.SCM, scm *scm.SCM,
repoStore store.RepoStore, repoStore store.RepoStore,
gitspaceSvc *gitspace.Service, gitspaceSvc *gitspace.Service,
gitspaceLimiter limiter.Gitspace, gitspaceLimiter limiter.Gitspace,

View File

@ -46,7 +46,7 @@ type Config struct {
} }
type orchestrator struct { type orchestrator struct {
scm scm.SCM scm *scm.SCM
infraProviderResourceStore store.InfraProviderResourceStore infraProviderResourceStore store.InfraProviderResourceStore
infraProvisioner infrastructure.InfraProvisioner infraProvisioner infrastructure.InfraProvisioner
containerOrchestrator container.Orchestrator containerOrchestrator container.Orchestrator
@ -60,7 +60,7 @@ type orchestrator struct {
var _ Orchestrator = (*orchestrator)(nil) var _ Orchestrator = (*orchestrator)(nil)
func NewOrchestrator( func NewOrchestrator(
scm scm.SCM, scm *scm.SCM,
infraProviderResourceStore store.InfraProviderResourceStore, infraProviderResourceStore store.InfraProviderResourceStore,
infraProvisioner infrastructure.InfraProvisioner, infraProvisioner infrastructure.InfraProvisioner,
containerOrchestrator container.Orchestrator, containerOrchestrator container.Orchestrator,

View File

@ -32,7 +32,7 @@ var WireSet = wire.NewSet(
) )
func ProvideOrchestrator( func ProvideOrchestrator(
scm scm.SCM, scm *scm.SCM,
infraProviderResourceStore store.InfraProviderResourceStore, infraProviderResourceStore store.InfraProviderResourceStore,
infraProvisioner infrastructure.InfraProvisioner, infraProvisioner infrastructure.InfraProvisioner,
containerOrchestrator container.Orchestrator, containerOrchestrator container.Orchestrator,

View File

@ -49,9 +49,11 @@ type GitnessSCM struct {
} }
// ListBranches implements Provider. // ListBranches implements Provider.
func (s *GitnessSCM) ListBranches(ctx context.Context, func (s *GitnessSCM) ListBranches(
ctx context.Context,
filter *BranchFilter, filter *BranchFilter,
_ *ResolvedCredentials) ([]Branch, error) { _ *ResolvedCredentials,
) ([]Branch, error) {
repo, err := s.repoStore.FindByRef(ctx, filter.Repository) repo, err := s.repoStore.FindByRef(ctx, filter.Repository)
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)
@ -83,10 +85,12 @@ func mapBranch(b git.Branch) Branch {
} }
} }
// ListReporisotries implements Provider. // ListRepositories implements Provider.
func (s *GitnessSCM) ListReporisotries(ctx context.Context, func (s *GitnessSCM) ListRepositories(
ctx context.Context,
filter *RepositoryFilter, filter *RepositoryFilter,
_ *ResolvedCredentials) ([]Repository, error) { _ *ResolvedCredentials,
) ([]Repository, error) {
repos, err := s.repoStore.List(ctx, filter.SpaceID, &types.RepoFilter{ repos, err := s.repoStore.List(ctx, filter.SpaceID, &types.RepoFilter{
Page: filter.Page, Page: filter.Page,
Size: filter.Size, Size: filter.Size,
@ -125,10 +129,12 @@ func mapRepository(repo *types.Repository) (Repository, error) {
}, nil }, nil
} }
func NewGitnessSCM(repoStore store.RepoStore, git git.Interface, func NewGitnessSCM(
repoStore store.RepoStore, git git.Interface,
tokenStore store.TokenStore, tokenStore store.TokenStore,
principalStore store.PrincipalStore, principalStore store.PrincipalStore,
urlProvider urlprovider.Provider) *GitnessSCM { urlProvider urlprovider.Provider,
) *GitnessSCM {
return &GitnessSCM{ return &GitnessSCM{
repoStore: repoStore, repoStore: repoStore,
git: git, git: git,
@ -138,7 +144,7 @@ func NewGitnessSCM(repoStore store.RepoStore, git git.Interface,
} }
} }
func (s GitnessSCM) ResolveCredentials( func (s *GitnessSCM) ResolveCredentials(
ctx context.Context, ctx context.Context,
gitspaceConfig types.GitspaceConfig, gitspaceConfig types.GitspaceConfig,
) (*ResolvedCredentials, error) { ) (*ResolvedCredentials, error) {
@ -200,7 +206,8 @@ func (s GitnessSCM) ResolveCredentials(
return resolvedCredentails, nil return resolvedCredentails, nil
} }
func (s GitnessSCM) GetFileContent(ctx context.Context, func (s *GitnessSCM) GetFileContent(
ctx context.Context,
gitspaceConfig types.GitspaceConfig, gitspaceConfig types.GitspaceConfig,
filePath string, filePath string,
_ *ResolvedCredentials, _ *ResolvedCredentials,
@ -243,8 +250,13 @@ func (s GitnessSCM) GetFileContent(ctx context.Context,
return catFileOutput, nil return catFileOutput, nil
} }
func findUserFromUID(ctx context.Context, func findUserFromUID(
ctx context.Context,
principalStore store.PrincipalStore, userUID string, principalStore store.PrincipalStore, userUID string,
) (*types.User, error) { ) (*types.User, error) {
return principalStore.FindUserByUID(ctx, userUID) return principalStore.FindUserByUID(ctx, userUID)
} }
func (s *GitnessSCM) GetBranchURL(_ string, repoURL string, branch string) (string, error) {
return fmt.Sprintf("%s/files/%s", strings.TrimSuffix(repoURL, ".git"), branch), nil
}

View File

@ -31,6 +31,8 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
var _ Provider = (*GenericSCM)(nil)
type GenericSCM struct { type GenericSCM struct {
} }
@ -38,21 +40,24 @@ func NewGenericSCM() *GenericSCM {
return &GenericSCM{} return &GenericSCM{}
} }
// ListBranches implements Provider. func (s *GenericSCM) ListBranches(
func (s *GenericSCM) ListBranches(_ context.Context, _ context.Context,
_ *BranchFilter, _ *BranchFilter,
_ *ResolvedCredentials) ([]Branch, error) { _ *ResolvedCredentials,
) ([]Branch, error) {
return []Branch{}, nil return []Branch{}, nil
} }
// ListReporisotries implements Provider. func (s *GenericSCM) ListRepositories(
func (s *GenericSCM) ListReporisotries(_ context.Context, _ context.Context,
_ *RepositoryFilter, _ *RepositoryFilter,
_ *ResolvedCredentials) ([]Repository, error) { _ *ResolvedCredentials,
) ([]Repository, error) {
return []Repository{}, nil return []Repository{}, nil
} }
func (s GenericSCM) GetFileContent(ctx context.Context, func (s *GenericSCM) GetFileContent(
ctx context.Context,
gitspaceConfig types.GitspaceConfig, gitspaceConfig types.GitspaceConfig,
filePath string, filePath string,
_ *ResolvedCredentials, _ *ResolvedCredentials,
@ -115,7 +120,7 @@ func (s GenericSCM) GetFileContent(ctx context.Context,
return catFileOutput.Bytes(), nil return catFileOutput.Bytes(), nil
} }
func (s GenericSCM) ResolveCredentials( func (s *GenericSCM) ResolveCredentials(
_ context.Context, _ context.Context,
gitspaceConfig types.GitspaceConfig, gitspaceConfig types.GitspaceConfig,
) (*ResolvedCredentials, error) { ) (*ResolvedCredentials, error) {
@ -131,3 +136,7 @@ func (s GenericSCM) ResolveCredentials(
resolvedCredentials.RepoName = repoName resolvedCredentials.RepoName = repoName
return resolvedCredentials, err return resolvedCredentials, err
} }
func (s *GenericSCM) GetBranchURL(_ string, repoURL string, _ string) (string, error) {
return repoURL, nil
}

View File

@ -34,29 +34,17 @@ var (
const devcontainerDefaultPath = ".devcontainer/devcontainer.json" const devcontainerDefaultPath = ".devcontainer/devcontainer.json"
var _ SCM = (*scm)(nil) type SCM struct {
type SCM interface {
// GetSCMRepoDetails fetches repository name, credentials & devcontainer config file from the given repo and branch.
GetSCMRepoDetails(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
) (*ResolvedDetails, error)
// CheckValidCodeRepo checks if the current URL is a valid and accessible code repo,
// input can be connector info, user token etc.
CheckValidCodeRepo(ctx context.Context, request CodeRepositoryRequest) (*CodeRepositoryResponse, error)
}
type scm struct {
scmProviderFactory Factory scmProviderFactory Factory
} }
func NewSCM(factory Factory) SCM { func NewSCM(factory Factory) *SCM {
return &scm{scmProviderFactory: factory} return &SCM{scmProviderFactory: factory}
} }
func (s scm) CheckValidCodeRepo( // CheckValidCodeRepo checks if the current URL is a valid and accessible code repo,
// input can be connector info, user token etc.
func (s *SCM) CheckValidCodeRepo(
ctx context.Context, ctx context.Context,
codeRepositoryRequest CodeRepositoryRequest, codeRepositoryRequest CodeRepositoryRequest,
) (*CodeRepositoryResponse, error) { ) (*CodeRepositoryResponse, error) {
@ -110,7 +98,8 @@ func (s scm) CheckValidCodeRepo(
return codeRepositoryResponse, nil return codeRepositoryResponse, nil
} }
func (s scm) GetSCMRepoDetails( // GetSCMRepoDetails fetches repository name, credentials & devcontainer config file from the given repo and branch.
func (s *SCM) GetSCMRepoDetails(
ctx context.Context, ctx context.Context,
gitspaceConfig types.GitspaceConfig, gitspaceConfig types.GitspaceConfig,
) (*ResolvedDetails, error) { ) (*ResolvedDetails, error) {
@ -172,3 +161,16 @@ func detectDefaultGitBranch(ctx context.Context, gitRepoDir string) (string, err
} }
return match[1], nil return match[1], nil
} }
func (s *SCM) GetBranchURL(
spacePath string,
repoType enum.GitspaceCodeRepoType,
repoURL string,
branch string,
) (string, error) {
scmProvider, err := s.scmProviderFactory.GetSCMProvider(repoType)
if err != nil {
return "", fmt.Errorf("failed to resolve scm provider while generating branch url: %w", err)
}
return scmProvider.GetBranchURL(spacePath, repoURL, branch)
}

View File

@ -15,29 +15,11 @@
package scm package scm
import ( import (
"context"
"fmt" "fmt"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum" "github.com/harness/gitness/types/enum"
) )
type Provider interface {
ResolveCredentials(ctx context.Context, gitspaceConfig types.GitspaceConfig) (*ResolvedCredentials, error)
GetFileContent(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
filePath string,
credentials *ResolvedCredentials,
) ([]byte, error)
ListReporisotries(ctx context.Context,
filter *RepositoryFilter,
credentials *ResolvedCredentials) ([]Repository, error)
ListBranches(ctx context.Context,
filter *BranchFilter,
credentials *ResolvedCredentials) ([]Branch, error)
}
type Factory struct { type Factory struct {
providers map[enum.GitspaceCodeRepoType]Provider providers map[enum.GitspaceCodeRepoType]Provider
} }

View File

@ -0,0 +1,46 @@
// 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 scm
import (
"context"
"github.com/harness/gitness/types"
)
type Provider interface {
ResolveCredentials(ctx context.Context, gitspaceConfig types.GitspaceConfig) (*ResolvedCredentials, error)
GetFileContent(
ctx context.Context,
gitspaceConfig types.GitspaceConfig,
filePath string,
credentials *ResolvedCredentials,
) ([]byte, error)
ListRepositories(
ctx context.Context,
filter *RepositoryFilter,
credentials *ResolvedCredentials,
) ([]Repository, error)
ListBranches(
ctx context.Context,
filter *BranchFilter,
credentials *ResolvedCredentials,
) ([]Branch, error)
GetBranchURL(spacePath string, repoURL string, branch string) (string, error)
}

View File

@ -44,6 +44,6 @@ func ProvideFactory(gitness *GitnessSCM, genericSCM *GenericSCM) Factory {
return NewFactory(gitness, genericSCM) return NewFactory(gitness, genericSCM)
} }
func ProvideSCM(factory Factory) SCM { func ProvideSCM(factory Factory) *SCM {
return NewSCM(factory) return NewSCM(factory)
} }

View File

@ -50,6 +50,7 @@ func (c *Service) Find(
if txErr != nil { if txErr != nil {
return nil, txErr return nil, txErr
} }
gitspaceConfigResult.BranchURL = c.GetBranchURL(ctx, gitspaceConfigResult)
return gitspaceConfigResult, nil return gitspaceConfigResult, nil
} }

View File

@ -20,11 +20,14 @@ import (
gitspaceevents "github.com/harness/gitness/app/events/gitspace" gitspaceevents "github.com/harness/gitness/app/events/gitspace"
"github.com/harness/gitness/app/gitspace/orchestrator" "github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/services/infraprovider" "github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store" "github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx" "github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum" "github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
) )
func NewService( func NewService(
@ -36,6 +39,7 @@ func NewService(
spaceStore store.SpaceStore, spaceStore store.SpaceStore,
infraProviderSvc *infraprovider.Service, infraProviderSvc *infraprovider.Service,
orchestrator orchestrator.Orchestrator, orchestrator orchestrator.Orchestrator,
scm *scm.SCM,
) *Service { ) *Service {
return &Service{ return &Service{
tx: tx, tx: tx,
@ -46,6 +50,7 @@ func NewService(
spaceStore: spaceStore, spaceStore: spaceStore,
infraProviderSvc: infraProviderSvc, infraProviderSvc: infraProviderSvc,
orchestrator: orchestrator, orchestrator: orchestrator,
scm: scm,
} }
} }
@ -58,6 +63,7 @@ type Service struct {
tx dbtx.Transactor tx dbtx.Transactor
infraProviderSvc *infraprovider.Service infraProviderSvc *infraprovider.Service
orchestrator orchestrator.Orchestrator orchestrator orchestrator.Orchestrator
scm *scm.SCM
} }
func (c *Service) ListGitspacesForSpace( func (c *Service) ListGitspacesForSpace(
@ -100,6 +106,7 @@ func (c *Service) ListGitspacesForSpace(
} else { } else {
gitspaceConfig.State = enum.GitspaceStateUninitialized gitspaceConfig.State = enum.GitspaceStateUninitialized
} }
gitspaceConfig.BranchURL = c.GetBranchURL(ctx, gitspaceConfig)
} }
return nil return nil
}, dbtx.TxDefaultReadOnly) }, dbtx.TxDefaultReadOnly)
@ -127,3 +134,14 @@ func (c *Service) getLatestInstanceMap(
} }
return gitspaceInstancesMap, nil return gitspaceInstancesMap, nil
} }
func (c *Service) GetBranchURL(ctx context.Context, config *types.GitspaceConfig) string {
branchURL, err := c.scm.GetBranchURL(config.SpacePath, config.CodeRepo.Type, config.CodeRepo.URL,
config.CodeRepo.Branch)
if err != nil {
log.Warn().Ctx(ctx).Err(err).Msgf("failed to get branch URL for gitspace config %s, returning repo url",
config.Identifier)
branchURL = config.CodeRepo.URL
}
return branchURL
}

View File

@ -17,6 +17,7 @@ package gitspace
import ( import (
gitspaceevents "github.com/harness/gitness/app/events/gitspace" gitspaceevents "github.com/harness/gitness/app/events/gitspace"
"github.com/harness/gitness/app/gitspace/orchestrator" "github.com/harness/gitness/app/gitspace/orchestrator"
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/app/services/infraprovider" "github.com/harness/gitness/app/services/infraprovider"
"github.com/harness/gitness/app/store" "github.com/harness/gitness/app/store"
"github.com/harness/gitness/store/database/dbtx" "github.com/harness/gitness/store/database/dbtx"
@ -37,8 +38,8 @@ func ProvideGitspace(
spaceStore store.SpaceStore, spaceStore store.SpaceStore,
infraProviderSvc *infraprovider.Service, infraProviderSvc *infraprovider.Service,
orchestrator orchestrator.Orchestrator, orchestrator orchestrator.Orchestrator,
scm *scm.SCM,
) *Service { ) *Service {
return NewService(tx, gitspaceStore, gitspaceInstanceStore, eventReporter, return NewService(tx, gitspaceStore, gitspaceInstanceStore, eventReporter,
gitspaceEventStore, spaceStore, infraProviderSvc, orchestrator) gitspaceEventStore, spaceStore, infraProviderSvc, orchestrator, scm)
} }

View File

@ -323,7 +323,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
passwordResolver := secret.ProvidePasswordResolver() passwordResolver := secret.ProvidePasswordResolver()
resolverFactory := secret.ProvideResolverFactory(passwordResolver) resolverFactory := secret.ProvideResolverFactory(passwordResolver)
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, eventsReporter, orchestratorConfig, vsCode, vsCodeWeb, resolverFactory) orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, eventsReporter, orchestratorConfig, vsCode, vsCodeWeb, resolverFactory)
gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, eventsReporter, gitspaceEventStore, spaceStore, infraproviderService, orchestratorOrchestrator) gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, eventsReporter, gitspaceEventStore, spaceStore, infraproviderService, orchestratorOrchestrator, scmSCM)
spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, listService, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService) spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, listService, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService)
reporter3, err := events5.ProvideReporter(eventsSystem) reporter3, err := events5.ProvideReporter(eventsSystem)
if err != nil { if err != nil {

View File

@ -152,15 +152,7 @@ func (d DockerProvider) Find(
infrastructure.SpaceID = spaceID infrastructure.SpaceID = spaceID
infrastructure.SpacePath = spacePath infrastructure.SpacePath = spacePath
infrastructure.GitspaceConfigIdentifier = gitspaceConfigIdentifier infrastructure.GitspaceConfigIdentifier = gitspaceConfigIdentifier
infrastructure.Storage = volumeName(spacePath, gitspaceConfigIdentifier)
name := volumeName(spacePath, gitspaceConfigIdentifier)
volumeInspect, err := dockerClient.VolumeInspect(ctx, name)
if err != nil {
log.Err(err).Msgf("couldn't find the volume for %s", name)
}
infrastructure.Storage = volumeInspect.Name
return infrastructure, nil return infrastructure, nil
} }

View File

@ -42,6 +42,7 @@ type CodeRepo struct {
Ref *string `json:"code_repo_ref"` Ref *string `json:"code_repo_ref"`
Type enum.GitspaceCodeRepoType `json:"code_repo_type"` Type enum.GitspaceCodeRepoType `json:"code_repo_type"`
Branch string `json:"branch"` Branch string `json:"branch"`
BranchURL string `json:"branch_url,omitempty"`
DevcontainerPath *string `json:"devcontainer_path,omitempty"` DevcontainerPath *string `json:"devcontainer_path,omitempty"`
IsPrivate bool `json:"code_repo_is_private"` IsPrivate bool `json:"code_repo_is_private"`
AuthType string `json:"-"` AuthType string `json:"-"`