Skip to content

Commit c886be6

Browse files
committed
initial commit
0 parents  commit c886be6

File tree

5 files changed

+222
-0
lines changed

5 files changed

+222
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# ADR Go
2+
A minimalist command line tool written in Go to work with [Architecture Decision Records](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) (ADRs).
3+
4+
Greatly inspired by the [adr-tools](https://github.com/npryce/adr-tools) with all of the added benefits of using the Go instead of Bash.
5+
6+
# Quick start
7+
## Installing adr
8+
9+
## Initializing adr
10+
11+
## Creating a new ADR

commands.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"github.com/fatih/color"
5+
"github.com/urfave/cli"
6+
)
7+
8+
func setCommands(app *cli.App) {
9+
app.Commands = []cli.Command{
10+
{
11+
Name: "new",
12+
Aliases: []string{"c"},
13+
Usage: "Create a new ADR",
14+
Flags: []cli.Flag{},
15+
Action: func(c *cli.Context) error {
16+
currentConfig := getConfig()
17+
currentConfig.CurrentAdr++
18+
updateConfig(currentConfig)
19+
newAdr(currentConfig, c.Args())
20+
return nil
21+
},
22+
},
23+
24+
{
25+
Name: "init",
26+
Aliases: []string{"i"},
27+
Usage: "Initializes the ADR configurations",
28+
UsageText: "adr init /home/user/adrs",
29+
Description: "Initializes the ADR configuration with an optional ADR base directory\n This is a a prerequisite to running any other adr sub-command",
30+
Action: func(c *cli.Context) error {
31+
initDir := c.Args().First()
32+
if initDir == "" {
33+
initDir = adrDefaultBaseFolder
34+
}
35+
color.Green("Initializing ADR base at " + initDir)
36+
initBaseDir(initDir)
37+
initConfig(initDir)
38+
initTemplate()
39+
return nil
40+
},
41+
},
42+
}
43+
}

context.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"html/template"
6+
"io/ioutil"
7+
"os"
8+
"os/user"
9+
"path/filepath"
10+
"strconv"
11+
"strings"
12+
"time"
13+
14+
"github.com/fatih/color"
15+
)
16+
17+
// AdrConfig ADR configuration, loaded and used by each sub-command
18+
type AdrConfig struct {
19+
BaseDir string `json:"base_directory"`
20+
CurrentAdr int `json:"current_id"`
21+
}
22+
23+
// Adr basic structure
24+
type Adr struct {
25+
Number int
26+
Title string
27+
Date string
28+
Status AdrStatus
29+
}
30+
31+
// AdrStatus type
32+
type AdrStatus string
33+
34+
// ADR status enums
35+
const (
36+
PROPOSED AdrStatus = "Proposed"
37+
ACCEPTED AdrStatus = "Accepted"
38+
DEPRECATED AdrStatus = "Deprecated"
39+
SUPERSEDED AdrStatus = "Superseded"
40+
)
41+
42+
var usr, err = user.Current()
43+
var adrConfigFolderName = ".adr"
44+
var adrConfigFileName = "config.json"
45+
var adrConfigTemplateName = "template.md"
46+
var adrConfigFolderPath = filepath.Join(usr.HomeDir, adrConfigFolderName)
47+
var adrConfigFilePath = filepath.Join(adrConfigFolderPath, adrConfigFileName)
48+
var adrTemplateFilePath = filepath.Join(adrConfigFolderPath, adrConfigTemplateName)
49+
var adrDefaultBaseFolder = filepath.Join(usr.HomeDir, "adr")
50+
51+
func initBaseDir(baseDir string) {
52+
if _, err := os.Stat(baseDir); os.IsNotExist(err) {
53+
os.Mkdir(baseDir, 0744)
54+
} else {
55+
color.Red(baseDir + " already exists, skipping folder creation")
56+
}
57+
}
58+
59+
func initConfig(baseDir string) {
60+
if _, err := os.Stat(adrConfigFolderPath); os.IsNotExist(err) {
61+
os.Mkdir(adrConfigFolderPath, 0744)
62+
}
63+
config := AdrConfig{baseDir, 0}
64+
bytes, err := json.MarshalIndent(config, "", " ")
65+
if err != nil {
66+
panic(err)
67+
}
68+
ioutil.WriteFile(adrConfigFilePath, bytes, 0644)
69+
}
70+
71+
func initTemplate() {
72+
body := []byte(`
73+
# {{.Number}}. {{.Title}}
74+
======
75+
Date: {{.Date}}
76+
77+
## Status
78+
======
79+
{{.Status}}
80+
81+
## Context
82+
======
83+
84+
## Decision
85+
======
86+
87+
## Consequences
88+
======
89+
90+
`)
91+
92+
ioutil.WriteFile(adrTemplateFilePath, body, 0644)
93+
}
94+
95+
func updateConfig(config AdrConfig) {
96+
bytes, err := json.MarshalIndent(config, "", " ")
97+
if err != nil {
98+
panic(err)
99+
}
100+
ioutil.WriteFile(adrConfigFilePath, bytes, 0644)
101+
}
102+
103+
func getConfig() AdrConfig {
104+
var currentConfig AdrConfig
105+
106+
bytes, err := ioutil.ReadFile(adrConfigFilePath)
107+
if err != nil {
108+
color.Red("No ADR configuration is found!")
109+
color.HiGreen("Start by initializing ADR configuration, check 'adr init --help' for more help")
110+
os.Exit(1)
111+
}
112+
113+
json.Unmarshal(bytes, &currentConfig)
114+
return currentConfig
115+
}
116+
117+
func newAdr(config AdrConfig, adrName []string) {
118+
adr := Adr{
119+
Title: strings.Join(adrName, " "),
120+
Date: time.Now().Format("02-01-2006 15:04:05"),
121+
Number: config.CurrentAdr,
122+
Status: PROPOSED,
123+
}
124+
template, err := template.ParseFiles(adrTemplateFilePath)
125+
if err != nil {
126+
panic(err)
127+
}
128+
adrFileName := strconv.Itoa(adr.Number) + "-" + strings.Join(strings.Split(strings.Trim(adr.Title, "\n \t"), " "), "-") + ".md"
129+
f, err := os.Create(filepath.Join(config.BaseDir, adrFileName))
130+
if err != nil {
131+
panic(err)
132+
}
133+
template.Execute(f, adr)
134+
f.Close()
135+
}

flags.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package main
2+
3+
import (
4+
"github.com/urfave/cli"
5+
)
6+
7+
func setFlags(app *cli.App) {
8+
app.Flags = []cli.Flag{}
9+
}

main.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
7+
"github.com/urfave/cli"
8+
)
9+
10+
func main() {
11+
12+
app := cli.NewApp()
13+
app.Name = "adr"
14+
app.Usage = "Work with Architecture Decision Records (ADRs)"
15+
app.Version = "0.1.0"
16+
17+
setFlags(app)
18+
setCommands(app)
19+
20+
err := app.Run(os.Args)
21+
if err != nil {
22+
log.Fatal(err)
23+
}
24+
}

0 commit comments

Comments
 (0)