Releases: svengreb/wand
0.8.0
Improvements
Improve runtime/debug
Go 1.18 incompatibility via stable go.mod
file parsing — #129 ⇄ #130 (⊶ df29129)
↠ As of Go 1.18 the debug.ReadBuildInfo function does not work for Mage executables anymore because the way how module information is stored changed. Therefore the fields of the returned debug.Module type only has zero values, including the module path. The debug.Module.Version field has a default value ((devel)
) which is not Semver compatible and causes the parsing to fail. The change in Go 1.18 also came with the new debug/buildinfo
package which allows to read the information from compiled binaries while the runtime/debug.ReadBuildInfo
function returns information from within the running binary. Both are not suitable anymore which is also described in the Go 1.18 version
command release notes:
The underlying data format of the embedded build information can change with new
go
releases, so an older version ofgo
may not handle the build information produced with a newer version ofgo
. To read the version information from a binary built withgo
1.18, use thego
version command and thedebug/buildinfo
package fromgo
1.18+.
To get the required module information that was previously provided by the runtime/debug package the official golang.org/x/mod/modfile package is now used instead that provides the implementation for a parser and formatter for go.mod
files 1. This allows to safely get the module path without the need to depend on runtime/dynamic logic that might change in future Go versions.
Note that this change also increased the minimum Go version from 1.17
to 1.19
!
Bug Fixes
Update to tmpl-go
template repository version 0.11.0
and 0.12.0
— #112, #127 ⇄ #113, #128 (⊶ a4e2a38, c4fe6cf)
↠ Updated to tmpl-go
version 0.11.0
and 0.12.0
which…
- fixed
golangci-lint
running errors due torevive
s unknowntime-equal
rule. - disabled the
revive
linter rulepackage-comments
. - updated to the
tmpl
template repository version0.11.0
.
See the full tmpl-go
version 0.11.0
and 0.12.0
and changelogs for all details.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.7.0
Improvements
Update to tmpl-go
template repository version 0.9.0
— #104 ⇄ #105 (⊶ 9caf10f)
↠ Updated to tmpl-go
version 0.9.0
which…
- updated to
golangci-lint
version1.43.0
— new linters are introduced and configurations of already supported ones are improved or added. - updated the Go module to Go
1.17
. - optimized the GitHub action workflows for Go and Node — the
ci
workflow has been optimized by splitting it into newci-go
andci-node
workflows. - updated to the
tmpl
template repository version0.10.0
.
See the full tmpl-go
version 0.9.0
changelog for all details.
Upgrade default GoModule
task versions — #106 ⇄ #107 (⊶ cabd635)
↠ Most of the GoModule
tasks used an outdated default Go module version so the following tasks have been updated and adjusted to the currently latest versions:
- mvdan.cc/gofumpt — The
github.com/svengreb/wand/pkg/task/gofumpt
task used versionv0.1.1
and has been updated to version0.2.0
by…
1.1 removing the-r
flag which has been removed in favor ofgofmt -r
.
1.2 removing the-s
flag (WithSimplify
option) as it is always enabled. - golang.org/x/tools/cmd/goimports — The
github.com/svengreb/wand/pkg/task/goimports
task used versionv0.1.0
and has been updated to version0.1.7
. - github.com/golangci/golangci-lint/cmd/golangci-lint — The
github.com/svengreb/wand/pkg/task/golangcilint
task used versionv1.39.0
and has been updated to version1.43.0
. The configuration has already been updated in #104.
Update to tmpl-go
template repository version 0.10.0
— #110 ⇄ #111 (⊶ ee52f08)
↠ Updated to tmpl-go
version 0.10.0
which…
- disables
golangci-lint
's default excluded issues — this prevents that explicitly enabled rules are not ignored due to the default set of excluded issues. - caches Go dependencies and build outputs in
ci-go
workflow — this improves the workflow execution time.
See the full tmpl-go
version 0.10.0
changelog for all details.
Bug Fixes
Insufficient repository fetch-depth for action workflows — #108 ⇄ #109 (⊶ c39b2c4)
↠ The GitHub action workflows uses the actions/checkout
action to fetch the repository that triggered the workflow. However, by default only the history of the latest commit was fetched which resulted in errors when wand tried to extract repository metadata information like the amount of commits ahead of the latest commit. As an example this can be seen when running the bootstrap
command in the test
job of the ci-go
workflow which failed with an object not found
error because the history only contained a single commit.
To fix this problem action/checkout
provides an option to fetch all history for all tags and branches which is now used to prevent errors like this in the pipeline.
Tasks
Go module dependency & GitHub action version updates — #97, #98, #102, #103
↠ Bumped outdated Go module dependencies and GitHub actions to their latest versions:
- #97 (⊶ 03ab104)
github.com/fatih/color
from v1.10.0 to v1.11.0 - #98 (⊶ 7b2ac86)
github.com/fatih/color
from v1.11.0 to v1.12.0 - #102 (⊶ eecbc52)
github.com/fatih/color
from v1.12.0 to v1.13.0 - #103 (⊶ b8b906c)
actions/setup-node
from v2.1.5 to v2.4.1
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.6.0
⇅ [Show all commits][gh-compare-tag-v0.5.0_v0.6.0]
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][go-pkg-task#task].
Task for Go toolchain env
command — #81 ⇄ #82 (⊶ 5e3764a)
↠ To support the [go env
command of the Go toolchain][go-pkg-cmd/go#install], a new [Task
][go-pkg-task#task] has been implemented in the new [env
][go-pkg-task/golang/env] package that can be used through a [Go toolchain Runner
][go-pkg-task/golang#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][go-pkg-v0.5.0-task#runner] 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][go-pkg-cmd/go#env].
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][gh-myitcv/gobin#103] of [gobin
][gh-myitcv/gobin] in favor of the new Go 1.16 [go install pkg@version
][go-pkg-cmd/go#install] syntax feature should have been handled for this project. The idea was to replace the [gobin
task runner][go-pkg-v0.5.0-task/gobin#runner] with a one that leverages [bingo][gh-bwplotka/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
][go-pkg-task#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][npm-docs-cli-v7-config-folders#node_modules] 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][gh-golang/go#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][gh-golang/go#44469-c-784534876] — tracks the process of making
go install
aware of the-o
flag like thego 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][go-pkg-v0.5.0-elder#elder.boostrap] of the [Wand
][go-pkg#wand] reference implementation [Elder
][go-pkg-elder#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][jetbrains-docs-idea-startup_tasks] 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][gh-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
][go-pkg-task#gomodule] has been implemented in the new [gomodupgrade
][go-pkg-task/gomodupgrade] package. It can be be run using a [command runner][go-pkg-task#runner] that handles tasks of kind [KindGoModule
][go-pkg-task#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
][go-pkg-elder] reference implementation will provide a new [GoModUpgrade
method][go-pkg-elder#elder.gomodupgrade].
Improvements
Remove unnecessary Wand
parameter in Task
creation functions — #76 ⇄ #77 (⊶ 536556b)
↠ Most Task
creation functions [1][go-pkg-v0.5.0-task/gofumpt#new] [2][go-pkg-v0.5.0-task/goimports#new] [3][go-pkg-v0.5.0-task/golang/build#new] [4][go-pkg-v0.5.0-task/golang/install#new] 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
][go-pkg-task#task] required an [app.Config
struct][go-pkg-v0.5.0-app#config], 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.
0.5.0
This release comes with support for Go 1.16 features like the new install
command behavior and removes the now unnecessary pkger
task runner in favor of the new embed
package and //go:embed
directive.
Features
Task for Go toolchain install
command — #70 ⇄ #71 (⊶ c36e8f3)
↠ As of Go version 1.16 go install $pkg@$version
allows to install commands without affecting the main
module. Additionally commands like go build
and go test
no longer modify go.mod
and go.sum
files by default but report an error if a module requirement or checksum needs to be added or updated (as if the -mod=readonly
flag were used).
This can be used as alternative to the already existing gobin
runner.
To support the go install
command of the Go toolchain, a new Task
has been implemented in the new install
package that can be used through a Go toolchain Runner
.
The task is customizable through the following functions:
WithEnv(env map[string]string) install.Option
— sets the task specific environment.WithModulePath(path string) install.Option
— sets the module import path.WithModuleVersion(version *semver.Version) install.Option
— sets the module version.
Tasks
Updated to "tmpl-go" template repository version 0.7.0
— #72 ⇄ #73 (⊶ 53fd75e)
↠ Updated to "tmpl-go" version 0.7.0 which comes with updates to GitHub Actions and Node development dependencies.
Removed pkger
task in favor of Go 1.16 embed
package — #74 ⇄ #75 (⊶ 1fc1f25)
↠ In #52 a task for the github.com/markbates/pkger Go module was added, a tool for embedding static files into Go binaries.
The issue also includes the “Official Static Assets Embedding“ section which mentions that the task might be removed later on again as soon as Go 1.16 will be released as it comes with toolchain support for embedding static assets (files) through the embed
package. Also see markbates/pkger#114 for more details about the project future of pkger
.
The pkger
package has been removed and the //go:embed
directive should be used instead.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.4.1
This release version fixes a bug that could occur when running the Install
method of the gobin
task runner in minimal environments like containers.
Bug Fixes
Fix missing environment variables in Install
method of gobin
task — #63 ⇄ #62 (⊶ ff54e91)
↠ Fixed possible errors like
build cache is required, but could not be located: GOCACHE is not defined and neither $XDG_CACHE_HOME nor $HOME are defined
when running the method in minimal environments like containers by ensuring that the inherited OS environment is prepended before applying custom environment variables.
Before the Install
method of the gobin
task runner has set the environment of the command that gets executed initially to os.Environ()
, but has overwritten it later on with custom variables configured through the WithEnv(map[string]string)
option.
This change also improves the debugging process by including the combined output (stdout
+ stderr
) in the error when the command execution fails.
Tasks
Go module dependency & GitHub action version updates — #60, #61
↠ Bumped outdated Go module dependencies and GitHub actions to their latest versions:
- #60 (⊶ 3fd3f8b)
actions/setup-node
from v2.1.3 to v2.1.4 - #61 (⊶ 6dd713e)
github.com/magefile/mage
from v1.10.0 to v1.11.0 - This release finally introduces a long-time requested feature: Target functions with arguments!
This allows to pass parameters to targets from the CLI to make functions even more dynamic.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.4.0
This release version introduces a new task for the “mvdan.cc/gofumpt“ Go module command.
Features
Task for “mvdan.cc/gofumpt“ Go module command — #56 ⇄ #57 (⊶ 3273e91)
↠ The mvdan.cc/gofumpt Go module provides the gofumpt
command, a tool that enforces a stricter format than gofmt
and provides additional rules, while being backwards compatible. It is a modified fork of gofmt
so it can be used as a drop-in replacement.
To configure and run the gofumpt
command, a new task.GoModule
has been implemented in the new gofumpt package that can be run using the gobin command runner or any other command runner that handles tasks of kind KindGoModule
.
The task is customizable through the following functions:
WithEnv(map[string]string) gofumpt.Option
— sets the task specific environment.WithExtraArgs(...string) gofumpt.Option
— sets additional arguments to pass to the command.WithExtraRules(bool) gofumpt.Option
— indicates whethergofumpt
‘s extra rules should be enabled. See the repository documentation for a listing of available rules.WithListNonCompliantFiles(bool) gofumpt.Option
— indicates whether files, whose formatting are not conform to the style guide, are listed.WithModulePath(string) gofumpt.Option
— sets the module import path.WithModuleVersion(*semver.Version) gofumpt.Option
— sets the module version.WithPaths(...string) gofumpt.Option
— sets the paths to search for Go source files. By default all directories are scanned recursively starting from the current working directory.WithReportAllErrors(bool) gofumpt.Option
— indicates whether all errors should be printed instead of only the first 10 on different lines.WithSimplify(bool) gofumpt.Option
— indicates whether code should be simplified.
The “elder“ reference implementation provides the new Gofumpt
method.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.3.0
This release version introduces a new task for the “github.com/markbates/pkger“ Go module command and updates for outdated dependencies.
Features
Task for “github.com/markbates/pkger“ Go module command — #52 ⇄ #53 (⊶ 660601d)
↠ The github.com/markbates/pkger Go module provides the pkger
command, a tool for embedding static files into Go binaries.
To configure and run the pkger
command, a new task.GoModule
has been implemented in a the pkger package that can be run using the gobin command runner or any other command runner that handles tasks of kind KindGoModule
.
The task is customizable through the following functions:
WithEnv(env map[string]string) pkger.Option
— sets the task specific environment.WithExtraArgs(extraArgs ...string) pkger.Option
— sets additional arguments to pass to the command.WithIncludes(includes ...string) pkger.Option
— adds the relative paths of files and directories that should be included.
By default the paths will be detected bypkger
itself when used within any of the packages of the target Go module.WithModulePath(path string) pkger.Option
— sets the module import path.WithModuleVersion(version *semver.Version) pkger.Option
— sets the module version.
The “elder“ reference implementation provides the new Pkger
method including the handling of the “monorepo“ workaround.
Official “Static Assets Embedding“
Please note that the pkger project might be superseded and discontinued due to the official Go toolchain support for embedding static assets (files) that will most probably be released with Go version 1.16.
Please see the official draft document and markbates/pkger#114 for more details.
“Monorepo“ Workaround
pkger tries to mimic the Go standard library and the way how the Go toolchain handles modules, but is therefore also affected by its problems and edge cases.
When the pkger
command is used from the root of a Go module repository, the directory where the go.mod
file is located, and there is no valid Go source file, the command will fail because it internally uses the same logic like the list
command of the Go toolchain (go list
).
Therefore a “dummy“ Go source file may need to be created as a workaround. This is mostly only required for repositories that use a “monorepo“ layout where one or more main
packages are placed in a subdirectory relative to the root directory, e.g. apps
or cmd
. For repositories where the root directory already has a Go package, that does not contain any build constraints/tags, or uses a “library“ layout, a “dummy“ file is probably not needed.
Please see markbates/pkger#109 and markbates/pkger#121 for more details.
The new Pkger
method of the “elder“ reference implementation handles the creation of a temporary “dummy“ file that gets deleted automatically when the tasks finishes in order to avoid the need for the user to add such a file to the repository and commit it into the VCS.
Update outdated dependencies — #47, #48
↠ Bumped outdated Go module dependencies to their latest versions:
- #47 (⊶ 41e11b94)
github.com/Masterminds/semver/v3
from 3.1.0 to 3.1.1 — Fixes an issue with generated regular expression operations. - #48 (⊶ 41e11b94)
github.com/imdario/mergo
from 0.3.9 to 0.3.11 — Includes a bunch of bug fixes that were pending, removes unused test code, reverts a faulty PR and announces a code freeze in preparation for a “cleanroom“ implementation with a new API in order to allow the codebase to be maintainable and clear again.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.2.0
This release version comes with a large API breaking change to introduce the new "task" + "runner" based API that uses a “normalized“ naming scheme.
Features
“Task“ API: Simplified usage and “normalized“ naming scheme — #49 ⇄ #51 (⊶ f51a4bf)
↠ With #14 the “abstract“ wand API was introduced with a naming scheme is inspired by the fantasy novel “Harry Potter“ that was used to to define interfaces.
The main motivation was to create a matching naming to the overall “magic“ topic and the actual target project Mage, but in retrospect this is way too abstract and confusing.
The goal of this change was to…
- rewrite the API to make it way easier to use.
- use a “normal“ naming scheme.
- improve all documentations to be more user-scoped and provide guides and examples.
New API Concept
The basic mindset of the API will remain partially the same, but it will be designed around the concept of tasks and the ways to run them.
Command Runner
🅸 task.Runner
is a new base interface that runs a command with parameters in a specific environment. It can be compared to the previous 🅸 cast.Caster
interface, but provides a cleaner method set accepting the new 🅸 task.Task
interface.
- 🅼
Handles() task.Kind
— returns the supported task kind. - 🅼
Run(task.Task) error
— runs a command. - 🅼
Validate() error
— validates the runner.
The new 🅸 task.RunnerExec
interface is a specialized task.Runner
and serves as an abstract representation for a command or action, in most cases a (binary) executable of external commands or Go module main
packages, that provides corresponding information like the path to the executable. It can be compared to the previous BinaryCaster
interface, but also comes with a cleaner method set and a more appropriate name.
- 🅼
FilePath() string
— returns the path to the (binary) command executable.
Tasks
🅸 task.Task
is the new interface that is scoped for Mage “target“ usage. It can be compared to the previous 🅸 spell.Incantation
interface, but provides a smaller method set without Formula() []string
.
- 🅼
Kind() task.Kind
— returns the task kind. - 🅼
Options() task.Options
— returns the task options.
The new 🅸 task.Exec
interface is a specialized task.Task
and serves as an abstract task for an executable command. It can be compared to the previous Binary
interface, but also comes with the new BuildParams() []string
method that enables a more flexible usage by exposing the parameters for command runner like task.RunnerExec
and also allows to compose with other tasks. See the Wikipedia page about the anatomy of a shell CLI for more details about parameters.
- 🅼
BuildParams() []string
— builds the parameters for a command runner where parameters can consist of options, flags and arguments. - 🅼
Env() map[string]string
— returns the task specific environment.
The new 🅸 task.GoModule
interface is a specialized task.Exec
for a executable Go module command. It can be compared to the previous spell.GoModule
interface and the method set has not changed except a renaming of the GoModuleID() *project.GoModuleID
to the more appropriate name ID() *project.GoModuleID
. See the official Go module reference documentation for more details about Go modules.
- 🅼
ID() *project.GoModuleID
— returns the identifier of a Go module.
New API Naming Scheme
The following listing shows the new name concept and how the previous API components can be mapped to the changes:
- Runner — A component that runs a command with parameters in a specific environment, in most cases a (binary) executable of external commands or Go module
main
packages. The current API component that can be compared to runners is 🅸cast.Caster
and its specialized interfaces. - Tasks — A component that is scoped for Mage “target“ usage in order to run a action. The current API component that can be compared to tasks is 🅸
spell.Incantation
and its specialized interfaces.
API Usage
Even though the API has been changed quite heavily, the basic usage almost did not change.
→ A task.Task
can only be run through a task.Runner
!
Before a spell.Incantation
was passed to a cast.Caster
in order to run it, in most cases a (binary) executable of a command that uses the Formula() []string
method of spell.Incantation
to pass the result as parameters.
The new API works the same: A task.Task
is passed to a task.Runner
that calls the BuildParams() []string
method when the runner is specialized for (binary) executable of commands.
Improved Documentations
Before the documentation was mainly scoped on technical details, but lacked more user-friendly sections about topics like the way how to implement own API components, how to compose the “elder“ reference implementation or usage examples for single or monorepo project layouts.
User Guide
Most of the current sections have been rewritten or removed entirely while new sections now provide more user-friendly guides about how to…
- use or compose the “elder“ reference implementation.
- build own tasks and runners using the new API.
- structure repositories independent of the layout, single or “monorepo“.
Usage Examples
Some examples have been added, that are linked and documented in the user guides described above, to show how to…
- use or compose the “elder“ reference implementation.
- build own tasks and runners using the new API.
- structure repositories independent of the layout, single or “monorepo“.
The full changelog is available in the repository
Copyright © 2019-present Sven Greb
0.1.0
⇅ [Show all commits][gh-compare-tag-init_v0.1.0]
This is the initial release version of wand.
The basic project setup, structure and development workflow has been bootstrapped by [the tmpl-go template repository][gh-svengreb/tmpl-go].
The following sections of this version changelog summarize used technologies, explain design decisions and provide an overview of the API and “elder“ reference implementation.
Features
Bootstrap based on “tmpl-go“ template repository — #1, #2, #4, #12 ⇄ #3, #5, #13 (⊶ dbf11bc, f1eee4a, f778fd9, 5d41725)
↠ Bootstrapped the basic project setup, structure and development workflow [from version 0.3.0][gh-svengreb/tmpl-go-rl-v0.3.0] of the [“tmpl-go“ template repository][gh-svengreb/tmpl-go].
Project specific files like the repository hero image, documentations and GitHub issue/PR templates have been adjusted.
Application configuration store — #8 ⇄ #9 (⊶ a233575)
↠ Like described in [the /apps
directory documentation][gh-svengreb/tmpl-go-tree-apps] of the tmpl-go template repository, wand also aims to support the [monorepo][trunkbasedev-monorepos] layout.
In order to manage multiple applications, their information and metadata is recorded in a configuration store where each entry is identified by a unique ID, usually the name of the application. The pkg/app
package provides two interfaces and an unexported struct that implements it that can be used through the exported NewStore() Store
function.
- 🆃
pkg/app.Config
— Astruct
type that holds information and metadata of an application. - 🅸
pkg/app.Store
— A storage that provides methods to record application configurations:Add(*Config)
— Adds a application configuration.Get(string) (*Config, error)
— Returns the application configuration for the given name or nil along with an error when not stored.
- 🆃
appStore
— A storage for application configurations. - 🅵
NewStore() Store
— Creates a new store for application configurations.
Project and VCS repository — #10, #18 ⇄ #11, #19 (⊶ 3e8add2, 3fa84e3)
↠ In [GH-9][gh-svengreb/wand#9] the store and configuration for applications has been implemented. wand applications are not standalone but part of a project which in turn is stored in a repository of [a VCS like Git][git-book-intro-vcs]. In case of wand this can also be a [monorepo][trunkbasedev-monorepos] to manage multiple applications, but there is always only a single project which all these applications are part of.
To store project and VCS repository information, some of the newly implemented packages provide the following types:
- 🆃
pkg/project.Metadata
— Astruct
type that stores information and metadata of a project. - 🆃
pkg/project.GoModuleID
— Astruct
type that stores partial information to identify a [Go module][go-ref-mod]. - 🆃
pkg/vcs.Kind
— Astruct
type that defines the kind of apkg/vcs.Repository
. - 🅸
pkg/vcs.Repository
— Ainterface
type to represents a VCS repository that provides methods to receive repository information:Kind() Kind
— returns the repositorypkg/vcs.Kind
.DeriveVersion() error
— derives the repository version based on thepkg/vcs.Kind
.Version() interface{}
— returns the repository version.
- 🆃
pkg/vcs/git.Git
— Astruct
type that implementspkg/vcs.Repository
to represent a [Git][] repository. - 🆃
pkg/vcs/git.Version
— Astruct
type that stores version information and metadata derived from a [Git][] repository. - 🆃
pkg/vcs/none.None
— Astruct
type that implementspkg/vcs.Repository
to represent a nonexistent repository.
Abstract “task“ API: _spell incantation_, _kind_ and _caster_ — #14 ⇄ #15 (⊶ 2b13b84)
↠ The wand API is inspired by the fantasy novel [“Harry Potter“][wikip-hp] and uses an abstract view to define interfaces. The main motivation to create a matching naming to the overall “magic“ topic and the actual target project [Mage][]. This might be too abstract for some, but is kept understandable insofar as it should allow everyone to use the “task“ API and to derive their own tasks from it.
- 🅸
cast.Caster
— Ainterface
type that casts aspell.Incantation
using a command for a specificspell.Kind
:Cast(spell.Incantation) error
— casts a spell incantation.Handles() spell.Kind
— returns the spell kind that can be casted.Validate() error
— validates the caster command.
- 🅸
cast.BinaryCaster
— Ainterface
type that composescast.Caster
to run commands using a binary executable:GetExec() string
— returns the path to the binary executable of the command.
- 🅸
spell.Incantation
— Ainterface
type that is the abstract representation of parameters for a command or action:Formula() []string
— returns all parameters of a spell.Kind() Kind
— returns the Kind of a spell.Options() interface{}
— return the options of a spell.
- 🅸
cast.Binary
— Ainterface
type that composescast.Caster
for commands which are using a binary executable:Env() map[string]string
— returns additional environment variables.
- 🅸
cast.GoCode
— Ainterface
type that composescast.Caster
for actions that can be casted without acast.Caster
:Cast() (interface{}, error)
— casts itself.
- 🅸
cast.GoModule
— Ainterface
type that composescast.Binary
for commands that are compiled from a [Go module][go-ref-mod]:GoModuleID() *project.GoModuleID
— returns the identifier of a Go module.
- 🆃
spell.Kind
— Astruct
type that defines the kind of a spell.
The API components can be roughly translated to their purpose:
cast.Caster
→ an executable command
It validates the command and defines whichspell.Kind
can be handled by this caster. It could be executed without parameters (spell.Incantation
), but in most cases needs at least one parameter.cast.BinaryCaster
→ a composedcast.Caster
to run commands using a binary executable.
It ensures that the executable file exists and stores information like the path. It could also be executed without parameters (spell.Incantation
), but would not have any effect im many cases.
spell.Incantation
→ the parameters of a executable command
It assemble all parameters based on the given options and ensures the they are correctly formatted for the execution in a shell environment. Except for special incantations likespell.GoCode
a incantation cannot be used alone but must be passed to acast.Caster
that is able to handle thespell.Kind
of this incantation.spell.Binary
→ a composedspell.Incantation
to run commands that are using binary executable.
It can inject or override environment variables in the shell environment in which the the command will be run.spell.GoCode
→ a composedspell.Incantation
for pure Go code instead of a (binary) executable command.
It can “cast itself“, e.g. to simply delete a directory using packages likeos
from the Go standard library. It has been designed this way to also allow such tasks to be handled by the incantation API.spell.GoModule
→ a composedspell.Binary
to run binary commands managed by a [Go module][go-ref-mod], in other words executables installed inGOBIN
or received viago get
.
It requires the module identifier (path@version
) in order to download and run the executable.
Basic “wand“ API — #16 ⇄ #17 (⊶ cc9f7c4)
↠ In [GH-15][gh-svengreb/wand#15] some parts of the wand API have been implemented in form of spell incantations, kinds and casters, inspired by the fantasy novel [“Harry Potter“][wikip-hp] as an abstract view to define interfaces. In [GH-9][gh-svengreb/wand#9] and [GH-11][gh-svengreb/wand#11] the API implementations for an application configuration store as well as project and VCS repository metadata were introduced.
These implementations are usable in a combined form via the main wand API that consists of the following types:
- 🅸
wand.Wand
— Ainterface
type that manages a project and its applications and stores their metadata. Applications are registered using a unique name and the stored metadata can be received based on this name:GetAppConfig(appName string) (app.Config, error)
— returns an application configuration.GetProjectMetadata() project.Metadata
— returns the project metadata.RegisterApp(name, displayName, pathRel string) error
— registers a new application.
- 🆃
wand.ctxKey
— Astruct
type that serves as context key used to wrap awand.Wand
. - 🅵
wand.GetCtxKey() interface{}
— Afunc
type that returns the key used to wrap awand.Wand
. - 🅵
wand.WrapCtx(parentCtx context.Context, wand Wand) context.Context
— Afunc
type that wraps the givenwand.Wand
into the parent context. Usewand.GetCtxKey() interface{}
to receive...