Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package cmd defines the cobra commands for the adr CLI.
// Use AdrCommands to build the full standalone command set, or EmbedCommands
// to embed ADR subcommands (without init-config and version) in another CLI.
package cmd
43 changes: 22 additions & 21 deletions cmd/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,34 @@ import (
"log"
"strconv"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// editCmd represents the edit command.
//
//nolint:exhaustruct,gochecknoglobals
var editCmd = &cobra.Command{
Use: "edit <id>",
Short: "open the adr with number <id> in the default editor",
Run: func(_ *cobra.Command, args []string) {
ctx := context.TODO()
func NewEditCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "edit <id>",
Short: "Open the ADR with number <id> in the default editor",
Long: `Open the ADR with the given number in the default editor.

number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)
The editor is determined by the $EDITOR environment variable. If $EDITOR is
not set, the command will fail.`,
Args: cobra.ExactArgs(1),
Run: func(_ *cobra.Command, args []string) {
ctx := context.TODO()

return
}
number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)

if err := app.Edit(ctx, number); err != nil {
log.Printf("couldn't edit adr %d: %v", number, err)
}
},
}
return
}

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(editCmd)
if err := app.Edit(ctx, conf, number); err != nil {
log.Printf("couldn't edit adr %d: %v", number, err)
}
},
}
}
72 changes: 49 additions & 23 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,59 @@ package cmd
import (
"log"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// initCmd represents the init command.
//
//nolint:exhaustruct,gochecknoglobals
var initCmd = &cobra.Command{
Use: "init [path]",
Short: "initialize the adr path (default is `docs/adr`)",
Args: cobra.MaximumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
path := "docs/adr"

if len(args) > 0 {
path = args[0]
}

if err := app.Init(path); err != nil {
log.Printf("couldn't initialize adr: %v", err)

return
}
},
func NewInitConfigCommand() *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "init [path]",
Short: "Initialize the ADR path (default is `docs/adr`)",
Long: `Initialize the ADR directory and configuration.

Creates the ADR directory, writes .adr.yaml at the project root, and copies
the default ADR and index templates into the directory. The project root is
determined by walking up from the current directory until a .git directory
is found.

The path argument sets the ADR directory relative to the project root
(default: docs/adr).`,
Args: cobra.MaximumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
path := "docs/adr"

if len(args) > 0 {
path = args[0]
}

conf, err := app.InitConfig(path)
if err != nil {
log.Printf("couldn't initialize adr: %v", err)

return
}

if err := app.Init(conf); err != nil {
log.Printf("couldn't initialize adr: %v", err)
}
},
}
}

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(initCmd)
func NewInitCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "init",
Short: "Initialize the ADR path",
Long: `Initialize the ADR directory using the pre-configured path.

Creates the ADR directory and copies the default ADR and index templates into it.`,
Run: func(_ *cobra.Command, args []string) {
if err := app.Init(conf); err != nil {
log.Printf("couldn't initialize adr: %v", err)
}
},
}
}
28 changes: 12 additions & 16 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,20 @@ package cmd
import (
"log"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// listCmd represents the list command.
//
//nolint:exhaustruct,gochecknoglobals
var listCmd = &cobra.Command{
Use: "list",
Short: "list all ADRs with their id, date and status",
Run: func(_ *cobra.Command, _ []string) {
if err := app.List(); err != nil {
log.Printf("couldn't list adrs: %v", err)
}
},
}

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(listCmd)
func NewListCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "list",
Short: "List all ADRs with their id, date and status",
Run: func(_ *cobra.Command, _ []string) {
if err := app.List(conf); err != nil {
log.Printf("couldn't list adrs: %v", err)
}
},
}
}
37 changes: 19 additions & 18 deletions cmd/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@ import (
"log"
"strings"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// newCmd represents the new command.
//
//nolint:exhaustruct,gochecknoglobals
var newCmd = &cobra.Command{
Use: "new [title]",
Aliases: []string{"add", "create"},
Short: "create a new ADR with optional title",
Run: func(_ *cobra.Command, args []string) {
ctx := context.TODO()
title := strings.Join(args, " ")
func NewNewCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "new [title]",
Aliases: []string{"add", "create"},
Short: "Create a new ADR with optional title",
Long: `Create a new ADR with an auto-incremented number and optional title.

if err := app.Create(ctx, title); err != nil {
log.Printf("couldn't create adr: %v", err)
}
},
}
The title can be supplied as arguments or left empty to be filled in later.
After creating the file, it is immediately opened in the default editor
(see $EDITOR).`,
Run: func(_ *cobra.Command, args []string) {
ctx := context.TODO()
title := strings.Join(args, " ")

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(newCmd)
if err := app.Create(ctx, conf, title); err != nil {
log.Printf("couldn't create adr: %v", err)
}
},
}
}
38 changes: 25 additions & 13 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
package cmd

import (
"os"

"github.com/corani/adr/config"
"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands.
//
//nolint:exhaustruct,gochecknoglobals
var rootCmd = &cobra.Command{
Use: "adr",
Short: "A command line tool to maintain Architecture Decision Records",
// EmbedCommands returns the commands suitable for embedding in another CLI.
// The caller is responsible for providing a fully populated `conf`; init-config
// and version are excluded as they are specific to the standalone `adr` CLI.
func EmbedCommands(conf *config.Config) []*cobra.Command {
return []*cobra.Command{
NewInitCommand(conf),
NewNewCommand(conf),
NewListCommand(conf),
NewShowCommand(conf),
NewEditCommand(conf),
NewUpdateCommand(conf),
}
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
// AdrCommands returns the full command set for the standalone `adr` CLI,
// including init-config (which discovers the project root and writes .adr.yaml)
// and version.
func AdrCommands(conf *config.Config) []*cobra.Command {
return []*cobra.Command{
NewInitConfigCommand(),
NewVersionCommand(),
NewNewCommand(conf),
NewListCommand(conf),
NewShowCommand(conf),
NewEditCommand(conf),
NewUpdateCommand(conf),
}
}
44 changes: 22 additions & 22 deletions cmd/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ import (
"log"
"strconv"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// showCmd represents the show command.
//
//nolint:exhaustruct,gochecknoglobals
var showCmd = &cobra.Command{
Use: "show <id>",
Aliases: []string{"view"},
Short: "show the adr with number <id>",
Args: cobra.ExactArgs(1),
Run: func(_ *cobra.Command, args []string) {
number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)
func NewShowCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "show <id>",
Aliases: []string{"view"},
Short: "Show the ADR with number <id>",
Long: `Show the ADR with the given number.

return
}
Prints a summary table (number, date, status, filename) followed by the
rendered markdown body of the ADR.`,
Args: cobra.ExactArgs(1),
Run: func(_ *cobra.Command, args []string) {
number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)

if err := app.Show(number); err != nil {
log.Printf("couldn't show adr %d: %v", number, err)
}
},
}
return
}

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(showCmd)
if err := app.Show(conf, number); err != nil {
log.Printf("couldn't show adr %d: %v", number, err)
}
},
}
}
51 changes: 26 additions & 25 deletions cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,35 @@ import (
"strconv"
"strings"

"github.com/corani/adr/config"
"github.com/corani/adr/internal/app"
"github.com/spf13/cobra"
)

// updateCmd represents the update command.
//
//nolint:exhaustruct,gochecknoglobals
var updateCmd = &cobra.Command{
Use: "update <id> <status>",
Short: "update the adr with number <id> to status <status>",
Args: cobra.ExactArgs(2), //nolint:mnd
Run: func(_ *cobra.Command, args []string) {
number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)

return
}

status := strings.ToLower(args[1])

if err := app.Update(number, status); err != nil {
log.Printf("couldn't update adr %d: %v", number, err)
}
},
}
func NewUpdateCommand(conf *config.Config) *cobra.Command {
//nolint:exhaustruct
return &cobra.Command{
Use: "update <id> <status>",
Short: "Update the ADR with number <id> to status <status>",
Long: `Update the status of the ADR with the given number.

Valid statuses are: proposed, accepted, deprecated, superseded.

The index (README.md) is regenerated automatically after the update.`,
Args: cobra.ExactArgs(2), //nolint:mnd
Run: func(_ *cobra.Command, args []string) {
number, err := strconv.Atoi(args[0])
if err != nil {
log.Printf("invalid argument: %v", err)

return
}

status := strings.ToLower(args[1])

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(updateCmd)
if err := app.Update(conf, number, status); err != nil {
log.Printf("couldn't update adr %d: %v", number, err)
}
},
}
}
Loading
Loading