From 8596601a7dc8b61c96cdc6da965f564d71192b86 Mon Sep 17 00:00:00 2001 From: "Christian G. Warden" Date: Fri, 6 Mar 2026 14:52:46 -0600 Subject: [PATCH] Add Dependency Support To package version create Add support for repeatable --dependency flags when creating a package version. - Add a repeatable StringArray --dependency flag to package version create. - Validate each dependency is a Subscriber Package Version ID (04t...). - Include dependencies in package2-descriptor.json when dependencies are provided, using subscriberPackageVersionId objects. --- command/package.go | 44 +++++++++++++++++++++++++++++--------- command/package_test.go | 47 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 11 deletions(-) diff --git a/command/package.go b/command/package.go index cf37ec3e..e61fd638 100644 --- a/command/package.go +++ b/command/package.go @@ -41,6 +41,7 @@ func init() { packageVersionCreateCmd.Flags().StringP("version-name", "m", "", "Version name (optional, defaults to version-number)") packageVersionCreateCmd.Flags().StringP("version-description", "d", "", "Version description (optional, defaults to version-number)") packageVersionCreateCmd.Flags().StringP("ancestor-id", "", "", "Ancestor version ID (optional)") + packageVersionCreateCmd.Flags().StringArrayP("dependency", "", []string{}, "Subscriber Package Version ID (04t) dependency (can be specified multiple times)") packageVersionCreateCmd.Flags().StringP("tag", "", "", "Tag to set on the Package2VersionCreateRequest") packageVersionCreateCmd.Flags().BoolP("skip-validation", "s", false, "Skip validation") packageVersionCreateCmd.Flags().BoolP("async-validation", "y", false, "Async validation") @@ -166,13 +167,14 @@ var packageVersionCreateCmd = &cobra.Command{ versionName, _ := cmd.Flags().GetString("version-name") versionDescription, _ := cmd.Flags().GetString("version-description") ancestorId, _ := cmd.Flags().GetString("ancestor-id") + dependencies, _ := cmd.Flags().GetStringArray("dependency") tag, _ := cmd.Flags().GetString("tag") skipValidation, _ := cmd.Flags().GetBool("skip-validation") asyncValidation, _ := cmd.Flags().GetBool("async-validation") codeCoverage, _ := cmd.Flags().GetBool("code-coverage") runCreatePackageVersion(path, packageId, namespace, versionNumber, versionName, - versionDescription, ancestorId, tag, skipValidation, asyncValidation, codeCoverage) + versionDescription, ancestorId, dependencies, tag, skipValidation, asyncValidation, codeCoverage) }, } @@ -570,7 +572,7 @@ func pollPackageUninstallStatus(requestId string) { } func runCreatePackageVersion(path string, packageId string, namespace string, versionNumber string, - versionName string, versionDescription string, ancestorId string, tag string, + versionName string, versionDescription string, ancestorId string, dependencies []string, tag string, skipValidation bool, asyncValidation bool, codeCoverage bool) { // Use version-number as default for version-name and version-description if not provided @@ -629,16 +631,15 @@ func runCreatePackageVersion(path string, packageId string, namespace string, ve } } - // Create package2-descriptor.json - descriptor := map[string]interface{}{ - "versionName": versionName, - "versionNumber": versionNumber, - "path": "salesforce", - "versionDescription": versionDescription, - "id": packageId, - "ancestorId": ancestorId, + for _, dependency := range dependencies { + if !strings.HasPrefix(dependency, "04t") { + ErrorAndExit(fmt.Sprintf("Invalid dependency ID: %s. Must be a Subscriber Package Version ID (04t)", dependency)) + } } + // Create package2-descriptor.json + descriptor := buildPackageVersionDescriptor(versionName, versionNumber, versionDescription, packageId, ancestorId, dependencies) + descriptorJson, err := json.Marshal(descriptor) if err != nil { ErrorAndExit("Failed to create descriptor JSON: " + err.Error()) @@ -822,6 +823,29 @@ func runCreatePackageVersion(path string, packageId string, namespace string, ve } } +func buildPackageVersionDescriptor(versionName string, versionNumber string, versionDescription string, packageId string, ancestorId string, dependencies []string) map[string]interface{} { + descriptor := map[string]interface{}{ + "versionName": versionName, + "versionNumber": versionNumber, + "path": "salesforce", + "versionDescription": versionDescription, + "id": packageId, + "ancestorId": ancestorId, + } + + if len(dependencies) > 0 { + descriptorDependencies := make([]map[string]string, 0, len(dependencies)) + for _, dependency := range dependencies { + descriptorDependencies = append(descriptorDependencies, map[string]string{ + "subscriberPackageVersionId": dependency, + }) + } + descriptor["dependencies"] = descriptorDependencies + } + + return descriptor +} + func pollPackageVersionStatus(requestId string) string { query := fmt.Sprintf("SELECT Id, Status, Package2VersionId FROM Package2VersionCreateRequest WHERE Id = '%s'", requestId) diff --git a/command/package_test.go b/command/package_test.go index d8e3c41d..22a46b39 100644 --- a/command/package_test.go +++ b/command/package_test.go @@ -1,6 +1,7 @@ package command import ( + "reflect" "testing" ) @@ -49,7 +50,7 @@ func Test_package_version_create_command_has_optional_flags(t *testing.T) { cmd := packageVersionCreateCmd // Test that optional flags exist - optionalFlags := []string{"version-name", "version-description", "ancestor-id", "skip-validation", "async-validation", "code-coverage"} + optionalFlags := []string{"version-name", "version-description", "ancestor-id", "dependency", "skip-validation", "async-validation", "code-coverage"} for _, flagName := range optionalFlags { flag := cmd.Flags().Lookup(flagName) @@ -59,6 +60,50 @@ func Test_package_version_create_command_has_optional_flags(t *testing.T) { } } +func Test_package_version_create_command_dependency_flag_is_repeatable(t *testing.T) { + cmd := packageVersionCreateCmd + + flag := cmd.Flags().Lookup("dependency") + if flag == nil { + t.Fatal("Flag dependency not found") + } + + if flag.Value.Type() != "stringArray" { + t.Errorf("Expected dependency flag type stringArray, got %s", flag.Value.Type()) + } +} + +func Test_buildPackageVersionDescriptor_includes_dependencies_when_provided(t *testing.T) { + dependencies := []string{"04tKA000000D34QYAS", "04tKA000000D34RYAS"} + descriptor := buildPackageVersionDescriptor("1.0.0.1", "1.0.0.1", "1.0.0.1", "0Ho000000000001", "05i000000000001", dependencies) + + rawDependencies, ok := descriptor["dependencies"] + if !ok { + t.Fatal("Expected dependencies to be present in descriptor") + } + + gotDependencies, ok := rawDependencies.([]map[string]string) + if !ok { + t.Fatalf("Expected dependencies to be []map[string]string, got %T", rawDependencies) + } + + wantDependencies := []map[string]string{ + {"subscriberPackageVersionId": "04tKA000000D34QYAS"}, + {"subscriberPackageVersionId": "04tKA000000D34RYAS"}, + } + if !reflect.DeepEqual(gotDependencies, wantDependencies) { + t.Errorf("Unexpected dependencies. got=%v want=%v", gotDependencies, wantDependencies) + } +} + +func Test_buildPackageVersionDescriptor_omits_dependencies_when_empty(t *testing.T) { + descriptor := buildPackageVersionDescriptor("1.0.0.1", "1.0.0.1", "1.0.0.1", "0Ho000000000001", "05i000000000001", []string{}) + + if _, ok := descriptor["dependencies"]; ok { + t.Error("Did not expect dependencies to be present in descriptor") + } +} + func Test_package_version_create_command_accepts_one_argument(t *testing.T) { cmd := packageVersionCreateCmd