Contributions are welcome, whether that is reporting an issue, proposing a fix, or improving
the documentation. ldo-go is the Go port of the Python ldo, which is the reference: a new
command belongs there first, and a difference between the two is a bug unless
docs/differences.md says why.
Working with an AI coding assistant? Its instructions are in AI.md, which
CLAUDE.md imports. They are the conventions for people too.
- Fork the repository and branch from
main. - Install Go (the version in
go.mod, or later) and just. - Make your change, with tests.
- Run
just check: gofmt, go vet, and the tests with coverage at or above the floor in the justfile.just ciruns staticcheck and govulncheck too. - Open a pull request using the template. CI runs
just cion Linux, and the tests on macOS and Windows; all of it must pass to merge.
Security issues are the exception: report those privately, as described in SECURITY.md.
- Keep the layering, which
internal/project/layering_test.goenforces:internal/coreis vendor-neutral, and depends on nothing else of ours. Put a shared helper here rather than copying it into a second package.- Each vendor (
internal/microsoft,internal/servicenow,internal/atlassian,internal/terraform) has a shared layer for what all of its features need, and each feature package under it depends oncoreand that layer only. A composite (internal/microsoft/devices) may also use the features it combines. internal/clisits on top of everything, and nothing imports it. It parses, calls a client, and renders: no logic.
- Library packages return
errserrors with a hint saying what to do, and never exit or print. Onlyinternal/cliturns errors into messages and exit codes. - Everything reads. A new command that writes to a tenant or an instance needs discussion in an issue first. Secrets come from the environment, never the config file or the command line.
- Never log or print an access token.
auth.AccessToken, and every credential type, keep the secret out ofStringandGoString; keep it that way. - Data goes to stdout, and notes, warnings and errors go to stderr, through
render.Console, so output can be piped. - Keep the dependencies to those in
go.mod. Anything else needs a good reason. - Everything must be testable, and tests must not touch the network, a real
azor a real clock. Inject the HTTP client, the runner, the environment and the clock, and use the fakes ininternal/fakes:httpfake,azfake,clockfake, and one per service. - Never hard-code the tool's names: they come from
internal/core/brand. - Use UK English and plain ASCII in code, comments and docs: no smart quotes, em or en dashes, or ellipsis glyphs. A test checks for the dashes.
- Never include real tokens, tenant ids, subscription ids or host names in code, tests or
issues. Use the placeholder GUIDs and
corp.examplenames the tests already use. - Keep coverage up, and never lower the floor to get a change in.
When you add or change a command, option or exit code, document it on its page in docs/,
record its JSON shape (just record-json), and add a line to CHANGELOG.md, in the same
pull request. A test runs every ldo-go example in the docs with --help and follows every
link, so a renamed command or option shows up there.
By contributing, you agree that your contributions are licensed under the MIT Licence that covers the project.