Skip to content

Commit e41d1be

Browse files
authored
feat: first iteration of the CLI (#3)
1 parent 5beaabf commit e41d1be

File tree

13 files changed

+322
-5
lines changed

13 files changed

+322
-5
lines changed

.github/workflows/release.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: "Build CLI"
2+
on:
3+
release:
4+
types: [created]
5+
6+
permissions:
7+
contents: write
8+
packages: write
9+
10+
jobs:
11+
release-linux-amd64:
12+
name: release linux/amd64
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- uses: wangyoucao577/go-release-action@v1
18+
with:
19+
github_token: ${{ secrets.GITHUB_TOKEN }}
20+
goos: linux
21+
goarch: amd64
22+
project_path: ./cli

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cli/actions
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
6+
jobs:
7+
deploy:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout code
11+
uses: actions/checkout@v3
12+
13+
- name: Fly!
14+
uses: superfly/flyctl-actions/[email protected]
15+
run: flyctl deploy --remote-only
16+
env:
17+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

cli/core/domain.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package core
2+
3+
type Secret struct {
4+
Description string `yaml:"description"`
5+
}
6+
7+
type meta struct {
8+
Id string `yaml:"id"`
9+
Name string `yaml:"name"`
10+
Description string `yaml:"description"`
11+
Secrets map[string]Secret `yaml:"secrets"`
12+
}
13+
14+
type Workflow struct {
15+
Meta meta
16+
Contents string
17+
}

cli/core/github.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package core
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
)
8+
9+
func FetchWorkflowFileContents(id *string) (*string, error) {
10+
response, error := http.Get("https://gist.githubusercontent.com/akoenig/c8173bfdb87f8809a9ab731bfed99a6f/raw/81cea0b7f6621ced4c34a49a7e679a07c5a7ceed/test.yaml")
11+
// response, error := http.Get("https://api.github.com/repos/openformation/actions/contents/workflows/" + *id + ".yml")
12+
13+
if error != nil {
14+
return nil, error
15+
}
16+
17+
if response.StatusCode == 404 {
18+
return nil, fmt.Errorf("the given workflow doesn't exist")
19+
}
20+
21+
defer response.Body.Close()
22+
23+
body, error := io.ReadAll(response.Body)
24+
25+
if error != nil {
26+
return nil, fmt.Errorf("reading the response from GitHub failed")
27+
}
28+
29+
contents := string(body)
30+
31+
return &contents, nil
32+
}

cli/core/installer.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package core
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"path"
8+
)
9+
10+
func InstallWorkflow(workflow *Workflow) error {
11+
cwd, error := os.Getwd()
12+
13+
if error != nil {
14+
return fmt.Errorf("failed to get the current working directory")
15+
}
16+
17+
pathOfWorkflowFiles := path.Join(cwd, ".github", "workflows")
18+
pathOfWorkflowFile := path.Join(pathOfWorkflowFiles, fmt.Sprintf("%s.yaml", workflow.Meta.Id))
19+
20+
{
21+
_, error := os.Stat(pathOfWorkflowFile)
22+
23+
if errors.Is(error, os.ErrExist) {
24+
return fmt.Errorf("the workflow already exists")
25+
} else if !errors.Is(error, os.ErrNotExist) {
26+
return fmt.Errorf("checking if the workflow already exists failed")
27+
}
28+
}
29+
30+
{
31+
error := os.MkdirAll(pathOfWorkflowFiles, os.ModePerm)
32+
33+
if error != nil {
34+
return fmt.Errorf("creating the directory for the workflow files failed")
35+
}
36+
37+
}
38+
39+
{
40+
error := os.WriteFile(pathOfWorkflowFile, []byte(workflow.Contents), os.ModePerm)
41+
42+
if error != nil {
43+
return fmt.Errorf("writing the workflow file failed")
44+
}
45+
46+
}
47+
48+
return nil
49+
}

cli/core/parser.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package core
2+
3+
import (
4+
"strings"
5+
6+
"github.com/adrg/frontmatter"
7+
)
8+
9+
func ParseWorkflowFile(rawContents *string) (*Workflow, error) {
10+
meta := meta{}
11+
12+
rest, error := frontmatter.Parse(strings.NewReader(*rawContents), &meta)
13+
14+
if error != nil {
15+
return nil, error
16+
}
17+
18+
contents := string(rest)
19+
20+
workflow := Workflow{
21+
Meta: meta,
22+
Contents: contents,
23+
}
24+
25+
return &workflow, nil
26+
}

cli/go.mod

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module openformation/actions
2+
3+
go 1.22.1
4+
5+
require (
6+
github.com/adrg/frontmatter v0.2.0
7+
github.com/fatih/color v1.16.0
8+
)
9+
10+
require (
11+
github.com/BurntSushi/toml v0.3.1 // indirect
12+
github.com/mattn/go-colorable v0.1.13 // indirect
13+
github.com/mattn/go-isatty v0.0.20 // indirect
14+
golang.org/x/sys v0.14.0 // indirect
15+
gopkg.in/yaml.v2 v2.3.0 // indirect
16+
)

cli/go.sum

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2+
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3+
github.com/adrg/frontmatter v0.2.0 h1:/DgnNe82o03riBd1S+ZDjd43wAmC6W35q67NHeLkPd4=
4+
github.com/adrg/frontmatter v0.2.0/go.mod h1:93rQCj3z3ZlwyxxpQioRKC1wDLto4aXHrbqIsnH9wmE=
5+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
6+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
7+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
8+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
9+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
10+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
11+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
12+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
14+
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
15+
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
16+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
17+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
18+
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
19+
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

cli/main.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"openformation/actions/core"
7+
"os"
8+
9+
"github.com/fatih/color"
10+
)
11+
12+
func handleError(error error) {
13+
if error != nil {
14+
output := color.New(color.FgRed)
15+
16+
output.Println()
17+
output.Println(fmt.Sprintf("\n ❌ An error occurred while installing the workflow: %s \n", error.Error()))
18+
19+
os.Exit(1)
20+
}
21+
}
22+
23+
func main() {
24+
id := flag.String("id", "", "The ID of the workflow you want to install.")
25+
26+
flag.Parse()
27+
28+
if *id == "" {
29+
flag.PrintDefaults()
30+
31+
os.Exit(1)
32+
}
33+
34+
output := color.New(color.FgHiCyan)
35+
output.Println(fmt.Sprintf("\n 🚀 Installing workflow '%s' ...", *id))
36+
37+
contents, error := core.FetchWorkflowFileContents(id)
38+
39+
handleError(error)
40+
41+
workflow, error := core.ParseWorkflowFile(contents)
42+
43+
handleError(error)
44+
45+
error = core.InstallWorkflow(workflow)
46+
47+
handleError(error)
48+
49+
output.Add(color.FgGreen).Println("\n ✅ Workflow installed successfully! Have fun! 🎉")
50+
output.Println()
51+
52+
if workflow.Meta.Secrets != nil {
53+
output.Add(color.FgRed).Println("\n Attention!")
54+
output.Add(color.Reset).Println("\n This workflow requires you to add the following secrets. Head over to your repository settings to add them:")
55+
output.Println()
56+
57+
for key, secret := range workflow.Meta.Secrets {
58+
output.Add(color.FgYellow).Print(fmt.Sprintf(" %s: ", key))
59+
output.Add(color.Reset).Printf("%s\n", secret.Description)
60+
}
61+
62+
output.Println()
63+
64+
output.Add(color.ResetBlinking)
65+
}
66+
}

0 commit comments

Comments
 (0)