diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6065347..784292f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,6 +18,8 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v6 + with: + fetch-tags: true - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff - uses: actions/setup-go@v6 with: diff --git a/Justfile b/Justfile index 8fbc486..a29060a 100644 --- a/Justfile +++ b/Justfile @@ -2,6 +2,7 @@ set shell := ["bash", "-u", "-c"] export scripts := ".github/workflows/scripts" export GOBIN := `echo $PWD/.bin` +export TAG := `git describe --tags $(git rev-list --tags --max-count=1)` # print available commands [private] diff --git a/go.mod b/go.mod index 0ece745..8a6d784 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/shoenig/ssh-key-sync go 1.26 require ( + cattlecloud.net/go/babycli v0.2.0 github.com/hashicorp/go-set/v3 v3.0.1 github.com/shoenig/go-landlock v1.3.0 github.com/shoenig/test v1.12.2 @@ -10,6 +11,7 @@ require ( ) require ( + cattlecloud.net/go/stacks v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gojuno/minimock/v3 v3.4.7 // indirect github.com/google/go-cmp v0.6.0 // indirect diff --git a/go.sum b/go.sum index 46a7a9e..8783603 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +cattlecloud.net/go/babycli v0.2.0 h1:niw4uPiFQT7bekq8OJ3LoiIsz2B7L6EZcO+esMx9AP0= +cattlecloud.net/go/babycli v0.2.0/go.mod h1:IhC9GNNMMlDr5sx/lMFBDa1d7jvkI1sluTPsKbpvoAU= +cattlecloud.net/go/stacks v1.1.0 h1:uXnOnluwPT+3IfRDzTmkEP8RCfToBeNremjahViWUhY= +cattlecloud.net/go/stacks v1.1.0/go.mod h1:BD7LcLq19hHEyA+oQOrInqmjjiCccCcVTIxt8eEmW4M= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= diff --git a/internal/command/cmd.go b/internal/command/cmd.go index 127ef3f..a7e8a3c 100644 --- a/internal/command/cmd.go +++ b/internal/command/cmd.go @@ -1,22 +1,56 @@ package command import ( - "errors" + "fmt" + "os" + "cattlecloud.net/go/babycli" "github.com/shoenig/ssh-key-sync/internal/config" "github.com/shoenig/ssh-key-sync/internal/netapi" "github.com/shoenig/ssh-key-sync/internal/ssh" + "github.com/shoenig/ssh-key-sync/version" ) -func Start(args []string) error { - arguments := config.ParseArguments(args[0], args[1:]) - if arguments.GitHubUser == "" { - arguments.Usage() - return errors.New("missing required argument(s)") - } +func Invoke(args []string) babycli.Code { + return babycli.New(&babycli.Configuration{ + Arguments: args, + Version: version.Version, + Top: &babycli.Component{ + Name: "ssh-key-sync", + Description: "Sync SSH public keys from GitHub to authorized_keys", + Flags: babycli.Flags{ + {Long: "verbose", Short: "v", Type: babycli.BooleanFlag, Help: "print verbose logging"}, + {Long: "prune", Short: "p", Type: babycli.BooleanFlag, Help: "delete all keys not found in GitHub"}, + {Long: "system-user", Short: "u", Type: babycli.StringFlag, Help: "specify the unix system user"}, + {Long: "authorized-keys", Type: babycli.StringFlag, Help: "override the output authorized_keys file"}, + {Long: "github-user", Short: "g", Type: babycli.StringFlag, Require: true, Help: "specify the GitHub user"}, + {Long: "github-api", Type: babycli.StringFlag, Help: "specify the GitHub API endpoint"}, + }, + Function: run, + }, + }).Run() +} + +func run(c *babycli.Component) babycli.Code { + githubUser := c.GetString("github-user") + + cfg := config.NewArguments( + c.GetBool("verbose"), + c.GetBool("prune"), + c.GetString("system-user"), + c.GetString("authorized-keys"), + githubUser, + c.GetString("github-api"), + ) reader := ssh.NewKeysReader() - githubClient := netapi.NewGithubClient(arguments) - exe := NewExec(arguments.Prune, arguments.Verbose, reader, githubClient) - return exe.Execute(arguments) + githubClient := netapi.NewGithubClient(cfg) + exe := NewExec(cfg.Prune, cfg.Verbose, reader, githubClient) + + if err := exe.Execute(cfg); err != nil { + fmt.Fprintf(os.Stderr, "unable to execute: %v", err) + return babycli.Failure + } + + return babycli.Success } diff --git a/internal/config/arguments.go b/internal/config/arguments.go index 9cb70cd..4c06275 100644 --- a/internal/config/arguments.go +++ b/internal/config/arguments.go @@ -43,6 +43,23 @@ func defaultUser() string { return current } +func NewArguments(verbose, prune bool, systemUser, authorizedKeys, githubUser, githubAPI string) Arguments { + if systemUser == "" { + systemUser = defaultUser() + } + if githubAPI == "" { + githubAPI = "https://api.github.com" + } + return Arguments{ + Verbose: verbose, + Prune: prune, + SystemUser: systemUser, + AuthorizedKeys: authorizedKeys, + GitHubUser: githubUser, + GitHubAPI: githubAPI, + } +} + func ParseArguments(program string, args []string) Arguments { flags := flag.NewFlagSet(program, flag.ContinueOnError) var arguments Arguments diff --git a/main.go b/main.go index db79a3f..635abcb 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,14 @@ package main import ( - "fmt" "os" + "cattlecloud.net/go/babycli" "github.com/shoenig/ssh-key-sync/internal/command" ) func main() { - if err := command.Start(os.Args); err != nil { - fmt.Println("[fatal]", err) - os.Exit(1) - } + args := babycli.Arguments() + rc := command.Invoke(args) + os.Exit(rc) } diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000..7b6d867 --- /dev/null +++ b/version/version.go @@ -0,0 +1,3 @@ +package version + +var Version = "deveopment"