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
4 changes: 2 additions & 2 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
go-version-file: "go.mod"
- name: Check Go formatting
run: |
unformatted=$(go fmt ./...)
Expand All @@ -48,4 +48,4 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.7.1
version: v2.12.2
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ help:
@echo " fmt - Format Go code"
@echo " ci - Run all CI checks locally (fmt, lint, test, verify-generate)"

# Tool versions
GOLANGCI_LINT_VERSION := v2.12.2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we configure Renovate to manage this version?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we switch to mise to manage our developer tools, then we would get the additional benefit of Renovate PRs without additional configuration, as Renovate has mise support.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mise is nice, but we need the GC and TC support for adoption. It would be a bad idea to start without that agreement.

Comment thread
erka marked this conversation as resolved.

# Build variables
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
Expand Down Expand Up @@ -105,7 +108,7 @@ lint:
@echo "Running golangci-lint..."
@if ! command -v golangci-lint &> /dev/null; then \
echo "Installing golangci-lint..."; \
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.1; \
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION); \
fi
@golangci-lint run
@echo "Linting completed successfully!"
Expand All @@ -115,7 +118,7 @@ lint-fix:
@echo "Running golangci-lint with auto-fix..."
@if ! command -v golangci-lint &> /dev/null; then \
echo "Installing golangci-lint..."; \
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.1; \
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION); \
fi
@golangci-lint run --fix
@echo "Linting with auto-fix completed successfully!"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/open-feature/cli

go 1.25.0
go 1.26.3
Comment thread
erka marked this conversation as resolved.

require (
dagger.io/dagger v0.20.6
Expand Down
2 changes: 1 addition & 1 deletion internal/generators/csharp/csharp.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func toCSharpDict(value any) string {
for _, key := range keys {
val := assertedMap[key]

builder.WriteString(fmt.Sprintf(".Set(%q, %s)", key, formatNestedValue(val)))
fmt.Fprintf(&builder, ".Set(%q, %s)", key, formatNestedValue(val))
}
builder.WriteString(".Build())")

Expand Down
2 changes: 1 addition & 1 deletion internal/generators/golang/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func toMapLiteral(value any) string {
}
val := assertedMap[key]

builder.WriteString(fmt.Sprintf(`%q: %s`, key, formatNestedValue(val)))
fmt.Fprintf(&builder, `%q: %s`, key, formatNestedValue(val))
}

builder.WriteString("}")
Expand Down
2 changes: 1 addition & 1 deletion internal/generators/java/java.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func toMapLiteral(value any) string {
}
val := assertedMap[key]

builder.WriteString(fmt.Sprintf("%q, %s", key, formatNestedValue(val)))
fmt.Fprintf(&builder, "%q, %s", key, formatNestedValue(val))
}
builder.WriteString(")")

Expand Down
2 changes: 1 addition & 1 deletion internal/generators/python/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func toPythonDict(value any) string {
}
val := assertedMap[key]

builder.WriteString(fmt.Sprintf(`%q: %s`, key, formatNestedValue(val)))
fmt.Fprintf(&builder, `%q: %s`, key, formatNestedValue(val))
}

builder.WriteString("}")
Expand Down
3 changes: 1 addition & 2 deletions internal/manifest/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ func getKnownFlagProperties() map[string]bool {

// Extract fields from BaseFlag struct
t := reflect.TypeFor[BaseFlag]()
for i := range t.NumField() {
field := t.Field(i)
for field := range t.Fields() {
Comment thread
erka marked this conversation as resolved.
jsonTag := field.Tag.Get("json")
if jsonTag != "" {
// Extract field name from json tag (e.g., "flagType,omitempty" -> "flagType")
Expand Down
6 changes: 2 additions & 4 deletions internal/manifest/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,10 @@ func FormatValidationError(issues []ValidationError) string {
if flagType == "" {
flagType = "missing"
}
sb.WriteString(fmt.Sprintf(
"- flagType: %s\n flagPath: %s\n errors:\n ~ %s\n \tSuggestions:\n \t- flagType: boolean\n \t- defaultValue: true\n\n",
fmt.Fprintf(&sb, "- flagType: %s\n flagPath: %s\n errors:\n ~ %s\n \tSuggestions:\n \t- flagType: boolean\n \t- defaultValue: true\n\n",
Comment thread
erka marked this conversation as resolved.
flagType,
path,
strings.Join(entry.messages, "\n ~ "),
))
strings.Join(entry.messages, "\n ~ "))
}
return sb.String()
}
31 changes: 24 additions & 7 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
{
"customType": "regex",
"description": "Update the GoBaseImage constant when a newer golang Docker image is available",
"managerFilePatterns": [
"test/integration/integration.go"
],
"managerFilePatterns": ["test/integration/integration.go"],
"matchStrings": [
"GoBaseImage = \"golang:(?<currentValue>\\d+\\.\\d+(?:\\.\\d+)?)-alpine\""
],
Expand All @@ -18,17 +16,32 @@
{
"customType": "regex",
"description": "Update minimum Go version mentioned in README and CONTRIBUTING",
"managerFilePatterns": [
"README.md",
"CONTRIBUTING.md"
],
"managerFilePatterns": ["README.md", "CONTRIBUTING.md"],
"matchStrings": [
"Go >= (?<currentValue>\\d+\\.\\d+(?:\\.\\d+)?)",
"Go (?<currentValue>\\d+\\.\\d+(?:\\.\\d+)?) or later"
],
"depNameTemplate": "go",
"datasourceTemplate": "golang-version",
"extractVersionTemplate": "^(?<version>\\d+\\.\\d+)"
},
{
"customType": "regex",
"managerFilePatterns": ["Makefile"],
"matchStrings": [
"GOLANGCI_LINT_VERSION\\s*:?=\\s*(?<currentValue>v?\\d+\\.\\d+\\.\\d+)"
],
"depNameTemplate": "golangci/golangci-lint",
"datasourceTemplate": "github-releases"
},
{
"customType": "regex",
"managerFilePatterns": [".github/workflows/pr-lint.yml"],
"matchStrings": [
"uses:\\s*golangci/golangci-lint-action@v\\d+[\\s\\S]*?version:\\s*(?<currentValue>v?\\d+\\.\\d+\\.\\d+)"
],
"depNameTemplate": "golangci/golangci-lint",
"datasourceTemplate": "github-releases"
}
],
"packageRules": [
Expand All @@ -37,6 +50,10 @@
"matchDatasources": ["docker", "golang-version"],
"matchPackageNames": ["golang", "go"],
"groupName": "go toolchain"
},
{
"matchDepNames": ["golangci/golangci-lint"],
"groupName": "golangci-lint"
}
]
}
2 changes: 1 addition & 1 deletion test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ make test-integration

```bash
# For C# tests
make test-csharp-dagger
make test-integration-csharp
```

## Adding a New Integration Test
Expand Down
22 changes: 8 additions & 14 deletions test/integration/cmd/angular/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@ import (
)

type Test struct {
ProjectDir string
projectDir string
TestDir string
}

func New(projectDir, testDir string) *Test {
return &Test{
ProjectDir: projectDir,
projectDir: projectDir,
TestDir: testDir,
}
}

func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) {
// Mount the project source
source := client.Host().Directory(t.ProjectDir)

func (t *Test) Run(ctx context.Context, client *dagger.Client, cli *dagger.Container) (*dagger.Container, error) {
// Mount the test files
testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{
Include: []string{
Expand All @@ -37,14 +34,7 @@ func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Containe
},
})

// Build the CLI in a Go container
cli := client.Container().
From(integration.GoBaseImage).
WithDirectory("/src", source).
WithWorkdir("/src").
WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"})

// Generate the Angular code
// Generate the Angular code using the pre-built CLI
generated := cli.WithExec([]string{
"./cli", "generate", "angular",
"--manifest=/src/sample/sample_manifest.json",
Expand Down Expand Up @@ -76,6 +66,10 @@ func (t *Test) Name() string {
return "angular"
}

func (t *Test) ProjectDir() string {
return t.projectDir
}

func main() {
ctx := context.Background()

Expand Down
25 changes: 11 additions & 14 deletions test/integration/cmd/csharp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,28 @@ import (

// Test implements the integration test for the C# generator
type Test struct {
// ProjectDir is the absolute path to the root of the project
ProjectDir string
// projectDir is the absolute path to the root of the project
projectDir string
// TestDir is the absolute path to the test directory
TestDir string
}

// New creates a new Test
func New(projectDir, testDir string) *Test {
return &Test{
ProjectDir: projectDir,
projectDir: projectDir,
TestDir: testDir,
}
}

// Run executes the C# integration test using Dagger
func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) {
// Source code container
source := client.Host().Directory(t.ProjectDir)
func (t *Test) Run(ctx context.Context, client *dagger.Client, cli *dagger.Container) (*dagger.Container, error) {
// Test source files
testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{
Include: []string{"CompileTest.csproj", "Program.cs"},
})

// Build the CLI
cli := client.Container().
From(integration.GoBaseImage).
WithDirectory("/src", source).
WithWorkdir("/src").
WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"})

// Generate C# client
// Generate C# client using the pre-built CLI
generated := cli.WithExec([]string{
"./cli", "generate", "csharp",
"--manifest=/src/sample/sample_manifest.json",
Expand Down Expand Up @@ -70,6 +62,11 @@ func (t *Test) Name() string {
return "csharp"
}

// ProjectDir returns the absolute path to the project root
func (t *Test) ProjectDir() string {
return t.projectDir
}

func main() {
ctx := context.Background()

Expand Down
37 changes: 13 additions & 24 deletions test/integration/cmd/go/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,28 @@ import (

// Test implements the integration test for the Go generator
type Test struct {
// ProjectDir is the absolute path to the root of the project
ProjectDir string
// projectDir is the absolute path to the root of the project
projectDir string
// TestDir is the absolute path to the test directory
TestDir string
}

// New creates a new Test
func New(projectDir, testDir string) *Test {
return &Test{
ProjectDir: projectDir,
projectDir: projectDir,
TestDir: testDir,
}
}

// Run executes the Go integration test using Dagger
func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) {
// Source code container
source := client.Host().Directory(t.ProjectDir)
func (t *Test) Run(ctx context.Context, client *dagger.Client, cli *dagger.Container) (*dagger.Container, error) {
// Test source files
testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{
Include: []string{"test.go", "go.mod"},
})

// goBase returns a Go container with git installed, used both to build
// the CLI and to compile the generated client against the test fixture.
goBase := func() *dagger.Container {
return client.Container().
From(integration.GoBaseImage).
WithExec([]string{"apk", "add", "--no-cache", "git"})
}

// Build the CLI
cli := goBase().
WithDirectory("/src", source).
WithWorkdir("/src").
WithExec([]string{"go", "mod", "tidy"}).
WithExec([]string{"go", "mod", "download"}).
WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"})

// Generate Go client
// Generate Go client using the pre-built CLI
generated := cli.WithExec([]string{
"./cli", "generate", "go",
"--manifest=/src/sample/sample_manifest.json",
Expand All @@ -62,7 +45,8 @@ func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Containe
generatedFiles := generated.Directory("/tmp/generated")

// Test Go compilation with the generated files
goContainer := goBase().
goContainer := client.Container().
From(integration.GoGenerateMinCompatImage).
WithWorkdir("/app").
WithDirectory("/app", testFiles).
WithDirectory("/app/openfeature", generatedFiles).
Expand All @@ -78,6 +62,11 @@ func (t *Test) Name() string {
return "go"
}

// ProjectDir returns the absolute path to the project root
func (t *Test) ProjectDir() string {
return t.projectDir
}

func main() {
ctx := context.Background()

Expand Down
Loading
Loading