diff --git a/workflow/workflow.go b/workflow/workflow.go index 11e5791..108e54e 100644 --- a/workflow/workflow.go +++ b/workflow/workflow.go @@ -169,7 +169,7 @@ func (w Workflow) migrate(telemetryDisabled bool) Workflow { } codeSamplesRegistry := &SourceRegistry{ - Location: codeSamplesRegistryLocation(source.Registry.Location), + Location: codeSamplesRegistryLocation(target.Target, source.Registry.Location), } if target.CodeSamples == nil { @@ -179,9 +179,11 @@ func (w Workflow) migrate(telemetryDisabled bool) Workflow { } } else if target.CodeSamples.Registry == nil { target.CodeSamples.Registry = codeSamplesRegistry - } else { - // Fix the registry location if it needs fixing - target.CodeSamples.Registry.Location = codeSamplesRegistryUpdatedLocation(w, target.CodeSamples) + } else if target.CodeSamples.Blocking != nil && !*target.CodeSamples.Blocking { + // Fix the registry location if it needs fixing. + // We only do this when the target is not blocking because that means we likely set it up automatically. + // We don't want to migrate a registry location that the user set up manually. + target.CodeSamples.Registry.Location = codeSamplesRegistryUpdatedLocation(target) } w.Targets[targetID] = target @@ -191,9 +193,11 @@ func (w Workflow) migrate(telemetryDisabled bool) Workflow { return w } -// For a brief time we were not properly adding -code-samples to the namespace and so we created some duplicated registry locations -// This function checks if the registry location is a duplicate and if so, updates it to include -code-samples -func codeSamplesRegistryUpdatedLocation(wf Workflow, codeSamples *CodeSamples) SourceRegistryLocation { +// This function cleans up any issues with the codeSamples registry location. +// It trims tags/revisions, removes duplicate "-code-samples" suffixes, and adds the target type to the namespace if it's missing +func codeSamplesRegistryUpdatedLocation(target Target) SourceRegistryLocation { + codeSamples := target.CodeSamples + if codeSamples.Registry == nil { return "" } @@ -203,27 +207,9 @@ func codeSamplesRegistryUpdatedLocation(wf Workflow, codeSamples *CodeSamples) S return "" } - // Registry namespaces should be unique - var namespaces []string - for _, source := range wf.Sources { - if source.Registry != nil { - namespaces = append(namespaces, getNamespace(source.Registry.Location)) - } - } - - for _, target := range wf.Targets { - if target.CodeSamples != nil && target.CodeSamples != codeSamples && target.CodeSamples.Registry != nil { - namespaces = append(namespaces, getNamespace(target.CodeSamples.Registry.Location)) - } - } - - // For a brief time we were not properly adding -code-samples to the namespace and so we created some duplicated registry locations - if slices.Contains(namespaces, namespace) { - namespace += "-code-samples" - } + namespace = codeSamplesNamespace(namespace, target.Target) - // Even if the namespace was already unique, we still want to return this because it also trims any tags/revisions, - // which should not be present in an output registry location + // Trims any tags/revisions, which should not be present in an output registry location return makeRegistryLocation(namespace) } @@ -234,12 +220,26 @@ func getNamespace(location SourceRegistryLocation) string { return "" } -func codeSamplesRegistryLocation(sourceRegistryURL SourceRegistryLocation) SourceRegistryLocation { +func codeSamplesRegistryLocation(target string, sourceRegistryURL SourceRegistryLocation) SourceRegistryLocation { registryDocument := ParseSpeakeasyRegistryReference(string(sourceRegistryURL)) - newNamespace := registryDocument.NamespaceID + "-code-samples" + newNamespace := codeSamplesNamespace(registryDocument.NamespaceID, target) return makeRegistryLocation(newNamespace) } +func codeSamplesNamespace(namespace, target string) string { + // There was a bug where we were adding the -code-samples suffix repeatedly to the namespace if there was more than one target + for strings.HasSuffix(namespace, "-code-samples") { + namespace = strings.TrimSuffix(namespace, "-code-samples") + } + + // Some people have their sources named things like "java-OAS" + if strings.Contains(namespace, target) { + return fmt.Sprintf("%s-code-samples", namespace) + } else { + return fmt.Sprintf("%s-%s-code-samples", namespace, target) + } +} + func makeRegistryLocation(namespace string) SourceRegistryLocation { return SourceRegistryLocation(path.Join(baseRegistryURL, namespace)) } diff --git a/workflow/workflow_test.go b/workflow/workflow_test.go index 3339d08..33ff5e7 100644 --- a/workflow/workflow_test.go +++ b/workflow/workflow_test.go @@ -301,9 +301,11 @@ func TestWorkflow_Validate(t *testing.T) { func TestMigrate_Success(t *testing.T) { tests := []struct { + name string in string expected string }{{ + name: "migrates a simple workflow", in: `workflowVersion: 1.0.0 sources: testSource: @@ -330,10 +332,44 @@ targets: source: testSource codeSamples: registry: - location: registry.speakeasyapi.dev/org/workspace/testSource-code-samples + location: registry.speakeasyapi.dev/org/workspace/testSource-typescript-code-samples blocking: false `, }, { + name: "doesn't migrate a blocking workflow with a registry location", + in: `workflowVersion: 1.0.0 +sources: + testSource: + inputs: + - location: ./openapi.yaml + registry: + location: registry.speakeasyapi.dev/org/workspace/testSource +targets: + typescript: + target: typescript + source: testSource + codeSamples: + registry: + location: registry.speakeasyapi.dev/org/workspace/testSource-custom-code-samples +`, + expected: `workflowVersion: 1.0.0 +speakeasyVersion: latest +sources: + testSource: + inputs: + - location: ./openapi.yaml + registry: + location: registry.speakeasyapi.dev/org/workspace/testSource +targets: + typescript: + target: typescript + source: testSource + codeSamples: + registry: + location: registry.speakeasyapi.dev/org/workspace/testSource-custom-code-samples +`, + }, { + name: "migrates a workflow with a tagged registry location", in: `workflowVersion: 1.0.0 sources: testSource: @@ -360,10 +396,11 @@ targets: source: testSource codeSamples: registry: - location: registry.speakeasyapi.dev/org/workspace/testSource-code-samples + location: registry.speakeasyapi.dev/org/workspace/testSource-typescript-code-samples blocking: false `, }, { + name: "migrates a workflow with a duplicate registry location", in: `workflowVersion: 1.0.0 sources: testSource: @@ -394,12 +431,13 @@ targets: source: testSource codeSamples: registry: - location: registry.speakeasyapi.dev/org/workspace/testSource-code-samples + location: registry.speakeasyapi.dev/org/workspace/testSource-typescript-code-samples blocking: false `}, { + name: "migrates a workflow with a code samples output and a source with a name that contains the target", in: `workflowVersion: 1.0.0 sources: - testSource: + testSource-typescript: inputs: - location: ./openapi.yaml registry: @@ -407,14 +445,14 @@ sources: targets: typescript: target: typescript - source: testSource + source: testSource-typescript codeSamples: output: output.yaml `, expected: `workflowVersion: 1.0.0 speakeasyVersion: latest sources: - testSource: + testSource-typescript: inputs: - location: ./openapi.yaml registry: @@ -422,24 +460,95 @@ sources: targets: typescript: target: typescript - source: testSource + source: testSource-typescript codeSamples: output: output.yaml registry: - location: registry.speakeasyapi.dev/org/workspace/testSource-code-samples + location: registry.speakeasyapi.dev/org/workspace/testSource-typescript-code-samples +`, + }, { + name: "migrates a workflow with multiple targets, some with multiple -code-samples suffixes", + in: `workflowVersion: 1.0.0 +speakeasyVersion: latest +sources: + Acuvity-OAS: + inputs: + - location: ./apex-openapi.yaml + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas +targets: + golang: + target: go + source: Acuvity-OAS + output: acuvity-go + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-code-samples + blocking: false + python: + target: python + source: Acuvity-OAS + output: acuvity-python + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-code-samples-code-samples + blocking: false + typescript: + target: typescript + source: Acuvity-OAS + output: acuvity-ts + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-code-samples-code-samples + blocking: false`, + expected: `workflowVersion: 1.0.0 +speakeasyVersion: latest +sources: + Acuvity-OAS: + inputs: + - location: ./apex-openapi.yaml + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas +targets: + golang: + target: go + source: Acuvity-OAS + output: acuvity-go + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-go-code-samples + blocking: false + python: + target: python + source: Acuvity-OAS + output: acuvity-python + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-python-code-samples + blocking: false + typescript: + target: typescript + source: Acuvity-OAS + output: acuvity-ts + codeSamples: + registry: + location: registry.speakeasyapi.dev/acuvity-9dx/acuvity/acuvity-oas-typescript-code-samples + blocking: false `, }} for _, tt := range tests { - var workflow workflow.Workflow - require.NoError(t, yaml.Unmarshal([]byte(tt.in), &workflow)) + t.Run(tt.name, func(t *testing.T) { + var workflow workflow.Workflow + require.NoError(t, yaml.Unmarshal([]byte(tt.in), &workflow)) - workflow = workflow.Migrate() + workflow = workflow.Migrate() - actual, err := yaml.Marshal(workflow) - require.NoError(t, err) + actual, err := yaml.Marshal(workflow) + require.NoError(t, err) - assert.Equal(t, tt.expected, string(actual)) + assert.Equal(t, tt.expected, string(actual)) + }) } }