feat(gitops): simplify the struct for Git sources BE-12919 (#2930)

This commit is contained in:
andres-portainer
2026-06-29 15:00:30 -03:00
committed by GitHub
parent 5c1c18b8f0
commit 331c2ee4e8
39 changed files with 194 additions and 151 deletions
+5 -5
View File
@@ -50,19 +50,19 @@ func Test_SanitizeAccesses_Admin(t *testing.T) {
test(nil, nil, errInvalidSource)
test(&portainer.Source{}, nil, noError)
test(&portainer.Source{Git: &gittypes.RepoConfig{}}, nil,
test(&portainer.Source{Git: &gittypes.GitSource{}}, nil,
noError, emptyUsers, emptyTeams, adminOnly(true), noOwner, public(false),
)
test(&portainer.Source{Git: &gittypes.RepoConfig{}, Public: true}, nil,
test(&portainer.Source{Git: &gittypes.GitSource{}, Public: true}, nil,
noError, emptyUsers, emptyTeams, adminOnly(false), noOwner, public(true),
)
test(&portainer.Source{Git: &gittypes.RepoConfig{}, AdministratorsOnly: true}, nil,
test(&portainer.Source{Git: &gittypes.GitSource{}, AdministratorsOnly: true}, nil,
noError, emptyUsers, emptyTeams, adminOnly(true), noOwner, public(false),
)
test(&portainer.Source{Git: &gittypes.RepoConfig{}, AdministratorsOnly: true, Public: true}, nil,
test(&portainer.Source{Git: &gittypes.GitSource{}, AdministratorsOnly: true, Public: true}, nil,
noError, emptyUsers, emptyTeams, adminOnly(true), noOwner, public(false),
)
test(&portainer.Source{Git: &gittypes.RepoConfig{}, AdministratorsOnly: true, Public: true, UserAccesses: []portainer.UserID{1, 2}}, nil,
test(&portainer.Source{Git: &gittypes.GitSource{}, AdministratorsOnly: true, Public: true, UserAccesses: []portainer.UserID{1, 2}}, nil,
noError, emptyUsers, emptyTeams, adminOnly(true), noOwner, public(false),
)
}
+1 -1
View File
@@ -184,7 +184,7 @@ func (service ServiceTx) FindOrCreateGitSource(context UserContext, src *portain
toCreate := &portainer.Source{
Name: src.Name,
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: src.Git.URL,
Authentication: src.Git.Authentication,
TLSSkipVerify: src.Git.TLSSkipVerify,
+11 -7
View File
@@ -116,7 +116,7 @@ func (m *Migrator) migrateGitConfigToSources_2_43_0() error {
sourcesByKey := make(map[sourceDedupeKey]portainer.SourceID, len(existingSources))
for _, src := range existingSources {
if src.Git != nil {
sourcesByKey[gitSourceKey(src.Git)] = src.ID
sourcesByKey[gitSourceKey(&gittypes.RepoConfig{URL: src.Git.URL, Authentication: src.Git.Authentication})] = src.ID
}
}
@@ -163,9 +163,13 @@ func (m *Migrator) migrateGitConfigToSources_2_43_0() error {
if !exists {
src := &portainer.Source{
Name: gittypes.RepoName(cfg.URL),
Type: portainer.SourceTypeGit,
Git: cfg,
Name: gittypes.RepoName(cfg.URL),
Type: portainer.SourceTypeGit,
Git: &gittypes.GitSource{
URL: cfg.URL,
Authentication: cfg.Authentication,
TLSSkipVerify: cfg.TLSSkipVerify,
},
OwnerID: ownerId,
Public: public,
AdministratorsOnly: adminOnly,
@@ -240,7 +244,7 @@ func (m *Migrator) migrateCustomTemplateGitConfigToSources_2_43_0() error {
sourcesByKey := make(map[sourceDedupeKey]portainer.SourceID, len(existingSources))
for _, src := range existingSources {
if src.Git != nil {
sourcesByKey[gitSourceKey(src.Git)] = src.ID
sourcesByKey[gitSourceKey(&gittypes.RepoConfig{URL: src.Git.URL, Authentication: src.Git.Authentication})] = src.ID
}
}
@@ -250,13 +254,13 @@ func (m *Migrator) migrateCustomTemplateGitConfigToSources_2_43_0() error {
continue
}
cfg := &gittypes.RepoConfig{
cfg := &gittypes.GitSource{
URL: gittypes.SanitizeURL(t.GitConfig.URL),
Authentication: t.GitConfig.Authentication,
TLSSkipVerify: t.GitConfig.TLSSkipVerify,
}
key := gitSourceKey(cfg)
key := gitSourceKey(&gittypes.RepoConfig{URL: cfg.URL, Authentication: cfg.Authentication})
var newSrcID portainer.SourceID
@@ -76,7 +76,7 @@ func TestMigrateGitConfigToSources_2_43_0_GitStackMigrated(t *testing.T) {
require.NoError(t, err)
require.Equal(t, portainer.SourceTypeGit, src.Type)
require.Equal(t, gitStack.GitConfig.URL, src.Git.URL)
require.Equal(t, gitStack.GitConfig.ReferenceName, src.Git.ReferenceName)
require.Equal(t, gitStack.GitConfig.ReferenceName, wf.Artifacts[0].Files[0].Ref)
}
func TestMigrateGitConfigToSources_2_43_0_NonGitStackUntouched(t *testing.T) {
+36
View File
@@ -35,6 +35,42 @@ type RepoConfig struct {
TLSSkipVerify bool `example:"false"`
}
// GitSource holds the shared connection fields stored on a Source.
// Per-file fields (ref, path, hash) are stored on ArtifactFile instead.
type GitSource struct {
URL string `example:"https://github.com/portainer/portainer.git"`
Authentication *GitAuthentication `json:",omitempty"`
TLSSkipVerify bool `example:"false"`
}
// ToRepoConfig returns a RepoConfig populated with the connection fields from gc
func (gc *GitSource) ToRepoConfig() *RepoConfig {
return &RepoConfig{
URL: gc.URL,
Authentication: gc.Authentication,
TLSSkipVerify: gc.TLSSkipVerify,
}
}
// SanitizeGitSource returns a copy of gc with the URL sanitized and password cleared,
// safe to return to clients
func SanitizeGitSource(gc *GitSource) *GitSource {
if gc == nil {
return nil
}
result := *gc
result.URL = SanitizeURL(result.URL)
if result.Authentication != nil && result.Authentication.Password != "" {
auth := *result.Authentication
auth.Password = ""
result.Authentication = &auth
}
return &result
}
// RepoName extracts the repository name from a git URL for use as a display name.
// e.g. "https://github.com/org/app-config.git" results in "app-config"
func RepoName(rawURL string) string {
+1 -1
View File
@@ -21,7 +21,7 @@ func TestResolveRepoConfig_WithSourceID_ReturnsSourceConfig(t *testing.T) {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/repo",
TLSSkipVerify: true,
Authentication: &gittypes.GitAuthentication{
+1 -1
View File
@@ -17,7 +17,7 @@ func TestValidateSourceForStack_ValidGitSource_ReturnsNil(t *testing.T) {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/org/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/org/repo"},
}
require.NoError(t, store.Source().Create(adminUserContext, src))
+5 -5
View File
@@ -27,7 +27,7 @@ func mustCreateGitWorkflow(t *testing.T, tx dataservices.DataStoreTx, stack *por
cfg := stack.GitConfig
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: cfg}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: cfg.URL, Authentication: cfg.Authentication, TLSSkipVerify: cfg.TLSSkipVerify}}
require.NoError(t, tx.Source().Create(adminUserContext, src))
wf := &portainer.Workflow{Artifacts: []portainer.Artifact{{
@@ -203,8 +203,8 @@ func TestFetchSourceStats_ReturnsAllSources(t *testing.T) {
_, store := datastore.MustNewTestStore(t, false, true)
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
require.NoError(t, tx.Source().Create(adminUserContext, &portainer.Source{Name: "source-1", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo1"}}))
require.NoError(t, tx.Source().Create(adminUserContext, &portainer.Source{Name: "source-2", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo2"}}))
require.NoError(t, tx.Source().Create(adminUserContext, &portainer.Source{Name: "source-1", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo1"}}))
require.NoError(t, tx.Source().Create(adminUserContext, &portainer.Source{Name: "source-2", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo2"}}))
return tx.User().Create(&portainer.User{ID: 1, Role: portainer.AdministratorRole})
}))
@@ -227,7 +227,7 @@ func TestFetchSourceStats_TracksWorkflowCountAndEndpoints(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "shared", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "shared", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
require.NoError(t, tx.Source().Create(adminUserContext, src))
srcID = src.ID
@@ -265,7 +265,7 @@ func TestFetchSourceStats_UnusedSourceHasZeroStats(t *testing.T) {
var unusedID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "unused", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "unused", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
require.NoError(t, tx.Source().Create(adminUserContext, src))
unusedID = src.ID
+5 -1
View File
@@ -193,7 +193,11 @@ func SaveWorkflowGitConfig(tx gitSourceStore, userContext source.UserContext, wo
newSrc, err := FindOrCreateGitSource(tx, userContext, &portainer.Source{
Name: gittypes.RepoName(cfg.URL),
Type: portainer.SourceTypeGit,
Git: cfg,
Git: &gittypes.GitSource{
URL: cfg.URL,
Authentication: cfg.Authentication,
TLSSkipVerify: cfg.TLSSkipVerify,
},
})
if err != nil {
return fmt.Errorf("failed to find or create source: %w", err)
+27 -34
View File
@@ -28,7 +28,7 @@ func TestMergeSourceAndFile_NilFileLeaveFileFieldsEmpty(t *testing.T) {
t.Parallel()
src := &portainer.Source{
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: true,
Authentication: &gittypes.GitAuthentication{
@@ -52,7 +52,7 @@ func TestMergeSourceAndFile_MergesAllFieldsFromFile(t *testing.T) {
t.Parallel()
src := &portainer.Source{
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: true,
},
@@ -96,7 +96,7 @@ func TestGitSourceAndArtifactForStack_ReturnsMatchingSourceAndFile(t *testing.T)
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
gitSrc := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, gitSrc)
require.NoError(t, err)
@@ -144,7 +144,7 @@ func TestGitSourceAndArtifactForStack_NoMatchingArtifactReturnsNil(t *testing.T)
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
@@ -199,7 +199,7 @@ func TestGitSourceAndArtifactForEdgeStack_ReturnsMatchingSourceAndFile(t *testin
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
gitSrc := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/edge-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/edge-repo"},
}
err := tx.Source().Create(adminUserContext, gitSrc)
require.NoError(t, err)
@@ -243,7 +243,7 @@ func TestUpdateArtifactFileForStack_NoMatchingArtifactIsNoOp(t *testing.T) {
var workflowID portainer.WorkflowID
var sourceID portainer.SourceID
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "https://example.com"}}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "https://example.com"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
sourceID = src.ID
@@ -281,7 +281,7 @@ func TestUpdateArtifactFileForStack_AppliesFnAndPersists(t *testing.T) {
var workflowID portainer.WorkflowID
var sourceID portainer.SourceID
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "https://example.com"}}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "https://example.com"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
sourceID = src.ID
@@ -319,7 +319,7 @@ func TestUpdateArtifactFileForEdgeStack_AppliesFnAndPersists(t *testing.T) {
var workflowID portainer.WorkflowID
var sourceID portainer.SourceID
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "https://example.com"}}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "https://example.com"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
sourceID = src.ID
@@ -360,7 +360,7 @@ func TestFindOrCreateGitSource_CreatesNewSource(t *testing.T) {
src, txErr = FindOrCreateGitSource(tx, adminUserContext, &portainer.Source{
Name: "my-repo",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
},
})
@@ -379,7 +379,7 @@ func TestFindOrCreateGitSource_ReusesExistingSourceForSameURLAndAuth(t *testing.
makeSource := func(tx dataservices.DataStoreTx) (*portainer.Source, error) {
return FindOrCreateGitSource(tx, adminUserContext, &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
},
})
@@ -422,7 +422,7 @@ func TestFindOrCreateGitSource_DifferentAuthCreatesNewSource(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
_, txErr := FindOrCreateGitSource(tx, adminUserContext, &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
Authentication: &gittypes.GitAuthentication{Username: "alice", Password: "pass1"},
},
@@ -434,7 +434,7 @@ func TestFindOrCreateGitSource_DifferentAuthCreatesNewSource(t *testing.T) {
err = store.UpdateTx(func(tx dataservices.DataStoreTx) error {
_, txErr := FindOrCreateGitSource(tx, adminUserContext, &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
Authentication: &gittypes.GitAuthentication{Username: "bob", Password: "pass2"},
},
@@ -458,7 +458,7 @@ func TestSaveWorkflowGitConfig_UpdatesFileAndSourceWhenURLUnchanged(t *testing.T
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: false,
Authentication: &gittypes.GitAuthentication{
@@ -533,7 +533,7 @@ func TestSaveWorkflowGitConfig_CreatesNewSourceOnURLChange(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/old-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/old-repo"},
}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
@@ -582,7 +582,7 @@ func TestSaveWorkflowGitConfig_ReusesExistingSourceOnURLChange(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
old := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/old-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/old-repo"},
}
err := tx.Source().Create(adminUserContext, old)
require.NoError(t, err)
@@ -590,7 +590,7 @@ func TestSaveWorkflowGitConfig_ReusesExistingSourceOnURLChange(t *testing.T) {
existing := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/shared-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/shared-repo"},
}
err = tx.Source().Create(adminUserContext, existing)
require.NoError(t, err)
@@ -638,7 +638,7 @@ func TestSaveWorkflowGitConfig_OnlyMatchingArtifactUpdated(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
@@ -687,7 +687,7 @@ func TestUpdateArtifactFileForStack_MultipleArtifactsOnlyMatchingUpdated(t *test
var workflowID portainer.WorkflowID
var srcID portainer.SourceID
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "https://example.com"}}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "https://example.com"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -731,7 +731,7 @@ func TestSaveWorkflowArtifact_SwitchesSourceWithoutMutatingIt(t *testing.T) {
// resolution would fail to switch.
old := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, old)
require.NoError(t, err)
@@ -739,7 +739,7 @@ func TestSaveWorkflowArtifact_SwitchesSourceWithoutMutatingIt(t *testing.T) {
selected := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
Authentication: &gittypes.GitAuthentication{
Username: "selected-user",
@@ -804,7 +804,7 @@ func TestUpdateArtifactFileForEdgeStack_MultipleArtifactsOnlyMatchingUpdated(t *
var workflowID portainer.WorkflowID
var srcID portainer.SourceID
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "https://example.com"}}
src := &portainer.Source{Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "https://example.com"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -846,7 +846,7 @@ func TestSaveWorkflowArtifact_SameSourceUpdatesArtifactOnly(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
@@ -898,7 +898,7 @@ func TestGitSourceAndArtifactForStack_MultipleArtifactsReturnsCorrectOne(t *test
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
gitSrc := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/shared-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/shared-repo"},
}
err := tx.Source().Create(adminUserContext, gitSrc)
require.NoError(t, err)
@@ -939,7 +939,7 @@ func TestGitSourceAndArtifactForEdgeStack_MultipleArtifactsReturnsCorrectOne(t *
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
gitSrc := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/shared-edge-repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/shared-edge-repo"},
}
err := tx.Source().Create(adminUserContext, gitSrc)
require.NoError(t, err)
@@ -975,17 +975,10 @@ func TestGitSourceAndArtifactForEdgeStack_MultipleArtifactsReturnsCorrectOne(t *
func TestMergeSourceAndFile_ConfigHashComesFromFileNotSource(t *testing.T) {
t.Parallel()
// ConfigHash must come from ArtifactFile.Hash, not src.Git.
// A Source shared by two stacks has one Git.ConfigHash field;
// if reads used it instead of ArtifactFile.Hash they would clobber each other.
src := &portainer.Source{
Git: &gittypes.RepoConfig{
URL: "https://github.com/example/repo",
},
}
file := &portainer.ArtifactFile{
Hash: "artifact-hash",
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
file := &portainer.ArtifactFile{Hash: "artifact-hash"}
cfg := MergeSourceAndFile(src, file)
require.NotNil(t, cfg)
@@ -1001,7 +994,7 @@ func TestFindOrCreateGitSource_StripsEmbeddedCredentialsFromURL(t *testing.T) {
var txErr error
src, txErr = FindOrCreateGitSource(tx, adminUserContext, &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://user:secret@github.com/example/repo",
},
})
@@ -340,7 +340,7 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (
src, err := workflows.FindOrCreateGitSource(handler.DataStore, userContext, &portainer.Source{
Name: gittypes.RepoName(gitConfig.URL),
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: gitConfig.URL,
Authentication: gitConfig.Authentication,
TLSSkipVerify: gitConfig.TLSSkipVerify,
@@ -1115,7 +1115,7 @@ func TestCustomTemplateCreate_FromRepository_WithSourceID_Success(t *testing.T)
src := &portainer.Source{
Name: "example/repo",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
},
}
@@ -151,7 +151,7 @@ func TestCustomTemplateFile_GitTemplate(t *testing.T) {
require.NoError(t, ds.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/example/repo"},
Git: &gittypes.GitSource{URL: "https://github.com/example/repo"},
}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
@@ -177,7 +177,7 @@ func Test_customTemplateGitFetch(t *testing.T) {
ID: 1,
Type: portainer.SourceTypeGit,
Public: true,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
},
}
@@ -169,7 +169,7 @@ func TestInspectHandler_GitConfigPopulatedFromSource(t *testing.T) {
require.NoError(t, ds.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: true,
},
@@ -23,7 +23,7 @@ func TestCustomTemplateList_PopulatesGitConfigFromSource(t *testing.T) {
require.NoError(t, ds.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: true,
},
@@ -89,7 +89,7 @@ func TestCustomTemplateList_StripsPasswordFromGitConfig(t *testing.T) {
require.NoError(t, ds.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
Authentication: &gittypes.GitAuthentication{
Username: "user",
@@ -237,7 +237,7 @@ func (handler *Handler) customTemplateUpdate(w http.ResponseWriter, r *http.Requ
src, err := workflows.FindOrCreateGitSource(handler.DataStore, userContext, &portainer.Source{
Name: gittypes.RepoName(gitConfig.URL),
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: gitConfig.URL,
Authentication: gitConfig.Authentication,
TLSSkipVerify: gitConfig.TLSSkipVerify,
@@ -480,7 +480,7 @@ func TestCustomTemplateUpdate_WithSourceID_Success(t *testing.T) {
src := &portainer.Source{
Name: "example/repo",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
},
}
+10 -5
View File
@@ -7,6 +7,7 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/dataservices/source"
gittypes "github.com/portainer/portainer/api/git/types"
)
func populateGitConfig(tx dataservices.DataStoreTx, userContext source.UserContext, template *portainer.CustomTemplate) {
@@ -21,10 +22,14 @@ func populateGitConfig(tx dataservices.DataStoreTx, userContext source.UserConte
return
}
cfg := *src.Git
cfg.ReferenceName = file.Ref
cfg.ConfigFilePath = file.Path
cfg.ConfigHash = file.Hash
cfg := &gittypes.RepoConfig{
URL: src.Git.URL,
Authentication: src.Git.Authentication,
TLSSkipVerify: src.Git.TLSSkipVerify,
ReferenceName: file.Ref,
ConfigFilePath: file.Path,
ConfigHash: file.Hash,
}
if cfg.Authentication != nil {
sanitized := *cfg.Authentication
@@ -32,7 +37,7 @@ func populateGitConfig(tx dataservices.DataStoreTx, userContext source.UserConte
cfg.Authentication = &sanitized
}
template.GitConfig = &cfg
template.GitConfig = cfg
}
// IsValidNote reports whether note is safe to display. Notes containing <img> tags are rejected.
@@ -58,7 +58,7 @@ func TestPopulateGitConfig_PopulatesFromSourceAndArtifact(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
TLSSkipVerify: true,
},
@@ -106,7 +106,7 @@ func TestPopulateGitConfig_StripsPassword(t *testing.T) {
err := store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/example/repo",
Authentication: &gittypes.GitAuthentication{
Username: "user",
@@ -89,7 +89,7 @@ func (h *Handler) gitSourceCreate(w http.ResponseWriter, r *http.Request) *httpe
return httperror.InternalServerError("Unable to create source", err)
}
src.Git = gittypes.SanitizeRepoConfig(src.Git)
src.Git = gittypes.SanitizeGitSource(src.Git)
return response.JSONWithStatus(w, src, http.StatusCreated)
}
@@ -112,7 +112,7 @@ func BuildBaseGitSource(payload GitSourceCreatePayload) *portainer.Source {
return &portainer.Source{
Name: name,
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: payload.URL,
TLSSkipVerify: payload.TLSSkipVerify,
},
@@ -20,7 +20,7 @@ func TestSourceDelete_Success(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "to-delete", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "to-delete", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -58,7 +58,7 @@ func TestSourceDelete_InUse(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "in-use", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "in-use", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -100,7 +100,7 @@ func TestSourceDelete_InUseByCustomTemplate(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "in-use-by-template", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "in-use-by-template", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
+25 -1
View File
@@ -37,12 +37,36 @@ func FetchSourceWorkflows(tx dataservices.DataStoreTx, src *portainer.Source) ([
return nil, ce.SourceStats{}, err
}
artifactByStack := make(map[portainer.StackID]portainer.ArtifactFile)
for _, wf := range wfs {
for _, artifact := range wf.Artifacts {
if artifact.StackID == 0 {
continue
}
if _, exists := artifactByStack[artifact.StackID]; exists {
continue
}
for _, file := range artifact.Files {
if file.SourceID == src.ID {
artifactByStack[artifact.StackID] = file
break
}
}
}
}
unknown := ce.WorkflowPhaseStatus{Status: ce.StatusUnknown}
items := make([]ce.Workflow, 0, len(stacks))
stats := ce.SourceStats{EndpointIDs: set.Set[portainer.EndpointID]{}}
for _, stacks := range stacks {
items = append(items, ce.MapStackToWorkflow(stacks, src.Git, unknown, unknown))
cfg := src.Git.ToRepoConfig()
if file, ok := artifactByStack[stacks.ID]; ok {
cfg.ReferenceName = file.Ref
cfg.ConfigFilePath = file.Path
cfg.ConfigHash = file.Hash
}
items = append(items, ce.MapStackToWorkflow(stacks, cfg, unknown, unknown))
stats.WorkflowCount++
if stacks.EndpointID != 0 {
stats.EndpointIDs.Add(stacks.EndpointID)
+2 -4
View File
@@ -20,7 +20,6 @@ type gitAuthInfo struct {
}
type connectionInfo struct {
ConfigFilePath string `json:"configFilePath"`
TLSSkipVerify bool `json:"tlsSkipVerify"`
Authentication *gitAuthInfo `json:"authentication,omitempty"`
}
@@ -103,7 +102,7 @@ func (h *Handler) getSource(w http.ResponseWriter, r *http.Request) *httperror.H
return response.JSON(w, detail)
}
func BuildSourceDetail(baseSource Source, cfg *gittypes.RepoConfig, sourceWfs []workflows.Workflow, access SourceAccess) SourceDetail {
func BuildSourceDetail(baseSource Source, cfg *gittypes.GitSource, sourceWfs []workflows.Workflow, access SourceAccess) SourceDetail {
var autoUpdate *AutoUpdateInfo
if len(sourceWfs) > 0 {
autoUpdate = BuildAutoUpdateInfo(sourceWfs[0].AutoUpdate)
@@ -140,12 +139,11 @@ func BuildSourceAccess(source *portainer.Source) SourceAccess {
}
}
func buildConnectionInfo(cfg *gittypes.RepoConfig) connectionInfo {
func buildConnectionInfo(cfg *gittypes.GitSource) connectionInfo {
if cfg == nil {
return connectionInfo{}
}
return connectionInfo{
ConfigFilePath: cfg.ConfigFilePath,
TLSSkipVerify: cfg.TLSSkipVerify,
Authentication: buildGitAuthInfo(cfg.Authentication),
}
+4 -7
View File
@@ -33,11 +33,9 @@ func TestGetSource_ReturnsDetail(t *testing.T) {
t.Parallel()
_, store := datastore.MustNewTestStore(t, false, true)
cfg := &gittypes.RepoConfig{
URL: "https://github.com/org/repo",
ReferenceName: "refs/heads/main",
ConfigFilePath: "docker-compose.yml",
TLSSkipVerify: true,
cfg := &gittypes.GitSource{
URL: "https://github.com/org/repo",
TLSSkipVerify: true,
}
var srcID portainer.SourceID
@@ -56,7 +54,6 @@ func TestGetSource_ReturnsDetail(t *testing.T) {
assert.Equal(t, srcID, detail.ID)
assert.Equal(t, "repo", detail.Name)
assert.Equal(t, 1, detail.UsedBy)
assert.Equal(t, "docker-compose.yml", detail.Connection.ConfigFilePath)
assert.True(t, detail.Connection.TLSSkipVerify)
require.Len(t, detail.Workflows, 1)
assert.Equal(t, "my-stack", detail.Workflows[0].Name)
@@ -66,7 +63,7 @@ func TestGetSource_RedactsCredentials(t *testing.T) {
t.Parallel()
_, store := datastore.MustNewTestStore(t, false, true)
cfg := &gittypes.RepoConfig{
cfg := &gittypes.GitSource{
URL: "https://github.com/org/secure",
Authentication: &gittypes.GitAuthentication{Username: "user", Password: "s3cr3t"},
}
@@ -22,7 +22,7 @@ var adminUserContext = source.InsecureNewAdminContext()
// createGitWorkflow creates a Source and Workflow for the given config and
// wires them up by setting stack.WorkflowID before creating the stack.
func createGitWorkflow(t *testing.T, tx dataservices.DataStoreTx, stack *portainer.Stack, cfg *gittypes.RepoConfig) portainer.SourceID {
func createGitWorkflow(t *testing.T, tx dataservices.DataStoreTx, stack *portainer.Stack, cfg *gittypes.GitSource) portainer.SourceID {
t.Helper()
src := &portainer.Source{
@@ -35,11 +35,7 @@ func createGitWorkflow(t *testing.T, tx dataservices.DataStoreTx, stack *portain
wf := &portainer.Workflow{
Artifacts: []portainer.Artifact{{
StackID: stack.ID,
Files: []portainer.ArtifactFile{{
SourceID: src.ID,
Path: cfg.ConfigFilePath,
Ref: cfg.ReferenceName,
}},
Files: []portainer.ArtifactFile{{SourceID: src.ID}},
}},
}
require.NoError(t, tx.Workflow().Create(wf))
@@ -94,12 +90,8 @@ func decodeSourceDetail(t *testing.T, rr *httptest.ResponseRecorder) SourceDetai
return item
}
func gitCfg(url string) *gittypes.RepoConfig {
return &gittypes.RepoConfig{
URL: url,
ConfigFilePath: "docker-compose.yml",
ReferenceName: "refs/heads/main",
}
func gitCfg(url string) *gittypes.GitSource {
return &gittypes.GitSource{URL: url}
}
func buildCreateReq(t *testing.T, userID portainer.UserID, body []byte) *http.Request {
@@ -117,7 +117,7 @@ func (h *Handler) gitSourceTest(w http.ResponseWriter, r *http.Request) *httperr
}
// testSourceConnection verifies that a git repository is reachable with the given config.
func testSourceConnection(ctx context.Context, gitService portainer.GitService, config *gittypes.RepoConfig) ConnectionTestResult {
func testSourceConnection(ctx context.Context, gitService portainer.GitService, config *gittypes.GitSource) ConnectionTestResult {
var username, password string
if config.Authentication != nil {
username = config.Authentication.Username
@@ -42,7 +42,7 @@ func TestSourcesSummary_CountsByStatus(t *testing.T) {
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
for idx, name := range []string{"source-a", "source-b", "source-c"} {
err := tx.Source().Create(adminUserContext, &portainer.Source{Name: name, Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: fmt.Sprintf("http://github.com/org/repo%d", idx)}})
err := tx.Source().Create(adminUserContext, &portainer.Source{Name: name, Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: fmt.Sprintf("http://github.com/org/repo%d", idx)}})
require.NoError(t, err)
}
@@ -20,11 +20,10 @@ var (
ErrNotGitSource = errors.New("source is not a Git source")
)
// GitSourceUpdatePayload holds the parameters for creating a git-backed source
// GitSourceUpdatePayload holds the parameters for updating a git-backed source
type GitSourceUpdatePayload struct {
Name *string `json:"name"`
URL *string `json:"url"`
ReferenceName *string `json:"referenceName"`
TLSSkipVerify *bool `json:"tlsSkipVerify"`
Authentication *GitAuthenticationUpdatePayload `json:"authentication"`
}
@@ -107,7 +106,7 @@ func (h *Handler) gitSourceUpdate(w http.ResponseWriter, r *http.Request) *httpe
return httperror.InternalServerError("Unable to update source", err)
}
src.Git = gittypes.SanitizeRepoConfig(src.Git)
src.Git = gittypes.SanitizeGitSource(src.Git)
return response.JSON(w, src)
}
@@ -144,17 +143,13 @@ func ApplyBaseGitSourceChanges(src *portainer.Source, payload GitSourceUpdatePay
}
if src.Git == nil {
src.Git = &gittypes.RepoConfig{}
src.Git = &gittypes.GitSource{}
}
if payload.URL != nil {
src.Git.URL = *payload.URL
}
if payload.ReferenceName != nil {
src.Git.ReferenceName = *payload.ReferenceName
}
if payload.TLSSkipVerify != nil {
src.Git.TLSSkipVerify = *payload.TLSSkipVerify
}
@@ -20,7 +20,7 @@ func TestGitSourceUpdate_Success(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "old-name", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "old-name", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -58,7 +58,7 @@ func TestGitSourceUpdate_PreservesAuthWhenNotProvided(t *testing.T) {
src := &portainer.Source{
Name: "auth-source",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/repo.git",
Authentication: &gittypes.GitAuthentication{
Username: "alice",
@@ -107,7 +107,7 @@ func TestGitSourceUpdate_ClearsAuthWhenRequested(t *testing.T) {
src := &portainer.Source{
Name: "auth-source",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/repo.git",
Authentication: &gittypes.GitAuthentication{
Username: "alice",
@@ -154,7 +154,7 @@ func TestGitSourceUpdate_ReplacesAuthWhenProvided(t *testing.T) {
src := &portainer.Source{
Name: "auth-source",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/repo.git",
Authentication: &gittypes.GitAuthentication{
Username: "alice",
@@ -225,14 +225,14 @@ func TestGitSourceUpdate_ConflictOnDuplicateURL(t *testing.T) {
existing := &portainer.Source{
Name: "existing",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/existing.git",
},
}
err := tx.Source().Create(adminUserContext, existing)
require.NoError(t, err)
src := &portainer.Source{Name: "other", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "other", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err = tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -259,7 +259,7 @@ func TestGitSourceUpdate_MalformedJSON(t *testing.T) {
var srcID portainer.SourceID
require.NoError(t, store.UpdateTx(func(tx dataservices.DataStoreTx) error {
src := &portainer.Source{Name: "src", Type: portainer.SourceTypeGit, Git: &gittypes.RepoConfig{URL: "http://github.com/org/repo"}}
src := &portainer.Source{Name: "src", Type: portainer.SourceTypeGit, Git: &gittypes.GitSource{URL: "http://github.com/org/repo"}}
err := tx.Source().Create(adminUserContext, src)
require.NoError(t, err)
srcID = src.ID
@@ -284,7 +284,7 @@ func TestGitSourceUpdate_ConflictWhenAuthChangesMatchAnotherSource(t *testing.T)
existing := &portainer.Source{
Name: "existing",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/repo.git",
Authentication: &gittypes.GitAuthentication{
Username: "alice",
@@ -299,7 +299,7 @@ func TestGitSourceUpdate_ConflictWhenAuthChangesMatchAnotherSource(t *testing.T)
other := &portainer.Source{
Name: "other",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/org/repo.git"},
Git: &gittypes.GitSource{URL: "https://github.com/org/repo.git"},
}
if err := tx.Source().Create(adminUserContext, other); err != nil {
return err
+1 -1
View File
@@ -12,7 +12,7 @@ func (h *Handler) buildSource(ctx context.Context, src *portainer.Source, stats
var status ce.Status
var sourceErr string
if src.Git != nil {
phase, _ := ce.ComputeGitPhasesForConfig(ctx, h.gitService, src.Git)
phase, _ := ce.ComputeGitPhasesForConfig(ctx, h.gitService, src.Git.ToRepoConfig())
status = phase.Status
sourceErr = phase.Error
} else {
@@ -68,17 +68,15 @@ func TestBuildConnectionInfo(t *testing.T) {
assert.Equal(t, connectionInfo{}, buildConnectionInfo(nil))
cfg := &gittypes.RepoConfig{
ConfigFilePath: "docker-compose.yml",
cfg := &gittypes.GitSource{
TLSSkipVerify: true,
Authentication: &gittypes.GitAuthentication{Username: "user"},
}
got := buildConnectionInfo(cfg)
assert.Equal(t, "docker-compose.yml", got.ConfigFilePath)
assert.True(t, got.TLSSkipVerify)
require.NotNil(t, got.Authentication)
assert.Equal(t, "user", got.Authentication.Username)
got = buildConnectionInfo(&gittypes.RepoConfig{})
got = buildConnectionInfo(&gittypes.GitSource{})
assert.Nil(t, got.Authentication)
}
@@ -49,7 +49,7 @@ func createGitStack(t *testing.T, tx dataservices.DataStoreTx, stack *portainer.
t.Helper()
if stack.GitConfig != nil {
src := &portainer.Source{Git: stack.GitConfig, Type: portainer.SourceTypeGit}
src := &portainer.Source{Git: &gittypes.GitSource{URL: stack.GitConfig.URL, Authentication: stack.GitConfig.Authentication, TLSSkipVerify: stack.GitConfig.TLSSkipVerify}, Type: portainer.SourceTypeGit}
require.NoError(t, tx.Source().Create(source.InsecureNewAdminContext(), src))
wf := &portainer.Workflow{Artifacts: []portainer.Artifact{{
+2 -3
View File
@@ -41,9 +41,8 @@ func TestStackFile_GitPendingRedeploy_Returns409(t *testing.T) {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
URL: "https://github.com/portainer/portainer.git",
ConfigFilePath: "docker-compose.yml",
Git: &gittypes.GitSource{
URL: "https://github.com/portainer/portainer.git",
},
}
require.NoError(t, store.Source().Create(source.InsecureNewAdminContext(), src))
@@ -39,7 +39,7 @@ func TestStackUpdateGitWebhookUniqueness(t *testing.T) {
sharedSrc := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{URL: "https://github.com/portainer/portainer.git"},
Git: &gittypes.GitSource{URL: "https://github.com/portainer/portainer.git"},
}
err = store.Source().Create(source.InsecureNewAdminContext(), sharedSrc)
require.NoError(t, err)
+7 -7
View File
@@ -1321,13 +1321,13 @@ type (
// Source represents a GitOps source that can be referenced by stacks or deployments.
Source struct {
ID SourceID `json:"id" example:"1"`
Name string `json:"name" example:"my-source"`
LastSync int64 `json:"lastSync,omitempty" example:"1587399600"`
Type SourceType `json:"type" example:"1"`
Git *gittypes.RepoConfig `json:"git,omitempty"`
Registry *Registry `json:"registry,omitempty"`
Helm *HelmConfig `json:"helm,omitempty"`
ID SourceID `json:"id" example:"1"`
Name string `json:"name" example:"my-source"`
LastSync int64 `json:"lastSync,omitempty" example:"1587399600"`
Type SourceType `json:"type" example:"1"`
Git *gittypes.GitSource `json:"git,omitempty"`
Registry *Registry `json:"registry,omitempty"`
Helm *HelmConfig `json:"helm,omitempty"`
Public bool `json:"public"`
AdministratorsOnly bool `json:"administratorsOnly"`
+6 -12
View File
@@ -203,10 +203,8 @@ func Test_redeployWhenChanged_DoesNothingWhenNoGitChanges(t *testing.T) {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
URL: "url",
ReferenceName: "ref",
ConfigHash: "oldHash",
Git: &gittypes.GitSource{
URL: "url",
},
}
err = store.Source().Create(adminUserContext, src)
@@ -250,10 +248,8 @@ func Test_redeployWhenChanged_FailsWhenCannotClone(t *testing.T) {
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
URL: "url",
ReferenceName: "ref",
ConfigHash: "oldHash",
Git: &gittypes.GitSource{
URL: "url",
},
}
err = store.Source().Create(adminUserContext, src)
@@ -293,10 +289,8 @@ func setupRedeployStore(t *testing.T, stackType portainer.StackType) (dataservic
src := &portainer.Source{
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
URL: "url",
ReferenceName: "ref",
ConfigHash: "oldHash",
Git: &gittypes.GitSource{
URL: "url",
},
}
err = store.Source().Create(adminUserContext, src)
@@ -127,7 +127,11 @@ func (b *GitMethodStackBuilder) prepare(ctx context.Context, payload *StackPaylo
src, err := workflows.FindOrCreateGitSource(tx, userContext, &portainer.Source{
Name: gittypes.RepoName(repoConfig.URL),
Type: portainer.SourceTypeGit,
Git: &repoConfig,
Git: &gittypes.GitSource{
URL: repoConfig.URL,
Authentication: repoConfig.Authentication,
TLSSkipVerify: repoConfig.TLSSkipVerify,
},
})
if err != nil {
return fmt.Errorf("failed to find or create source: %w", err)
@@ -47,7 +47,7 @@ func TestGitMethodStackBuilder_WithSourceID_ReferencesExistingSource(t *testing.
src := &portainer.Source{
Name: "my-repo",
Type: portainer.SourceTypeGit,
Git: &gittypes.RepoConfig{
Git: &gittypes.GitSource{
URL: "https://github.com/org/private-repo",
Authentication: &gittypes.GitAuthentication{
Username: "git-user",