├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── test.yml │ └── release.yml └── CODEOWNERS ├── .dockerignore ├── _image └── logo.png ├── .mergify.yml ├── providers ├── gcp │ ├── testdata │ │ └── gcloud │ ├── gcp_test.go │ └── gcp.go ├── providers.go ├── google │ └── google.go ├── youtube │ └── youtube.go ├── pagerduty │ └── pagerduty.go ├── aws │ └── aws.go ├── jira │ └── jira.go ├── circleci │ └── circleci.go ├── firebase │ └── firebase.go ├── github │ └── github.go ├── azure │ └── azure.go ├── datadog │ └── datadog.go └── googleworkspace │ └── googleworkspace.go ├── Makefile ├── cli ├── consts.go ├── version.go ├── root.go ├── google.go ├── youtube.go ├── github.go ├── circleci.go ├── pagerduty.go ├── azure.go ├── googleworkspace.go ├── datadog.go ├── jira.go ├── firebase.go ├── aws.go └── gcp.go ├── go.mod ├── .gitignore ├── alias ├── testdata │ └── config.toml ├── alias_test.go └── alias.go ├── Dockerfile ├── .config └── default.toml ├── .goreleaser.yml ├── cmd └── biko │ └── main.go ├── browser └── browser.go ├── .golangci.yml ├── go.sum ├── LICENSE └── README.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What 2 | 3 | ## Why -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git 2 | /bin 3 | /_image 4 | /.circleci 5 | /.github -------------------------------------------------------------------------------- /_image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KeisukeYamashita/biko/HEAD/_image/logo.png -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: Automatic merge on approval 3 | conditions: 4 | - "#approved-reviews-by>=1" 5 | actions: 6 | merge: 7 | method: merge 8 | -------------------------------------------------------------------------------- /providers/gcp/testdata/gcloud: -------------------------------------------------------------------------------- 1 | [core] 2 | account = biko.is.nice.tool@maybe.com 3 | project = i-am-biko 4 | 5 | [compute] 6 | zone = asia-roppongi-c 7 | region = asia-minatoku 8 | 9 | [container] 10 | cluster = biko-cluster 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | go build -o bin/biko \ 4 | ./cmd/biko 5 | 6 | .PHONY: dockerbuild 7 | dockerbuild: 8 | docker build . -t biko 9 | 10 | .PHONY: install 11 | install: build 12 | mkdir -p ${HOME}/.biko 13 | cp .config/default.toml ${HOME}/.biko/config.toml -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## What 11 | 12 | 13 | ## Why 14 | 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - "master" 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-go@v2 14 | with: 15 | go-version: 1.16 16 | - run: go test -v ./... 17 | -------------------------------------------------------------------------------- /cli/consts.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | const ( 4 | categoryCloudProvider = "Cloud Provider" 5 | categoryContinousIntegration = "Continous Integration" 6 | categoryIncidentManagement = "Incident Management" 7 | categoryMonitor = "Monitor" 8 | categoryWebService = "Web service" 9 | categoryVersioning = "Versioning" 10 | ) 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/KeisukeYamashita/biko 2 | 3 | require ( 4 | github.com/BurntSushi/toml v0.3.1 5 | github.com/go-ini/ini v1.62.0 6 | github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect 7 | github.com/stretchr/testify v1.7.0 8 | github.com/urfave/cli v1.22.5 9 | gopkg.in/ini.v1 v1.48.0 // indirect 10 | ) 11 | 12 | go 1.16 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## What's happening 11 | 12 | 13 | ## How should it be 14 | 15 | 16 | ## Additional context 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/c1b7904af6689bd01646f008b0561d4f19a0e972/Go.gitignore 2 | 3 | # Binaries for programs and plugins 4 | *.exe 5 | *.exe~ 6 | *.dll 7 | *.so 8 | *.dylib 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Build artifact 17 | bin/ -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a CODEOWNERS file to define individuals or teams that are responsible 2 | # for code in a repository. 3 | # 4 | # For more detail about CODEOWNERS, refer to following articles: 5 | # - https://help.github.com/articles/about-codeowners/ 6 | # - https://blog.github.com/2017-07-06-introducing-code-owners/ 7 | 8 | # Allow KeisukeYamashita to approve the modification of all code. 9 | * 19yamashita15@gmail.com 10 | -------------------------------------------------------------------------------- /alias/testdata/config.toml: -------------------------------------------------------------------------------- 1 | [aws] 2 | [aws.alias] 3 | 4 | [azure] 5 | [azure.alias] 6 | 7 | [gcp] 8 | [gcp.alias] 9 | myalias = "Hello" 10 | 11 | [datadog] 12 | [datadog.alias] 13 | 14 | [google] 15 | [google.alias] 16 | 17 | [youtube] 18 | [youtube.alias] 19 | 20 | [pagerduty] 21 | [pagerduty.alias] 22 | 23 | [github] 24 | [github.alias] 25 | 26 | [firebase] 27 | [firebase.alias] 28 | 29 | [jira] 30 | [jira.alias] 31 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build Go Server Binary 2 | FROM golang:1.16 3 | LABEL MAINTAINER=KeisukeYamashita 4 | 5 | ENV GO111MODULE on 6 | 7 | ARG SERVICE_NAME 8 | ARG VERSION 9 | 10 | WORKDIR /project 11 | 12 | COPY . ./ 13 | RUN CGO_ENABLED=0 GOOS=linux go install -v \ 14 | -ldflags="-w -s -X main.version=${VERSION} -X main.serviceName=${SERVICE_NAME}" \ 15 | ./cmd/biko 16 | 17 | FROM alpine:latest 18 | COPY --from=0 /go/bin/biko /bin/biko 19 | ENTRYPOINT ["/bin/biko"] -------------------------------------------------------------------------------- /.config/default.toml: -------------------------------------------------------------------------------- 1 | [aws] 2 | [aws.alias] 3 | 4 | [azure] 5 | [azure.alias] 6 | 7 | [gcp] 8 | [gcp.alias] 9 | 10 | [datadog] 11 | [datadog.alias] 12 | 13 | [google] 14 | [google.alias] 15 | 16 | [googleworkspace] 17 | [googleworkspace.alias] 18 | 19 | [youtube] 20 | [youtube.alias] 21 | 22 | [pagerduty] 23 | [pagerduty.alias] 24 | 25 | [github] 26 | [github.alias] 27 | 28 | [circleci] 29 | [circleci.alias] 30 | 31 | [firebase] 32 | [firebase.alias] 33 | 34 | [jira] 35 | [jira.alias] 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9]+.[0-9]+.[0-9]+" 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.16 18 | - uses: goreleaser/goreleaser-action@v2 19 | with: 20 | version: latest 21 | args: release --rm-dist 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - main: ./cmd/biko/main.go 3 | ldflags: 4 | - -s -w 5 | - -X github.com/KeisukeYamashita/biko/cli.Version={{.Tag}} 6 | goos: 7 | - linux 8 | - darwin 9 | - windows 10 | brews: 11 | - tap: 12 | owner: KeisukeYamashita 13 | name: homebrew-tap 14 | token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" 15 | url_template: "http://github.com/KeisukeYamashita/biko/releases/download/{{ .Tag }}/{{ .ArtifactName }}" 16 | commit_author: 17 | name: goreleaserbot 18 | email: goreleaser@carlosbecker.com 19 | folder: Formula 20 | description: "CLI tool to jump to your browser directly" 21 | homepage: "https://github.com/KeisukeYamashita/biko" 22 | test: | 23 | system "#{bin}/biko --version" 24 | -------------------------------------------------------------------------------- /cmd/biko/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "log" 19 | 20 | "github.com/KeisukeYamashita/biko/cli" 21 | ) 22 | 23 | func main() { 24 | if err := cli.Run(); err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /providers/providers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package providers 16 | 17 | import "github.com/urfave/cli" 18 | 19 | // Provider are interfaces ... 20 | type Provider interface { 21 | Init(c *cli.Context) error 22 | GetTargetURL() (string, error) 23 | } 24 | -------------------------------------------------------------------------------- /cli/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | const ( 24 | // Version is injected by goreleaser. 25 | Version = "" 26 | ) 27 | 28 | func newVersionCmd() cli.Command { 29 | return cli.Command{ 30 | Name: "version", 31 | Usage: "Show biko version", 32 | Aliases: []string{"v"}, 33 | Action: func(c *cli.Context) error { 34 | fmt.Printf("Biko %s\n", Version) 35 | return nil 36 | }, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cli/root.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "os" 19 | 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | // Run creates command and run the command 24 | func Run() error { 25 | cmd := NewCmdRoot() 26 | return cmd.Run(os.Args) 27 | } 28 | 29 | // NewCmdRoot will create root command 30 | func NewCmdRoot() *cli.App { 31 | cmd := cli.NewApp() 32 | cmd.Version = Version 33 | cmd.Commands = rootSubCommands() 34 | return cmd 35 | } 36 | 37 | func rootSubCommands() []cli.Command { 38 | return []cli.Command{ 39 | newAWSCmd(), 40 | newAzureCmd(), 41 | newCircleCICmd(), 42 | newDatadaogCmd(), 43 | newFirebaseCmd(), 44 | newGCPCmd(), 45 | newGithubCmd(), 46 | newGoogleCmd(), 47 | newGoogleWorkspaceCmd(), 48 | newJIRACmd(), 49 | newPagerDutyCmd(), 50 | newVersionCmd(), 51 | newYoutubeCmd(), 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /browser/browser.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package browser 16 | 17 | import ( 18 | "fmt" 19 | "os/exec" 20 | "runtime" 21 | 22 | "github.com/KeisukeYamashita/biko/providers" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | // Open wraps the browser opener 27 | func Open(c *cli.Context, provider providers.Provider) error { 28 | if err := provider.Init(c); err != nil { 29 | return err 30 | } 31 | url, err := provider.GetTargetURL() 32 | if err != nil { 33 | return err 34 | } 35 | return openbrowser(url) 36 | } 37 | 38 | func openbrowser(url string) error { 39 | var err error 40 | switch runtime.GOOS { 41 | case "linux": 42 | err = exec.Command("xdg-open", url).Start() 43 | case "windows": 44 | err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() 45 | case "darwin": 46 | err = exec.Command("open", url).Start() 47 | default: 48 | err = fmt.Errorf("unsupported platform") 49 | } 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /alias/alias_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alias 16 | 17 | import ( 18 | "reflect" 19 | "testing" 20 | ) 21 | 22 | func TestGetConfig(t *testing.T) { 23 | // This should be same in the testdata/config.toml 24 | wantConf := &TomlConfig{ 25 | GCP: map[string]interface{}{ 26 | "alias": map[string]interface{}{ 27 | "myalias": "biko", 28 | }, 29 | }, 30 | } 31 | 32 | testCases := map[string]struct { 33 | path string 34 | wantConf *TomlConfig 35 | wantResult bool 36 | }{ 37 | "ok": { 38 | path: "./testdata/config.toml", 39 | wantConf: wantConf, 40 | wantResult: true, 41 | }, 42 | "bad path": { 43 | path: "bad/path", 44 | wantConf: nil, 45 | wantResult: false, 46 | }, 47 | } 48 | 49 | for n, tc := range testCases { 50 | defaultConfigPath = tc.path 51 | conf, err := GetConfig() 52 | if err != nil { 53 | if tc.wantResult { 54 | t.Fatalf("GetConfig fail testCase => %s, error:%v", n, err) 55 | continue 56 | } 57 | continue 58 | } 59 | 60 | if conf == nil { 61 | t.Fatalf("GetConfig fail with nil conf testCase => %s", n) 62 | } 63 | 64 | if reflect.DeepEqual(conf, wantConf) { 65 | t.Fatalf("GetConfig fail not get config, want:%v, got:%v", wantConf, conf) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /cli/google.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/google" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | func newGoogleCmd() cli.Command { 24 | return cli.Command{ 25 | Name: "google", 26 | Aliases: []string{"g"}, 27 | Usage: "Open Google source", 28 | Category: categoryWebService, 29 | Flags: []cli.Flag{ 30 | cli.StringFlag{ 31 | Name: "project", 32 | Usage: "Specify the project to open", 33 | }, 34 | }, 35 | Action: func(c *cli.Context) error { 36 | g, err := google.GetProvider() 37 | if err != nil { 38 | return err 39 | } 40 | return browser.Open(c, g) 41 | }, 42 | Subcommands: []cli.Command{ 43 | newGoogleSearchCmd(), 44 | }, 45 | } 46 | } 47 | 48 | func newGoogleSearchCmd() cli.Command { 49 | return cli.Command{ 50 | Name: "search", 51 | Aliases: []string{"s"}, 52 | Usage: "Search a page", 53 | Flags: []cli.Flag{ 54 | cli.StringFlag{ 55 | Name: "query, q", 56 | Usage: "Query a page", 57 | }, 58 | }, 59 | Action: func(c *cli.Context) error { 60 | g, err := google.GetProvider() 61 | if err != nil { 62 | return err 63 | } 64 | return browser.Open(c, g) 65 | }, 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /cli/youtube.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/youtube" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | func newYoutubeCmd() cli.Command { 24 | return cli.Command{ 25 | Name: "youtube", 26 | Aliases: []string{"yt"}, 27 | Usage: "Open Youtube source", 28 | Category: categoryWebService, 29 | Flags: []cli.Flag{ 30 | cli.StringFlag{ 31 | Name: "project", 32 | Usage: "Specify the project to open", 33 | }, 34 | }, 35 | Action: func(c *cli.Context) error { 36 | yt, err := youtube.GetProvider() 37 | if err != nil { 38 | return err 39 | } 40 | return browser.Open(c, yt) 41 | }, 42 | Subcommands: []cli.Command{ 43 | newYoutubeSearchCmd(), 44 | }, 45 | } 46 | } 47 | 48 | func newYoutubeSearchCmd() cli.Command { 49 | return cli.Command{ 50 | Name: "search", 51 | Aliases: []string{"s"}, 52 | Usage: "Search a page", 53 | Flags: []cli.Flag{ 54 | cli.StringFlag{ 55 | Name: "query, q", 56 | Usage: "Query a page", 57 | }, 58 | }, 59 | Action: func(c *cli.Context) error { 60 | yt, err := youtube.GetProvider() 61 | if err != nil { 62 | return err 63 | } 64 | return browser.Open(c, yt) 65 | }, 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Biko Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | service: 16 | golangci-lint-version: 1.17.x 17 | run: 18 | deadline: 5m 19 | 20 | skip-dirs: 21 | - vendor$ 22 | 23 | skip-files: 24 | - ".*\\.pb\\.go" 25 | - ".*\\.mock\\.go" 26 | - ".*(.|_)gen\\.go" 27 | 28 | linters: 29 | enable-all: true 30 | disable: 31 | - depguard 32 | - dupl 33 | - gochecknoglobals 34 | - gochecknoinits 35 | - goconst 36 | - gocyclo 37 | - gosec 38 | - nakedret 39 | - prealloc 40 | - scopelint 41 | fast: false 42 | 43 | linters-settings: 44 | errcheck: 45 | check-type-assertions: false 46 | check-blank: true 47 | exclude: .errcheckignore 48 | govet: 49 | check-shadowing: false 50 | golint: 51 | min-confidence: 0.8 52 | gofmt: 53 | simplify: true 54 | goimports: 55 | local-prefixes: github.com/micnncim/protocol-buffers-language-server 56 | maligned: 57 | suggest-new: true 58 | misspell: 59 | locale: US 60 | lll: 61 | line-length: 160 62 | tab-width: 1 63 | unused: 64 | check-exported: false 65 | unparam: 66 | algo: cha 67 | check-exported: false 68 | gocritic: 69 | disabled-checks: 70 | - regexpMust 71 | enabled-tags: 72 | - performance 73 | settings: 74 | captLocal: 75 | paramsOnly: true 76 | hugeParam: 77 | sizeThreshold: 80 78 | rangeExprCopy: 79 | sizeThreshold: 512 80 | rangeValCopy: 81 | sizeThreshold: 128 82 | issues: 83 | exclude-rules: 84 | - path: _test\.go$ 85 | linters: 86 | - errcheck 87 | - maligned -------------------------------------------------------------------------------- /providers/gcp/gcp_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package gcp 16 | 17 | import ( 18 | "reflect" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | const ( 25 | testDataPath = "./testdata/gcloud" 26 | ) 27 | 28 | func TestGetSDKConfig(t *testing.T) { 29 | defaultGoogleSDKConfigPath = testDataPath 30 | 31 | conf, err := getSDKConfig() 32 | want := &SDKConfig{ 33 | &Core{ 34 | Account: "biko.is.nice.tool@maybe.com", 35 | Project: "i-am-biko", 36 | }, 37 | &Compute{ 38 | Zone: "asia-roppongi-c", 39 | Region: "asia-minatoku", 40 | }, 41 | &Container{ 42 | Cluster: "biko-cluster", 43 | }, 44 | } 45 | if err != nil { 46 | t.Fatalf("getSDKConfig failed error:%v", err) 47 | } 48 | 49 | if !reflect.DeepEqual(conf, want) { 50 | t.Fatalf("getSDKConfig failed not deep equal got:%v, want:%v", conf, want) 51 | } 52 | } 53 | 54 | func TestConstructPageStateParam(t *testing.T) { 55 | tests := map[string]struct { 56 | namespace string 57 | want string 58 | }{ 59 | "single namespace": { 60 | namespace: "abc", 61 | want: "(\"savedViews\":(\"n\":[\"abc\"]))", 62 | }, 63 | "two namespaces": { 64 | namespace: "test1,test2", 65 | want: "(\"savedViews\":(\"n\":[\"test1\",\"test2\"]))", 66 | }, 67 | "three namespaces": { 68 | namespace: "test1,test2,test3", 69 | want: "(\"savedViews\":(\"n\":[\"test1\",\"test2\",\"test3\"]))", 70 | }, 71 | } 72 | 73 | for name, tt := range tests { 74 | t.Run(name, func(t *testing.T) { 75 | assert.Equal(t, tt.want, constructPageStateParam(tt.namespace)) 76 | }) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /providers/google/google.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package google 16 | 17 | import ( 18 | "net/url" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | type Provider struct { 27 | baseURL *url.URL 28 | URL *url.URL 29 | Ctx *cli.Context 30 | Aliases map[string]interface{} 31 | } 32 | 33 | // GetProvider ... 34 | func GetProvider() (*Provider, error) { 35 | conf, err := alias.GetConfig() 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &Provider{ 41 | Aliases: conf.Github["alias"].(map[string]interface{}), 42 | }, nil 43 | } 44 | 45 | // Init ... 46 | func (p *Provider) Init(c *cli.Context) error { 47 | p.Ctx = c 48 | return nil 49 | } 50 | 51 | // GetTargetURL ... 52 | func (p *Provider) GetTargetURL() (string, error) { 53 | const baseURL = "https://google.com" 54 | var err error 55 | if p.baseURL, err = url.Parse(baseURL); err != nil { 56 | return "", err 57 | } 58 | p.addProductPath(p.Ctx.Command.Name) 59 | return p.URL.String(), nil 60 | } 61 | 62 | func (p *Provider) addProductPath(product string) { 63 | p.URL = p.baseURL 64 | switch product { 65 | case "search": 66 | p.join("search") 67 | param := url.Values{} 68 | var query string 69 | if query = p.GetCtxString("query"); query != "" { 70 | param.Add("q", query) 71 | p.URL.RawQuery = param.Encode() 72 | } 73 | } 74 | } 75 | 76 | func (p *Provider) join(additionPath string) { 77 | if p.URL == nil { 78 | p.URL = p.baseURL 79 | } 80 | p.URL.Path = path.Join(p.URL.Path, additionPath) 81 | } 82 | 83 | // GetCtxString ... 84 | func (p *Provider) GetCtxString(str string) string { 85 | key := p.Ctx.String(str) 86 | if key == "" { 87 | return "" 88 | } 89 | value, ok := p.Aliases[key].(string) 90 | if !ok { 91 | return key 92 | } 93 | if value == "" { 94 | return key 95 | } 96 | return value 97 | } 98 | -------------------------------------------------------------------------------- /providers/youtube/youtube.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package youtube 16 | 17 | import ( 18 | "net/url" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | type Provider struct { 27 | baseURL *url.URL 28 | URL *url.URL 29 | Ctx *cli.Context 30 | Aliases map[string]interface{} 31 | } 32 | 33 | // GetProvider ... 34 | func GetProvider() (*Provider, error) { 35 | conf, err := alias.GetConfig() 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &Provider{ 41 | Aliases: conf.Youtube["alias"].(map[string]interface{}), 42 | }, nil 43 | } 44 | 45 | // Init ... 46 | func (p *Provider) Init(c *cli.Context) error { 47 | p.Ctx = c 48 | return nil 49 | } 50 | 51 | // GetTargetURL ... 52 | func (p *Provider) GetTargetURL() (string, error) { 53 | const baseURL = "https://youtube.com" 54 | var err error 55 | if p.baseURL, err = url.Parse(baseURL); err != nil { 56 | return "", err 57 | } 58 | 59 | p.addProductPath(p.Ctx.Command.Name) 60 | return p.URL.String(), nil 61 | } 62 | 63 | func (p *Provider) addProductPath(product string) { 64 | switch product { 65 | case "search": 66 | p.join("results") 67 | param := url.Values{} 68 | var query string 69 | if query = p.Ctx.String("query"); query != "" { 70 | param.Add("search_query", query) 71 | p.URL.RawQuery = param.Encode() 72 | } 73 | } 74 | } 75 | 76 | // GetCtxString ... 77 | func (p *Provider) GetCtxString(str string) string { 78 | key := p.Ctx.String(str) 79 | if key == "" { 80 | return "" 81 | } 82 | value, ok := p.Aliases[key].(string) 83 | if !ok { 84 | return key 85 | } 86 | if value == "" { 87 | return key 88 | } 89 | return value 90 | } 91 | 92 | func (p *Provider) join(additionPath string) { 93 | if p.URL == nil { 94 | p.URL = p.baseURL 95 | } 96 | p.URL.Path = path.Join(p.URL.Path, additionPath) 97 | } 98 | -------------------------------------------------------------------------------- /alias/alias.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alias 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | 21 | "github.com/BurntSushi/toml" 22 | ) 23 | 24 | var ( 25 | defaultConfigPath = os.Getenv("HOME") + "/.biko/config.toml" 26 | ) 27 | 28 | // TomlConfig ... 29 | type TomlConfig struct { 30 | AWS map[string]interface{} `toml:"aws"` 31 | Azure map[string]interface{} `toml:"azure"` 32 | GCP map[string]interface{} `toml:"gcp"` 33 | Datadog map[string]interface{} `toml:"datadog"` 34 | Google map[string]interface{} `toml:"google"` 35 | GoogleWorkspace map[string]interface{} `toml:"googleworkspace"` 36 | Youtube map[string]interface{} `toml:"youtube"` 37 | PagerDuty map[string]interface{} `toml:"pagerduty"` 38 | Github map[string]interface{} `toml:"github"` 39 | CircleCI map[string]interface{} `toml:"circleci"` 40 | Firebase map[string]interface{} `toml:"firebase"` 41 | JIRA map[string]interface{} `toml:"jira"` 42 | } 43 | 44 | // GetConfig ... 45 | func GetConfig() (*TomlConfig, error) { 46 | confPath, err := getConfigPath() 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | conf, err := getConfig(confPath) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | return conf, nil 57 | } 58 | 59 | func getConfigPath() (string, error) { 60 | var confPath string 61 | if confPath = os.Getenv("BIKO_CONFIG_PATH"); confPath == "" { 62 | confPath = defaultConfigPath 63 | } 64 | 65 | if !configFileExists(confPath) { 66 | return "", fmt.Errorf("config file doesn't exists in %s", confPath) 67 | } 68 | 69 | return confPath, nil 70 | } 71 | 72 | func configFileExists(path string) bool { 73 | _, err := os.Stat(path) 74 | return err == nil 75 | } 76 | 77 | func getConfig(loadPath string) (*TomlConfig, error) { 78 | var conf TomlConfig 79 | if _, err := toml.DecodeFile(loadPath, &conf); err != nil { 80 | return nil, err 81 | } 82 | 83 | return &conf, nil 84 | } 85 | -------------------------------------------------------------------------------- /providers/pagerduty/pagerduty.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pagerduty 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "path" 21 | 22 | "github.com/KeisukeYamashita/biko/alias" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | // Provider ... 27 | type Provider struct { 28 | baseURL *url.URL 29 | URL *url.URL 30 | Ctx *cli.Context 31 | Org string 32 | Aliases map[string]interface{} 33 | } 34 | 35 | // GetProvider ... 36 | func GetProvider() (*Provider, error) { 37 | conf, err := alias.GetConfig() 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | return &Provider{ 43 | Aliases: conf.PagerDuty["alias"].(map[string]interface{}), 44 | }, nil 45 | } 46 | 47 | // Init ... 48 | func (p *Provider) Init(c *cli.Context) error { 49 | p.Ctx = c 50 | return nil 51 | } 52 | 53 | // GetTargetURL ... 54 | func (p *Provider) GetTargetURL() (string, error) { 55 | var baseURL = fmt.Sprintf("https://%s.pagerduty.com", p.Org) 56 | var err error 57 | if p.baseURL, err = url.Parse(baseURL); err != nil { 58 | return "", err 59 | } 60 | 61 | p.addProductPath(p.Ctx.Command.Name) 62 | return p.URL.String(), nil 63 | } 64 | 65 | func (p *Provider) addProductPath(product string) { 66 | switch product { 67 | case "incidents": 68 | p.join("incidents") 69 | case "alerts": 70 | p.join("alerts") 71 | case "schedules": 72 | p.join("schedules") 73 | default: 74 | p.join("incidents") 75 | } 76 | 77 | return 78 | } 79 | 80 | func (p *Provider) join(additionPath string) { 81 | if p.URL == nil { 82 | p.URL = p.baseURL 83 | } 84 | p.URL.Path = path.Join(p.URL.Path, additionPath) 85 | } 86 | 87 | // GetCtxString ... 88 | func (p *Provider) GetCtxString(str string) string { 89 | key := p.Ctx.String(str) 90 | if key == "" { 91 | return "" 92 | } 93 | value, ok := p.Aliases[key].(string) 94 | if !ok { 95 | return key 96 | } 97 | if value == "" { 98 | return key 99 | } 100 | return value 101 | } 102 | -------------------------------------------------------------------------------- /providers/aws/aws.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aws 16 | 17 | import ( 18 | "net/url" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | type Provider struct { 27 | baseURL *url.URL 28 | URL *url.URL 29 | Ctx *cli.Context 30 | Aliases map[string]interface{} 31 | } 32 | 33 | // GetProvider ... 34 | func GetProvider() (*Provider, error) { 35 | conf, err := alias.GetConfig() 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &Provider{ 41 | Aliases: conf.AWS["alias"].(map[string]interface{}), 42 | }, nil 43 | } 44 | 45 | // Init ... 46 | func (p *Provider) Init(c *cli.Context) error { 47 | p.Ctx = c 48 | return nil 49 | } 50 | 51 | // GetTargetURL ... 52 | func (p *Provider) GetTargetURL() (string, error) { 53 | const baseURL = "https://console.aws.amazon.com" 54 | var err error 55 | if p.baseURL, err = url.Parse(baseURL); err != nil { 56 | return "", err 57 | } 58 | p.addProductPath(p.Ctx.Command.Name) 59 | return p.URL.String(), nil 60 | } 61 | 62 | func (p *Provider) addProductPath(product string) { 63 | p.join(product) 64 | switch product { 65 | case "ec2": 66 | p.join("v2") 67 | case "s3": 68 | p.URL, _ = url.Parse("https://s3.console.aws.amazon.com/s3") 69 | default: 70 | return 71 | } 72 | 73 | var region string 74 | if region = p.GetCtxString("region"); region != "" { 75 | params := url.Values{} 76 | params.Add("region", region) 77 | p.URL.RawQuery = params.Encode() 78 | } 79 | } 80 | 81 | // GetCtxString ... 82 | func (p *Provider) GetCtxString(str string) string { 83 | key := p.Ctx.String(str) 84 | if key == "" { 85 | return "" 86 | } 87 | value, ok := p.Aliases[key].(string) 88 | if !ok { 89 | return key 90 | } 91 | if value == "" { 92 | return key 93 | } 94 | return value 95 | } 96 | 97 | func (p *Provider) join(additionPath string) { 98 | if p.URL == nil { 99 | p.URL = p.baseURL 100 | } 101 | p.URL.Path = path.Join(p.URL.Path, additionPath) 102 | } 103 | -------------------------------------------------------------------------------- /providers/jira/jira.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package jira 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "path" 21 | 22 | "github.com/KeisukeYamashita/biko/alias" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | // Provider ... 27 | type Provider struct { 28 | BaseURL *url.URL 29 | URL *url.URL 30 | Ctx *cli.Context 31 | Aliases map[string]interface{} 32 | } 33 | 34 | // GetProvider ... 35 | func GetProvider() (*Provider, error) { 36 | conf, err := alias.GetConfig() 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return &Provider{ 42 | Aliases: conf.JIRA["alias"].(map[string]interface{}), 43 | }, nil 44 | } 45 | 46 | // Init ... 47 | func (p *Provider) Init(c *cli.Context) error { 48 | p.Ctx = c 49 | return nil 50 | } 51 | 52 | // GetTargetURL ... 53 | func (p *Provider) GetTargetURL() (string, error) { 54 | p.addProductPath(p.Ctx.Command.Name) 55 | return p.URL.String(), nil 56 | } 57 | 58 | func (p *Provider) addProductPath(product string) { 59 | switch product { 60 | case "dashboard": 61 | p.join("secure/Dashboard.jspa") 62 | case "projects": 63 | p.join("secure/BrowseProjects.jspa") 64 | case "people": 65 | p.join(fmt.Sprintf("jira/%s", product)) 66 | case "issues": 67 | p.join(product) 68 | case "backlog": 69 | p.join("browse") 70 | if project := p.GetCtxString("project"); project != "" { 71 | p.join(project) 72 | } 73 | case "reports": 74 | project := p.GetCtxString("project") 75 | p.join(fmt.Sprintf("projects/%s?selectedItem=com.atlassian.jira.jira-projects-plugin%%3Areport-page", project)) 76 | default: 77 | p.join("secure/Dashboard.jspa") 78 | } 79 | 80 | return 81 | } 82 | 83 | func (p *Provider) join(additionPath string) { 84 | if p.URL == nil { 85 | p.URL = p.BaseURL 86 | } 87 | p.URL.Path = path.Join(p.URL.Path, additionPath) 88 | } 89 | 90 | // GetCtxString ... 91 | func (p *Provider) GetCtxString(str string) string { 92 | key := p.Ctx.String(str) 93 | if key == "" { 94 | return "" 95 | } 96 | value, ok := p.Aliases[key].(string) 97 | if !ok { 98 | return key 99 | } 100 | if value == "" { 101 | return key 102 | } 103 | return value 104 | } 105 | -------------------------------------------------------------------------------- /providers/circleci/circleci.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package circleci 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "path" 21 | 22 | "github.com/KeisukeYamashita/biko/alias" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | // Provider ... 27 | type Provider struct { 28 | baseURL *url.URL 29 | URL *url.URL 30 | Ctx *cli.Context 31 | Org string 32 | Aliases map[string]interface{} 33 | } 34 | 35 | // GetProvider ... 36 | func GetProvider(org string) (*Provider, error) { 37 | conf, err := alias.GetConfig() 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | return &Provider{ 43 | Aliases: conf.CircleCI["alias"].(map[string]interface{}), 44 | Org: org, 45 | }, nil 46 | } 47 | 48 | // Init ... 49 | func (p *Provider) Init(c *cli.Context) error { 50 | p.Ctx = c 51 | return nil 52 | } 53 | 54 | // GetTargetURL ... 55 | func (p *Provider) GetTargetURL() (string, error) { 56 | const baseURL = "https://circleci.com/" 57 | var err error 58 | if p.baseURL, err = url.Parse(baseURL); err != nil { 59 | return "", err 60 | } 61 | p.addProductPath(p.Ctx.Command.Name) 62 | return p.URL.String(), nil 63 | } 64 | 65 | func (p *Provider) addProductPath(product string) { 66 | p.URL = p.baseURL 67 | switch product { 68 | case "jobs": 69 | p.join(fmt.Sprintf("gh/%s", p.Org)) 70 | var project string 71 | if project = p.GetCtxString("project"); project != "" { 72 | p.join(fmt.Sprintf("gh/%s/%s/", p.Org, project)) 73 | return 74 | } 75 | return 76 | case "workflows": 77 | p.join(fmt.Sprintf("gh/%s/workflows", p.Org)) 78 | var project string 79 | if project = p.GetCtxString("project"); project != "" { 80 | p.join(project) 81 | return 82 | } 83 | return 84 | default: 85 | return 86 | } 87 | } 88 | 89 | // GetCtxString ... 90 | func (p *Provider) GetCtxString(str string) string { 91 | key := p.Ctx.String(str) 92 | if key == "" { 93 | return "" 94 | } 95 | value, ok := p.Aliases[key].(string) 96 | if !ok { 97 | return key 98 | } 99 | if value == "" { 100 | return key 101 | } 102 | return value 103 | } 104 | 105 | func (p *Provider) join(additionPath string) { 106 | if p.URL == nil { 107 | p.URL = p.baseURL 108 | } 109 | p.URL.Path = path.Join(p.URL.Path, additionPath) 110 | } 111 | -------------------------------------------------------------------------------- /providers/firebase/firebase.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package firebase 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "path" 21 | 22 | "github.com/KeisukeYamashita/biko/alias" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | // Provider ... 27 | type Provider struct { 28 | baseURL *url.URL 29 | URL *url.URL 30 | Ctx *cli.Context 31 | Aliases map[string]interface{} 32 | } 33 | 34 | // GetProvider ... 35 | func GetProvider() (*Provider, error) { 36 | conf, err := alias.GetConfig() 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return &Provider{ 42 | Aliases: conf.Firebase["alias"].(map[string]interface{}), 43 | }, nil 44 | } 45 | 46 | // Init ... 47 | func (p *Provider) Init(c *cli.Context) error { 48 | p.Ctx = c 49 | return nil 50 | } 51 | 52 | // GetTargetURL ... 53 | func (p *Provider) GetTargetURL() (string, error) { 54 | const baseURL = "https://console.firebase.google.com/u/0" 55 | var err error 56 | if p.baseURL, err = url.Parse(baseURL); err != nil { 57 | return "", err 58 | } 59 | p.addProductPath(p.Ctx.Command.Name) 60 | return p.URL.String(), nil 61 | } 62 | 63 | func (p *Provider) addProductPath(product string) { 64 | p.URL = p.baseURL 65 | if product == "" { 66 | return 67 | } 68 | 69 | var project string 70 | if project = p.GetCtxString("project"); project != "" { 71 | p.join(fmt.Sprintf("project/%s", project)) 72 | switch product { 73 | case "retention": 74 | p.join("cohort") 75 | case "ab": 76 | p.join("experiments/list") 77 | case "notification": 78 | // This is "Cloud Messaging" 79 | p.join("notification") 80 | case "inappmessaging": 81 | p.join("inappmessaging/onboarding") 82 | case "dynamicLinks": 83 | p.join("durablelinks") 84 | default: 85 | p.join(product) 86 | } 87 | 88 | return 89 | } 90 | 91 | p.join("overview") 92 | return 93 | } 94 | 95 | // GetCtxString ... 96 | func (p *Provider) GetCtxString(str string) string { 97 | key := p.Ctx.String(str) 98 | if key == "" { 99 | return "" 100 | } 101 | value, ok := p.Aliases[key].(string) 102 | if !ok { 103 | return key 104 | } 105 | if value == "" { 106 | return key 107 | } 108 | return value 109 | } 110 | 111 | func (p *Provider) join(additionPath string) { 112 | if p.URL == nil { 113 | p.URL = p.baseURL 114 | } 115 | p.URL.Path = path.Join(p.URL.Path, additionPath) 116 | } 117 | -------------------------------------------------------------------------------- /providers/github/github.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package github 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "path" 21 | 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | type Provider struct { 27 | baseURL *url.URL 28 | URL *url.URL 29 | Ctx *cli.Context 30 | Aliases map[string]interface{} 31 | } 32 | 33 | // Init ... 34 | func (p *Provider) Init(c *cli.Context) error { 35 | p.Ctx = c 36 | return nil 37 | } 38 | 39 | // GetTargetURL ... 40 | func (p *Provider) GetTargetURL() (string, error) { 41 | const baseURL = "https://github.com" 42 | var err error 43 | if p.baseURL, err = url.Parse(baseURL); err != nil { 44 | return "", err 45 | } 46 | 47 | p.addProductPath(p.Ctx.Command.Name) 48 | return p.URL.String(), nil 49 | } 50 | 51 | func (p *Provider) addProductPath(product string) { 52 | switch product { 53 | case "dashboard": 54 | if org := p.Ctx.String("org"); org != "" { 55 | p.join(fmt.Sprintf("orgs/%s/dashboard", org)) 56 | return 57 | } 58 | p.URL = p.baseURL 59 | return 60 | case "trending": 61 | p.join("trending") 62 | if since := p.Ctx.String("since"); since != "" { 63 | param := url.Values{} 64 | param.Add("since", since) 65 | p.URL.RawQuery = param.Encode() 66 | } 67 | if language := p.Ctx.String("language"); language != "" { 68 | p.join(language) 69 | return 70 | } 71 | case "repository": 72 | 73 | users := p.Ctx.String("users") 74 | org := p.Ctx.String("org") 75 | if users != "" && org != "" { 76 | p.URL = p.baseURL 77 | return 78 | } 79 | if users != "" { 80 | p.join(users) 81 | } else { 82 | p.join(org) 83 | } 84 | 85 | if name := p.Ctx.String("name"); name != "" { 86 | if users != "" || org != "" { 87 | p.join(name) 88 | } 89 | return 90 | } 91 | p.URL = p.baseURL 92 | return 93 | default: 94 | p.URL = p.baseURL 95 | } 96 | } 97 | 98 | // GetCtxString ... 99 | func (p *Provider) GetCtxString(str string) string { 100 | key := p.Ctx.String(str) 101 | if key == "" { 102 | return "" 103 | } 104 | value, ok := p.Aliases[key].(string) 105 | if !ok { 106 | return key 107 | } 108 | if value == "" { 109 | return key 110 | } 111 | return value 112 | } 113 | 114 | func (p *Provider) join(additionPath string) { 115 | if p.URL == nil { 116 | p.URL = p.baseURL 117 | } 118 | p.URL.Path = path.Join(p.URL.Path, additionPath) 119 | } 120 | -------------------------------------------------------------------------------- /providers/azure/azure.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package azure 16 | 17 | import ( 18 | "fmt" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | // TODO(KeisukeYamashita): Use url package for baseURL and URL 27 | type Provider struct { 28 | baseURL string 29 | URL string 30 | Ctx *cli.Context 31 | Aliases map[string]interface{} 32 | } 33 | 34 | // GetProvider ... 35 | func GetProvider() (*Provider, error) { 36 | conf, err := alias.GetConfig() 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return &Provider{ 42 | Aliases: conf.Azure["alias"].(map[string]interface{}), 43 | }, nil 44 | } 45 | 46 | // Init ... 47 | func (p *Provider) Init(c *cli.Context) error { 48 | p.Ctx = c 49 | return nil 50 | } 51 | 52 | // GetTargetURL ... 53 | func (p *Provider) GetTargetURL() (string, error) { 54 | p.baseURL = "https://portal.azure.com" 55 | p.addProductPath(p.Ctx.Command.Name) 56 | return p.URL, nil 57 | } 58 | 59 | func (p *Provider) addProductPath(product string) { 60 | p.URL = p.baseURL 61 | if product == "" { 62 | p.join("#home") 63 | return 64 | } 65 | 66 | var productType, path string 67 | suffix := "Blade" 68 | switch product { 69 | case "vm": 70 | productType = "Compute" 71 | path = "VirtualMachines" 72 | case "appservices": 73 | productType = "Web" 74 | path = "sites" 75 | case "funcion": 76 | productType = "Web" 77 | path = "sites/king/functionapp" 78 | case "sql": 79 | productType = "Sql" 80 | path = "services/databases" 81 | case "cosmos": 82 | productType = "DocumentDB" 83 | path = "databaseAccounts" 84 | suffix = "" 85 | case "storage": 86 | productType = "Storage" 87 | path = "StorageAccounts" 88 | default: 89 | return 90 | } 91 | p.join(fmt.Sprintf("#blade/HubsExtension/BrowseResource%s/resourceType/Microsoft.%s%%2F%s", suffix, productType, path)) 92 | } 93 | 94 | // GetCtxString ... 95 | func (p *Provider) GetCtxString(str string) string { 96 | key := p.Ctx.String(str) 97 | if key == "" { 98 | return "" 99 | } 100 | value, ok := p.Aliases[key].(string) 101 | if !ok { 102 | return key 103 | } 104 | if value == "" { 105 | return key 106 | } 107 | return value 108 | } 109 | 110 | func (p *Provider) join(additionPath string) { 111 | if p.URL == "" { 112 | p.URL = p.baseURL 113 | } 114 | p.URL = path.Join(p.URL, additionPath) 115 | } 116 | -------------------------------------------------------------------------------- /providers/datadog/datadog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package datadog 16 | 17 | import ( 18 | "net/url" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | // Provider ... 26 | type Provider struct { 27 | baseURL *url.URL 28 | URL *url.URL 29 | Product string 30 | Ctx *cli.Context 31 | Aliases map[string]interface{} 32 | } 33 | 34 | // GetProvider ... 35 | func GetProvider() (*Provider, error) { 36 | conf, err := alias.GetConfig() 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return &Provider{ 42 | Aliases: conf.Datadog["alias"].(map[string]interface{}), 43 | }, nil 44 | } 45 | 46 | // Init ... 47 | func (p *Provider) Init(c *cli.Context) error { 48 | p.Ctx = c 49 | return nil 50 | } 51 | 52 | // GetTargetURL ... 53 | func (p *Provider) GetTargetURL() (string, error) { 54 | const baseURL = "https://app.datadoghq.com" 55 | var err error 56 | if p.baseURL, err = url.Parse(baseURL); err != nil { 57 | return "", err 58 | } 59 | 60 | p.addProductPath(p.Ctx.Command.Name) 61 | return p.URL.String(), nil 62 | } 63 | func (p *Provider) addProductPath(product string) { 64 | switch product { 65 | case "watchdogs": 66 | p.join(product) 67 | case "events": 68 | p.join("events/stream") 69 | case "dashboard": 70 | p.join(product) 71 | case "infrastructure": 72 | p.join(product) 73 | case "monitors": 74 | p.join(product) 75 | case "metrics": 76 | p.join(product) 77 | case "integrations": 78 | p.join("account/settings") 79 | case "apm": 80 | p.join(product) 81 | case "notebook": 82 | p.join(product) 83 | case "logs": 84 | p.join(product) 85 | var view string 86 | if view = p.GetCtxString("view"); view != "" { 87 | param := url.Values{} 88 | param.Add("saved_view", view) 89 | p.URL.RawQuery = param.Encode() 90 | } 91 | case "synthetics": 92 | p.join(product) 93 | default: 94 | p.join("apm/home") 95 | } 96 | return 97 | } 98 | 99 | func (p *Provider) join(additionPath string) { 100 | if p.URL == nil { 101 | p.URL = p.baseURL 102 | } 103 | p.URL.Path = path.Join(p.URL.Path, additionPath) 104 | } 105 | 106 | // GetCtxString ... 107 | func (p *Provider) GetCtxString(str string) string { 108 | key := p.Ctx.String(str) 109 | if key == "" { 110 | return "" 111 | } 112 | value, ok := p.Aliases[key].(string) 113 | if !ok { 114 | return key 115 | } 116 | if value == "" { 117 | return key 118 | } 119 | return value 120 | } 121 | -------------------------------------------------------------------------------- /cli/github.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | gh "github.com/KeisukeYamashita/biko/providers/github" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | func newGithubCmd() cli.Command { 24 | return cli.Command{ 25 | Name: "github", 26 | Aliases: []string{"gh"}, 27 | Usage: "Open Github resource", 28 | Category: categoryVersioning, 29 | Flags: []cli.Flag{ 30 | cli.StringFlag{ 31 | Name: "project", 32 | Usage: "Specify the project to open", 33 | }, 34 | }, 35 | Action: func(c *cli.Context) error { 36 | github := &gh.Provider{} 37 | return browser.Open(c, github) 38 | }, 39 | Subcommands: []cli.Command{ 40 | newGithubDashboardCmd(), 41 | newGithubTrendingCmd(), 42 | newGithubRepositoryCmd(), 43 | }, 44 | } 45 | } 46 | 47 | func newGithubDashboardCmd() cli.Command { 48 | return cli.Command{ 49 | Name: "dashboard", 50 | Aliases: []string{"db"}, 51 | Usage: "Open a dashboard page", 52 | Flags: []cli.Flag{ 53 | cli.StringFlag{ 54 | Name: "org", 55 | Usage: "Organization to open", 56 | }, 57 | }, 58 | Action: func(c *cli.Context) error { 59 | 60 | github := &gh.Provider{} 61 | return browser.Open(c, github) 62 | }, 63 | } 64 | 65 | } 66 | 67 | func newGithubTrendingCmd() cli.Command { 68 | return cli.Command{ 69 | Name: "trending", 70 | Aliases: []string{"t"}, 71 | Usage: "Open the trending page", 72 | Flags: []cli.Flag{ 73 | cli.StringFlag{ 74 | Name: "language, l", 75 | Usage: "filter trending with language", 76 | }, 77 | cli.StringFlag{ 78 | Name: "since, s", 79 | Usage: "filter trending with date range(daily, weekly, monthly)", 80 | }, 81 | }, 82 | Action: func(c *cli.Context) error { 83 | 84 | github := &gh.Provider{} 85 | return browser.Open(c, github) 86 | }, 87 | } 88 | 89 | } 90 | 91 | func newGithubRepositoryCmd() cli.Command { 92 | return cli.Command{ 93 | Name: "repository", 94 | Aliases: []string{"r"}, 95 | Usage: "Open the repository page", 96 | Flags: []cli.Flag{ 97 | cli.StringFlag{ 98 | Name: "org", 99 | Usage: "Organization to open", 100 | }, 101 | cli.StringFlag{ 102 | Name: "users, u", 103 | Usage: "User page to open", 104 | }, 105 | cli.StringFlag{ 106 | Name: "name, n", 107 | Usage: "Name of repository that depend on Organization", 108 | }, 109 | }, 110 | Action: func(c *cli.Context) error { 111 | 112 | github := &gh.Provider{} 113 | return browser.Open(c, github) 114 | }, 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /cli/circleci.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/KeisukeYamashita/biko/browser" 21 | cc "github.com/KeisukeYamashita/biko/providers/circleci" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | func newCircleCICmd() cli.Command { 26 | return cli.Command{ 27 | Name: "circleci", 28 | Aliases: []string{"cc"}, 29 | Usage: "Open CircleCI resource", 30 | Category: categoryContinousIntegration, 31 | Flags: []cli.Flag{ 32 | cli.StringFlag{ 33 | Name: "org", 34 | EnvVar: "BIKO_CIRCLECI", 35 | Usage: "Specify CircleCI Organization", 36 | }, 37 | }, 38 | Action: func(c *cli.Context) error { 39 | var org string 40 | if org = c.String("org"); org == "" { 41 | return fmt.Errorf("Org for circleci not configured pass --org or set BIKO_CIRCLECI") 42 | } 43 | cc := &cc.Provider{ 44 | Org: org, 45 | } 46 | return browser.Open(c, cc) 47 | }, 48 | Subcommands: []cli.Command{ 49 | newCircleCIJobsCmd(), 50 | newCircleCIWorkflowsCmd(), 51 | }, 52 | } 53 | } 54 | 55 | func newCircleCIJobsCmd() cli.Command { 56 | return cli.Command{ 57 | Name: "jobs", 58 | Aliases: []string{"j"}, 59 | Usage: "Open jobs page", 60 | Flags: []cli.Flag{ 61 | cli.StringFlag{ 62 | Name: "project, p", 63 | Usage: "Specify the project to open", 64 | }, 65 | cli.StringFlag{ 66 | Name: "org", 67 | EnvVar: "BIKO_CIRCLECI", 68 | Usage: "Specify CircleCI Organization", 69 | }, 70 | }, 71 | Action: func(c *cli.Context) error { 72 | var org string 73 | if org = c.String("org"); org == "" { 74 | return fmt.Errorf("Org for circleci not configured pass --org or set BIKO_CIRCLECI") 75 | } 76 | cc, err := cc.GetProvider(org) 77 | if err != nil { 78 | return err 79 | } 80 | return browser.Open(c, cc) 81 | }, 82 | } 83 | } 84 | 85 | func newCircleCIWorkflowsCmd() cli.Command { 86 | return cli.Command{ 87 | Name: "workflows", 88 | Aliases: []string{"wf"}, 89 | Usage: "Open workflows page", 90 | Flags: []cli.Flag{ 91 | cli.StringFlag{ 92 | Name: "project, p", 93 | Usage: "Specify the project to open", 94 | }, 95 | cli.StringFlag{ 96 | Name: "org", 97 | EnvVar: "BIKO_CIRCLECI", 98 | Usage: "Specify CircleCI Organization", 99 | }, 100 | }, 101 | Action: func(c *cli.Context) error { 102 | var org string 103 | if org = c.String("org"); org == "" { 104 | return fmt.Errorf("Org for circleci not configured pass --org or set BIKO_CIRCLECI") 105 | } 106 | cc, err := cc.GetProvider(org) 107 | if err != nil { 108 | return err 109 | } 110 | return browser.Open(c, cc) 111 | }, 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /cli/pagerduty.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/KeisukeYamashita/biko/browser" 21 | pd "github.com/KeisukeYamashita/biko/providers/pagerduty" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | func newPagerDutyCmd() cli.Command { 26 | return cli.Command{ 27 | Name: "pagerduty", 28 | Aliases: []string{"pd"}, 29 | Usage: "Open PagerDuty resource", 30 | Category: categoryIncidentManagement, 31 | Flags: []cli.Flag{ 32 | cli.StringFlag{ 33 | Name: "project", 34 | Usage: "Specify the project to open", 35 | }, 36 | cli.StringFlag{ 37 | Name: "org", 38 | EnvVar: "BIKO_PAGERDUTY", 39 | Usage: "Specify Pagerduty Organization", 40 | }, 41 | }, 42 | Action: func(c *cli.Context) error { 43 | var org string 44 | if org = c.String("org"); org == "" { 45 | return fmt.Errorf("Org for pagerduty not configured pass --org or set BIKO_PAGERDUTY") 46 | } 47 | pd := &pd.Provider{ 48 | Org: org, 49 | } 50 | return browser.Open(c, pd) 51 | }, 52 | Subcommands: []cli.Command{ 53 | newPagerDudyIncidentCmd(), 54 | newPagerDudyAlertCmd(), 55 | newPagerDudySchedulesCmd(), 56 | }, 57 | } 58 | } 59 | 60 | func newPagerDudyIncidentCmd() cli.Command { 61 | return cli.Command{ 62 | Name: "incident", 63 | Aliases: []string{"i"}, 64 | Usage: "Open incident page", 65 | Flags: []cli.Flag{ 66 | cli.StringFlag{ 67 | Name: "org", 68 | EnvVar: "BIKO_PAGERDUTY", 69 | Usage: "Specify Pagerduty Organization", 70 | }, 71 | }, 72 | Action: func(c *cli.Context) error { 73 | var org string 74 | if org = c.String("org"); org == "" { 75 | return fmt.Errorf("Org for pagerduty not configured pass --org or set BIKO_PAGERDUTY") 76 | } 77 | pd := &pd.Provider{ 78 | Org: org, 79 | } 80 | return browser.Open(c, pd) 81 | }, 82 | } 83 | 84 | } 85 | 86 | func newPagerDudyAlertCmd() cli.Command { 87 | return cli.Command{ 88 | Name: "alert", 89 | Aliases: []string{"a"}, 90 | Usage: "Open alert page", 91 | Flags: []cli.Flag{}, 92 | Action: func(c *cli.Context) error { 93 | var org string 94 | if org = c.String("org"); org == "" { 95 | return fmt.Errorf("Org for pagerduty not configured pass --org or set BIKO_PAGERDUTY") 96 | } 97 | pd := &pd.Provider{ 98 | Org: org, 99 | } 100 | return browser.Open(c, pd) 101 | }, 102 | } 103 | } 104 | 105 | func newPagerDudySchedulesCmd() cli.Command { 106 | return cli.Command{ 107 | Name: "schedules", 108 | Aliases: []string{"s"}, 109 | Usage: "Open schedules page", 110 | Flags: []cli.Flag{ 111 | cli.StringFlag{ 112 | Name: "org", 113 | EnvVar: "BIKO_PAGERDUTY", 114 | Usage: "Specify Pagerduty Organization", 115 | }, 116 | }, 117 | Action: func(c *cli.Context) error { 118 | var org string 119 | if org = c.String("org"); org == "" { 120 | return fmt.Errorf("Org for pagerduty not configured pass --org or set BIKO_PAGERDUTY") 121 | } 122 | pd := &pd.Provider{ 123 | Org: org, 124 | } 125 | return browser.Open(c, pd) 126 | }, 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= 4 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 5 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU= 8 | github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 9 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 10 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 11 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 12 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 13 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 14 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 15 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 16 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 17 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= 18 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 19 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 20 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 21 | github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= 22 | github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 23 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 24 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 25 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 26 | github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= 27 | github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 28 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 29 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 30 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 31 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 32 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 33 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 34 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 35 | gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8= 36 | gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 37 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 38 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 39 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 40 | -------------------------------------------------------------------------------- /cli/azure.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | az "github.com/KeisukeYamashita/biko/providers/azure" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | const ( 24 | categoryAZuComputing = "Computing" 25 | ) 26 | 27 | func newAzureCmd() cli.Command { 28 | return cli.Command{ 29 | Name: "azure", 30 | Aliases: []string{"az"}, 31 | Usage: "Open Microsoft Azure resource", 32 | Category: categoryCloudProvider, 33 | Flags: []cli.Flag{}, 34 | Action: func(c *cli.Context) error { 35 | aws, err := az.GetProvider() 36 | if err != nil { 37 | return err 38 | } 39 | return browser.Open(c, aws) 40 | }, 41 | Subcommands: []cli.Command{ 42 | newAzureVMCmd(), 43 | newAzureAppServicesCmd(), 44 | newAzureFunctionAppCmd(), 45 | newAzureSQLDatabaseCmd(), 46 | newAzureCosmosDBCmd(), 47 | newAzureStorageAccountsCmd(), 48 | }, 49 | } 50 | } 51 | 52 | func newAzureVMCmd() cli.Command { 53 | return cli.Command{ 54 | Name: "vm", 55 | Usage: "Open VM", 56 | Flags: []cli.Flag{}, 57 | Action: func(c *cli.Context) error { 58 | aws, err := az.GetProvider() 59 | if err != nil { 60 | return err 61 | } 62 | return browser.Open(c, aws) 63 | }, 64 | } 65 | } 66 | 67 | func newAzureAppServicesCmd() cli.Command { 68 | return cli.Command{ 69 | Name: "appservices", 70 | Aliases: []string{"as", "sites"}, 71 | Usage: "Open App Services", 72 | Flags: []cli.Flag{}, 73 | Action: func(c *cli.Context) error { 74 | aws, err := az.GetProvider() 75 | if err != nil { 76 | return err 77 | } 78 | return browser.Open(c, aws) 79 | }, 80 | } 81 | } 82 | 83 | func newAzureFunctionAppCmd() cli.Command { 84 | return cli.Command{ 85 | Name: "function", 86 | Aliases: []string{"f"}, 87 | Usage: "Open Function App", 88 | Flags: []cli.Flag{}, 89 | Action: func(c *cli.Context) error { 90 | aws, err := az.GetProvider() 91 | if err != nil { 92 | return err 93 | } 94 | return browser.Open(c, aws) 95 | }, 96 | } 97 | } 98 | 99 | func newAzureSQLDatabaseCmd() cli.Command { 100 | return cli.Command{ 101 | Name: "sql", 102 | Usage: "Open SQL Database", 103 | Flags: []cli.Flag{}, 104 | Action: func(c *cli.Context) error { 105 | aws, err := az.GetProvider() 106 | if err != nil { 107 | return err 108 | } 109 | return browser.Open(c, aws) 110 | }, 111 | } 112 | } 113 | 114 | func newAzureCosmosDBCmd() cli.Command { 115 | return cli.Command{ 116 | Name: "cosmos", 117 | Usage: "Open Cosmos Database", 118 | Flags: []cli.Flag{}, 119 | Action: func(c *cli.Context) error { 120 | aws, err := az.GetProvider() 121 | if err != nil { 122 | return err 123 | } 124 | return browser.Open(c, aws) 125 | }, 126 | } 127 | } 128 | 129 | func newAzureStorageAccountsCmd() cli.Command { 130 | return cli.Command{ 131 | Name: "storage", 132 | Usage: "Open Storage Accounts", 133 | Flags: []cli.Flag{}, 134 | Action: func(c *cli.Context) error { 135 | aws, err := az.GetProvider() 136 | if err != nil { 137 | return err 138 | } 139 | return browser.Open(c, aws) 140 | }, 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /providers/googleworkspace/googleworkspace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package googleworkspace 16 | 17 | import ( 18 | "net/url" 19 | "path" 20 | 21 | "github.com/KeisukeYamashita/biko/alias" 22 | "github.com/urfave/cli" 23 | ) 24 | 25 | const ( 26 | drive = "drive" 27 | document = "document" 28 | spreadsheets = "spreadsheets" 29 | presentation = "presentation" 30 | forms = "forms" 31 | ) 32 | 33 | // Provider ... 34 | type Provider struct { 35 | baseURL *url.URL 36 | URL *url.URL 37 | Ctx *cli.Context 38 | Aliases map[string]interface{} 39 | } 40 | 41 | // GetProvider ... 42 | func GetProvider() (*Provider, error) { 43 | conf, err := alias.GetConfig() 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | return &Provider{ 49 | Aliases: conf.GoogleWorkspace["alias"].(map[string]interface{}), 50 | }, nil 51 | } 52 | 53 | // Init ... 54 | func (p *Provider) Init(c *cli.Context) error { 55 | p.Ctx = c 56 | return nil 57 | } 58 | 59 | // GetTargetURL ... 60 | func (p *Provider) GetTargetURL() (string, error) { 61 | newFlag := p.GetCtxString("new") 62 | if newFlag == "true" { // HACK: need to fix GetCtxString 63 | return p.getNewCmdURL(), nil 64 | } 65 | 66 | var baseURL string 67 | product := p.Ctx.Command.Name 68 | switch product { 69 | case drive: 70 | baseURL = "https://drive.google.com" 71 | case document, spreadsheets, presentation, forms: 72 | baseURL = "https://docs.google.com/" 73 | } 74 | 75 | var err error 76 | if p.baseURL, err = url.Parse(baseURL); err != nil { 77 | return "", err 78 | } 79 | p.addProductPath(product) 80 | return p.URL.String(), nil 81 | } 82 | 83 | func (p *Provider) addProductPath(product string) { 84 | p.URL = p.baseURL 85 | switch product { 86 | case drive: 87 | p.join(drive) 88 | param := url.Values{} 89 | var query string 90 | if query = p.GetCtxString("query"); query != "" { 91 | p.join("search") 92 | param.Add("q", query) 93 | p.URL.RawQuery = param.Encode() 94 | } 95 | case document: 96 | p.join(document) 97 | param := url.Values{} 98 | var query string 99 | if query = p.GetCtxString("query"); query != "" { 100 | param.Add("q", query) 101 | p.URL.RawQuery = param.Encode() 102 | } 103 | case spreadsheets: 104 | p.join(spreadsheets) 105 | param := url.Values{} 106 | var query string 107 | if query = p.GetCtxString("query"); query != "" { 108 | param.Add("q", query) 109 | p.URL.RawQuery = param.Encode() 110 | } 111 | case presentation: 112 | p.join(presentation) 113 | param := url.Values{} 114 | var query string 115 | if query = p.GetCtxString("query"); query != "" { 116 | param.Add("q", query) 117 | p.URL.RawQuery = param.Encode() 118 | } 119 | case forms: 120 | p.join(forms) 121 | param := url.Values{} 122 | var query string 123 | if query = p.GetCtxString("query"); query != "" { 124 | param.Add("q", query) 125 | p.URL.RawQuery = param.Encode() 126 | } 127 | } 128 | } 129 | 130 | func (p *Provider) join(additionPath string) { 131 | if p.URL == nil { 132 | p.URL = p.baseURL 133 | } 134 | p.URL.Path = path.Join(p.URL.Path, additionPath) 135 | } 136 | 137 | func (p *Provider) getNewCmdURL() string { 138 | product := p.Ctx.Command.Name 139 | switch product { 140 | case document: 141 | return "https://document.new" 142 | case spreadsheets: 143 | return "https://spreadsheets.new" 144 | case presentation: 145 | return "https://presentation.new" 146 | case forms: 147 | return "https://forms.new" 148 | } 149 | return "" 150 | } 151 | 152 | // GetCtxString ... 153 | func (p *Provider) GetCtxString(str string) string { 154 | key := p.Ctx.String(str) 155 | if key == "" { 156 | return "" 157 | } 158 | value, ok := p.Aliases[key].(string) 159 | if !ok { 160 | return key 161 | } 162 | if value == "" { 163 | return key 164 | } 165 | return value 166 | } 167 | -------------------------------------------------------------------------------- /cli/googleworkspace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/googleworkspace" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | func newGoogleWorkspaceCmd() cli.Command { 24 | return cli.Command{ 25 | Name: "googleworkspace", 26 | Aliases: []string{"gw"}, 27 | Usage: "Open Google Workspace resource", 28 | Category: categoryWebService, 29 | Flags: []cli.Flag{}, 30 | Action: func(c *cli.Context) error { 31 | g, err := googleworkspace.GetProvider() 32 | if err != nil { 33 | return err 34 | } 35 | return browser.Open(c, g) 36 | }, 37 | Subcommands: []cli.Command{ 38 | newDriveCmd(), 39 | newDocumentCmd(), 40 | newSpreadsheetsCmd(), 41 | newPresentationCmd(), 42 | newFormsCmd(), 43 | }, 44 | } 45 | } 46 | 47 | func newDriveCmd() cli.Command { 48 | return cli.Command{ 49 | Name: "drive", 50 | Aliases: []string{"dr"}, 51 | Usage: "Open Google Drive directory", 52 | Flags: []cli.Flag{ 53 | cli.StringFlag{ 54 | Name: "query, q", 55 | Usage: "Query to search", 56 | }, 57 | }, 58 | Action: func(c *cli.Context) error { 59 | g, err := googleworkspace.GetProvider() 60 | if err != nil { 61 | return err 62 | } 63 | return browser.Open(c, g) 64 | }, 65 | } 66 | 67 | } 68 | 69 | func newDocumentCmd() cli.Command { 70 | return cli.Command{ 71 | Name: "document", 72 | Aliases: []string{"doc"}, 73 | Usage: "Open Google Document page", 74 | Flags: []cli.Flag{ 75 | cli.StringFlag{ 76 | Name: "query, q", 77 | Usage: "Query a page", 78 | }, 79 | cli.BoolFlag{ 80 | Name: "new, n", 81 | Usage: "Create a new document (this flag prioritize over query flag)", 82 | }, 83 | }, 84 | Action: func(c *cli.Context) error { 85 | g, err := googleworkspace.GetProvider() 86 | if err != nil { 87 | return err 88 | } 89 | return browser.Open(c, g) 90 | }, 91 | } 92 | 93 | } 94 | 95 | func newSpreadsheetsCmd() cli.Command { 96 | return cli.Command{ 97 | Name: "spreadsheets", 98 | Aliases: []string{"ss"}, 99 | Usage: "Open Google Spreadsheets page", 100 | Flags: []cli.Flag{ 101 | cli.StringFlag{ 102 | Name: "query, q", 103 | Usage: "Query a page", 104 | }, 105 | cli.BoolFlag{ 106 | Name: "new, n", 107 | Usage: "Create a new spreadsheet (this flag prioritize over query flag)", 108 | }, 109 | }, 110 | Action: func(c *cli.Context) error { 111 | g, err := googleworkspace.GetProvider() 112 | if err != nil { 113 | return err 114 | } 115 | return browser.Open(c, g) 116 | }, 117 | } 118 | 119 | } 120 | 121 | func newPresentationCmd() cli.Command { 122 | return cli.Command{ 123 | Name: "presentation", 124 | Aliases: []string{"pr"}, 125 | Usage: "Open Google Slides page", 126 | Flags: []cli.Flag{ 127 | cli.StringFlag{ 128 | Name: "query, q", 129 | Usage: "Query a page", 130 | }, 131 | cli.BoolFlag{ 132 | Name: "new, n", 133 | Usage: "Create a new presentation (this flag prioritize over query flag)", 134 | }, 135 | }, 136 | Action: func(c *cli.Context) error { 137 | g, err := googleworkspace.GetProvider() 138 | if err != nil { 139 | return err 140 | } 141 | return browser.Open(c, g) 142 | }, 143 | } 144 | 145 | } 146 | 147 | func newFormsCmd() cli.Command { 148 | return cli.Command{ 149 | Name: "forms", 150 | Aliases: []string{"fm"}, 151 | Usage: "Open Google Forms page", 152 | Flags: []cli.Flag{ 153 | cli.StringFlag{ 154 | Name: "query, q", 155 | Usage: "Query a page", 156 | }, 157 | cli.BoolFlag{ 158 | Name: "new, n", 159 | Usage: "Create a new form (this flag prioritize over query flag)", 160 | }, 161 | }, 162 | Action: func(c *cli.Context) error { 163 | g, err := googleworkspace.GetProvider() 164 | if err != nil { 165 | return err 166 | } 167 | return browser.Open(c, g) 168 | }, 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /cli/datadog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | dd "github.com/KeisukeYamashita/biko/providers/datadog" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | func newDatadaogCmd() cli.Command { 24 | return cli.Command{ 25 | Name: "datadog", 26 | Aliases: []string{"dd"}, 27 | Usage: "Open Datadog resource", 28 | Category: categoryMonitor, 29 | Flags: []cli.Flag{}, 30 | Subcommands: []cli.Command{ 31 | newDDWatchDogCmd(), 32 | newDDEventCmd(), 33 | newDDDashboardCmd(), 34 | newDDInfrastructureCmd(), 35 | newDDMonitorsCmd(), 36 | newDDIntegrationsCmd(), 37 | newDDApmCmd(), 38 | newDDNotebookCmd(), 39 | newDDLogsCmd(), 40 | newDDSyntheticsCmd(), 41 | }, 42 | } 43 | } 44 | 45 | func newDDWatchDogCmd() cli.Command { 46 | return cli.Command{ 47 | Name: "watchdog", 48 | Aliases: []string{"wd"}, 49 | Usage: "Open Watchdog page", 50 | Flags: []cli.Flag{}, 51 | Action: func(c *cli.Context) error { 52 | dd, err := dd.GetProvider() 53 | if err != nil { 54 | return err 55 | } 56 | return browser.Open(c, dd) 57 | }, 58 | } 59 | } 60 | 61 | func newDDEventCmd() cli.Command { 62 | return cli.Command{ 63 | Name: "events", 64 | Usage: "Open Events page", 65 | Flags: []cli.Flag{}, 66 | Action: func(c *cli.Context) error { 67 | dd, err := dd.GetProvider() 68 | if err != nil { 69 | return err 70 | } 71 | return browser.Open(c, dd) 72 | }, 73 | } 74 | } 75 | 76 | func newDDDashboardCmd() cli.Command { 77 | return cli.Command{ 78 | Name: "dashboard", 79 | Usage: "Open Dashboard page", 80 | Flags: []cli.Flag{}, 81 | Action: func(c *cli.Context) error { 82 | dd, err := dd.GetProvider() 83 | if err != nil { 84 | return err 85 | } 86 | return browser.Open(c, dd) 87 | }, 88 | } 89 | } 90 | 91 | func newDDInfrastructureCmd() cli.Command { 92 | return cli.Command{ 93 | Name: "infrastructure", 94 | Usage: "Open Infrastructure page", 95 | Flags: []cli.Flag{}, 96 | Action: func(c *cli.Context) error { 97 | dd, err := dd.GetProvider() 98 | if err != nil { 99 | return err 100 | } 101 | return browser.Open(c, dd) 102 | }, 103 | } 104 | } 105 | 106 | func newDDMonitorsCmd() cli.Command { 107 | return cli.Command{ 108 | Name: "monitors", 109 | Usage: "Open Monitors page", 110 | Flags: []cli.Flag{}, 111 | Action: func(c *cli.Context) error { 112 | dd, err := dd.GetProvider() 113 | if err != nil { 114 | return err 115 | } 116 | return browser.Open(c, dd) 117 | }, 118 | } 119 | } 120 | 121 | func newDDIntegrationsCmd() cli.Command { 122 | return cli.Command{ 123 | Name: "integrations", 124 | Usage: "Open Integrations page", 125 | Flags: []cli.Flag{}, 126 | Action: func(c *cli.Context) error { 127 | dd, err := dd.GetProvider() 128 | if err != nil { 129 | return err 130 | } 131 | return browser.Open(c, dd) 132 | }, 133 | } 134 | } 135 | 136 | func newDDApmCmd() cli.Command { 137 | return cli.Command{ 138 | Name: "apm", 139 | Usage: "Open APM page", 140 | Flags: []cli.Flag{}, 141 | Action: func(c *cli.Context) error { 142 | dd, err := dd.GetProvider() 143 | if err != nil { 144 | return err 145 | } 146 | return browser.Open(c, dd) 147 | }, 148 | } 149 | } 150 | 151 | func newDDNotebookCmd() cli.Command { 152 | return cli.Command{ 153 | Name: "notebook", 154 | Usage: "Open Notebook page", 155 | Flags: []cli.Flag{}, 156 | Action: func(c *cli.Context) error { 157 | dd, err := dd.GetProvider() 158 | if err != nil { 159 | return err 160 | } 161 | return browser.Open(c, dd) 162 | }, 163 | } 164 | } 165 | 166 | func newDDLogsCmd() cli.Command { 167 | return cli.Command{ 168 | Name: "logs", 169 | Usage: "Open Logs page", 170 | Flags: []cli.Flag{ 171 | cli.StringFlag{ 172 | Name: "view, v", 173 | Usage: "Specify the saved view to open", 174 | }, 175 | }, 176 | Action: func(c *cli.Context) error { 177 | dd, err := dd.GetProvider() 178 | if err != nil { 179 | return err 180 | } 181 | return browser.Open(c, dd) 182 | }, 183 | } 184 | } 185 | 186 | func newDDSyntheticsCmd() cli.Command { 187 | return cli.Command{ 188 | Name: "synthetics", 189 | Usage: "Open Synthetics page", 190 | Flags: []cli.Flag{}, 191 | Action: func(c *cli.Context) error { 192 | dd, err := dd.GetProvider() 193 | if err != nil { 194 | return err 195 | } 196 | return browser.Open(c, dd) 197 | }, 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /providers/gcp/gcp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package gcp 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | "os" 21 | "path" 22 | "strconv" 23 | "strings" 24 | 25 | "github.com/KeisukeYamashita/biko/alias" 26 | "github.com/go-ini/ini" 27 | "github.com/urfave/cli" 28 | ) 29 | 30 | const ( 31 | baseURL = "https://console.cloud.google.com" 32 | ) 33 | 34 | var ( 35 | defaultGoogleSDKConfigPath = os.Getenv("HOME") + "/.config/gcloud/configurations/config_default" 36 | ) 37 | 38 | // Provider ... 39 | type Provider struct { 40 | baseURL *url.URL 41 | URL *url.URL 42 | SDKConfig *SDKConfig 43 | Product string 44 | Ctx *cli.Context 45 | Aliases map[string]interface{} 46 | } 47 | 48 | // SDKConfig ... 49 | type SDKConfig struct { 50 | Core *Core 51 | Compute *Compute 52 | Cluster *Container 53 | } 54 | 55 | // Core ... 56 | type Core struct { 57 | Account string 58 | Project string 59 | } 60 | 61 | // Compute ... 62 | type Compute struct { 63 | Zone string 64 | Region string 65 | } 66 | 67 | // Container ... 68 | type Container struct { 69 | Cluster string 70 | } 71 | 72 | // GetProvider ... 73 | func GetProvider() (*Provider, error) { 74 | conf, err := alias.GetConfig() 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | return &Provider{ 80 | Aliases: conf.GCP["alias"].(map[string]interface{}), 81 | }, nil 82 | } 83 | 84 | // Init ... 85 | func (p *Provider) Init(c *cli.Context) error { 86 | var err error 87 | if p.SDKConfig, err = getSDKConfig(); err != nil { 88 | return err 89 | } 90 | 91 | if c.String("project") != "" { 92 | p.SDKConfig.Core.Project = c.String("project") 93 | } 94 | 95 | p.Ctx = c 96 | return nil 97 | } 98 | 99 | // GetTargetURL ... 100 | func (p *Provider) GetTargetURL() (string, error) { 101 | var err error 102 | if p.baseURL, err = url.Parse(baseURL); err != nil { 103 | return "", err 104 | } 105 | 106 | p.addProductPath(p.Ctx.Command.Name) 107 | p.addProjectParam() 108 | return p.URL.String(), nil 109 | } 110 | 111 | func getSDKConfig() (*SDKConfig, error) { 112 | cfg, err := ini.Load(defaultGoogleSDKConfigPath) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | conf := &SDKConfig{ 118 | &Core{ 119 | Account: cfg.Section("core").Key("account").MustString("xxx@email.com"), 120 | Project: cfg.Section("core").Key("project").MustString("xxx"), 121 | }, 122 | &Compute{ 123 | Zone: cfg.Section("compute").Key("zone").MustString("xxx"), 124 | Region: cfg.Section("compute").Key("region").MustString("xxx"), 125 | }, 126 | &Container{ 127 | Cluster: cfg.Section("container").Key("cluster").MustString("xxx"), 128 | }, 129 | } 130 | 131 | return conf, nil 132 | } 133 | 134 | func (p *Provider) addProductPath(product string) { 135 | switch product { 136 | case "appengine": 137 | p.join(product) 138 | case "bigquery": 139 | p.join(product) 140 | var db, table string 141 | if db = p.GetCtxString("database"); db != "" { 142 | q := p.URL.Query() 143 | q.Add("d", db) 144 | if table = p.GetCtxString("table"); table != "" { 145 | q.Add("t", table) 146 | } 147 | p.URL.RawQuery = q.Encode() 148 | } 149 | case "kubernetes": 150 | p.join(product) 151 | var region, name, namespaces string 152 | if region = p.GetCtxString("region"); region != "" { 153 | p.join(fmt.Sprintf("details/%s", region)) 154 | if name = p.GetCtxString("name"); name != "" { 155 | p.join(name) 156 | } 157 | } else if namespaces = p.GetCtxString("namespaces"); namespaces != "" { 158 | p.join("workload") 159 | p.addGKEPageStateParam(namespaces) 160 | } 161 | case "secret-manager": 162 | p.join(fmt.Sprintf("security/%s", product)) 163 | var secret string 164 | if secret = p.GetCtxString("secret"); secret != "" { 165 | p.join(fmt.Sprintf("secret/%s", secret)) 166 | } 167 | case "spanner": 168 | p.join(product) 169 | var instance, db, scheme string 170 | if instance = p.GetCtxString("instance"); instance != "" { 171 | p.join(fmt.Sprintf("instances/%s", instance)) 172 | if db = p.GetCtxString("database"); db != "" { 173 | p.join(fmt.Sprintf("databases/%s", db)) 174 | if scheme = p.GetCtxString("table"); scheme != "" { 175 | p.join(fmt.Sprintf("schema/%s", scheme)) 176 | } 177 | } 178 | } 179 | case "gcr": 180 | p.join(product) 181 | var name string 182 | p.join(fmt.Sprintf("images/%s/", p.SDKConfig.Core.Project)) 183 | if name = p.GetCtxString("name"); name != "" { 184 | p.join(fmt.Sprintf("GLOBAL/%s", name)) 185 | } 186 | case "run", "functions": 187 | p.join(product) 188 | var region, name string 189 | if region = p.GetCtxString("region"); region != "" { 190 | p.join(fmt.Sprintf("details/%s", region)) 191 | 192 | if name = p.GetCtxString("name"); name != "" { 193 | p.join(name) 194 | } 195 | } 196 | 197 | switch product { 198 | case "run": 199 | case "functions": 200 | } 201 | case "logs": 202 | p.join(product) 203 | case "iam": 204 | p.join("iam-admin") 205 | case "sql": 206 | p.join(product) 207 | case "pubsub": 208 | p.join("cloudpubsub") 209 | case "storage": 210 | p.join(fmt.Sprintf("%s/browser", product)) 211 | var bucket string 212 | if bucket = p.GetCtxString("bucket"); bucket != "" { 213 | p.join(bucket) 214 | } 215 | case "dataflow": 216 | p.join(product) 217 | case "kms": 218 | p.join("security/kms") 219 | default: 220 | p.join("home/dashboard") 221 | } 222 | 223 | return 224 | } 225 | 226 | func (p *Provider) addProjectParam() { 227 | q := p.URL.Query() 228 | q.Add("project", p.SDKConfig.Core.Project) 229 | p.URL.RawQuery = q.Encode() 230 | return 231 | } 232 | 233 | func (p *Provider) addGKEPageStateParam(namespaces string) { 234 | q := p.URL.Query() 235 | q.Add("pageState", constructPageStateParam(namespaces)) 236 | p.URL.RawQuery = q.Encode() 237 | return 238 | } 239 | 240 | func constructPageStateParam(rawNamespaces string) string { 241 | nss := strings.Split(rawNamespaces, ",") 242 | quotedNamespaces := make([]string, 0, len(nss)) 243 | for _, s := range nss { 244 | quotedNamespaces = append(quotedNamespaces, strconv.Quote(s)) 245 | } 246 | return fmt.Sprintf("(\"savedViews\":(\"n\":[%s]))", strings.Join(quotedNamespaces, ",")) 247 | } 248 | 249 | // GetCtxString ... 250 | func (p *Provider) GetCtxString(str string) string { 251 | key := p.Ctx.String(str) 252 | if key == "" { 253 | return "" 254 | } 255 | value, ok := p.Aliases[key].(string) 256 | if !ok { 257 | return key 258 | } 259 | if value == "" { 260 | return key 261 | } 262 | return value 263 | } 264 | 265 | func (p *Provider) join(additionPath string) { 266 | if p.URL == nil { 267 | p.URL = p.baseURL 268 | } 269 | p.URL.Path = path.Join(p.URL.Path, additionPath) 270 | } 271 | -------------------------------------------------------------------------------- /cli/jira.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | 21 | "github.com/KeisukeYamashita/biko/browser" 22 | jr "github.com/KeisukeYamashita/biko/providers/jira" 23 | "github.com/urfave/cli" 24 | ) 25 | 26 | func newJIRACmd() cli.Command { 27 | return cli.Command{ 28 | Name: "jira", 29 | Aliases: []string{"jr"}, 30 | Usage: "Open JIRA resource", 31 | Category: categoryCloudProvider, 32 | Flags: []cli.Flag{ 33 | cli.StringFlag{ 34 | Name: "org", 35 | EnvVar: "BIKO_JIRA", 36 | Usage: "Specify JIRA Organization", 37 | }, 38 | cli.StringFlag{ 39 | Name: "base", 40 | EnvVar: "BIKO_JIRA_BASE", 41 | Usage: "Specify JIRA Base URL (for self-managed plan)", 42 | }, 43 | }, 44 | Action: func(c *cli.Context) error { 45 | baseURL, err := getBaseURL(c) 46 | if err != nil { 47 | return err 48 | } 49 | jr := &jr.Provider{} 50 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 51 | return err 52 | } 53 | return browser.Open(c, jr) 54 | }, 55 | Subcommands: []cli.Command{ 56 | newJIRADashboardCmd(), 57 | newJIRAProjectsCmd(), 58 | newJIRAPeopleCmd(), 59 | newJIRAIssuesCmd(), 60 | newJIRABacklogCmd(), 61 | newJIRAReportsCmd(), 62 | }, 63 | } 64 | } 65 | 66 | func newJIRADashboardCmd() cli.Command { 67 | return cli.Command{ 68 | Name: "dashboard", 69 | Aliases: []string{"db"}, 70 | Usage: "Open dashboard page", 71 | Flags: []cli.Flag{ 72 | cli.StringFlag{ 73 | Name: "org", 74 | EnvVar: "BIKO_JIRA", 75 | Usage: "Specify JIRA Organization", 76 | }, 77 | cli.StringFlag{ 78 | Name: "base", 79 | EnvVar: "BIKO_JIRA_BASE", 80 | Usage: "Specify JIRA Base URL (for self-managed plan)", 81 | }, 82 | }, 83 | Action: func(c *cli.Context) error { 84 | baseURL, err := getBaseURL(c) 85 | if err != nil { 86 | return err 87 | } 88 | jr := &jr.Provider{} 89 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 90 | return err 91 | } 92 | return browser.Open(c, jr) 93 | }, 94 | } 95 | } 96 | 97 | func newJIRAProjectsCmd() cli.Command { 98 | return cli.Command{ 99 | Name: "projects", 100 | Aliases: []string{"ps"}, 101 | Usage: "Open projects page", 102 | Flags: []cli.Flag{ 103 | cli.StringFlag{ 104 | Name: "org", 105 | EnvVar: "BIKO_JIRA", 106 | Usage: "Specify JIRA Organization", 107 | }, 108 | cli.StringFlag{ 109 | Name: "base", 110 | EnvVar: "BIKO_JIRA_BASE", 111 | Usage: "Specify JIRA Base URL (for self-managed plan)", 112 | }, 113 | }, 114 | Action: func(c *cli.Context) error { 115 | baseURL, err := getBaseURL(c) 116 | if err != nil { 117 | return err 118 | } 119 | jr := &jr.Provider{} 120 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 121 | return err 122 | } 123 | return browser.Open(c, jr) 124 | }, 125 | } 126 | } 127 | 128 | func newJIRAPeopleCmd() cli.Command { 129 | return cli.Command{ 130 | Name: "people", 131 | Aliases: []string{"pp"}, 132 | Usage: "Open people page", 133 | Flags: []cli.Flag{ 134 | cli.StringFlag{ 135 | Name: "org", 136 | EnvVar: "BIKO_JIRA", 137 | Usage: "Specify JIRA Organization", 138 | }, 139 | cli.StringFlag{ 140 | Name: "base", 141 | EnvVar: "BIKO_JIRA_BASE", 142 | Usage: "Specify JIRA Base URL (for self-managed plan)", 143 | }, 144 | }, 145 | Action: func(c *cli.Context) error { 146 | baseURL, err := getBaseURL(c) 147 | if err != nil { 148 | return err 149 | } 150 | jr := &jr.Provider{} 151 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 152 | return err 153 | } 154 | return browser.Open(c, jr) 155 | }, 156 | } 157 | } 158 | 159 | func newJIRAIssuesCmd() cli.Command { 160 | return cli.Command{ 161 | Name: "issues", 162 | Aliases: []string{"is"}, 163 | Usage: "Open issues page", 164 | Flags: []cli.Flag{ 165 | cli.StringFlag{ 166 | Name: "org", 167 | EnvVar: "BIKO_JIRA", 168 | Usage: "Specify JIRA Organization", 169 | }, 170 | cli.StringFlag{ 171 | Name: "base", 172 | EnvVar: "BIKO_JIRA_BASE", 173 | Usage: "Specify JIRA Base URL (for self-managed plan)", 174 | }, 175 | }, 176 | Action: func(c *cli.Context) error { 177 | baseURL, err := getBaseURL(c) 178 | if err != nil { 179 | return err 180 | } 181 | jr := &jr.Provider{} 182 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 183 | return err 184 | } 185 | return browser.Open(c, jr) 186 | }, 187 | } 188 | } 189 | 190 | func newJIRABacklogCmd() cli.Command { 191 | return cli.Command{ 192 | Name: "backlog", 193 | Aliases: []string{"bl"}, 194 | Usage: "Open backlog page", 195 | Flags: []cli.Flag{ 196 | cli.StringFlag{ 197 | Name: "project, p", 198 | EnvVar: "BIKO_JIRA_PROJECT", 199 | Usage: "Specify the project to open", 200 | }, 201 | cli.StringFlag{ 202 | Name: "org", 203 | EnvVar: "BIKO_JIRA", 204 | Usage: "Specify JIRA Organization", 205 | }, 206 | cli.StringFlag{ 207 | Name: "base", 208 | EnvVar: "BIKO_JIRA_BASE", 209 | Usage: "Specify JIRA Base URL (for self-managed plan)", 210 | }, 211 | }, 212 | Action: func(c *cli.Context) error { 213 | baseURL, err := getBaseURL(c) 214 | if err != nil { 215 | return err 216 | } 217 | jr := &jr.Provider{} 218 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 219 | return err 220 | } 221 | return browser.Open(c, jr) 222 | }, 223 | } 224 | } 225 | 226 | func newJIRAReportsCmd() cli.Command { 227 | return cli.Command{ 228 | Name: "reports", 229 | Aliases: []string{"rp"}, 230 | Usage: "Open reports page", 231 | Flags: []cli.Flag{ 232 | cli.StringFlag{ 233 | Name: "project, p", 234 | EnvVar: "BIKO_JIRA_PROJECT", 235 | Usage: "Specify the project to open", 236 | }, 237 | cli.StringFlag{ 238 | Name: "org", 239 | EnvVar: "BIKO_JIRA", 240 | Usage: "Specify JIRA Organization", 241 | }, 242 | cli.StringFlag{ 243 | Name: "base", 244 | EnvVar: "BIKO_JIRA_BASE", 245 | Usage: "Specify JIRA Base URL (for self-managed plan)", 246 | }, 247 | }, 248 | Action: func(c *cli.Context) error { 249 | var project string 250 | if project = c.String("project"); project == "" { 251 | return fmt.Errorf("Project for jira not configured pass --project or set BIKO_JIRA_PROJECT") 252 | } 253 | baseURL, err := getBaseURL(c) 254 | if err != nil { 255 | return err 256 | } 257 | jr := &jr.Provider{} 258 | if jr.BaseURL, err = url.Parse(baseURL); err != nil { 259 | return err 260 | } 261 | return browser.Open(c, jr) 262 | }, 263 | } 264 | } 265 | 266 | func getBaseURL(c *cli.Context) (string, error) { 267 | org := c.String("org") 268 | base := c.String("base") 269 | if org == "" && base == "" { 270 | return "", fmt.Errorf("Org and Base for jira not configured pass --org/BIKO_JIRA or --base/BIKO_JIRA_BASE") 271 | } 272 | var baseURL = fmt.Sprintf("https://%s.atlassian.net", org) // for jira cloud 273 | if base != "" { 274 | baseURL = base // for self-managed 275 | } 276 | return baseURL, nil 277 | } 278 | -------------------------------------------------------------------------------- /cli/firebase.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/firebase" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | const ( 24 | categoryDevelop = "Develop" 25 | categoryQuality = "Quality" 26 | categoryAnalytics = "Analitics" 27 | categoryGrow = "Grow" 28 | ) 29 | 30 | func newFirebaseCmd() cli.Command { 31 | return cli.Command{ 32 | Name: "firebase", 33 | Aliases: []string{"fb"}, 34 | Usage: "Open Firebase source", 35 | Category: categoryCloudProvider, 36 | Flags: []cli.Flag{ 37 | cli.StringFlag{ 38 | Name: "project", 39 | Usage: "Specify the project to open", 40 | }, 41 | }, 42 | Action: func(c *cli.Context) error { 43 | g, err := firebase.GetProvider() 44 | if err != nil { 45 | return err 46 | } 47 | return browser.Open(c, g) 48 | }, 49 | Subcommands: []cli.Command{ 50 | newFirebaseAuthenticateCmd(), 51 | newFirebaseDatabaseCmd(), 52 | newFirebaseStorageCmd(), 53 | newFirebaseHostingCmd(), 54 | newFirebaseFunctionsCmd(), 55 | newFirebaseMLKitCmd(), 56 | newFirebaseCrashlyticsCmd(), 57 | newFirebasePerformanceCmd(), 58 | newFirebaseTestLabCmd(), 59 | newFirebaseAppDistributionCmd(), 60 | newFirebasePredictionsCmd(), 61 | }, 62 | } 63 | } 64 | 65 | func newFirebaseAuthenticateCmd() cli.Command { 66 | return cli.Command{ 67 | Name: "authentication", 68 | Aliases: []string{"auth"}, 69 | Category: categoryDevelop, 70 | Usage: "Open authentication page", 71 | Flags: []cli.Flag{ 72 | cli.StringFlag{ 73 | Name: "project", 74 | Usage: "Specify the project to open", 75 | }, 76 | }, 77 | Action: func(c *cli.Context) error { 78 | fb, err := firebase.GetProvider() 79 | if err != nil { 80 | return err 81 | } 82 | return browser.Open(c, fb) 83 | }, 84 | } 85 | } 86 | 87 | func newFirebaseDatabaseCmd() cli.Command { 88 | return cli.Command{ 89 | Name: "database", 90 | Aliases: []string{"db"}, 91 | Category: categoryDevelop, 92 | Usage: "Open database page", 93 | Flags: []cli.Flag{ 94 | cli.StringFlag{ 95 | Name: "project", 96 | Usage: "Specify the project to open", 97 | }, 98 | }, 99 | Action: func(c *cli.Context) error { 100 | fb, err := firebase.GetProvider() 101 | if err != nil { 102 | return err 103 | } 104 | return browser.Open(c, fb) 105 | }, 106 | } 107 | } 108 | 109 | func newFirebaseStorageCmd() cli.Command { 110 | return cli.Command{ 111 | Name: "storage", 112 | Category: categoryDevelop, 113 | Usage: "Open storage page", 114 | Flags: []cli.Flag{ 115 | cli.StringFlag{ 116 | Name: "project", 117 | Usage: "Specify the project to open", 118 | }, 119 | }, 120 | Action: func(c *cli.Context) error { 121 | fb, err := firebase.GetProvider() 122 | if err != nil { 123 | return err 124 | } 125 | return browser.Open(c, fb) 126 | }, 127 | } 128 | } 129 | 130 | func newFirebaseHostingCmd() cli.Command { 131 | return cli.Command{ 132 | Name: "hosting", 133 | Aliases: []string{"host", "h"}, 134 | Category: categoryDevelop, 135 | Usage: "Open storage page", 136 | Flags: []cli.Flag{ 137 | cli.StringFlag{ 138 | Name: "project", 139 | Usage: "Specify the project to open", 140 | }, 141 | }, 142 | Action: func(c *cli.Context) error { 143 | fb, err := firebase.GetProvider() 144 | if err != nil { 145 | return err 146 | } 147 | return browser.Open(c, fb) 148 | }, 149 | } 150 | } 151 | 152 | func newFirebaseFunctionsCmd() cli.Command { 153 | return cli.Command{ 154 | Name: "functions", 155 | Aliases: []string{"func", "f"}, 156 | Category: categoryDevelop, 157 | Usage: "Open functions page", 158 | Flags: []cli.Flag{ 159 | cli.StringFlag{ 160 | Name: "project", 161 | Usage: "Specify the project to open", 162 | }, 163 | }, 164 | Action: func(c *cli.Context) error { 165 | fb, err := firebase.GetProvider() 166 | if err != nil { 167 | return err 168 | } 169 | return browser.Open(c, fb) 170 | }, 171 | } 172 | } 173 | 174 | func newFirebaseMLKitCmd() cli.Command { 175 | return cli.Command{ 176 | Name: "ml", 177 | Category: categoryDevelop, 178 | Usage: "Open ML kit page", 179 | Flags: []cli.Flag{ 180 | cli.StringFlag{ 181 | Name: "project", 182 | Usage: "Specify the project to open", 183 | }, 184 | }, 185 | Action: func(c *cli.Context) error { 186 | fb, err := firebase.GetProvider() 187 | if err != nil { 188 | return err 189 | } 190 | return browser.Open(c, fb) 191 | }, 192 | } 193 | } 194 | 195 | func newFirebaseCrashlyticsCmd() cli.Command { 196 | return cli.Command{ 197 | Name: "crashlytics", 198 | Aliases: []string{"crash"}, 199 | Category: categoryQuality, 200 | Usage: "Open crashlytics page", 201 | Flags: []cli.Flag{ 202 | cli.StringFlag{ 203 | Name: "project", 204 | Usage: "Specify the project to open", 205 | }, 206 | }, 207 | Action: func(c *cli.Context) error { 208 | fb, err := firebase.GetProvider() 209 | if err != nil { 210 | return err 211 | } 212 | return browser.Open(c, fb) 213 | }, 214 | } 215 | } 216 | 217 | func newFirebasePerformanceCmd() cli.Command { 218 | return cli.Command{ 219 | Name: "performance", 220 | Aliases: []string{"perf"}, 221 | Category: categoryQuality, 222 | Usage: "Open performance page", 223 | Flags: []cli.Flag{ 224 | cli.StringFlag{ 225 | Name: "project", 226 | Usage: "Specify the project to open", 227 | }, 228 | }, 229 | Action: func(c *cli.Context) error { 230 | fb, err := firebase.GetProvider() 231 | if err != nil { 232 | return err 233 | } 234 | return browser.Open(c, fb) 235 | }, 236 | } 237 | } 238 | 239 | func newFirebaseTestLabCmd() cli.Command { 240 | return cli.Command{ 241 | Name: "testlab", 242 | Aliases: []string{"tl"}, 243 | Category: categoryQuality, 244 | Usage: "Open testlab page", 245 | Flags: []cli.Flag{ 246 | cli.StringFlag{ 247 | Name: "project", 248 | Usage: "Specify the project to open", 249 | }, 250 | }, 251 | Action: func(c *cli.Context) error { 252 | fb, err := firebase.GetProvider() 253 | if err != nil { 254 | return err 255 | } 256 | return browser.Open(c, fb) 257 | }, 258 | } 259 | } 260 | 261 | func newFirebaseAppDistributionCmd() cli.Command { 262 | return cli.Command{ 263 | Name: "appdistribution", 264 | Aliases: []string{"ad"}, 265 | Category: categoryQuality, 266 | Usage: "Open app distribution page", 267 | Flags: []cli.Flag{ 268 | cli.StringFlag{ 269 | Name: "project", 270 | Usage: "Specify the project to open", 271 | }, 272 | }, 273 | Action: func(c *cli.Context) error { 274 | fb, err := firebase.GetProvider() 275 | if err != nil { 276 | return err 277 | } 278 | return browser.Open(c, fb) 279 | }, 280 | } 281 | } 282 | 283 | func newFirebaseDashboardCmd() cli.Command { 284 | return cli.Command{ 285 | Name: "dashboard", 286 | Aliases: []string{"a"}, 287 | Category: categoryAnalytics, 288 | Usage: "Open dashboard page", 289 | Flags: []cli.Flag{ 290 | cli.StringFlag{ 291 | Name: "project", 292 | Usage: "Specify the project to open", 293 | }, 294 | }, 295 | Action: func(c *cli.Context) error { 296 | fb, err := firebase.GetProvider() 297 | if err != nil { 298 | return err 299 | } 300 | return browser.Open(c, fb) 301 | }, 302 | } 303 | } 304 | 305 | func newFirebasePredictionsCmd() cli.Command { 306 | return cli.Command{ 307 | Name: "predictions", 308 | Aliases: []string{"pred"}, 309 | Category: categoryGrow, 310 | Usage: "Open predictions page", 311 | Flags: []cli.Flag{ 312 | cli.StringFlag{ 313 | Name: "project", 314 | Usage: "Specify the project to open", 315 | }, 316 | }, 317 | Action: func(c *cli.Context) error { 318 | fb, err := firebase.GetProvider() 319 | if err != nil { 320 | return err 321 | } 322 | return browser.Open(c, fb) 323 | }, 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /cli/aws.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/aws" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | const ( 24 | categoryAWSComputing = "Computing" 25 | categoryAWSStorage = "Storage" 26 | categoryAWSDatabase = "Database" 27 | categoryAWSNetworking = "Networking and Contens Delivery" 28 | ) 29 | 30 | func newAWSCmd() cli.Command { 31 | return cli.Command{ 32 | Name: "aws", 33 | Usage: "Open AWS resource", 34 | Category: categoryCloudProvider, 35 | Flags: []cli.Flag{}, 36 | Action: func(c *cli.Context) error { 37 | aws, err := aws.GetProvider() 38 | if err != nil { 39 | return err 40 | } 41 | return browser.Open(c, aws) 42 | }, 43 | Subcommands: []cli.Command{ 44 | newAWSEC2Cmd(), 45 | newAWSECRCmd(), 46 | newAWSECSCmd(), 47 | newAWSLambdaCmd(), 48 | newAWSBatchCmd(), 49 | newAWSS3Cmd(), 50 | newAWSEFSCmd(), 51 | newAWSRDSCmd(), 52 | newAWSDynamoDBCmd(), 53 | newAWSNeptuneCmd(), 54 | newAWSVPCCmd(), 55 | newAWSRoute53Cmd(), 56 | }, 57 | } 58 | } 59 | 60 | func newAWSEC2Cmd() cli.Command { 61 | return cli.Command{ 62 | Name: "ec2", 63 | Usage: "Open EC2 page", 64 | Category: categoryAWSComputing, 65 | Flags: []cli.Flag{ 66 | cli.StringFlag{ 67 | Name: "region, r", 68 | Usage: "Specify the region to open", 69 | }, 70 | }, 71 | Action: func(c *cli.Context) error { 72 | aws, err := aws.GetProvider() 73 | if err != nil { 74 | return err 75 | } 76 | return browser.Open(c, aws) 77 | }, 78 | } 79 | } 80 | 81 | func newAWSECRCmd() cli.Command { 82 | return cli.Command{ 83 | Name: "ecr", 84 | Usage: "Open ECR page", 85 | Category: categoryAWSComputing, 86 | Flags: []cli.Flag{}, 87 | Action: func(c *cli.Context) error { 88 | aws, err := aws.GetProvider() 89 | if err != nil { 90 | return err 91 | } 92 | return browser.Open(c, aws) 93 | }, 94 | } 95 | } 96 | 97 | func newAWSECSCmd() cli.Command { 98 | return cli.Command{ 99 | Name: "ecs", 100 | Usage: "Open ECS page", 101 | Category: categoryAWSComputing, 102 | Flags: []cli.Flag{ 103 | cli.StringFlag{ 104 | Name: "region, r", 105 | Usage: "Specify the region to open", 106 | }, 107 | }, 108 | Action: func(c *cli.Context) error { 109 | aws, err := aws.GetProvider() 110 | if err != nil { 111 | return err 112 | } 113 | return browser.Open(c, aws) 114 | }, 115 | } 116 | } 117 | 118 | func newAWSEKSCmd() cli.Command { 119 | return cli.Command{ 120 | Name: "eks", 121 | Usage: "Open EKS page", 122 | Category: categoryAWSComputing, 123 | Flags: []cli.Flag{ 124 | cli.StringFlag{ 125 | Name: "region, r", 126 | Usage: "Specify the region to open", 127 | }, 128 | }, 129 | Action: func(c *cli.Context) error { 130 | aws, err := aws.GetProvider() 131 | if err != nil { 132 | return err 133 | } 134 | return browser.Open(c, aws) 135 | }, 136 | } 137 | } 138 | 139 | func newAWSLambdaCmd() cli.Command { 140 | return cli.Command{ 141 | Name: "lambda", 142 | Aliases: []string{"lam", "l"}, 143 | Usage: "Open EKS page", 144 | Category: categoryAWSComputing, 145 | Flags: []cli.Flag{ 146 | cli.StringFlag{ 147 | Name: "region, r", 148 | Usage: "Specify the region to open", 149 | }, 150 | }, 151 | Action: func(c *cli.Context) error { 152 | aws, err := aws.GetProvider() 153 | if err != nil { 154 | return err 155 | } 156 | return browser.Open(c, aws) 157 | }, 158 | } 159 | } 160 | 161 | func newAWSBatchCmd() cli.Command { 162 | return cli.Command{ 163 | Name: "batch", 164 | Aliases: []string{"b"}, 165 | Usage: "Open Batch page", 166 | Category: categoryAWSComputing, 167 | Flags: []cli.Flag{ 168 | cli.StringFlag{ 169 | Name: "region, r", 170 | Usage: "Specify the region to open", 171 | }, 172 | }, 173 | Action: func(c *cli.Context) error { 174 | aws, err := aws.GetProvider() 175 | if err != nil { 176 | return err 177 | } 178 | return browser.Open(c, aws) 179 | }, 180 | } 181 | } 182 | 183 | func newAWSS3Cmd() cli.Command { 184 | return cli.Command{ 185 | Name: "s3", 186 | Usage: "Open S3 page", 187 | Category: categoryAWSStorage, 188 | Flags: []cli.Flag{ 189 | cli.StringFlag{ 190 | Name: "region, r", 191 | Usage: "Specify the region to open", 192 | }, 193 | }, 194 | Action: func(c *cli.Context) error { 195 | aws, err := aws.GetProvider() 196 | if err != nil { 197 | return err 198 | } 199 | return browser.Open(c, aws) 200 | }, 201 | } 202 | } 203 | 204 | func newAWSEFSCmd() cli.Command { 205 | return cli.Command{ 206 | Name: "efs", 207 | Usage: "Open EFS page", 208 | Category: categoryAWSStorage, 209 | Flags: []cli.Flag{ 210 | cli.StringFlag{ 211 | Name: "region, r", 212 | Usage: "Specify the region to open", 213 | }, 214 | }, 215 | Action: func(c *cli.Context) error { 216 | aws, err := aws.GetProvider() 217 | if err != nil { 218 | return err 219 | } 220 | return browser.Open(c, aws) 221 | }, 222 | } 223 | } 224 | 225 | func newAWSRDSCmd() cli.Command { 226 | return cli.Command{ 227 | Name: "rds", 228 | Usage: "Open RDS page", 229 | Category: categoryAWSDatabase, 230 | Flags: []cli.Flag{ 231 | cli.StringFlag{ 232 | Name: "region, r", 233 | Usage: "Specify the region to open", 234 | }, 235 | }, 236 | Action: func(c *cli.Context) error { 237 | aws, err := aws.GetProvider() 238 | if err != nil { 239 | return err 240 | } 241 | return browser.Open(c, aws) 242 | }, 243 | } 244 | } 245 | 246 | func newAWSDynamoDBCmd() cli.Command { 247 | return cli.Command{ 248 | Name: "dynamodb", 249 | Aliases: []string{"dynamo", "dyn"}, 250 | Usage: "Open Dynamo page", 251 | Category: categoryAWSDatabase, 252 | Flags: []cli.Flag{ 253 | cli.StringFlag{ 254 | Name: "region, r", 255 | Usage: "Specify the region to open", 256 | }, 257 | }, 258 | Action: func(c *cli.Context) error { 259 | aws, err := aws.GetProvider() 260 | if err != nil { 261 | return err 262 | } 263 | return browser.Open(c, aws) 264 | }, 265 | } 266 | } 267 | 268 | func newAWSNeptuneCmd() cli.Command { 269 | return cli.Command{ 270 | Name: "neptune", 271 | Usage: "Open Neptune page", 272 | Category: categoryAWSDatabase, 273 | Flags: []cli.Flag{ 274 | cli.StringFlag{ 275 | Name: "region, r", 276 | Usage: "Specify the region to open", 277 | }, 278 | }, 279 | Action: func(c *cli.Context) error { 280 | aws, err := aws.GetProvider() 281 | if err != nil { 282 | return err 283 | } 284 | return browser.Open(c, aws) 285 | }, 286 | } 287 | } 288 | 289 | func newAWSRedshiftCmd() cli.Command { 290 | return cli.Command{ 291 | Name: "redshift", 292 | Aliases: []string{"red", "rs"}, 293 | Usage: "Open Neptune page", 294 | Category: categoryAWSDatabase, 295 | Flags: []cli.Flag{ 296 | cli.StringFlag{ 297 | Name: "region, r", 298 | Usage: "Specify the region to open", 299 | }, 300 | }, 301 | Action: func(c *cli.Context) error { 302 | aws, err := aws.GetProvider() 303 | if err != nil { 304 | return err 305 | } 306 | return browser.Open(c, aws) 307 | }, 308 | } 309 | } 310 | 311 | func newAWSVPCCmd() cli.Command { 312 | return cli.Command{ 313 | Name: "vpc", 314 | Usage: "Open VPC page", 315 | Category: categoryAWSNetworking, 316 | Flags: []cli.Flag{ 317 | cli.StringFlag{ 318 | Name: "region, r", 319 | Usage: "Specify the region to open", 320 | }, 321 | }, 322 | Action: func(c *cli.Context) error { 323 | aws, err := aws.GetProvider() 324 | if err != nil { 325 | return err 326 | } 327 | return browser.Open(c, aws) 328 | }, 329 | } 330 | } 331 | 332 | func newAWSRoute53Cmd() cli.Command { 333 | return cli.Command{ 334 | Name: "route53", 335 | Usage: "Open Route53 page", 336 | Aliases: []string{"route", "53"}, 337 | Category: categoryAWSNetworking, 338 | Flags: []cli.Flag{ 339 | cli.StringFlag{ 340 | Name: "region, r", 341 | Usage: "Specify the region to open", 342 | }, 343 | }, 344 | Action: func(c *cli.Context) error { 345 | aws, err := aws.GetProvider() 346 | if err != nil { 347 | return err 348 | } 349 | return browser.Open(c, aws) 350 | }, 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /cli/gcp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Biko Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cli 16 | 17 | import ( 18 | "github.com/KeisukeYamashita/biko/browser" 19 | "github.com/KeisukeYamashita/biko/providers/gcp" 20 | "github.com/urfave/cli" 21 | ) 22 | 23 | const ( 24 | categoryCommon = "Common" 25 | categoryCompute = "Compute" 26 | categoryStorage = "Storage" 27 | categoryNetworking = "Networking" 28 | categoryStackdriver = "Stackdriver" 29 | categoryTools = "Tools" 30 | categoryBigData = "Big Data" 31 | ) 32 | 33 | func newGCPCmd() cli.Command { 34 | return cli.Command{ 35 | Name: "gcp", 36 | Usage: "Open GCP resource", 37 | Category: categoryCloudProvider, 38 | Flags: []cli.Flag{ 39 | cli.StringFlag{ 40 | Name: "project", 41 | Usage: "Specify the project to open", 42 | }, 43 | }, 44 | Action: func(c *cli.Context) error { 45 | gcp := &gcp.Provider{} 46 | return browser.Open(c, gcp) 47 | }, 48 | Subcommands: []cli.Command{ 49 | newGCPGAECmd(), 50 | newGCPBQCmd(), 51 | newGCPCloudRunCmd(), 52 | newGCPDataflowCmd(), 53 | newGCPFunctionsCmd(), 54 | newGCPGCECmd(), 55 | newGCPGCRCmd(), 56 | newGCPGKECmd(), 57 | newGCPIAMCmd(), 58 | newGCPLogsCmd(), 59 | newGCPKMSCmd(), 60 | newGCPPubSubCmd(), 61 | newGCPSecretManagerCmd(), 62 | newGCPSpannerCmd(), 63 | newGCPStorageCmd(), 64 | newGCPSQLCmd(), 65 | }, 66 | } 67 | } 68 | 69 | func newGCPGAECmd() cli.Command { 70 | return cli.Command{ 71 | Name: "appengine", 72 | Aliases: []string{"gae"}, 73 | Category: categoryCompute, 74 | Usage: "Open GAE page", 75 | Flags: []cli.Flag{ 76 | cli.StringFlag{ 77 | Name: "project", 78 | Usage: "Specify the project to open", 79 | }, 80 | }, 81 | Action: func(c *cli.Context) error { 82 | gcp, err := gcp.GetProvider() 83 | if err != nil { 84 | return err 85 | } 86 | return browser.Open(c, gcp) 87 | }, 88 | } 89 | } 90 | 91 | func newGCPBQCmd() cli.Command { 92 | return cli.Command{ 93 | Name: "bigquery", 94 | Aliases: []string{"bq"}, 95 | Category: categoryBigData, 96 | Usage: "Open Bigquery page", 97 | Flags: []cli.Flag{ 98 | cli.StringFlag{ 99 | Name: "project", 100 | Usage: "Specify the project to open", 101 | }, 102 | cli.StringFlag{ 103 | Name: "database, db", 104 | Usage: "Database to show", 105 | }, 106 | cli.StringFlag{ 107 | Name: "table, t", 108 | Usage: "Table to show", 109 | }, 110 | }, 111 | Action: func(c *cli.Context) error { 112 | gcp, err := gcp.GetProvider() 113 | if err != nil { 114 | return err 115 | } 116 | return browser.Open(c, gcp) 117 | }, 118 | } 119 | } 120 | 121 | func newGCPGKECmd() cli.Command { 122 | return cli.Command{ 123 | Name: "kubernetes", 124 | Aliases: []string{"gke"}, 125 | Category: categoryCompute, 126 | Usage: "Open GKE page", 127 | Flags: []cli.Flag{ 128 | cli.StringFlag{ 129 | Name: "project", 130 | Usage: "Specify the project to open", 131 | }, 132 | cli.StringFlag{ 133 | Name: "region, r", 134 | Usage: "Region of the cluster", 135 | }, 136 | cli.StringFlag{ 137 | Name: "name, n", 138 | Usage: "Name of the cluter", 139 | }, 140 | cli.StringFlag{ 141 | Name: "namespaces, ns", 142 | Usage: "Namespaces of workload page to open (you can input multiple namespaces by comma-speparated string)", 143 | }, 144 | }, 145 | Action: func(c *cli.Context) error { 146 | gcp, err := gcp.GetProvider() 147 | if err != nil { 148 | return err 149 | } 150 | return browser.Open(c, gcp) 151 | }, 152 | } 153 | } 154 | 155 | func newGCPSpannerCmd() cli.Command { 156 | return cli.Command{ 157 | Name: "spanner", 158 | Usage: "Open Cloud Spanner page", 159 | Category: categoryStorage, 160 | Flags: []cli.Flag{ 161 | cli.StringFlag{ 162 | Name: "project", 163 | Usage: "Specify the project to open", 164 | }, 165 | cli.StringFlag{ 166 | Name: "instance, i", 167 | Usage: "Instance name", 168 | }, 169 | cli.StringFlag{ 170 | Name: "database, db", 171 | Usage: "Database name", 172 | }, 173 | cli.StringFlag{ 174 | Name: "table, tb", 175 | Usage: "Table name", 176 | }, 177 | }, 178 | Action: func(c *cli.Context) error { 179 | gcp, err := gcp.GetProvider() 180 | if err != nil { 181 | return err 182 | } 183 | return browser.Open(c, gcp) 184 | }, 185 | } 186 | } 187 | 188 | func newGCPSecretManagerCmd() cli.Command { 189 | return cli.Command{ 190 | Name: "secret-manager", 191 | Aliases: []string{"sm", "secretmanager", "secretManager"}, 192 | Usage: "Open Secret Manager page", 193 | Category: categoryStorage, 194 | Flags: []cli.Flag{ 195 | cli.StringFlag{ 196 | Name: "project", 197 | Usage: "Specify the project to open", 198 | }, 199 | cli.StringFlag{ 200 | Name: "secret, s", 201 | Usage: "Secret name", 202 | }, 203 | }, 204 | Action: func(c *cli.Context) error { 205 | gcp, err := gcp.GetProvider() 206 | if err != nil { 207 | return err 208 | } 209 | return browser.Open(c, gcp) 210 | }, 211 | } 212 | } 213 | 214 | func newGCPGCRCmd() cli.Command { 215 | return cli.Command{ 216 | Name: "gcr", 217 | Usage: "Open Cloud Registry page", 218 | Category: categoryTools, 219 | Flags: []cli.Flag{ 220 | cli.StringFlag{ 221 | Name: "project", 222 | Usage: "Specify the project to open", 223 | }, 224 | cli.StringFlag{ 225 | Name: "name, n", 226 | Usage: "Name of the image", 227 | }, 228 | }, 229 | Action: func(c *cli.Context) error { 230 | gcp, err := gcp.GetProvider() 231 | if err != nil { 232 | return err 233 | } 234 | return browser.Open(c, gcp) 235 | }, 236 | } 237 | } 238 | 239 | func newGCPFunctionsCmd() cli.Command { 240 | return cli.Command{ 241 | Name: "functions", 242 | Aliases: []string{"f"}, 243 | Category: categoryCompute, 244 | Usage: "Open Cloud Functions page", 245 | Flags: []cli.Flag{ 246 | cli.StringFlag{ 247 | Name: "project", 248 | Usage: "Specify the project to open", 249 | }, 250 | cli.StringFlag{ 251 | Name: "name, n", 252 | Usage: "Name of the function", 253 | }, 254 | cli.StringFlag{ 255 | Name: "region, r", 256 | Usage: "Region of the function", 257 | }, 258 | }, 259 | Action: func(c *cli.Context) error { 260 | gcp, err := gcp.GetProvider() 261 | if err != nil { 262 | return err 263 | } 264 | return browser.Open(c, gcp) 265 | }, 266 | } 267 | } 268 | 269 | func newGCPCloudRunCmd() cli.Command { 270 | return cli.Command{ 271 | Name: "run", 272 | Category: categoryCompute, 273 | Usage: "Open Cloud Run page", 274 | Flags: []cli.Flag{ 275 | cli.StringFlag{ 276 | Name: "project", 277 | Usage: "Specify the project to open", 278 | }, 279 | cli.StringFlag{ 280 | Name: "name, n", 281 | Usage: "Name of the function", 282 | }, 283 | cli.StringFlag{ 284 | Name: "region, r", 285 | Usage: "Region of the function", 286 | }, 287 | }, 288 | Action: func(c *cli.Context) error { 289 | gcp, err := gcp.GetProvider() 290 | if err != nil { 291 | return err 292 | } 293 | return browser.Open(c, gcp) 294 | }, 295 | } 296 | } 297 | 298 | func newGCPGCECmd() cli.Command { 299 | return cli.Command{ 300 | Name: "compute", 301 | Aliases: []string{"gce"}, 302 | Category: categoryCompute, 303 | Usage: "Open Compute Engine page", 304 | Flags: []cli.Flag{ 305 | cli.StringFlag{ 306 | Name: "project", 307 | Usage: "Specify the project to open", 308 | }, 309 | }, 310 | Action: func(c *cli.Context) error { 311 | gcp, err := gcp.GetProvider() 312 | if err != nil { 313 | return err 314 | } 315 | return browser.Open(c, gcp) 316 | }, 317 | } 318 | } 319 | 320 | func newGCPLogsCmd() cli.Command { 321 | return cli.Command{ 322 | Name: "logs", 323 | Aliases: []string{"l"}, 324 | Category: categoryStackdriver, 325 | Usage: "Open Stackdriver log page", 326 | Flags: []cli.Flag{ 327 | cli.StringFlag{ 328 | Name: "project", 329 | Usage: "Specify the project to open", 330 | }, 331 | }, 332 | Action: func(c *cli.Context) error { 333 | gcp, err := gcp.GetProvider() 334 | if err != nil { 335 | return err 336 | } 337 | return browser.Open(c, gcp) 338 | }, 339 | } 340 | } 341 | 342 | func newGCPIAMCmd() cli.Command { 343 | return cli.Command{ 344 | Name: "iam", 345 | Category: categoryCommon, 346 | Usage: "Open IAM & admin page", 347 | Flags: []cli.Flag{ 348 | cli.StringFlag{ 349 | Name: "project", 350 | Usage: "Specify the project to open", 351 | }, 352 | }, 353 | Action: func(c *cli.Context) error { 354 | gcp, err := gcp.GetProvider() 355 | if err != nil { 356 | return err 357 | } 358 | return browser.Open(c, gcp) 359 | }, 360 | } 361 | } 362 | 363 | func newGCPSQLCmd() cli.Command { 364 | return cli.Command{ 365 | Name: "sql", 366 | Category: categoryStorage, 367 | Usage: "Open Cloud SQL page", 368 | Flags: []cli.Flag{ 369 | cli.StringFlag{ 370 | Name: "project", 371 | Usage: "Specify the project to open", 372 | }, 373 | }, 374 | Action: func(c *cli.Context) error { 375 | gcp, err := gcp.GetProvider() 376 | if err != nil { 377 | return err 378 | } 379 | return browser.Open(c, gcp) 380 | }, 381 | } 382 | } 383 | 384 | func newGCPPubSubCmd() cli.Command { 385 | return cli.Command{ 386 | Name: "pubsub", 387 | Category: categoryBigData, 388 | Usage: "Open Cloud PubSub page", 389 | Flags: []cli.Flag{ 390 | cli.StringFlag{ 391 | Name: "project", 392 | Usage: "Specify the project to open", 393 | }, 394 | }, 395 | Action: func(c *cli.Context) error { 396 | gcp, err := gcp.GetProvider() 397 | if err != nil { 398 | return err 399 | } 400 | return browser.Open(c, gcp) 401 | }, 402 | } 403 | } 404 | 405 | func newGCPStorageCmd() cli.Command { 406 | return cli.Command{ 407 | Name: "storage", 408 | Aliases: []string{"gcs"}, 409 | Category: categoryStorage, 410 | Usage: "Open Cloud Storage page", 411 | Flags: []cli.Flag{ 412 | cli.StringFlag{ 413 | Name: "project", 414 | Usage: "Specify the project to open", 415 | }, 416 | cli.StringFlag{ 417 | Name: "bucket, b", 418 | Usage: "Specify the bucket to open", 419 | }, 420 | }, 421 | Action: func(c *cli.Context) error { 422 | gcp, err := gcp.GetProvider() 423 | if err != nil { 424 | return err 425 | } 426 | return browser.Open(c, gcp) 427 | }, 428 | } 429 | } 430 | 431 | func newGCPDataflowCmd() cli.Command { 432 | return cli.Command{ 433 | Name: "dataflow", 434 | Category: categoryBigData, 435 | Usage: "Open Cloud Dataflow page", 436 | Flags: []cli.Flag{ 437 | cli.StringFlag{ 438 | Name: "project", 439 | Usage: "Specify the project to open", 440 | }, 441 | }, 442 | Action: func(c *cli.Context) error { 443 | gcp, err := gcp.GetProvider() 444 | if err != nil { 445 | return err 446 | } 447 | return browser.Open(c, gcp) 448 | }, 449 | } 450 | } 451 | 452 | func newGCPKMSCmd() cli.Command { 453 | return cli.Command{ 454 | Name: "kms", 455 | Category: categoryBigData, 456 | Usage: "Open Cloud KMS", 457 | Flags: []cli.Flag{ 458 | cli.StringFlag{ 459 | Name: "project", 460 | Usage: "Specify the project to open", 461 | }, 462 | }, 463 | Action: func(c *cli.Context) error { 464 | gcp, err := gcp.GetProvider() 465 | if err != nil { 466 | return err 467 | } 468 | return browser.Open(c, gcp) 469 | }, 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Biko 2 | 3 | > CLI tool to jump to your browser directly to improve productivity 4 | 5 |
6 |

7 |
8 | 9 | [![Go][go-badge]][go] 10 | ![Test](https://github.com/KeisukeYamashita/biko/workflows/Test/badge.svg) 11 | [![GolangCI][golangci-badge]][golangci] 12 | [![Go Report Card][go-report-card-badge]][go-report-card] 13 | [![GoDoc][godoc-badge]][godoc] 14 | [![Dependabot][dependabot-badge]][dependabot] 15 | ![License](https://img.shields.io/badge/license-Apache%202.0-%23E93424) 16 | 17 | 18 | 19 | 20 | 21 | 22 | - [Install](#install) 23 | - [By Homebrew](#by-homebrew) 24 | - [By source code](#by-source-code) 25 | - [Usage](#usage) 26 | - [Go to your target directly](#go-to-your-target-directly) 27 | - [Exaple1. Open GCP Cloud Spanner to specified project](#exaple1-open-gcp-cloud-spanner-to-specified-project) 28 | - [Example2. Open Datadog Dashboad](#example2-open-datadog-dashboad) 29 | - [Alias](#alias) 30 | - [Support](#support) 31 | - [AWS](#aws) 32 | - [Azure](#azure) 33 | - [CircleCI](#circleci) 34 | - [Datadog](#datadog) 35 | - [Firebase](#firebase) 36 | - [GCP](#gcp) 37 | - [Github](#github) 38 | - [Google](#google) 39 | - [GoogleWorkspace](#googleworkspace) 40 | - [Pagerduty](#pagerduty) 41 | - [Youtube](#youtube) 42 | - [(Advanced): Docker image](#advanced-docker-image) 43 | - [Contribute](#contribute) 44 | - [Add a provider](#add-a-provider) 45 | - [Maintainers](#maintainers) 46 | - [Contributers](#contributers) 47 | - [Roadmap](#roadmap) 48 | - [License](#license) 49 | 50 | 51 | 52 | 53 | ## Install 54 | 55 | ### By Homebrew 56 | 57 | Install by homebrew. 58 | 59 | ```console 60 | $ brew install KeisukeYamashita/tap/biko 61 | ``` 62 | 63 | ### By source code 64 | 65 | Install by source code. 66 | 67 | ```console 68 | $ go get github.com/KeisukeYamashita/biko/cmd/biko 69 | ``` 70 | 71 | Then build it. 72 | 73 | ``` 74 | $ make install 75 | ``` 76 | 77 | ## Usage 78 | 79 | ### Go to your target directly 80 | 81 | #### Exaple1. Open GCP Cloud Spanner to specified project 82 | 83 | ``` 84 | $ biko gcp spanner --project my-spanner-project 85 | ``` 86 | 87 | If you don't specify the project, it will use the value configured by `gcloud` SDK config. 88 | 89 | #### Example2. Open Datadog Dashboad 90 | 91 | ``` 92 | $ biko dd dashboard 93 | ``` 94 | 95 | ## Alias 96 | 97 | You can configure your alias for whatever you want for frequently used projects, products, names, etc. 98 | For example, if you use the Cloud Function `my-cloud-functions` in region `asia-northeast1`, you can configure it like below in `$HOME/.biko/config.toml`. 99 | 100 | ```toml 101 | [gcp] 102 | [gcp.alias] 103 | mcf = "my-cloud-functions" 104 | an1 = "asia-northeast1" 105 | ``` 106 | 107 | Now, you can open your page like below using the configured alias. 108 | 109 | ``` 110 | $ biko gcp functions -r as1 -n mcf 111 | ``` 112 | 113 | You can directly go to your page without waiting to load pages many times. 114 | 115 | ## Support 116 | 117 | The supported provider are here. 118 | 119 | * Amazon Web Service(AWS) 120 | * Microsoft Azure 121 | * CircleCI 122 | * Datadog 123 | * Firebase 124 | * GoogleCloudPlatform(GCP) 125 | * Github 126 | * Google 127 | * Pagerduty 128 | * Youtube 129 | * JIRA 130 | 131 | ### AWS 132 | 133 | * Open AWS Console product page 134 | * To open region page, please pass `--region, -r` flag. 135 | 136 | ``` 137 | $ biko aws [product] [flag(s)] 138 | ``` 139 | 140 | **Supported Product** 141 | 142 | **Computing** 143 | 144 | | Product | What | Command | Flags(Optional) | 145 | |:----:|:----:|:----:|:----:| 146 | | EC2 | Open EC2 | `ec2` | - | 147 | | ECR | Open ECR | `ecr` | - | 148 | | ECS | Open ECR | `ecs` | - | 149 | | EKS | Open EKR | `eks` | - | 150 | | Lambda | Open Lambda | `lambda, lam` | - | 151 | | Batch | Open Batch | `batch, b` | - | 152 | 153 | **Storage** 154 | 155 | | Product | What | Command | Flags(Optional) | 156 | |:----:|:----:|:----:|:----:| 157 | | S3 | Open S3 page | `s3` | - | 158 | | EFS | Open EFS page | `efs` | - | 159 | 160 | **Database** 161 | 162 | | Product | What | Command | Flags(Optional) | 163 | |:----:|:----:|:----:|:----:| 164 | | RDS | Open RDS | `rds` | - | 165 | | DynamoDB | Open DynamoDB |`dynamo, dyn` | - | 166 | | Neptune | Open Neptune | `neptune, nep` | - | 167 | | Redshift | Open Redshift | `redshift, red, rs` | - | 168 | 169 | **Networking** 170 | 171 | | Product | What | Command | Flags(Optional) | 172 | |:----:|:----:|:----:|:----:| 173 | | VPC | Open VPC | `vpc` | - | 174 | | Route53 | Open Route53 |`route53, route, 53` | - | 175 | 176 | ### Azure 177 | 178 | * Open Microsoft Azure console 179 | 180 | ``` 181 | $ biko azure [product] [flag(s)] 182 | # or 183 | $ biko az [product] [flag(s)] 184 | ``` 185 | 186 | **Supported Product** 187 | 188 | | Product | What | Command | Flags(Optional) | 189 | |:----:|:----:|:----:|:----:| 190 | | Virtual Machines | Open VM | `vm` | - | 191 | | App Services | Open App Services | `appservices`, `as`, `sites` | - | 192 | | Function App | Open Function App | `functions, f` | - | 193 | | Storage Accounts | Open Storage Accounts | `storage` | - | 194 | | SQL Databases | Open SQL Database | `sql` | - | 195 | | Cosmos DB | Open Cosmos Database | `cosmos` | - | 196 | 197 | ### CircleCI 198 | 199 | * Open CircleCI from your terminal. 200 | * You need to pass `--org` or configure `BIKO_CIRCLECI` 201 | 202 | ``` 203 | $ biko circleci [product] [flag(s)] 204 | # or 205 | $ biko cc [product] [flag(s)] 206 | ``` 207 | 208 | | Product | What | Command | Flags(Optional) | 209 | |:----:|:----:|:----:|:----:| 210 | | Jobs | Open CircleCI Jobs | `jobs, j` | `--project`, `-p` | 211 | | Workflows | Open CircleCI Workflows | `workflows, wf` | `--project`, `-p` | 212 | 213 | ### Datadog 214 | 215 | * `datadog` or `dd` command is supported for Datadog. 216 | 217 | ``` 218 | $ biko datadog [product] [flag(s)] 219 | # or 220 | $ biko dd [product] [flag(s)] 221 | ``` 222 | 223 | **Supported Product** 224 | 225 | | Product | What | Command | Flags(Optional) | 226 | |:----:|:----:|:----:|:----:| 227 | | Watchdog | Go to Watchdog Dashboard | `watchdog`, `wd` | - | 228 | | Events | Go to Events Dashboard | `events` | - | 229 | | Dashboard | Go to Dashboard page | `dashboard` | - | 230 | | Infrastructure | Go to Infrastructure page | `infrastructure` | - | 231 | | Monitors | Go to Monitors Dashboard | `moniters` | - | 232 | | Integrations | Go to Integrations page | `integrations` | - | 233 | | APM | Go to APM page | `apm` | - | 234 | | Notebook | Go to Notebook page | `notebook` | - | 235 | | Logs | Go to logs page | `logs` | `--view, -v` | 236 | | Synthetics | Go to synthetics page | `synthetics` | - | 237 | 238 | 239 | ### Firebase 240 | 241 | * Open Google Firebase form your terminal. 242 | * Please pass `--project` to open supported products page. 243 | 244 | ``` 245 | $ biko firebase [product] [flag(s)] 246 | # or 247 | $ biko fb [product] [flag(s)] 248 | ``` 249 | 250 | **Supported Product** 251 | 252 | **Development** 253 | 254 | | Product | What | Command | Flags(Optional) | 255 | |:----:|:----:|:----:|:----:| 256 | | Authentication | Go to auth | `authentications, auth` | - | 257 | | Database | Go to database | `database, db` | - | 258 | | Storage | Go to storage | `storage` | - | 259 | | Hosting | Go to Hosting | `hosting, host, h` | - | 260 | | Functions | Go to functions | `funcitons, func, f` | - | 261 | | ML Kit | Go to ML Kit | `ml` | - | 262 | 263 | **Quality** 264 | 265 | | Product | What | Command | Flags(Optional) | 266 | |:----:|:----:|:----:|:----:| 267 | | Crashlytics | Go to cryshlytics | `crashlytics, crash` | - | 268 | | Performance | Go to performance | `performance, perf` | - | 269 | | Test Lab | Go to Test Lab | `testlab, tl` | - | 270 | | App Distribution | Go to App Distribution | `appdistribution, ad` | - | 271 | 272 | **Analytics** 273 | 274 | | Product | What | Command | Flags(Optional) | 275 | |:----:|:----:|:----:|:----:| 276 | | Dashboard | Go to dashboard | `dashboard` | - | 277 | 278 | **Grow** 279 | 280 | | Product | What | Command | Flags(Optional) | 281 | |:----:|:----:|:----:|:----:| 282 | | Grow | Go to grow | `grow` | - | 283 | 284 | ### GCP 285 | 286 | * By default, it will open the project configured by `gcloud` command. 287 | 288 | ``` 289 | $ biko gcp [product] [flag(s)] 290 | ``` 291 | 292 | **Supported Product** 293 | 294 | **Common** 295 | 296 | | Product | What | Command | Flags(Optional) | 297 | |:----:|:----:|:----:|:----:| 298 | | IAM & admin | Go to IAM & admin logging | `iam` | - | 299 | 300 | **Compute** 301 | 302 | | Product | What | Command | Flags(Optional) | 303 | |:----:|:----:|:----:|:----:| 304 | | App Engine | Go to GAE Dashboard | `appengine`, `gae` | - | 305 | | Compute Engine | Go to GCE page | `compute` | - | 306 | | Cloud Functions | Go to Cloud Functions page or the functions detail | `functions`, `f` | `--region, -r`, `--name, -n` | 307 | | Cloud Run | Go to Cloud Run page or the deployments detail | `run` | `--region, -r`, `--name, -n` | 308 | | KMS | Go to security's cryptographic keys page | `kms` | - | 309 | | Kubernetes | Go to GKE page, or the cluster detail | `kubernetes`, `gke` | `--region, -r`, `--name, -n` `--namespaces, -ns` | 310 | 311 | **Storage** 312 | 313 | | Product | What | Command | Flags(Optional) | 314 | |:----:|:----:|:----:|:----:| 315 | | Cloud SQL | Go to Cloud SQL | `sql` | - | 316 | | Cloud Storage | Go to Cloud Storage `storage` | - | 317 | | Spanner | Go to spanner page, or the instance, database, table | `spanner` | `--instance, -i`, `--database, -db`, `--table, -t` | 318 | 319 | **Networking** 320 | 321 | | Product | What | Command | Flags(Optional) | 322 | |:----:|:----:|:----:|:----:| 323 | 324 | **Stackdriver** 325 | 326 | | Product | What | Command | Flags(Optional) | 327 | |:----:|:----:|:----:|:----:| 328 | | Stackdriver Logging | Go to Stackdriver logging | `logs`, `l` | - | 329 | 330 | **Tools** 331 | 332 | | Product | What | Command | Flags(Optional) | 333 | |:----:|:----:|:----:|:----:| 334 | | Container Registry | Go to container registry or the container detail | `gcr` | `--name, -n` | 335 | 336 | 337 | **Security** 338 | 339 | | Secret Manager | Go to secret manager's detail | `secret-manager`, `sm`, `secretmanager`, `secretManager` | `--secret, -s` | 340 | 341 | 342 | **Big Data** 343 | 344 | | Product | What | Command | Flags(Optional) | 345 | |:----:|:----:|:----:|:----:| 346 | | Bigquery | Go to Bigquery top or the database, table | `bigquery`, `bq` | `--database, -db`, `--table, -tb` | 347 | | Cloud PubSub | Go to Cloud PubSub | `pubsub` | - | 348 | | Cloud Dataflow | Go to Cloud Dataflow | `dataflow` | - | 349 | 350 | Note that there is `--project` command flag for all commands. 351 | 352 | ### Github 353 | 354 | * Open Github from your terminal. 355 | 356 | ``` 357 | $ biko github [product] [flag(s)] 358 | # or 359 | $ biko gh [product] [flag(s)] 360 | ``` 361 | 362 | | Product | What | Command | Flags(Optional) | 363 | | :----: | :----: | :----: | :----: | 364 | | Dashboard | Open github Dashboard | `dashboard`, `db` | `--org` | 365 | | Trending | Open github Treinding | `trending`, `t` | `--language, -l`, `--since, -s` | 366 | | Repository | Open github Repository | `repository`, `r` | `--org`, `--name, -n` | 367 | 368 | ### Google 369 | 370 | * Open Google and search from your terminal. 371 | 372 | ``` 373 | $ biko google [product] [flag(s)] 374 | # or 375 | $ biko g [product] [flag(s)] 376 | ``` 377 | 378 | | Product | What | Command | Flags(Optional) | 379 | |:----:|:----:|:----:|:----:| 380 | | Search | Search on Google | `search`, `s` | `--query, -q` | 381 | 382 | 383 | If you bump into something you want to lookup when you are using the terminal... 384 | 385 | ``` 386 | $ biko g s -q "How to configure biko" 387 | ``` 388 | 389 | Blazing fast. 390 | 391 | ### Google Workspace 392 | 393 | * Open Google Workspace search from your terminal. 394 | 395 | ``` 396 | $ biko googleworkspace [product] [flag(s)] 397 | # or 398 | $ biko gw [product] [flag(s)] 399 | ``` 400 | 401 | | Product | What | Command | Flags(Optional) | 402 | | :----: | :----: | :----: | :----: | 403 | | drive | Search on Google Drive | `drive`, `dr` | `--query, -q` | 404 | | document | Search on Google Docs | `document`, `doc` | `--query, -q` | 405 | | document | Create a new Google Docs | `document`, `doc` | `--new, -n` | 406 | | spreadsheets | Search on Google Sheets | `spreadsheets`, `ss` | `--query, -q` | 407 | | spreadsheets | Create a new Google Sheets | `spreadsheets`, `ss` | `--new, -n` | 408 | | presentation | Search on Google Slides | `presentation`, `pr` | `--query, -q` | 409 | | presentation | Create a new Google Slides | `presentation`, `pr` | `--new, -n` | 410 | | forms | Search on Google Forms | `forms`, `fm` | `--query, -q` | 411 | | forms | Create a new Google Forms | `forms`, `fm` | `--new, -n` | 412 | 413 | 414 | ### Pagerduty 415 | 416 | * If you are using SSO, you need to pass `--org` or configure `BIKO_PAGERDUTY` 417 | 418 | ``` 419 | $ biko pagerduty [product] [flag(s)] 420 | # or 421 | $ biko pd [product] [flag(s)] 422 | ``` 423 | 424 | | Product | What | Command | Flags(Optional) | 425 | |:----:|:----:|:----:|:----:| 426 | | Incident | Go to incident page | `incident`, `i` | - | 427 | | Alert | Go to alert page | `alert`, `a` | - | 428 | | Schedules | Go to schedules page | `schedules`, `s` | - | 429 | 430 | ### Youtube 431 | 432 | * Open Youtube and search from your terminal. 433 | 434 | ``` 435 | $ biko youtube [product] [flag(s)] 436 | # or 437 | $ biko yt [product] [flag(s)] 438 | ``` 439 | 440 | | Product | What | Command | Flags(Optional) | 441 | |:----:|:----:|:----:|:----:| 442 | | Search | Search on Youtube | `search`, `s` | `--query, -q` | 443 | 444 | ### JIRA 445 | 446 | * If you are using SSO, you need to pass `--org` or configure `BIKO_JIRA` 447 | * If you are using Jira self-managed plan, you need to specify base URL by passing `--base` or setting `BIKO_JIRA_BASE` 448 | * This `--project` flag can be omitted by set `BIKO_JIRA_PROJECT` to the env variable 449 | 450 | ``` 451 | $ biko jira [product] [flag(s)] 452 | # or 453 | $ biko jr [product] [flag(s)] 454 | ``` 455 | 456 | | Product | What | Command | Flags(Optional) | 457 | |:----:|:----:|:----:|:----:| 458 | | Dashboard | Go to dashboard page | `dashboard`, `db` | - | 459 | | Projects | Go to projects page | `projects`, `ps` | - | 460 | | People | Go to people page | `people`, `pp` | - | 461 | | Issues | Go to issues page | `issues`, `is` | - | 462 | | Backlog | Go to backlog page | `backlog`, `bl` | `--project, -p` | 463 | | Reports | Go to reports page | `reports`, `rp` | `--project, -p` | 464 | 465 | ## (Advanced): Docker image 466 | 467 | You can execute the cli with docker image. 468 | 469 | ``` 470 | $ docker run biko help 471 | ``` 472 | 473 | ## Contribute 474 | 475 | ### Add a provider 476 | 477 | You can add a provider by implementing this interface. 478 | 479 | ```go 480 | // Provider are interfaces ... 481 | type Provider interface { 482 | Init(c *cli.Context) error 483 | GetTargetURL() (string, error) 484 | } 485 | ``` 486 | 487 | * `Init` will initialize your provider struct 488 | * `GetTargetURL` should return a URL which will the browser will open 489 | 490 | ## Maintainers 491 | 492 | [![KeisukeYamashita](https://avatars0.githubusercontent.com/u/23056537?s=80&u=c5d3b68a3af8c1ce35312e75fdb9aa0df1dcfbfe&v=4)](https://github.com/KeisukeYamashita) 493 | [![sapuri](https://avatars3.githubusercontent.com/u/18478610?s=80&u=997adb161c67b36cffaad898c0f8a92323b74147&v=4)](https://github.com/sapuri) 494 | 495 | ## Contributers 496 | [![KeisukeYamashita](https://avatars0.githubusercontent.com/u/23056537?s=80&u=c5d3b68a3af8c1ce35312e75fdb9aa0df1dcfbfe&v=4)](https://github.com/KeisukeYamashita) 497 | [![sapuri](https://avatars3.githubusercontent.com/u/18478610?s=80&u=997adb161c67b36cffaad898c0f8a92323b74147&v=4)](https://github.com/sapuri) 498 | [![shopetan](https://avatars2.githubusercontent.com/u/5266288?s=80&v=4)](https://github.com/shopetan) 499 | [![micnncim](https://avatars2.githubusercontent.com/u/21333876?s=80&u=60396941fae4b274d90db1aafa47fd462ef9ad4d&v=4)](https://github.com/micnncim) 500 | [![hirosassa](https://avatars0.githubusercontent.com/u/423223?s=80&u=92f27ae1540d2edb911d7bd2abfc2c3b59224d84&v=4)](https://github.com/hirosassa) 501 | 502 | ## Roadmap 503 | 504 | * See `docs/ROADMAP.md` for the project's roadmap. 505 | * Proposal are welcome. 506 | 507 | ## License 508 | 509 | Copyright 2019 The Biko Authors. 510 | Biko is released under the Apache License 2.0. 511 | 512 | 513 | [go]: https://golang.org/dl 514 | [go-badge]: https://img.shields.io/badge/Go-1.16-blue 515 | 516 | [godoc]: https://godoc.org/github.com/KeisukeYamashita/biko 517 | [godoc-badge]: https://img.shields.io/badge/godoc.org-reference-blue.svg 518 | 519 | [golangci]: https://golangci.com/r/github.com/KeisukeYamashita/biko 520 | [golangci-badge]: https://golangci.com/badges/github.com/KeisukeYamashita/biko.svg 521 | 522 | [go-report-card]: https://goreportcard.com/report/github.com/KeisukeYamashita/biko 523 | [go-report-card-badge]: https://goreportcard.com/badge/github.com/KeisukeYamashita/biko 524 | 525 | [dependabot]: https://dependabot.com 526 | [dependabot-badge]: https://badgen.net/badge/icon/Dependabot?icon=dependabot&label&color=blue 527 | --------------------------------------------------------------------------------