├── .go-version ├── proto ├── buf.yaml └── buf.lock ├── Dockerfile ├── cli ├── run_default.go ├── run_darwin.go ├── color.go ├── run_linux.go ├── error.go ├── generate_docs_default.go ├── version.go ├── main_test.go ├── version_test.go ├── text.go ├── main.go ├── switch.go ├── generate_docs.go ├── console.go ├── dispatch.go ├── login.go ├── verification.go ├── style.go ├── log.go ├── switch_test.go ├── any.go ├── any_test.go ├── init_test.go ├── config.go ├── run_test.go ├── python.go ├── init.go ├── run.go └── tui.go ├── main.go ├── .gitignore ├── .github └── workflows │ ├── release.yml │ └── build.yml ├── Makefile ├── README.md ├── go.mod ├── .goreleaser.yml └── go.sum /.go-version: -------------------------------------------------------------------------------- 1 | 1.22.0 2 | -------------------------------------------------------------------------------- /proto/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | deps: 3 | - buf.build/stealthrocket/dispatch-proto 4 | breaking: 5 | use: 6 | - FILE 7 | lint: 8 | use: 9 | - DEFAULT 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.22.0-alpine3.19 2 | RUN apk update 3 | RUN apk add --no-cache ca-certificates 4 | ENV CGO_ENABLED=0 5 | COPY go.mod go.sum . 6 | COPY . . 7 | RUN go build -o /bin/dispatch . 8 | ENTRYPOINT ["/bin/dispatch"] 9 | -------------------------------------------------------------------------------- /cli/run_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !darwin 2 | 3 | package cli 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | ) 9 | 10 | func setSysProcAttr(attr *syscall.SysProcAttr) {} 11 | 12 | func killProcess(process *os.Process, _ os.Signal) { 13 | process.Kill() 14 | } 15 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dispatchrun/dispatch/cli" 7 | ) 8 | 9 | func main() { 10 | if err := cli.Main(); err != nil { 11 | // The error is logged by the CLI library. 12 | // No need to log here too. 13 | os.Exit(1) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cli/run_darwin.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | func setSysProcAttr(attr *syscall.SysProcAttr) { 9 | attr.Setpgid = true 10 | } 11 | 12 | func killProcess(process *os.Process, signal os.Signal) { 13 | // Sending the signal to -pid sends it to all processes 14 | // in the process group. 15 | _ = syscall.Kill(-process.Pid, signal.(syscall.Signal)) 16 | } 17 | -------------------------------------------------------------------------------- /cli/color.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import "github.com/charmbracelet/lipgloss" 4 | 5 | var ( 6 | defaultColor = lipgloss.NoColor{} 7 | 8 | // See https://www.hackitu.de/termcolor256/ 9 | grayColor = lipgloss.ANSIColor(102) 10 | redColor = lipgloss.ANSIColor(160) 11 | greenColor = lipgloss.ANSIColor(34) 12 | yellowColor = lipgloss.ANSIColor(142) 13 | magentaColor = lipgloss.ANSIColor(127) 14 | ) 15 | -------------------------------------------------------------------------------- /cli/run_linux.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | func setSysProcAttr(attr *syscall.SysProcAttr) { 9 | attr.Setpgid = true 10 | attr.Pdeathsig = syscall.SIGTERM 11 | } 12 | 13 | func killProcess(process *os.Process, signal os.Signal) { 14 | // Sending the signal to -pid sends it to all processes 15 | // in the process group. 16 | _ = syscall.Kill(-process.Pid, signal.(syscall.Signal)) 17 | } 18 | -------------------------------------------------------------------------------- /cli/error.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import "fmt" 4 | 5 | type authError struct{} 6 | 7 | func (authError) Error() string { 8 | const message = "Authentication error" 9 | var detail string 10 | switch DispatchApiKeyLocation { 11 | case "env": 12 | detail = "check DISPATCH_API_KEY environment variable" 13 | case "cli": 14 | detail = "check the -k,--api-key command-line option" 15 | default: 16 | detail = "please login again using: dispatch login" 17 | } 18 | return fmt.Sprintf("%s (%s)", message, detail) 19 | } 20 | -------------------------------------------------------------------------------- /cli/generate_docs_default.go: -------------------------------------------------------------------------------- 1 | //go:build !docs 2 | 3 | package cli 4 | 5 | import "github.com/spf13/cobra" 6 | 7 | const DispatchCmdLong = `Welcome to Dispatch! 8 | 9 | To get started, use the login command to authenticate with Dispatch or create an account. 10 | 11 | Documentation: https://docs.dispatch.run 12 | Discord: https://dispatch.run/discord 13 | Support: support@dispatch.run 14 | ` 15 | 16 | const RunExampleText = " dispatch run [options] -- " 17 | 18 | func generateDocs(_ *cobra.Command, _ string) { 19 | // do nothing if the build tag "docs" is not set 20 | } 21 | -------------------------------------------------------------------------------- /proto/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v1 3 | deps: 4 | - remote: buf.build 5 | owner: bufbuild 6 | repository: protovalidate 7 | commit: e097f827e65240ac9fd4b1158849a8fc 8 | digest: shake256:f19252436fd9ded945631e2ffaaed28247a92c9015ccf55ae99db9fb3d9600c4fdb00fd2d3bd7701026ec2fd4715c5129e6ae517c25a59ba690020cfe80bf8ad 9 | - remote: buf.build 10 | owner: stealthrocket 11 | repository: dispatch-proto 12 | commit: 639d52c5db754187a9461d96d783c093 13 | digest: shake256:0fc989737c9db14c41feab7f2dc847b9cf7949cdb1852e3a5337dbb99d909a38acd9211b60501274cac55924ea18c2b18889a7087183ab5d850e79e3b4c3eaed 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | /build 11 | /dispatch 12 | 13 | # Test binary, built with `go test -c` 14 | *.test 15 | *.py 16 | 17 | # Output of the go coverage tool, specifically when used with LiteIDE 18 | *.out 19 | 20 | # Dependency directories (remove the comment below to include it) 21 | vendor/ 22 | 23 | # Go workspace file 24 | go.work 25 | go.work.sum 26 | 27 | # goreleaser 28 | goreleaser/ 29 | 30 | # Emacs 31 | *~ 32 | 33 | # Secrets 34 | .netrc 35 | 36 | .dispatch 37 | 38 | docs/ 39 | -------------------------------------------------------------------------------- /cli/version.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "runtime/debug" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | func versionCommand() *cobra.Command { 10 | return &cobra.Command{ 11 | Use: "version", 12 | Short: "Print the version", 13 | RunE: func(cmd *cobra.Command, args []string) error { 14 | // Match dispatch -v,--version output: 15 | cmd.Println("dispatch version " + version()) 16 | return nil 17 | }, 18 | } 19 | } 20 | 21 | func version() string { 22 | version := "devel" 23 | if info, ok := debug.ReadBuildInfo(); ok { 24 | switch info.Main.Version { 25 | case "": 26 | case "(devel)": 27 | default: 28 | version = info.Main.Version 29 | } 30 | for _, setting := range info.Settings { 31 | if setting.Key == "vcs.revision" { 32 | version += " " + setting.Value 33 | } 34 | } 35 | } 36 | return version 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Stable release of the Dispatch CLI 2 | name: release 3 | 4 | on: 5 | push: 6 | tags: 7 | - "v*" 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | goreleaser: 14 | env: 15 | GH_TOKEN_HOMEBREW_DISPATCH: ${{ secrets.GH_TOKEN_HOMEBREW_DISPATCH }} 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | 22 | - uses: actions/setup-go@v4 23 | with: 24 | go-version-file: .go-version 25 | - uses: goreleaser/goreleaser-action@v4 26 | with: 27 | distribution: goreleaser 28 | version: latest 29 | args: release --clean 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | GH_TOKEN_HOMEBREW_DISPATCH: ${{ env.GH_TOKEN_HOMEBREW_DISPATCH }} 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test lint fmt dispatch clean image push 2 | 3 | BUILD = build/$(GOOS)/$(GOARCH) 4 | GOOS ?= $(shell go env GOOS) 5 | GOARCH ?= $(shell go env GOARCH) 6 | GOEXE ?= $(shell go env GOEXE) 7 | GO ?= go 8 | 9 | DOCKER ?= docker 10 | TAG ?= $(shell git log --pretty=format:'%h' -n 1) 11 | REGISTRY ?= 714918108619.dkr.ecr.us-west-2.amazonaws.com 12 | DISPATCH = $(BUILD)/dispatch$(GOEXE) 13 | IMAGE = $(REGISTRY)/dispatch:$(TAG) 14 | 15 | test: dispatch 16 | $(GO) test ./... 17 | 18 | test-cover: dispatch 19 | $(GO) test -cover ./... 20 | 21 | lint: 22 | golangci-lint run ./... 23 | 24 | fmt: 25 | $(GO) fmt ./... 26 | 27 | dispatch: 28 | $(GO) build -o $(DISPATCH) . 29 | 30 | clean: 31 | rm -rf ./build 32 | 33 | image: 34 | $(DOCKER) build -t $(IMAGE) . 35 | 36 | push: image 37 | $(DOCKER) push $(IMAGE) 38 | 39 | update: 40 | for ref in $$(yq -r '.deps[] | .remote + "/gen/go/" + .owner + "/" + .repository + "/protocolbuffers/go@" + .commit' proto/buf.lock); do go get $$ref; done 41 | go mod tidy 42 | 43 | dispatch-docs: 44 | ${GO} build -tags docs -o ${DISPATCH} . 45 | ${DISPATCH} 46 | -------------------------------------------------------------------------------- /cli/main_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var expectedCommands = []string{"login", "switch [organization]", "verification", "run", "version", "init