Skip to content

switch to internal project structure#290

Closed
kindermax wants to merge 1 commit intomasterfrom
switch-to-internal-project-structure
Closed

switch to internal project structure#290
kindermax wants to merge 1 commit intomasterfrom
switch-to-internal-project-structure

Conversation

@kindermax
Copy link
Copy Markdown
Collaborator

@kindermax kindermax commented Mar 10, 2026

Summary by Sourcery

Adopt an internal Go project layout centered on cmd/lets and wire versioning through an exported Version variable across builds, tests, and release tooling.

Enhancements:

  • Move the main application entrypoint to cmd/lets/main.go and expose the version string as an exported Version variable used throughout the CLI.
  • Update build scripts, docker-compose, and GoReleaser config to build the binary from cmd/lets/main.go and inject version information via main.Version.
  • Improve build feedback by reporting the compiled binary's runtime --version output and printing an explicit failure message when builds fail.
  • Add a lets.build.yaml command to run GoReleaser in a local dev/test mode.

Tests:

  • Adjust Bats tests to build and execute the lets binary from the new cmd/lets/main.go entrypoint while continuing to validate config version handling.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 10, 2026

Reviewer's Guide

Refactors the project into an internal-style layout by moving the main entrypoint to cmd/lets, updating version variable wiring and ldflags, and aligning build/test/release tooling to the new structure while cleaning up some run configs.

File-Level Changes

Change Details Files
Move main application entrypoint to cmd/lets and expose version as exported variable wired through the application.
  • Relocate main.go to cmd/lets/main.go and update imports and setup logic to use the new path.
  • Rename the version variable to exported Version and pass it to command initialization, config loading, workdir init, and upgrader creation.
  • Ensure all internal consumers reference Version instead of the old unexported version symbol.
cmd/lets/main.go
Update build and test scripts to target the new main package path and use the exported Version variable via ldflags.
  • Change go build invocations in tests, lets.yaml tasks, docker-compose test service, and local builds to compile cmd/lets/main.go instead of *.go.
  • Adjust ldflags keys from main.version to main.Version wherever the binary version is injected.
  • Improve dev build task to report the actual binary version from --version output and add basic error handling on build failure.
tests/config_version.bats
lets.yaml
docker-compose.yml
Align GoReleaser configuration with the new project layout and version variable name, and add a helper task to exercise GoReleaser locally.
  • Point GoReleaser builds at ./cmd/lets as the main package instead of project root.
  • Update GoReleaser ldflags from main.version to main.Version to match the exported variable.
  • Introduce a lets.build.yaml goreleaser-dev command to run goreleaser build with validation skipped for local testing.
.goreleaser.yml
lets.build.yaml
Minor repository housekeeping related to tooling and project layout cleanup.
  • Normalize indentation in Bats tests for readability.
  • Remove obsolete IDE run configuration files while leaving .gitignore and VS Code launch configuration in place.
tests/config_version.bats
.gitignore
.vscode/launch.json
.run/lets --version.run.xml
.run/lets print-env.run.xml
.run/lets.run.xml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • The new exported Version symbol is now set via ldflags in several places, but some build configs (e.g., parts of .goreleaser.yml) still reference main.version; it would be good to standardize all ldflags to main.Version to avoid version mismatches across artifacts.
  • In the updated build command in lets.yaml, when the go build fails you print "Failed to build" but don't propagate the non-zero exit status; consider exiting with the build's status (e.g., exit $success) so callers can detect failures correctly.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new exported `Version` symbol is now set via ldflags in several places, but some build configs (e.g., parts of `.goreleaser.yml`) still reference `main.version`; it would be good to standardize all ldflags to `main.Version` to avoid version mismatches across artifacts.
- In the updated `build` command in `lets.yaml`, when the `go build` fails you print "Failed to build" but don't propagate the non-zero exit status; consider exiting with the build's status (e.g., `exit $success`) so callers can detect failures correctly.

## Individual Comments

### Comment 1
<location path=".goreleaser.yml" line_range="26" />
<code_context>
     ldflags:
       - -s -w -X main.version={{.Version}}
   - id: darwin-arm64
-    main: .
</code_context>
<issue_to_address>
**issue (bug_risk):** The ldflags symbol still targets `main.version` while the variable has been renamed to `main.Version`, which will break this build.

In this config, `main` now builds from `./cmd/lets` and the variable in `cmd/lets/main.go` is `Version`, so `-X main.version` refers to a non‑existent symbol and will cause the linker step to fail. Update this entry to match the others, e.g. `-X main.Version={{.Version}}`.
</issue_to_address>

### Comment 2
<location path="lets.yaml" line_range="124-133" />
<code_context>
-      go build -ldflags="-X main.version=${VERSION:1}-dev" -o ${BIN} *.go && \
-      echo " - binary './${BIN}' (version ${VERSION}) successfully build"
+      
+      go build \
+        -ldflags="-X main.Version=${VERSION:1}-dev" \
+        -o ${BIN} cmd/lets/main.go
+      
+      success=$?
+      if [[ $success -eq 0 ]]; then
+        version=$(./${BIN} --version)
+        echo " - binary './${BIN}' ($version) successfully build"
+      else
+        echo "Failed to build"
+      fi

</code_context>
<issue_to_address>
**issue (bug_risk):** The build command failure is swallowed, causing the script to succeed even when the binary was not built.

Because you only echo on failure and don’t exit non‑zero, callers (CI, wrapper scripts) will see this as a successful run even when `go build` fails. Please propagate the build status (e.g. `exit $success` in the `else` branch) or use `if go build ...; then ... else exit 1; fi` so failures are correctly reported.
</issue_to_address>

### Comment 3
<location path="docker-compose.yml" line_range="34" />
<code_context>
       - -c
       - |
-        go build -o /usr/bin/lets *.go
+        go build -o /usr/bin/lets cmd/lets/main.go
         if [[ -n "${LETSOPT_TEST}" ]]; then
           bats tests/"${LETSOPT_TEST}" ${LETSOPT_OPTS}
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Building a single source file may skip other files in the `cmd/lets` package; consider building the package path instead.

Building `cmd/lets/main.go` directly will ignore any other files in the `cmd/lets` package (e.g., future platform-specific or split-out logic). To match how the binary is normally built and avoid missing code later, prefer `go build -o /usr/bin/lets ./cmd/lets` instead.

```suggestion
        go build -o /usr/bin/lets ./cmd/lets
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -25,7 +25,7 @@ builds:
ldflags:
- -s -w -X main.version={{.Version}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): The ldflags symbol still targets main.version while the variable has been renamed to main.Version, which will break this build.

In this config, main now builds from ./cmd/lets and the variable in cmd/lets/main.go is Version, so -X main.version refers to a non‑existent symbol and will cause the linker step to fail. Update this entry to match the others, e.g. -X main.Version={{.Version}}.

Comment on lines +124 to +133
go build \
-ldflags="-X main.Version=${VERSION:1}-dev" \
-o ${BIN} cmd/lets/main.go

success=$?
if [[ $success -eq 0 ]]; then
version=$(./${BIN} --version)
echo " - binary './${BIN}' ($version) successfully build"
else
echo "Failed to build"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): The build command failure is swallowed, causing the script to succeed even when the binary was not built.

Because you only echo on failure and don’t exit non‑zero, callers (CI, wrapper scripts) will see this as a successful run even when go build fails. Please propagate the build status (e.g. exit $success in the else branch) or use if go build ...; then ... else exit 1; fi so failures are correctly reported.

- -c
- |
go build -o /usr/bin/lets *.go
go build -o /usr/bin/lets cmd/lets/main.go
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Building a single source file may skip other files in the cmd/lets package; consider building the package path instead.

Building cmd/lets/main.go directly will ignore any other files in the cmd/lets package (e.g., future platform-specific or split-out logic). To match how the binary is normally built and avoid missing code later, prefer go build -o /usr/bin/lets ./cmd/lets instead.

Suggested change
go build -o /usr/bin/lets cmd/lets/main.go
go build -o /usr/bin/lets ./cmd/lets

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR migrates the project to a standard Go internal layout by moving main.go to cmd/lets/main.go and updates all build references accordingly. The rename also exports the version variable as Version to allow linker injection via -X main.Version.

The structural change is clean, but the rename was only partially propagated in .goreleaser.yml: the darwin-amd64 and linux-amd64 release builds still reference the old -X main.version symbol (lowercase), while only darwin-arm64 was corrected to -X main.Version. This means published binaries for those two platforms will embed 0.0.0-dev instead of the actual release tag — a silent but significant regression for every release going forward.

Additionally, the new build command in lets.yaml captures the go build exit code but then exits 0 regardless of the result, masking compilation failures from callers.

Key changes:

  • main.gocmd/lets/main.go (standard Go project layout)
  • var versionvar Version for linker symbol injection
  • All go build invocations, IDE configs, .goreleaser.yml main: fields, and test setup updated to the new path
  • .gitignore tightened: lets/lets to anchor the rule to the repo root
  • New goreleaser-dev convenience command added to lets.build.yaml

Issues found:

  • .goreleaser.yml lines 26 and 54: darwin-amd64 and linux-amd64 still use -X main.version (lowercase) — release binaries will report 0.0.0-dev
  • lets.yaml build command: build failure is silently swallowed, command exits 0 on error
  • docker-compose.yml and lets.yaml: use file-path form (cmd/lets/main.go) instead of package-path form (./cmd/lets) for go build

Confidence Score: 2/5

  • Not safe to merge — two of three release targets will embed the wrong version string, silently breaking every future release for darwin-amd64 and linux-amd64 users.
  • The structural refactor is correct and well-executed, but the incomplete linker-flag rename in .goreleaser.yml is a high-impact regression: darwin-amd64 and linux-amd64 release binaries will report 0.0.0-dev, which breaks version-gated features and upgrade checks. The build-failure masking in lets.yaml is a secondary but real correctness issue. Both must be fixed before merging.
  • .goreleaser.yml requires the most attention — lines 26 and 54 must be updated from -X main.version to -X main.Version before any release is cut.

Important Files Changed

Filename Overview
.goreleaser.yml Entry point updated to ./cmd/lets for all three builds, but darwin-amd64 (line 26) and linux-amd64 (line 54) still use the old -X main.version linker flag instead of -X main.Version, causing those release binaries to report 0.0.0-dev.
cmd/lets/main.go Renamed from main.go to cmd/lets/main.go; version variable exported to Version to allow linker injection — change is consistent within the file.
lets.yaml Updated ldflags to -X main.Version and build target to cmd/lets/main.go; the build command's error branch silently exits 0, masking Go compilation failures.
docker-compose.yml Build step updated to reference cmd/lets/main.go; uses file-path form instead of package-path form (./cmd/lets), which could exclude future sibling files.
tests/config_version.bats Updated build command to use -X main.Version and cmd/lets/main.go; indentation normalised — no issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[go source\ncmd/lets/main.go] -->|go build -ldflags\n-X main.Version=...| B[lets binary]

    subgraph goreleaser [goreleaser builds]
        G1["darwin-amd64\n❌ -X main.version (lowercase)"]
        G2["darwin-arm64\n✅ -X main.Version (uppercase)"]
        G3["linux-amd64\n❌ -X main.version (lowercase)"]
    end

    subgraph local [local builds]
        L1["lets build\ncmd/lets/main.go\n✅ -X main.Version"]
        L2["lets build-and-install\ncmd/lets/main.go\n✅ -X main.Version"]
        L3["docker-compose test-bats\ncmd/lets/main.go\n(no version flag)"]
    end

    A --> goreleaser
    A --> local

    G1 -->|version = 0.0.0-dev| R1[darwin-amd64 release ❌]
    G2 -->|version = tag| R2[darwin-arm64 release ✅]
    G3 -->|version = 0.0.0-dev| R3[linux-amd64 release ❌]
Loading

Comments Outside Diff (1)

  1. .goreleaser.yml, line 54 (link)

    Stale main.version linker flag — version won't be injected for linux-amd64

    Same issue as line 26: the linux-amd64 build still uses the old lowercase symbol name -X main.version={{.Version}}. Releases built for linux-amd64 will display 0.0.0-dev instead of the actual release version.

Last reviewed commit: 8595e99

@@ -25,7 +25,7 @@ builds:
ldflags:
- -s -w -X main.version={{.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.

Stale main.version linker flag — version won't be injected for darwin-amd64

The variable was renamed from version to Version (uppercase) in cmd/lets/main.go, but the darwin-amd64 build still references the old lowercase name. At link time, -X main.version={{.Version}} will silently do nothing because no such symbol exists, so all darwin-amd64 releases will report 0.0.0-dev as the version.

The same issue also appears on line 54 for the linux-amd64 build — only darwin-arm64 (line 41) was correctly updated to -X main.Version={{.Version}}.

Suggested change
- -s -w -X main.version={{.Version}}
- -s -w -X main.Version={{.Version}}

Comment on lines +128 to +134
success=$?
if [[ $success -eq 0 ]]; then
version=$(./${BIN} --version)
echo " - binary './${BIN}' ($version) successfully build"
else
echo "Failed to build"
fi
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.

Build failure is silently swallowed — command always exits 0

success=$? correctly captures the go build exit code, but the else branch only echos a message and then falls through to the end of the script. The final command executed is echo "Failed to build", which exits with 0, so lets build will appear to succeed even when the Go compilation failed. This will cause callers (CI, scripts) to believe the build produced a valid binary when it did not.

To propagate the failure, exit explicitly with the captured code:

go build \
  -ldflags="-X main.Version=${VERSION:1}-dev" \
  -o ${BIN} cmd/lets/main.go

success=$?
if [[ $success -eq 0 ]]; then
  version=$(./${BIN} --version)
  echo " - binary './${BIN}' ($version) successfully build"
else
  echo "Failed to build"
  exit $success
fi

- -c
- |
go build -o /usr/bin/lets *.go
go build -o /usr/bin/lets cmd/lets/main.go
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.

Prefer package path over file path for go build

Passing a file path (cmd/lets/main.go) to go build limits compilation to that single file. If any additional .go files are ever added to the cmd/lets package they will be silently excluded. The idiomatic and future-proof form is to pass the package directory, consistent with how .goreleaser.yml references the same entry-point.

The same pattern also appears in lets.yaml at lines 112 and 126.

Suggested change
go build -o /usr/bin/lets cmd/lets/main.go
go build -o /usr/bin/lets ./cmd/lets

@kindermax kindermax closed this Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant