From 170541679c67f6b308a5b355b100517d6cc6bb28 Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 14:43:44 -0600 Subject: [PATCH 1/6] fix: allow downloading any quickstart [CLI-30] --- go.mod | 2 +- internal/cli/data/quickstarts.json | 364 +++++++++++++++++++++++++++++ internal/cli/quickstarts.go | 101 +++++++- 3 files changed, 457 insertions(+), 10 deletions(-) create mode 100644 internal/cli/data/quickstarts.json diff --git a/go.mod b/go.mod index 4def956a0..bff712678 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/auth0/auth0-cli -go 1.14 +go 1.16 require ( github.com/AlecAivazis/survey/v2 v2.2.7 diff --git a/internal/cli/data/quickstarts.json b/internal/cli/data/quickstarts.json new file mode 100644 index 000000000..9d8d8b107 --- /dev/null +++ b/internal/cli/data/quickstarts.json @@ -0,0 +1,364 @@ +{ + "backend": [ + { + "name": "ASP.NET Core Web API", + "samples": [ + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnetcore-webapi-samples" + }, + { + "name": "ASP.NET Core Web API v2.1", + "samples": [ + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnetcore-webapi-samples", + "branch": "netcore2.1" + }, + { + "name": "Django API", + "samples": [ + "01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-django-api" + }, + { + "name": "Go", + "samples": [ + "01-Authorization-RS256" + ], + "org": "auth0-samples", + "repo": "auth0-golang-api-samples" + }, + { + "name": "Spring Security 4 Java API", + "samples": [ + "01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-spring-security-api-sample" + }, + { + "name": "Spring Security 5 Java API", + "samples": [ + "01-Authorization-MVC" + ], + "org": "auth0-samples", + "repo": "auth0-spring-security5-api-sample" + }, + { + "name": "Laravel API", + "samples": [ + "01-Authorization-RS256" + ], + "org": "auth0-samples", + "repo": "auth0-laravel-api-samples" + }, + { + "name": "Node (Express) API", + "samples": [ + "01-Authorization-RS256" + ], + "org": "auth0-samples", + "repo": "auth0-express-api-samples" + }, + { + "name": "PHP API", + "samples": [ + "01-Authorization-RS256" + ], + "org": "auth0-samples", + "repo": "auth0-php-api-samples" + }, + { + "name": "Python API", + "samples": [ + "00-Starter-Seed" + ], + "org": "auth0-samples", + "repo": "auth0-python-api-samples" + }, + { + "name": "Ruby On Rails API", + "samples": [ + "01-Authentication-RS256" + ], + "org": "auth0-samples", + "repo": "auth0-rubyonrails-api-samples" + }, + { + "name": "ASP.NET Web API (OWIN)", + "samples": [ + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnet-owin-webapi-samples" + } + ], + "native": [ + { + "name": "Android", + "samples": [ + "00-Login-Kt" + ], + "org": "auth0-samples", + "repo": "auth0-android-sample" + }, + { + "name": "Android - Facebook Login", + "samples": [ + "00-login-facebook" + ], + "org": "auth0-samples", + "repo": "auth0-android-native-social-sample" + }, + { + "name": "Cordova", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-cordova-samples" + }, + { + "name": "Ionic 4", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-ionic4-samples" + }, + { + "name": "iOS Swift", + "samples": [ + "00-Login", + "03-User-Sessions", + "04-Calling-APIs", + "05-5uthorization", + "07-Linking-Accounts", + "08-Credentials-TouchID" + ], + "org": "auth0-samples", + "repo": "auth0-ios-swift-sample" + }, + { + "name": "iOS Swift - Facebook Login", + "samples": [ + "00-login-facebook" + ], + "org": "auth0-samples", + "repo": "auth0-ios-swift-native-social-samples" + }, + { + "name": "iOS Swift - Sign In With Apple", + "samples": [ + "00-login-siwa" + ], + "org": "auth0-samples", + "repo": "auth0-ios-swift-native-social-samples" + }, + { + "name": "React Native", + "samples": [ + "00-Login" + ], + "org": "auth0-samples", + "repo": "auth0-react-native-sample" + }, + { + "name": "Windows Universal App C#", + "samples": [ + "Quickstart/00-Starter-Seed" + ], + "org": "auth0-samples", + "repo": "auth0-uwp-oidc-samples" + }, + { + "name": "WPF / Winforms", + "samples": [ + "Quickstart/00-Starter-Seed" + ], + "org": "auth0-samples", + "repo": "auth0-WinFormsWPF-oidc-samples" + }, + { + "name": "Xamarin", + "samples": [ + "Quickstart/01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-xamarin-oidc-samples" + } + ], + "spa": [ + { + "name": "Angular", + "samples": [ + "Sample-01" + ], + "org": "auth0-samples", + "repo": "auth0-angular-samples" + }, + { + "name": "React", + "samples": [ + "Sample-01" + ], + "org": "auth0-samples", + "repo": "auth0-react-samples" + }, + { + "name": "JavaScript", + "samples": [ + "01-Login", + "02-Calling-an-API" + ], + "org": "auth0-samples", + "repo": "auth0-javascript-samples" + }, + { + "name": "Vue", + "samples": [ + "01-Login", + "02-Calling-an-API" + ], + "org": "auth0-samples", + "repo": "auth0-vue-samples" + } + ], + "webapp": [ + { + "name": "ASP.NET Core", + "samples": [ + "Quickstart/01-Login", + "Quickstart/01-User-Profile", + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnetcore-mvc-samples" + }, + { + "name": "ASP.NET Core v2.1", + "samples": [ + "Quickstart/01-Login", + "Quickstart/01-User-Profile", + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnetcore-mvc-samples", + "branch": "netcore2.1" + }, + { + "name": "ASP.NET (OWIN)", + "samples": [ + "Quickstart/01-Login", + "Quickstart/01-User-Profile", + "Quickstart/01-Authorization" + ], + "org": "auth0-samples", + "repo": "auth0-aspnet-owin-mvc-samples" + }, + { + "name": "Django", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-django-web-app" + }, + { + "name": "Express", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-express-webapp-sample" + }, + { + "name": "Go", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-golang-web-app" + }, + { + "name": "Java", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-servlet-sample" + }, + { + "name": "Java EE", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-java-ee-sample" + }, + { + "name": "Java Spring Boot", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-spring-boot-login-samples" + }, + { + "name": "PHP (Laravel)", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-laravel-php-web-app" + }, + { + "name": "Next.js", + "samples": [ + "Sample-01" + ], + "org": "auth0-samples", + "repo": "auth0-nextjs-samples", + "branch": "main" + }, + { + "name": "Node.js", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-nodejs-webapp-sample" + }, + { + "name": "PHP", + "samples": [ + "00-Starter-Seed" + ], + "org": "auth0-samples", + "repo": "auth0-php-web-app" + }, + { + "name": "Python", + "samples": [ + "01-Login" + ], + "org": "auth0-samples", + "repo": "auth0-python-web-app" + }, + { + "name": "Ruby On Rails", + "samples": [ + "01-Login", + "02-Session-Handling", + "03-User-Profile" + ], + "org": "auth0-samples", + "repo": "auth0-rubyonrails-sample" + } + ] + } diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index ed7928555..64202249b 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -3,6 +3,7 @@ package cli import ( "bytes" "context" + _ "embed" "encoding/json" "fmt" "io" @@ -11,13 +12,34 @@ import ( "os" "path" "regexp" + "sort" "github.com/auth0/auth0-cli/internal/ansi" + "github.com/auth0/auth0-cli/internal/prompt" "github.com/mholt/archiver/v3" "github.com/spf13/cobra" "gopkg.in/auth0.v5/management" ) +var ( + //go:embed data/quickstarts.json + qsBuf []byte + quickstartsByType = func() (qs map[string][]quickstart) { + if err := json.Unmarshal(qsBuf, &qs); err != nil { + panic(err) + } + return + }() +) + +type quickstart struct { + Name string `json:"name"` + Samples []string `json:"samples"` + Org string `json:"org"` + Repo string `json:"repo"` + Branch string `json:"branch,omitempty"` +} + func quickstartsCmd(cli *cli) *cobra.Command { cmd := &cobra.Command{ Use: "quickstarts", @@ -48,6 +70,26 @@ func downloadQuickstart(cli *cli) *cobra.Command { return err } + var selectedType = flags.Type + var selectedStack = flags.Stack + + if selectedType == "" { + input := prompt.SelectInput("type", "Quickstart Type:", "Type of quickstart to download", quickstartTypes(), true) + if err := prompt.AskOne(input, &selectedType); err != nil { + return err + } + } + if selectedStack == "" { + stacks, err := quickstartStacksFromType(selectedType) + if err != nil { + return err + } + input := prompt.SelectInput("stack", "Quickstart Stack:", "Tech/Language to use for quickstart", stacks, true) + if err := prompt.AskOne(input, &selectedStack); err != nil { + return err + } + } + target, exists, err := quickstartPathFor(client) if err != nil { return err @@ -60,8 +102,13 @@ func downloadQuickstart(cli *cli) *cobra.Command { return nil } + q, err := getQuickstart(selectedType, selectedStack) + if err != nil { + return err + } + err = ansi.Spinner("Downloading quickstart", func() error { - return downloadQuickStart(context.TODO(), cli, client, flags.Stack, target) + return downloadQuickStart(context.TODO(), cli, client, target, q) }) if err != nil { @@ -77,7 +124,7 @@ func downloadQuickstart(cli *cli) *cobra.Command { cmd.Flags().StringVar(&flags.ClientID, "client-id", "", "ID of the client.") cmd.Flags().StringVarP(&flags.Type, "type", "t", "", "Type of the quickstart to download.") cmd.Flags().StringVarP(&flags.Stack, "stack", "s", "", "Tech stack of the quickstart to use.") - mustRequireFlags(cmd, "client-id", "type", "stack") + mustRequireFlags(cmd, "client-id") return cmd } @@ -89,7 +136,7 @@ const ( quickstartDefaultCallbackURL = `https://YOUR_APP/callback` ) -func downloadQuickStart(ctx context.Context, cli *cli, client *management.Client, target, stack string) error { +func downloadQuickStart(ctx context.Context, cli *cli, client *management.Client, target string, q quickstart) error { var payload struct { Branch string `json:"branch"` Org string `json:"org"` @@ -110,12 +157,14 @@ func downloadQuickStart(ctx context.Context, cli *cli, client *management.Client payload.Tenant = ten.Name payload.Domain = ten.Domain - // FIXME(cyx): these are hard coded. We can followup with a lookup - // table -- which I don't know if there's a canonical place for that - // already. - payload.Branch = "master" - payload.Repo = "auth0-cordova-samples" - payload.Path = "01-Login" + // FIXME(copland): Default to first item from list of samples. + // Eventually we should add a forced survey for user to select one if + // there are multiple. + payload.Branch = q.Branch + payload.Repo = q.Repo + payload.Path = q.Samples[0] + + fmt.Printf("%+v\n", payload) // These appear to be largely constant and refers to the github // username they're under. @@ -195,3 +244,37 @@ func quickstartPathFor(client *management.Client) (p string, exists bool, err er return target, exists, nil } + +func getQuickstart(typ, stack string) (quickstart, error) { + quickstarts, ok := quickstartsByType[typ] + if !ok { + return quickstart{}, fmt.Errorf("unknown quickstart type %s", typ) + } + for _, q := range quickstarts { + if q.Name == stack { + return q, nil + } + } + return quickstart{}, fmt.Errorf("quickstart not found for %s/%s", typ, stack) +} + +func quickstartTypes() []string { + keys := make([]string, 0, len(quickstartsByType)) + for k := range quickstartsByType { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +func quickstartStacksFromType(t string) ([]string, error) { + _, ok := quickstartsByType[t] + if !ok { + return nil, fmt.Errorf("unknown quickstart type %s", t) + } + stacks := make([]string, 0, len(quickstartsByType[t])) + for _, s := range quickstartsByType[t] { + stacks = append(stacks, s.Name) + } + return stacks, nil +} From 6e77a65dec02bbd193a69a09f4c71e21e45eb8d6 Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 14:59:02 -0600 Subject: [PATCH 2/6] remove printf --- internal/cli/quickstarts.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 64202249b..e4361202d 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -164,8 +164,6 @@ func downloadQuickStart(ctx context.Context, cli *cli, client *management.Client payload.Repo = q.Repo payload.Path = q.Samples[0] - fmt.Printf("%+v\n", payload) - // These appear to be largely constant and refers to the github // username they're under. payload.Org = quickstartOrg From 95bddf6c07483066f122779ba27e91ddcc875d3b Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 15:07:30 -0600 Subject: [PATCH 3/6] update to Go 1.16 in workflow --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index ae475136a..c4e7c8a55 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -6,10 +6,10 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v1 with: - go-version: 1.15 + go-version: 1.16 id: go - name: Check out code into the Go module directory From b4453cb54959d38bc958f8a3d8ae2a4f28f0eca9 Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 15:08:42 -0600 Subject: [PATCH 4/6] 1.16 in gorelease workflow too --- .github/workflows/goreleaser.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 4ba810003..74e23fe14 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -14,10 +14,10 @@ jobs: - name: Unshallow run: git fetch --prune --unshallow - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v1 with: - go-version: 1.15 + go-version: 1.16 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2.4.1 From 51d95da58d5e564cb4913d8855092abf80b1c584 Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 15:31:10 -0600 Subject: [PATCH 5/6] Update to newer version of golangci-lint --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c4e7c8a55..8d45f09a9 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v2 - name: Install golanglint-ci - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.6 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.37.1 - name: ci run: PATH=$(go env GOPATH)/bin:$PATH make ci From 7433355b86a80c5d593a2d25832289a881b5242c Mon Sep 17 00:00:00 2001 From: Chris Opland Date: Fri, 26 Feb 2021 18:22:48 -0600 Subject: [PATCH 6/6] PR fixes --- internal/cli/quickstarts.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index e4361202d..2a0d3ab75 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -30,6 +30,14 @@ var ( } return }() + quickstartTypes = func() []string { + keys := make([]string, 0, len(quickstartsByType)) + for k := range quickstartsByType { + keys = append(keys, k) + } + sort.Strings(keys) + return keys + }() ) type quickstart struct { @@ -70,11 +78,11 @@ func downloadQuickstart(cli *cli) *cobra.Command { return err } - var selectedType = flags.Type - var selectedStack = flags.Stack + selectedType := flags.Type + selectedStack := flags.Stack if selectedType == "" { - input := prompt.SelectInput("type", "Quickstart Type:", "Type of quickstart to download", quickstartTypes(), true) + input := prompt.SelectInput("type", "Quickstart Type:", "Type of quickstart to download", quickstartTypes, true) if err := prompt.AskOne(input, &selectedType); err != nil { return err } @@ -256,15 +264,6 @@ func getQuickstart(typ, stack string) (quickstart, error) { return quickstart{}, fmt.Errorf("quickstart not found for %s/%s", typ, stack) } -func quickstartTypes() []string { - keys := make([]string, 0, len(quickstartsByType)) - for k := range quickstartsByType { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - func quickstartStacksFromType(t string) ([]string, error) { _, ok := quickstartsByType[t] if !ok {