Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: cmd/go: add project config to go.mod #42343

Closed
distinctdan opened this issue Nov 2, 2020 · 19 comments
Closed

proposal: cmd/go: add project config to go.mod #42343

distinctdan opened this issue Nov 2, 2020 · 19 comments

Comments

@distinctdan
Copy link

The way things are today, go relies on environment variables for things like build architecture and os, as well as resolving private repos. This isn't good because they live outside of source control, so the build breaks when someone else clones the repo and tries to run go get or go build.

Instead, what about making these settings live in go.mod, similar to how node has a package.json? It might look like

env (
    GOOS linux
    GOPRIVATE github.com/myOrganization
)

My goal is to ensure it builds the same way every time for everyone that clones the repo, without them having to do any manual environment config.

@gopherbot gopherbot added this to the Proposal milestone Nov 2, 2020
@bcmills
Copy link
Contributor

bcmills commented Nov 2, 2020

See previously #39005 (CC @dominikh @mvdan @jayconrod @matloob)

@bcmills
Copy link
Contributor

bcmills commented Nov 2, 2020

See also #33985.

@mvdan
Copy link
Member

mvdan commented Nov 2, 2020

Note that #39005 was not about altering the default build behavior, though. It was simply about listing the "build configurations" which are well supported by a module. This distinction makes me worry about this proposal.

@distinctdan
Copy link
Author

Hmm, I hadn't considered different build configs. That is definitely a useful feature though. For security, I'm not experienced enough with Go to know all the options, but I'm thinking of just setting build options, not necessarily going as far as allowing shell scripts. Perhaps something like, where you have different available configs for the build:

buildConfig (
    default (
        Output myApp
        GOOS linux
        GOPRIVATE github.com/myOrganization
    )
    windows (
        Output myApp.exe
        GOOS windows
        // Inherits GOPRIVATE value from default
    )
)

@mvdan
Copy link
Member

mvdan commented Nov 2, 2020

I'm still not convinced that a "default" makes sense. It would be very confusing for go build on Linux to produce a Windows binary, or to produce a binary in an unexpected directory, for example.

I think we should design the semantics (what do we want to list, and for what purpose?) before we worry about what file it would go under or with what syntax. The semantics is why #39005 was retracted, after all - it opened up the go tool to executing arbitrary code, and overall the idea gained no traction.

@distinctdan
Copy link
Author

So I'm thinking that the build config section would be optional. Any values omitted would use the current behavior, so if an organization was running locally and had a mix of windows and linux machines, they could still omit the GOOS variable so that it would use the OS's default. My particular use case is we've got a small app that's being deployed to aws lambda, so it always needs to build for linux, and my org uses several private repos, so when I first tried to build the project, I got a bunch of errors and had to do a bunch of googling to figure out how to get it to work.

Coming from a web background, the npm and webpack ecosystems offer a lot more tooling. It's normal to have a default task that builds and runs in dev mode, often with hot code reloading, then you've got a task that builds in release mode. It's expected that things just work out of the box and that each module you import is self contained. Coming from that, it just seems strange to have to make global environment changes to get a local project to build, or to have to pass a bunch of flags every time. I've worked around this in the meantime by putting all my flags in a shell script that calls go build, but this seems like a pretty common use case, so I think it'd be nice if Go natively supported it.

@bcmills
Copy link
Contributor

bcmills commented Nov 3, 2020

As an alternative, note that you could at least reduce the number of environment variables from many to just one, by setting the GOENV environment variable to point to a location within your repo.

@pickfire
Copy link

pickfire commented Nov 6, 2020

As an alternative, note that you could at least reduce the number of environment variables from many to just one, by setting the GOENV environment variable to point to a location within your repo.

Setting environment variable is not user friendly, it cannot be checked into the repo (it can through a file) and requires an extra step for new developers (new clone) to get started.

For example, one requires to source env.sh first before go build. Comparing to rust, one can just cargo build with the options in Cargo.toml.

@networkimprov
Copy link

I build app releases for Linux, Windows, and MacOS. Each release includes a platform specific tree of files beside the executable, and is packed into a TGZ or ZIP file. I built a shell script to do this, tho I could have used a makefile. I've essentially duplicated the script in multiple projects.

If there's a Go-native way to do this, I overlooked it.

@rsc rsc changed the title Proposal: Project config should live in go.mod instead of relying on env variables cmd/go: proposal add project config to go.mod Nov 18, 2020
@rsc rsc changed the title cmd/go: proposal add project config to go.mod proposal: cmd/go: add project config to go.mod Dec 2, 2020
@rsc
Copy link
Contributor

rsc commented Dec 2, 2020

In general go.mod is very narrowly scoped to information about dependency versions. It's not a catch-all for all possible configuration, in contrast to similar files in other systems, like package.json.

I would suggest that you check in a script with environment settings to be sourced, if you want your developers to be on the same page.

@rsc
Copy link
Contributor

rsc commented Dec 9, 2020

Based on the discussion above, this seems like a likely decline.

@distinctdan
Copy link
Author

Even if this specific proposal is declined, the root problem still exists of building a project from source without having to do any manual configuration. I'm not locked in to my specific proposal, but I do think this needs to be addressed for go to be on par with other language ecosystems. It may be as simple as choosing a tool such as make, and updating the official docs to say something like "we recommend building with this tool in order to get consistent builds".

@ianlancetaylor
Copy link
Contributor

@rsc already suggested checking in a script that sets environment variables. Is that sufficient, or would something else be required? Would it suffice to declare a convention for what the script should be called?

We seem to only be talking about environment variables. We currently already have a three level hierarchy for them: environment variables have default values set when Go is installed, which are overridden by values set by go env -w, which are overridden by values set in the environment when invoking the go tool. It sounds like you are suggesting that we need to another level in that hierarchy, in between go env -w and the user environment: module level environment variables. Does that sound right?

@distinctdan
Copy link
Author

My main point would be that we need a single source of truth for build config that lives in source control. From someone who's relatively new to Go, it feels like kind of a mess right now, where your build might be pulling values from any of the sources you mentioned, none of which are in source control.

If the Go team doesn't want to go the route of package.json and do a full build file, I think it might be enough to update the docs to recommend creating a make file, or perhaps a shell script, to controls the build. Or, at least having a warning that Go relies on things outside your project's repo, and if you don't like that, then you need to implement a custom solution.

@ianlancetaylor
Copy link
Contributor

Part of the reason we don't worry about this too much is that setting these environment variables is rarely necessary. Your example suggests setting GOOS=linux, but that will never be correct on a per-module basis. And setting GOPRIVATE is also not per-module, but rather a characteristic of the organization. So while it makes sense to put that kind of thing into source code control, the module does not seem like the right place for it.

@distinctdan
Copy link
Author

Well, at least for my use case, it is always necessary to build with GOOS=linux, and I did have to manually set up GOPRIVATE when I first cloned the repo. Any top level project is probably going to have well-defined build targets. Like, if your company is deploying to aws, you always want to build the same way, regardless of whether the developer is on windows or linux.

You do have a point though about the os architecture not being applicable at the module level. Really, it's at the build target level, like you wouldn't expect imported modules to affect your build params in any way. However, for GOPRIVATE, it seems like that is still applicable to a module since that affects the module's imports.

@antichris
Copy link

antichris commented Dec 13, 2020

Create a module-local go.env file, list your GOOS, GOPRIVATE and other (if any) Go environment adjustments there, build with GOENV=go.env go build. If you need scripting, custom targets (e.g. with tags), etc., use make. I don't think this is something that should be ported into Go.

I can see that someone coming from web background is used to tooling lock-in. Anyone with systems background is perfectly comfortable with creating a Makefile when additional configuration/tasks are needed in the build process. Using make (or one of the many alternatives) actually makes a project tooling-agnostic (apart from the selected build tool and its config), not even the language is set in stone: one can mix and match tools, libraries, components and languages in whatever way makes the most sense for their project's goals. I've actually seen people using make in their npm projects, which IMO suggests that they too have come to the above or quite similar conclusions.

@rsc
Copy link
Contributor

rsc commented Dec 16, 2020

Even if this specific proposal is declined, the root problem still exists of building a project from source without having to do any manual configuration.

Just to reply to this, that root problem is not something the go command aims to solve. Shell scripts and more complex build systems are possible solutions.

@rsc
Copy link
Contributor

rsc commented Dec 16, 2020

No change in consensus, so declined.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants