Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .jfrog-pipelines/pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pipelines:
description: "Forward Artifactory logs from the deployed ephemeral environment to Kibana (via Coralogix). Maps to the LOGS_TO_KIBANA parameter of the environment_setup_gen2 Jenkins job. Set 'false' to disable."
allowCustom: true
DEPLOYMENT_SIZING:
default: "large"
default: "common"
description: "Artifactory deployment sizing profile."
allowCustom: true
MAX_RUN_RETRIES:
Expand Down
62 changes: 31 additions & 31 deletions lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func TestReleaseBundleCreationFromMultipleBuildsAndBundlesUsingCommandFlags(t *t
func TestReleaseBundleCreationFromMultiBundlesUsingCommandFlagWithProject(t *testing.T) {
cleanCallback := initLifecycleTest(t, minMultiSourcesArtifactoryVersion)
defer cleanCallback()
deleteProject := createTestProject(t)
deleteProject := createTestProject(t, tests.ProjectKey2)
if deleteProject != nil {
defer func() {
if err := deleteProject(); err != nil {
Expand All @@ -169,32 +169,32 @@ func TestReleaseBundleCreationFromMultiBundlesUsingCommandFlagWithProject(t *tes
defer deleteBuilds()

// Create first release bundle from builds with project
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey2, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey2)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey2)

// Verify first release bundle exists with project
isExist, err := lcManager.IsReleaseBundleExist(tests.LcRbName1, number1, tests.ProjectKey)
isExist, err := lcManager.IsReleaseBundleExist(tests.LcRbName1, number1, tests.ProjectKey2)
assert.NoError(t, err)
assert.True(t, isExist, "Release bundle %s/%s should exist in project %s", tests.LcRbName1, number1, tests.ProjectKey)
assert.True(t, isExist, "Release bundle %s/%s should exist in project %s", tests.LcRbName1, number1, tests.ProjectKey2)

// Create second release bundle from builds with project
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, tests.ProjectKey, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName2, number2, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName2, number2, "", tests.ProjectKey)
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, tests.ProjectKey2, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName2, number2, tests.ProjectKey2)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName2, number2, "", tests.ProjectKey2)

// Verify second release bundle exists with project
isExist, err = lcManager.IsReleaseBundleExist(tests.LcRbName2, number2, tests.ProjectKey)
isExist, err = lcManager.IsReleaseBundleExist(tests.LcRbName2, number2, tests.ProjectKey2)
assert.NoError(t, err)
assert.True(t, isExist, "Release bundle %s/%s should exist in project %s", tests.LcRbName2, number2, tests.ProjectKey)
assert.True(t, isExist, "Release bundle %s/%s should exist in project %s", tests.LcRbName2, number2, tests.ProjectKey2)

// Wait a bit to ensure release bundles are fully indexed before using them as sources
time.Sleep(5 * time.Second)

// Create release bundle from the two previous release bundles with project
createRbFromMultiSourcesUsingCommandFlagsWithProject(t, lcManager, "", createReleaseBundlesSource(), tests.LcRbName3, number3, tests.ProjectKey, true)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName3, number3, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName3, number3, "", tests.ProjectKey)
createRbFromMultiSourcesUsingCommandFlagsWithProject(t, lcManager, "", createReleaseBundlesSource(), tests.LcRbName3, number3, tests.ProjectKey2, true)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName3, number3, tests.ProjectKey2)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName3, number3, "", tests.ProjectKey2)
}

func TestReleaseBundleCreationFromMultipleSourcesUsingSpec(t *testing.T) {
Expand Down Expand Up @@ -667,9 +667,9 @@ func uploadBuilds(t *testing.T) func() {
}

func uploadBuildsWithProject(t *testing.T) func() {
uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecA, tests.LcBuildName1, number1, tests.ProjectKey)
uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecB, tests.LcBuildName2, number2, tests.ProjectKey)
uploadBuildWithDepsAndProject(t, tests.LcBuildName3, number3, tests.ProjectKey)
uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecA, tests.LcBuildName1, number1, tests.ProjectKey2)
uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecB, tests.LcBuildName2, number2, tests.ProjectKey2)
uploadBuildWithDepsAndProject(t, tests.LcBuildName3, number3, tests.ProjectKey2)
return func() {
inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName1, artHttpDetails)
inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName2, artHttpDetails)
Expand Down Expand Up @@ -716,7 +716,7 @@ func TestCreateBundleWithoutSpec(t *testing.T) {
func TestCreateBundleWithoutSpecAndWithProject(t *testing.T) {
cleanCallback := initLifecycleTest(t, signingKeyOptionalArtifactoryMinVersion)
defer cleanCallback()
deleteProject := createTestProject(t)
deleteProject := createTestProject(t, tests.ProjectKey2)
if deleteProject != nil {
defer func() {
if err := deleteProject(); err != nil {
Expand All @@ -728,9 +728,9 @@ func TestCreateBundleWithoutSpecAndWithProject(t *testing.T) {
deleteBuilds := uploadBuildsWithProject(t)
defer deleteBuilds()

createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, false, false, false)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey2, false, false, false)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey2)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey2)
}

func createRbWithFlags(t *testing.T, specFilePath, sourceOption, buildName, buildNumber, rbName, rbVersion, project string,
Expand Down Expand Up @@ -1416,7 +1416,7 @@ func TestReleaseBundlesSearchVersions(t *testing.T) {
projectVersionB := "1.0.1"

// Setup: Create test project and upload builds with project
deleteProject := createTestProject(t)
deleteProject := createTestProject(t, tests.ProjectKey2)
if deleteProject != nil {
defer func() {
if err := deleteProject(); err != nil {
Expand All @@ -1430,13 +1430,13 @@ func TestReleaseBundlesSearchVersions(t *testing.T) {

// Delete existing release bundle versions with project
for _, version := range []string{projectVersionA, projectVersionB} {
isExist, err := lcManager.IsReleaseBundleExist(projectRbName, version, tests.ProjectKey)
isExist, err := lcManager.IsReleaseBundleExist(projectRbName, version, tests.ProjectKey2)
if err == nil && isExist {
rbDetails := services.ReleaseBundleDetails{
ReleaseBundleName: projectRbName,
ReleaseBundleVersion: version,
}
err := lcManager.DeleteReleaseBundleVersion(rbDetails, services.CommonOptionalQueryParams{Async: false, ProjectKey: tests.ProjectKey})
err := lcManager.DeleteReleaseBundleVersion(rbDetails, services.CommonOptionalQueryParams{Async: false, ProjectKey: tests.ProjectKey2})
if err != nil {
if !strings.Contains(err.Error(), "404") && !strings.Contains(err.Error(), "not found") {
t.Logf("Warning: Failed to delete release bundle %s/%s: %v", projectRbName, version, err)
Expand All @@ -1448,15 +1448,15 @@ func TestReleaseBundlesSearchVersions(t *testing.T) {
}

// Create release bundles with project
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, projectRbName, projectVersionA, tests.ProjectKey, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionA, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionA, "", tests.ProjectKey)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, projectRbName, projectVersionA, tests.ProjectKey2, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionA, tests.ProjectKey2)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionA, "", tests.ProjectKey2)

time.Sleep(1 * time.Second)

createRbWithFlags(t, "", "", tests.LcBuildName2, number2, projectRbName, projectVersionB, tests.ProjectKey, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionB, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionB, "", tests.ProjectKey)
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, projectRbName, projectVersionB, tests.ProjectKey2, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionB, tests.ProjectKey2)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionB, "", tests.ProjectKey2)

log.Info("Created two versions for release bundle '%s' with project for search testing.", projectRbName)
time.Sleep(3 * time.Second)
Expand All @@ -1474,7 +1474,7 @@ func TestReleaseBundlesSearchVersions(t *testing.T) {
name: "Search with project",
releaseBundleName: projectRbName,
queryParams: services.GetSearchOptionalQueryParams{
Project: tests.ProjectKey,
Project: tests.ProjectKey2,
},
expectedRbVersions: []string{projectVersionA, projectVersionB},
expectedTotal: 2,
Expand Down
12 changes: 6 additions & 6 deletions transfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ func TestTransferConfigMerge(t *testing.T) {
// The module type only exist in Artifactory 7
if projectsSupported {
// Create project on Source server
deleteProject := createTestProject(t)
deleteProject := createTestProject(t, tests.ProjectKey)
if deleteProject != nil {
defer func() {
assert.NoError(t, deleteProject())
Expand Down Expand Up @@ -537,11 +537,11 @@ func validateCsvConflicts(t *testing.T, csvPath string, projectsSupported bool)
}
}

func createTestProject(t *testing.T) func() error {
func createTestProject(t *testing.T, projectKey string) func() error {
accessManager, err := rtUtils.CreateAccessServiceManager(serverDetails, false)
assert.NoError(t, err)
// Delete the project if already exists
deleteProjectIfExists(t, accessManager, tests.ProjectKey)
deleteProjectIfExists(t, accessManager, projectKey)

// Create new project
adminPrivileges := accessServices.AdminPrivileges{
Expand All @@ -550,17 +550,17 @@ func createTestProject(t *testing.T) func() error {
IndexResources: utils.Pointer(false),
}
projectDetails := accessServices.Project{
DisplayName: tests.ProjectKey + "MyProject",
DisplayName: projectKey + "MyProject",
Description: "My Test Project",
AdminPrivileges: &adminPrivileges,
SoftLimit: utils.Pointer(false),
StorageQuotaBytes: 1073741825,
ProjectKey: tests.ProjectKey,
ProjectKey: projectKey,
}

if assert.NoError(t, accessManager.CreateProject(accessServices.ProjectParams{ProjectDetails: projectDetails})) {
return func() error {
return accessManager.DeleteProject(tests.ProjectKey)
return accessManager.DeleteProject(projectKey)
}
}
return nil
Expand Down
5 changes: 3 additions & 2 deletions utils/tests/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,9 @@ var (
Password1 = "A12356789z"
UserName2 = "bob"
// jfrog-ignore - not a real password
Password2 = "1B234578y9"
ProjectKey = "prj"
Password2 = "1B234578y9"
ProjectKey = "prj"
ProjectKey2 = "prjlc"
)

func GetTxtUploadExpectedRepo1() []string {
Expand Down
55 changes: 51 additions & 4 deletions utils/tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,28 @@ var (
timestampAdded bool
)

// nonProjectKeyCharsRegex matches any character that isn't allowed in an Artifactory
// project key (project keys allow only lowercase alphanumeric characters and hyphens).
// We use this to sanitize the --ci.runId value before splicing it into resource names
// whose format is constrained (project keys, GPG keypair names, etc.). Project-key
// charset is a strict subset of the GPG keypair charset, so a single sanitization is
// safe for both.
var nonProjectKeyCharsRegex = regexp.MustCompile(`[^a-z0-9-]+`)

// SanitizedCiRunId returns the --ci.runId flag value lowercased with any characters
// outside [a-z0-9-] collapsed to a single hyphen and surrounding hyphens trimmed.
// Returns "" if the flag wasn't set. Callers that need a per-runId suffix on
// resources whose name format is constrained (e.g. Artifactory project keys, GPG
// keypair names) should use this so concurrent runs against a shared JPD don't
// clobber each other.
func SanitizedCiRunId() string {
if ciRunId == nil || *ciRunId == "" {
return ""
}
sanitized := nonProjectKeyCharsRegex.ReplaceAllString(strings.ToLower(*ciRunId), "-")
return strings.Trim(sanitized, "-")
}

func init() {
JfrogUrl = flag.String("jfrog.url", "http://localhost:8081/", "JFrog platform url")
JfrogUser = flag.String("jfrog.user", "admin", "JFrog platform username")
Expand All @@ -114,8 +136,8 @@ func init() {
TestPip = flag.Bool("test.pip", false, "Test Pip")
TestPipenv = flag.Bool("test.pipenv", false, "Test Pipenv")
TestPoetry = flag.Bool("test.poetry", false, "Test Poetry")
TestUv = flag.Bool("test.uv", false, "Test UV")
TestNix = flag.Bool("test.nix", false, "Test Nix")
TestUv = flag.Bool("test.uv", false, "Test UV")
TestNix = flag.Bool("test.nix", false, "Test Nix")
TestConan = flag.Bool("test.conan", false, "Test Conan")
TestHelm = flag.Bool("test.helm", false, "Test Helm")
TestHuggingFace = flag.Bool("test.huggingface", false, "Test HuggingFace")
Expand Down Expand Up @@ -645,12 +667,37 @@ func AddTimestampToGlobalVars() {
Password1 += uniqueSuffix + strconv.FormatFloat(randomSequence.Float64(), 'f', 2, 32)
Password2 += uniqueSuffix + strconv.FormatFloat(randomSequence.Float64(), 'f', 2, 32)

// Projects
ProjectKey += timestamp[len(timestamp)-7:]
// Projects. The artifactory and lifecycle suites use distinct base keys
// (ProjectKey vs LcProjectKey) so neither can delete the other's project
// when run concurrently against a shared JPD.
ProjectKey = appendProjectKeySuffix(ProjectKey, timestamp)
ProjectKey2 = appendProjectKeySuffix(ProjectKey2, timestamp)

timestampAdded = true
}

// appendProjectKeySuffix appends a per-run suffix to an Artifactory project-key
// base. Project keys must be 2-32 chars, lowercase alphanumeric or hyphen, and
// start with a letter. We always include the sanitized --ci.runId (when set) so
// that concurrent runs against a shared JPD don't clobber each other's project —
// createTestProject calls deleteProjectIfExists(<key>) unconditionally, so a
// colliding key from another concurrent suite would silently delete the project
// (and every release bundle inside it) out from under us.
func appendProjectKeySuffix(base, timestamp string) string {
suffix := timestamp[len(timestamp)-7:]
if sanitizedRunId := SanitizedCiRunId(); sanitizedRunId != "" {
suffix = sanitizedRunId + "-" + suffix
}
// The total must be <= 32. Trim from the front so the trailing timestamp
// (used for visual debuggability) is preserved and we don't end up with a
// key that starts with a hyphen.
const maxProjectKeyLen = 32
if maxSuffixLen := maxProjectKeyLen - len(base); len(suffix) > maxSuffixLen {
suffix = strings.TrimLeft(suffix[len(suffix)-maxSuffixLen:], "-")
}
return base + suffix
}

// Replace all variables in the form of ${VARIABLE} in the input file, according to the substitution map (see getSubstitutionMap()).
// path - Path to the input file.
// destPath - Path to the output file. If empty, the output file will be under ${CWD}/tmp/.
Expand Down
Loading