Skip to content
Open
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
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

Generate code from launch YML

1. [Running](#running)
2. [Migrating to use in a Golang repo](#migrating-to-use-in-a-golang-repo)
3. [Dependency overrides](#dependency-overrides)

```sh
$ launch-gen --help
Usage of ./bin/launch-gen:
-d string
Dependency name to override. You can provide multiple dependencies in the format dep1:replacementDep1,dep2:replacementDep2,...
-o string
optional output to file. Default is stdout
-p string
optional package name (default "main")
-skip-dependency value
Dependency to skip generating wag clients. Can be added mulitple times e.g. -skip-dependency a -skip-dependency b
```

## Running

Build it
Expand Down Expand Up @@ -74,3 +91,44 @@ generate:
6. Run `make generate`. `launch.go` should be within the specified directory.

7. Call `InitLaunchConfig()` during startup of your program, and use it when needed.

## Dependencies

By default, each dependency listed in `dependencies` will generate the following in `launch.go`:

1. An import of the service's client package – see below
2. The addition of a struct member for the service's `Client` type in the `Dependencies` struct
3. Constructing the client via discovery in `InitLaunchConfig()`
4. Returning the constructed client in the `LaunchConfig`

By default, `launch-gen` will map a service name specified in `dependencies` to a package of the form `github.com/Clever/[SERVICE_NAME]/gen-go/client`, matching the client package generated by WAG. For example, a dependency on `my-service` generates an import of package `github.com/Clever/my-service/gen-go/client`. You can customize the generated package name using the features documented below.

### Versions

If your service's module name and correspondingly its package names include the major version in the format `v2`, `v3`, and so on, you can specify the dependency in the format `my-service@vN`, where `my-service` is the service name and `N` is a whole number representing the major version.

This mapping assumes that the major version `vN` is appended to the default package name as a suffix:

```
my-service@v2 -> github.com/Clever/my-service/gen-go/client/v2
```

This mapping matches the convention used by WAG for services with a major version greater than 1. If your service dependency uses a different format, continue reading to [`Overrides`](#overrides) for greater control over the package name.

### Overrides

You can optionally override the package name for a service client dependency with the `-d` arg. Specifying `-d` will change the import statement in the generated `launch.go`. Originally, this option was also used to support services with a major version specified in the package and module names; this use case is now supported directly with the [Versions](#versions) syntax, although you can still achieve the same output with `-d`.

Dependency mappings are defined as a colon-separated pair of strings, as in `configuredDependency:replacementDependency`. You can specify multiple overrides with a comma-separated string of these mappings: `dependency1:replacementDependency1,dependency2:replacementDependency2`.

Since `launch.go` depends on the `client` package within each module, `launch-gen` appends a `/gen-go/client` suffix to the module name to specific the service's client package. If you override the dependency, you **must** specify the whole package path yourself; `launch-gen` will not automatically insert the `/gen-go/client` path anywhere in the override package name, since it cannot assume any particular format.

```sh
$ launch-gen -d "servica-a:service-a/gen-go/client/v4,service-b:api-b-client/special/unique/client"
# service-a -> github.com/Clever/service-a/gen-go/client/v4
# service-b -> github.com/Clever/api-b-client/special/unique/client
```

### Skipping

If you don't want to generate the package client at all, you can prevent that behavior by specifying `-skip-dependency SERVICE_NAME`. This argument can be specified multiple times.
118 changes: 118 additions & 0 deletions dependencies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"fmt"
"log"
"regexp"
"strings"

. "github.com/dave/jennifer/jen"
)

type ServiceDependency struct {
name string
version string
override string
}

func parseOverrideDependencies(overrideDependenciesString *string, dependencies []string) map[string]string {

// parsing through the list of overrides to make an original:new string map

overrideDependenciesMap := make(map[string]string)

if overrideDependenciesString == nil || *overrideDependenciesString == "" {
return overrideDependenciesMap
}

overrideDependenciesList := strings.Split(*overrideDependenciesString, ",")
for _, overrideRule := range overrideDependenciesList {
depReplacementArr := strings.Split(overrideRule, ":")

if len(depReplacementArr) != 2 || depReplacementArr[1] == "" {
log.Fatal("usage: invalid formatting for the -d flag")
}

flag := 0
for _, d := range dependencies {
if d == depReplacementArr[0] {
flag = 1
break
}
}

if flag == 0 {
log.Fatal(depReplacementArr[0], " is not a dependency specified in the provided yaml file")
}

overrideDependenciesMap[depReplacementArr[0]] = depReplacementArr[1]
}

return overrideDependenciesMap
}

func parseDependencies(
launchConfig *LaunchYML,
skipDependencies flagsSet,
overridesMap map[string]string,
) []ServiceDependency {
versionedModuleRegex := regexp.MustCompile("(?i)^([a-z][a-z0-9-_]+)@(v[0-9]+)$")
parsed := []ServiceDependency{}
for _, d := range launchConfig.Dependencies {
// skip
if _, ok := skipDependencies[d]; ok {
continue
}

// check for override
overridePath, hasOverride := overridesMap[d]
if hasOverride {
parsed = append(parsed, ServiceDependency{name: d, override: overridePath})
continue
}

// check for configured version
submatches := versionedModuleRegex.FindStringSubmatch(d)
if len(submatches) == 3 {
parsed = append(parsed, ServiceDependency{name: submatches[1], version: submatches[2]})
continue
}

// default: just the name
parsed = append(parsed, ServiceDependency{name: d})
}

return parsed
}

func (d ServiceDependency) packageName() string {
// with wagv9 onwards /gen-go/client is after the service name in the package path
importPackage := fmt.Sprintf("%s/gen-go/client", d.name)
if d.override != "" {
importPackage = d.override
} else if d.version != "" {
importPackage = fmt.Sprintf("%s/%s", importPackage, d.version)
}

return fmt.Sprintf("github.com/Clever/%s", importPackage)
}

func mapDependenciesToCode(dependencies []ServiceDependency) []Code {
imports := []Code{}
for _, d := range dependencies {
identifier := Id(strings.Title(toPublicVar(d.name)))

// // with wagv9 onwards /gen-go/client is after the service name in the package path
// importPackage := fmt.Sprintf("%s/gen-go/client", d.name)
// if d.override != "" {
// importPackage = d.override
// } else if d.version != "" {
// importPackage = fmt.Sprintf("%s/%s", importPackage, d.version)
// }

statement := identifier.Qual(d.packageName(), "Client")
imports = append(imports, statement)
}

return imports
}
38 changes: 38 additions & 0 deletions dependencies_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestParseDependencies(t *testing.T) {
fakeConfig := &LaunchYML{
Dependencies: []string{
"service-a",
"service-b",
"service-c@v4",
"service-d",
},
}

skip := flagsSet{}
skip.Set("service-b")
result := parseDependencies(fakeConfig, skip, map[string]string{
"service-d": "service-d/custom/package/path",
})

assert.Equal(t, []ServiceDependency{
{
name: "service-a",
},
{
name: "service-c",
version: "v4",
},
{
name: "service-d",
override: "service-d/custom/package/path",
},
}, result)
}
7 changes: 7 additions & 0 deletions fixtures/launch1.expected
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package packagename

import (
client1 "github.com/Clever/dapple/gen-go/client"
v2 "github.com/Clever/il-config-service/gen-go/client/v2"
v9 "github.com/Clever/wag/clientconfig/v9"
client "github.com/Clever/workflow-manager/gen-go/client"
trace "go.opentelemetry.io/otel/sdk/trace"
Expand All @@ -23,6 +24,7 @@ type LaunchConfig struct {
type Dependencies struct {
WorkflowManager client.Client
Dapple client1.Client
IlConfigService v2.Client
}

// Environment has environment variables and their values
Expand Down Expand Up @@ -55,6 +57,10 @@ func InitLaunchConfig(exp *trace.SpanExporter) LaunchConfig {
if err != nil {
log.Fatalf("discovery error: %s", err)
}
ilConfigService, err := v2.NewFromDiscovery(v9.WithTracing("il-config-service", exporter))
if err != nil {
log.Fatalf("discovery error: %s", err)
}
return LaunchConfig{
AwsResources: AwsResources{
S3ReadAndWriteMe: getS3NameByEnv("read-and-write-me"),
Expand All @@ -63,6 +69,7 @@ func InitLaunchConfig(exp *trace.SpanExporter) LaunchConfig {
},
Deps: Dependencies{
Dapple: dapple,
IlConfigService: ilConfigService,
WorkflowManager: workflowManager,
},
Env: Environment{
Expand Down
1 change: 1 addition & 0 deletions fixtures/launch1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ dependencies:
- workflow-manager
- dapple
- dependency-to-skip
- il-config-service@v2
aws:
s3:
read:
Expand Down
7 changes: 7 additions & 0 deletions fixtures/launch2.expected
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package packagename

import (
v5 "github.com/Clever/dapple/gen-go/client/v5"
v2 "github.com/Clever/il-config-service/gen-go/client/v2"
v9 "github.com/Clever/wag/clientconfig/v9"
client "github.com/Clever/workflow-manager/gen-go/client"
trace "go.opentelemetry.io/otel/sdk/trace"
Expand All @@ -23,6 +24,7 @@ type LaunchConfig struct {
type Dependencies struct {
WorkflowManager client.Client
Dapple v5.Client
IlConfigService v2.Client
}

// Environment has environment variables and their values
Expand Down Expand Up @@ -55,6 +57,10 @@ func InitLaunchConfig(exp *trace.SpanExporter) LaunchConfig {
if err != nil {
log.Fatalf("discovery error: %s", err)
}
ilConfigService, err := v2.NewFromDiscovery(v9.WithTracing("il-config-service", exporter))
if err != nil {
log.Fatalf("discovery error: %s", err)
}
return LaunchConfig{
AwsResources: AwsResources{
S3ReadAndWriteMe: getS3NameByEnv("read-and-write-me"),
Expand All @@ -63,6 +69,7 @@ func InitLaunchConfig(exp *trace.SpanExporter) LaunchConfig {
},
Deps: Dependencies{
Dapple: dapple,
IlConfigService: ilConfigService,
WorkflowManager: workflowManager,
},
Env: Environment{
Expand Down
1 change: 1 addition & 0 deletions fixtures/launch2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ dependencies:
- workflow-manager
- dapple
- dependency-to-skip
- il-config-service@v2
aws:
s3:
read:
Expand Down
Loading