diff --git a/.config/default.toml b/.config/default.toml index ba9ec15..41142e9 100644 --- a/.config/default.toml +++ b/.config/default.toml @@ -18,3 +18,6 @@ [circleci] [circleci.alias] + +[firebase] + [firebase.alias] \ No newline at end of file diff --git a/README.md b/README.md index 26bf9d1..bb9ec0a 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ The supported provider are here. * Pagerduty * Github * CircleCI +* Firebase ## Alias @@ -292,6 +293,50 @@ $ biko cc [product] [flag(s)] | Jobs | Open CircleCI Jobs | `jobs, j` | `--project`, `-p` | | Workflows | Open CircleCI Workflows | `workflows, wf` | `--project`, `-p` | +### Firebase + +* Open Google Firebase form your terminal. +* Please pass `--project` to open supported products page. + +``` +$ biko firebase [product] [flag(s)] +# or +$ biko fb [product] [flag(s)] +``` + +**Supported Product** + +**Development** + +| Product | What | Command | Flags(Optional) | +|:----:|:----:|:----:|:----:| +| Authentication | Go to auth | `authentications, auth` | - | +| Database | Go to database | `database, db` | - | +| Storage | Go to storage | `storage` | - | +| Hosting | Go to Hosting | `hosting, host, h` | - | +| Functions | Go to functions | `funcitons, func, f` | - | +| ML Kit | Go to ML Kit | `ml` | - | + +**Quality** + +| Product | What | Command | Flags(Optional) | +|:----:|:----:|:----:|:----:| +| Crashlytics | Go to cryshlytics | `crashlytics, crash` | - | +| Performance | Go to performance | `performance, perf` | - | +| Test Lab | Go to Test Lab | `testlab, tl` | - | +| App Distribution | Go to App Distribution | `appdistribution, ad` | - | + +**Analytics** + +| Product | What | Command | Flags(Optional) | +|:----:|:----:|:----:|:----:| +| Dashboard | Go to dashboard | `dashboard` | - | + +**Grow** + +| Product | What | Command | Flags(Optional) | +|:----:|:----:|:----:|:----:| +| Grow | Go to grow | `grow` | - | ## (Advanced): Docker image diff --git a/alias/alias.go b/alias/alias.go index 1ea5fda..e3ac322 100644 --- a/alias/alias.go +++ b/alias/alias.go @@ -34,6 +34,7 @@ type TomlConfig struct { PagerDuty map[string]interface{} `toml:"pagerduty"` Github map[string]interface{} `toml:"github"` CircleCI map[string]interface{} `toml:"circleci"` + Firebase map[string]interface{} `toml:"firebase"` } // GetConfig ... diff --git a/alias/testdata/config.toml b/alias/testdata/config.toml index c48e06e..332a0c6 100644 --- a/alias/testdata/config.toml +++ b/alias/testdata/config.toml @@ -16,3 +16,6 @@ [github] [github.alias] + +[firebase] + [firebase.alias] \ No newline at end of file diff --git a/cli/firebase.go b/cli/firebase.go new file mode 100644 index 0000000..0b8a8c7 --- /dev/null +++ b/cli/firebase.go @@ -0,0 +1,324 @@ +// Copyright 2019 The Biko Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cli + +import ( + "github.com/KeisukeYamashita/biko/browser" + "github.com/KeisukeYamashita/biko/providers/firebase" + "github.com/urfave/cli" +) + +const ( + categoryDevelop = "Develop" + categoryQuality = "Quality" + categoryAnalytics = "Analitics" + categoryGrow = "Grow" +) + +func newFirebaseCmd() cli.Command { + return cli.Command{ + Name: "firebase", + Aliases: []string{"fb"}, + Usage: "Open Firebase source", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + g, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, g) + }, + Subcommands: []cli.Command{ + newFirebaseAuthenticateCmd(), + newFirebaseDatabaseCmd(), + newFirebaseStorageCmd(), + newFirebaseHostingCmd(), + newFirebaseFunctionsCmd(), + newFirebaseMLKitCmd(), + newFirebaseCrashlyticsCmd(), + newFirebasePerformanceCmd(), + newFirebaseTestLabCmd(), + newFirebaseAppDistributionCmd(), + newFirebasePredictionsCmd(), + }, + } +} + +func newFirebaseAuthenticateCmd() cli.Command { + return cli.Command{ + Name: "authentication", + Aliases: []string{"auth"}, + Category: categoryDevelop, + Usage: "Open authentication page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseDatabaseCmd() cli.Command { + return cli.Command{ + Name: "database", + Aliases: []string{"db"}, + Category: categoryDevelop, + Usage: "Open database page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseStorageCmd() cli.Command { + return cli.Command{ + Name: "storage", + Category: categoryDevelop, + Usage: "Open storage page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseHostingCmd() cli.Command { + return cli.Command{ + Name: "hosting", + Aliases: []string{"host", "h"}, + Category: categoryDevelop, + Usage: "Open storage page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseFunctionsCmd() cli.Command { + return cli.Command{ + Name: "functions", + Aliases: []string{"func", "f"}, + Category: categoryDevelop, + Usage: "Open functions page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseMLKitCmd() cli.Command { + return cli.Command{ + Name: "ml", + Category: categoryDevelop, + Usage: "Open ML kit page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseCrashlyticsCmd() cli.Command { + return cli.Command{ + Name: "crashlytics", + Aliases: []string{"crash"}, + Category: categoryQuality, + Usage: "Open crashlytics page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebasePerformanceCmd() cli.Command { + return cli.Command{ + Name: "performance", + Aliases: []string{"perf"}, + Category: categoryQuality, + Usage: "Open performance page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseTestLabCmd() cli.Command { + return cli.Command{ + Name: "testlab", + Aliases: []string{"tl"}, + Category: categoryQuality, + Usage: "Open testlab page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseAppDistributionCmd() cli.Command { + return cli.Command{ + Name: "appdistribution", + Aliases: []string{"ad"}, + Category: categoryQuality, + Usage: "Open app distribution page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebaseDashboardCmd() cli.Command { + return cli.Command{ + Name: "dashboard", + Aliases: []string{"a"}, + Category: categoryAnalytics, + Usage: "Open dashboard page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} + +func newFirebasePredictionsCmd() cli.Command { + return cli.Command{ + Name: "predictions", + Aliases: []string{"pred"}, + Category: categoryGrow, + Usage: "Open predictions page", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "project", + Usage: "Specify the project to open", + }, + }, + Action: func(c *cli.Context) error { + fb, err := firebase.GetProvider() + if err != nil { + return err + } + return browser.Open(c, fb) + }, + } +} diff --git a/cli/root.go b/cli/root.go index f838dcb..b12d487 100644 --- a/cli/root.go +++ b/cli/root.go @@ -44,5 +44,6 @@ func rootSubCommands() []cli.Command { newPagerDutyCmd(), newGithubCmd(), newCircleCICmd(), + newFirebaseCmd(), } } diff --git a/cli/version.go b/cli/version.go index 3617026..e5621d3 100644 --- a/cli/version.go +++ b/cli/version.go @@ -21,7 +21,7 @@ import ( ) const ( - version = "0.0.1" + version = "0.0.11" ) func newVersionCmd() cli.Command { diff --git a/providers/firebase/firebase.go b/providers/firebase/firebase.go new file mode 100644 index 0000000..d8cb3ae --- /dev/null +++ b/providers/firebase/firebase.go @@ -0,0 +1,116 @@ +// Copyright 2019 The Biko Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package firebase + +import ( + "fmt" + "net/url" + "path" + + "github.com/KeisukeYamashita/biko/alias" + "github.com/urfave/cli" +) + +// Provider ... +type Provider struct { + baseURL *url.URL + URL *url.URL + Ctx *cli.Context + Aliases map[string]interface{} +} + +// GetProvider ... +func GetProvider() (*Provider, error) { + conf, err := alias.GetConfig() + if err != nil { + return nil, err + } + + return &Provider{ + Aliases: conf.Firebase["alias"].(map[string]interface{}), + }, nil +} + +// Init ... +func (p *Provider) Init(c *cli.Context) error { + p.Ctx = c + return nil +} + +// GetTargetURL ... +func (p *Provider) GetTargetURL() (string, error) { + const baseURL = "https://console.firebase.google.com/u/0" + var err error + if p.baseURL, err = url.Parse(baseURL); err != nil { + return "", err + } + p.addProductPath(p.Ctx.Command.Name) + return p.URL.String(), nil +} + +func (p *Provider) addProductPath(product string) { + p.URL = p.baseURL + if product == "" { + return + } + + var project string + if project = p.GetCtxString("project"); project != "" { + p.join(fmt.Sprintf("project/%s", project)) + switch product { + case "retention": + p.join("cohort") + case "ab": + p.join("experiments/list") + case "notification": + // This is "Cloud Messaging" + p.join("notification") + case "inappmessaging": + p.join("inappmessaging/onboarding") + case "dynamicLinks": + p.join("durablelinks") + default: + p.join(product) + } + + return + } + + p.join("overview") + return +} + +// GetCtxString ... +func (p *Provider) GetCtxString(str string) string { + key := p.Ctx.String(str) + if key == "" { + return "" + } + value, ok := p.Aliases[key].(string) + if !ok { + return key + } + if value == "" { + return key + } + return value +} + +func (p *Provider) join(additionPath string) { + if p.URL == nil { + p.URL = p.baseURL + } + p.URL.Path = path.Join(p.URL.Path, additionPath) +}