diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8cce65bbd..85c940614 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -161,21 +161,6 @@ To make the new version the default version that is installed - **DEPRECATED** Change `version.txt` and commit it. (This file is no longer user for versions of the Flow CLI later than v1.18.0, although it should still be maintained to support older versions of the CLI for a while) -## Adding a scaffold -You can add your own scaffold by creating a GitHub repository containing the scaffold content and then making a PR -to update the `scaffolds.json` in the Flow CLI repository. You need to add an entry to the list -with the bellow content. - -```json -{ - "name": "name of the scaffold", - "repo": "HTTP URL to the repository containing the scaffold", - "commit": "Hash of the (latest) commit in your scaffold repository", - "branch": "scaffold repository branch", - "description": "user friendly description of the scaffold (what it contains, why it is used...)" -} -``` - # CLI Guidelines This is a design guideline used for the development of the Flow CLI. The purpose of this guideline is to achieve consistency across new features and allow composability of commands that build the fundamentals of great CLI design. diff --git a/internal/prompt/prompt.go b/internal/prompt/prompt.go index b169bcbfe..4f939ecc8 100644 --- a/internal/prompt/prompt.go +++ b/internal/prompt/prompt.go @@ -728,75 +728,6 @@ func InstallPathPrompt(defaultPath string) string { return filepath.Clean(install) } -type ScaffoldItem struct { - Index int - Title string - Category string - assignedIndex int -} - -func ScaffoldPrompt(logger output.Logger, scaffoldItems []ScaffoldItem) int { - const ( - general = "" - mobile = "mobile" - web = "web" - unity = "unity" - ) - outputType := map[string]string{ - general: "🔨 General Scaffolds", - mobile: "📱 Mobile Scaffolds", - web: "💻 Web Scaffolds", - unity: "🏀 Unity Scaffolds", - } - - index := 0 - outputCategory := func(category string, items []ScaffoldItem) { - logger.Info(output.Bold(output.Magenta(outputType[category]))) - for i := range items { - if items[i].Category == category { - index++ - logger.Info(fmt.Sprintf(" [%d] %s", index, items[i].Title)) - items[i].assignedIndex = index - } - } - logger.Info("") - } - - outputCategory(general, scaffoldItems) - outputCategory(web, scaffoldItems) - outputCategory(mobile, scaffoldItems) - outputCategory(unity, scaffoldItems) - - prompt := promptui.Prompt{ - Label: "Enter the scaffold number", - Validate: func(s string) error { - n, err := strconv.Atoi(s) - if err != nil { - return fmt.Errorf("input must be a number") - } - - if n < 0 && n > len(scaffoldItems) { - return fmt.Errorf("not a valid number") - } - return nil - }, - } - - input, err := prompt.Run() - if err == promptui.ErrInterrupt { - os.Exit(-1) - } - num, _ := strconv.Atoi(input) - - for _, item := range scaffoldItems { - if item.assignedIndex == num { - return item.Index - } - } - - return 0 -} - func GenericBoolPrompt(msg string) bool { prompt := promptui.Select{ Label: msg, diff --git a/internal/super/scaffolds.go b/internal/super/scaffolds.go deleted file mode 100644 index 2046aaf7f..000000000 --- a/internal/super/scaffolds.go +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Flow CLI - * - * Copyright Flow Foundation - * - * 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 super - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/onflow/flow-cli/internal/prompt" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/onflow/flowkit/v2/output" -) - -const scaffoldListURL = "https://raw.githubusercontent.com/onflow/flow-cli/master/scaffolds.json" - -type scaffold struct { - Repo string `json:"repo"` - Branch string `json:"branch"` - Name string `json:"name"` - Description string `json:"description"` - Commit string `json:"commit"` - Folder string `json:"folder"` - Type string `json:"type"` -} - -func handleScaffold( - projectName string, - logger output.Logger, -) (string, error) { - targetDir, err := getTargetDirectory(projectName) - if err != nil { - return "", err - } - - selectedScaffold, err := selectScaffold(logger) - if err != nil { - return "", fmt.Errorf("error selecting scaffold %w", err) - } - - logger.StartProgress(fmt.Sprintf("Creating your project %s", targetDir)) - defer logger.StopProgress() - - if selectedScaffold != nil { - err = cloneScaffold(targetDir, *selectedScaffold) - if err != nil { - return "", fmt.Errorf("failed creating scaffold %w", err) - } - } - - return targetDir, nil -} - -func selectScaffold(logger output.Logger) (*scaffold, error) { - scaffolds, err := getScaffolds() - if err != nil { - return nil, err - } - - // default to first scaffold - basic scaffold - pickedScaffold := scaffolds[0] - - if setupFlags.ScaffoldID != 0 { - if setupFlags.ScaffoldID > len(scaffolds) { - return nil, fmt.Errorf("scaffold with id %d does not exist", setupFlags.ScaffoldID) - } - pickedScaffold = scaffolds[setupFlags.ScaffoldID-1] - } - - if setupFlags.Scaffold { - scaffoldItems := make([]prompt.ScaffoldItem, 0) - for i, s := range scaffolds { - scaffoldItems = append( - scaffoldItems, - prompt.ScaffoldItem{ - Index: i, - Title: fmt.Sprintf("%s - %s", output.Bold(s.Name), s.Description), - Category: s.Type, - }, - ) - } - - selected := prompt.ScaffoldPrompt(logger, scaffoldItems) - pickedScaffold = scaffolds[selected] - } - - return &pickedScaffold, nil -} - -func getScaffolds() ([]scaffold, error) { - httpClient := http.Client{ - Timeout: time.Second * 5, - } - - req, err := http.NewRequest(http.MethodGet, scaffoldListURL, nil) - if err != nil { - return nil, fmt.Errorf("failed creating request for scaffold list: %w", err) - } - - res, err := httpClient.Do(req) - if err != nil { - return nil, fmt.Errorf("failed requesting scaffold list: %w", err) - } - if res.Body != nil { - defer res.Body.Close() - } - - body, err := io.ReadAll(res.Body) - if err != nil { - return nil, fmt.Errorf("failed reading scaffold list response: %w", err) - } - - var all []scaffold - err = json.Unmarshal(body, &all) - if err != nil { - return nil, fmt.Errorf("failed parsing scaffold list response: %w", err) - } - - valid := make([]scaffold, 0) - for _, s := range all { - if s.Repo != "" && s.Description != "" && s.Name != "" && s.Commit != "" { - valid = append(valid, s) - } - } - - return valid, nil -} - -func cloneScaffold(targetDir string, conf scaffold) error { - repo, err := git.PlainClone(targetDir, false, &git.CloneOptions{ - URL: conf.Repo, - }) - if err != nil { - return fmt.Errorf("could not download the scaffold: %w", err) - } - - worktree, _ := repo.Worktree() - err = worktree.Checkout(&git.CheckoutOptions{ - Hash: plumbing.NewHash(conf.Commit), - Force: true, - }) - if err != nil { - return fmt.Errorf("could not find the scaffold version") - } - - // if we defined a folder remove everything else - if conf.Folder != "" { - err = os.Rename( - filepath.Join(targetDir, conf.Folder), - filepath.Join(targetDir, "../scaffold-temp"), - ) - if err != nil { - return err - } - - if err = os.RemoveAll(targetDir); err != nil { - return err - } - - if err = os.Rename(filepath.Join(targetDir, "../scaffold-temp"), targetDir); err != nil { - return err - } - } - - return os.RemoveAll(filepath.Join(targetDir, ".git")) -} diff --git a/internal/super/setup.go b/internal/super/setup.go index 696eef133..6dc8b6005 100644 --- a/internal/super/setup.go +++ b/internal/super/setup.go @@ -44,8 +44,6 @@ import ( type flagsSetup struct { ConfigOnly bool `default:"false" flag:"config-only" info:"Only create a flow.json default config"` - Scaffold bool `default:"" flag:"scaffold" info:"Interactively select a provided scaffold for project creation"` - ScaffoldID int `default:"" flag:"scaffold-id" info:"Use provided scaffold ID for project creation"` } var setupFlags = flagsSetup{} @@ -73,17 +71,7 @@ func create( var targetDir string var err error - if setupFlags.Scaffold || setupFlags.ScaffoldID != 0 { - // Error if no project name is given - if len(args) < 1 || args[0] == "" { - return nil, fmt.Errorf("no project name provided") - } - - targetDir, err = handleScaffold(args[0], logger) - if err != nil { - return nil, err - } - } else if setupFlags.ConfigOnly { + if setupFlags.ConfigOnly { if len(args) > 0 { return nil, fmt.Errorf("project name not required when using --config-only flag") } diff --git a/scaffolds.json b/scaffolds.json deleted file mode 100644 index 574ac3918..000000000 --- a/scaffolds.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "FCL Web Dapp", - "repo": "https://github.com/chasefleming/fcl-next-scaffold.git", - "description": "Simple TypeScript web application using next.js, FCL, and Cadence.", - "commit": "eb52658d7a8fdc95cd6fe57dc65d6ee94a7531d8", - "type": "web" - }, - { - "name": "Simple Cadence Project", - "repo": "https://github.com/sideninja/flow-basic-scaffold.git", - "description": "Scaffold contains required folder structure as well as some example Cadence code.", - "commit": "8065287e55bc298d776665bef98a577ceb4a226c" - }, - { - "name": "Cadence NFT Project", - "repo": "https://github.com/nvdtf/flow-nft-scaffold.git", - "description": "Scaffold contains the ExampleNFT sample NFT contract.", - "commit": "ef9437c05549e3f581cf619dec9d59d8c7f6e3ec" - } -]