Skip to content

0.6.0

Compare
Choose a tag to compare
@svengreb svengreb released this 29 Apr 07:55
· 15 commits to main since this release
v0.6.0

Release Date: 2021-04-29 Project Board Milestone

Show all commits

Features

Expose task name via Task interface#79, #87#80, #88 (⊶ bd15824, 8b30110)

↠ Most tasks provided a TaskName package constant that contained the name of the task, but this was not an idiomatic and consistent way. To make sure that this information is part of the API, the new Name() string method has been added to the Task interface.

Task for Go toolchain env command#81#82 (⊶ 5e3764a)

↠ To support the go env command of the Go toolchain, a new Task has been implemented in the new env package that can be used through a Go toolchain Runner.
The task is customizable through the following functions:

  • WithEnv(env map[string]string) env.Option — sets the task specific environment.
  • WithEnvVars(envVars ...string) env.Option — sets the names of the target environment variables.
  • WithExtraArgs(extraArgs ...string) env.Option — sets additional arguments to pass to the command.
RunOut method for Runner interface#83#84 (⊶ d818065)

↠ The Run method of the Runner interface allows to run a command, but did not return its output. This was blocking when running commands like go env GOBIN to get the path to the GOBIN environment variable.
To support such uses cases, the new RunOut(Task) (string, error) method has been added to the Runner interface that runs a command and returns its output.

Replace deprecated gobin with custom go install based task runner#89#90 (⊶ 9c510a7)

↠ This feature supersedes #78 which documents how the official deprecation of gobin in favor of the new Go 1.16 go install pkg@version syntax feature should have been handled for this project. The idea was to replace the gobin task runner with a one that leverages bingo, a project similar to gobin, that comes with many great features and also allows to manage development tools on a per-module basis. The problem is that bingo uses some non-default and nontransparent mechanisms under the hood and automatically generates files in the repository without the option to disable this behavior. It does not make use of the go install command but relies on custom dependency resolution mechanisms, making it prone to future changes in the Go toolchain and therefore not a good choice for the maintainability of projects.

go install is still not perfect

Support for the new go install features, which allow to install commands without affecting the main module, have already been added in #71 as an alternative to gobin, but one significant problem was still not addressed: install module/package executables globally without overriding already installed executables of different versions.
Since go install will always place compiled binaries in the path defined by go env GOBIN, any already existing executable with the same name will be replaced. It is not possible to install a module command with two different versions since go install still messes up the local user environment.

The Workaround: Hybrid go install task runner

The solution was to implement a custom Runner that uses go install under the hood, but places the compiled executable in a custom cache directory instead of go env GOBIN. The runner checks if the executable already exists, installs it if not so, and executes it afterwards.

The concept of storing dependencies locally on a per-project basis is well-known from the node_modules directory of the Node package manager npm. Storing executables in a cache directory within the repository (not tracked by Git) allows to use go install mechanisms while not affect the global user environment and executables stored in go env GOBIN. The runner achieves this by changing the GOBIN environment variable to the custom cache directory during the execution of go install. This way it bypasses the need for “dirty hacks“ while using a custom output path.

The only known disadvantage is the increased usage of storage disk space, but since most Go executables are small in size anyway, this is perfectly acceptable compared to the clearly outweighing advantages.

Note that the runner dynamically runs executables based on the given task so Validate() error is a NOOP.

Upcoming Changes

The solution described above works totally fine, but is still not a clean solution that uses the Go toolchain without any special logic so as soon as the following changes are made to the Go toolchain (Go 1.17 or later), the custom runner will be removed again:

  • golang/go/issues#42088 — tracks the process of adding support for the Go module syntax to the go run command. This will allow to let the Go toolchain handle the way how compiled executable are stored, located and executed.
  • golang/go#44469 — tracks the process of making go install aware of the -o flag like the go build command which is the only reason why the custom runner has been implemented.

Further Adjustments

Because the new custom task runner dynamically runs executables based on the given task, the Bootstrap method of the Wand reference implementation Elder now additionally allows to pass Go module import paths, optionally including a version suffix (pkg@version), to install executables from Go module-based main packages into the local cache directory. This way the local development environment can be set up, for e.g. by running it as startup task in JetBrains IDEs.
The method also ensures that the local cache directory exists and will create a .gitignore file that includes ignore pattern for the cache directory.

Task for go-mod-upgrade Go module command#95#96 (⊶ c944173)

↠ The github.com/oligot/go-mod-upgrade Go module provides the go-mod-upgrade command, a tool that to update outdated Go module dependencies interactively.

To configure and run the go-mod-upgrade command, a new task.GoModule has been implemented in the new gomodupgrade package. It can be be run using a command runner that handles tasks of kind KindGoModule.

The task is customizable through the following functions:

  • WithEnv(map[string]string) gomodupgrade.Option — sets the task specific environment.
  • WithExtraArgs(...string) gomodupgrade.Option — sets additional arguments to pass to the command.
  • WithModulePath(string) gomodupgrade.Option — sets the module import path.
  • WithModuleVersion(*semver.Version) gomodupgrade.Option — sets the module version.

The Elder reference implementation will provide a new GoModUpgrade method.

Improvements

Remove unnecessary Wand parameter in Task creation functions#76#77 (⊶ 536556b)

↠ Most Task creation functions 1 2 3 4 required a Wand as parameter which was not used but blocked the internal usage for task runners. Therefore these parameters have been removed. When necessary, it can be added individually later on or can be reintroduced through a dedicated function with extended parameters to cover different use cases.

Remove unnecessary app.Config parameter from Task creation functions#85#86 (⊶ 72dd6a1)

↠ Some functions that create a Task required an app.Config struct, but most tasks did not use the data in any way. To improve the code quality and simplify the internal usage of tasks these parameters have been removed as well as the field from the structs that implement the Task interfaces.

Update to tmpl-go template repository version 0.8.0#91#92 (⊶ 3e18917)

↠ Updated to tmpl-go version 0.8.0 which updates golangci-lint to version 1.39.0 and the tmpl repository version 0.9.0.

Dogfooding: Introduce Mage with wand toolkit#93#94 (⊶ 85c466d)

↠ The project only used GitHub Action workflows for CI but not Mage to automate tasks for itself though.
Following the “dogfooding“ concept Mage has finally been added to the repository, using wand as toolkit through the Elder wand reference implementation.

The full changelog is available in the repository

Copyright © 2019-present Sven Greb