gome-assistant icon indicating copy to clipboard operation
gome-assistant copied to clipboard

How to prevent version skew between the example app and `gome-assistant` itself

Open mhagger opened this issue 2 months ago • 1 comments

When working on the current version of gome-assistant, I noticed that the example app didn't compile. #35 fixes the problems that I encountered. But one of the problems was that the version of gome-assistant required by the example app was out of sync with the version of the library being shipped and also with the code in the example app. This problem will recur if we don't find a way to keep them in sync systematically.

The most convenient way, at least when developing, would be for the example app to always build using the version of gome-assistant that it ships with. That would prevent its go.mod from getting out of sync again in the future, and also make it easy to test that it builds with a version of gome-assistant that hasn't been released yet. Ensuring that the example app still compiles would also provide a slight regression test against unintended backwards-incompatible changes to the library.

However, the example app is not only interesting for gome-assistant devs but also for library users. They are more likely to want a tiny app that they can copy into their own repository and tweak to get it to work in their own setup. Anything that depends on requiring the example app to be embedded in the gome-assistant project tree will make life less convenient for those users.

Brainstorming some ways to keep the two in sync:

  1. The example app could be made part of the gome-assistant module, for example by moving it to cmd/example and removing its go.mod and go.sum files. This would add a few dependencies to the main project, but would also prevent gratuitous skew that currently exists between versions of other dependencies required by the main project vs. the example app:

    $ git diff --no-index -U0 <(sort go.mod | sed -nE -e 's| // indirect$||' -e 's|^\t(.*)$|\1|p') <(sort example/go.mod | sed -nE -e 's| // indirect$||' -e 's|^\t(.*)$|\1|p') | grep '^[-+][^-+]' | sort --stable -k 1.2,1 -k1.1,1.2r
    +github.com/golang-cz/devslog v0.0.8
    -github.com/golang-module/carbon v1.7.1
    +github.com/golang-module/carbon v1.7.3
    -github.com/joho/godotenv v1.4.0
    +github.com/joho/godotenv v1.5.1
    -github.com/rogpeppe/go-internal v1.9.0
    +github.com/rogpeppe/go-internal v1.11.0
    -github.com/stretchr/objx v0.5.0
    +golang.org/x/mod v0.9.0
    +saml.dev/gome-assistant v0.6.0
    

    On the other hand, this would be it a bit harder for a user to copy the example directory and use it as the starting point for their own app.

  2. The example app's go.mod could use a replace directive to cause it to use the saml-dev/gome-assistant that is located in its parent directory:

    index 6973a7a..42b3204 100644
    --- a/example/go.mod
    +++ b/example/go.mod
    @@ -22,3 +22,5 @@ require (
            github.com/rogpeppe/go-internal v1.11.0 // indirect
            golang.org/x/mod v0.9.0 // indirect
     )
    +
    +replace saml.dev/gome-assistant => ..
    

    But this would also make it a bit harder to copy the example directory and use it as the starting point for one's own app.

  3. The README.md could include instructions for setting up a go.work file locally containing similar replace directive, and encourage devs to use that. However, I find the use of workspaces somewhat confusing, and ran into a lot of dependency friction when I tried this. I guess that it also makes it possible for example/go.sum to get out of sync with the top-level go.sum.

  4. We could create a test suite that checks that example builds, and encourage devs to run the test suite while working, and/or set up GitHub actions to run the build test automatically against PRs. But this still doesn't prevent version drift, including the risk that the "current" example app doesn't compile against the gome-assistant in the corresponding commit.

  5. We could add an automated test that the example app's go.mod depends on the corresponding version of gome-assistant. But this is awkward to determine, as it depends on the presence/absence of upstream tags, plus it doesn't allow compiling the example app against non-released versions of gome-assistant.

All in all, my personal opinion is that the least-bad option is (1), ideally combined with automated tests that all components compile (including cmd/generate).

Or maybe this is all overengineering, and we shouldn't worry about the problem.

mhagger avatar Oct 12 '25 12:10 mhagger