Skip to content

Commit

Permalink
Rework marketplace TUI
Browse files Browse the repository at this point in the history
  • Loading branch information
Ehsan-saradar committed Dec 19, 2023
1 parent 30d817e commit 449bf15
Show file tree
Hide file tree
Showing 12 changed files with 465 additions and 121 deletions.
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,7 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
Expand Down
107 changes: 59 additions & 48 deletions marketplace/cmd/info.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
package cmd

import (
"context"
"fmt"
"strings"
"hash/fnv"
"path"
"strconv"
"time"

"github.com/charmbracelet/lipgloss"
"github.com/dustin/go-humanize"
"github.com/google/go-github/v56/github"
"github.com/gookit/color"
"github.com/ignite/apps/marketplace/pkg/apps"
"github.com/ignite/apps/marketplace/pkg/xgithub"
"github.com/ignite/cli/ignite/pkg/cliui"
"github.com/spf13/cobra"
)

// NewInfo creates a new info command that shows the details of an ignite app.
const igniteCLIPackage = "github.com/ignite/cli"

Check failure on line 18 in marketplace/cmd/info.go

View workflow job for this annotation

GitHub Actions / Lint Go Code: ./marketplace

const `igniteCLIPackage` is unused (unused)

var (
linkStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("10")).
Underline(true)
installaitonStyle = lipgloss.NewStyle().
Border(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("9")).
MarginLeft(7)
commandStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("2")).
Bold(true)
)

// NewInfo creates a new info command that shows the details of an ignite application repository.
func NewInfo() *cobra.Command {
return &cobra.Command{
Use: "info [app-name]",
Short: "Show the details of an ignite app",
Use: "info [package-url]",
Short: "Show the details of an ignite application repository",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
appName := args[0]
repoOwner, repoName, err := validateAppName(appName)
if err != nil {
return err
}
githubToken, _ := cmd.Flags().GetString(githubTokenFlag)

session := cliui.New(cliui.StartSpinner())
defer session.End()

session.StartSpinner("Fetching app details from GitHub...")
repo, err := getRepo(cmd.Context(), repoOwner, repoName)
session.StartSpinner("🔎 Fetching repository details from GitHub...")

client := xgithub.NewClient(githubToken)
repo, err := apps.GetRepositoryDetails(cmd.Context(), client, args[0])
if err != nil {
return err
}
session.StopSpinner()

if !isIgniteApp(repo) {
return fmt.Errorf("the repository is not an ignite app")
}
session.StopSpinner()

printRepoDetails(session, repo)

Expand All @@ -48,41 +59,41 @@ func NewInfo() *cobra.Command {
}
}

func validateAppName(appName string) (owner, name string, err error) {
appName = strings.TrimPrefix(appName, "github.com/")
appNameParts := strings.Split(appName, "/")
if len(appNameParts) != 2 {
return "", "", fmt.Errorf("invalid app name: %s", appName)
func printRepoDetails(sess *cliui.Session, repo *apps.AppRepositoryDetails) {
sess.Println("Description:", repo.Description)
sess.Print("Tags:")
for _, tag := range repo.Tags {
sess.Print(lipgloss.NewStyle().Background(colorFromText(tag)).Render(tag), " ")
}
owner = appNameParts[0]
name = appNameParts[1]

return owner, name, nil
sess.Println()
sess.Println("Stars ⭐️:", repo.Stars)
sess.Println("License ⚖️ :", repo.License)
sess.Printf("Updated At 🕒: %s %s\n", repo.UpdatedAt.Format(time.DateTime), updatedAtStyle.Render("("+humanize.Time(repo.UpdatedAt)+")"))
sess.Println("URL 🌎: ", linkStyle.Render(repo.URL))
sess.Println("Apps 🔥:")
printAppsTable(sess, repo)
}

func getRepo(ctx context.Context, owner, name string) (*github.Repository, error) {
client := xgithub.NewClient(githubToken)
return client.GetRepository(ctx, owner, name)
func colorFromText(text string) lipgloss.Color {
h := fnv.New64a()
h.Write([]byte(text))
return lipgloss.Color(strconv.FormatUint(h.Sum64()%16, 10))
}

func isIgniteApp(repo *github.Repository) bool {
for _, topic := range repo.Topics {
if topic == "ignite-app" {
return true
func printAppsTable(sess *cliui.Session, repo *apps.AppRepositoryDetails) {
for i, app := range repo.Apps {
sess.Println("\tName:", app.Name)
sess.Println("\tDescription:", app.Description)
sess.Println("\tPath:", app.Path)
sess.Println("\tGo Version:", app.GoVersion)
sess.Println("\tIgnite Version:", app.IgniteVersion)
sess.Println(installaitonStyle.Render(fmt.Sprintf(
"🚀 Install via: %s",
commandStyle.Render(fmt.Sprintf("ignite app -g install %s", path.Join(repo.PackageURL, app.Path))),
)))

if i < len(repo.Apps)-1 {
sess.Println()
}
}

return false
}

func printRepoDetails(sess *cliui.Session, repo *github.Repository) {
sess.Println("Name: ", repo.GetName())
sess.Println("Owner: ", repo.GetOwner().GetLogin())
sess.Println("Description: ", repo.GetDescription())
sess.Println("Stars ⭐️: ", repo.GetStargazersCount())
sess.Println("License: ", repo.GetLicense().GetName())
sess.Printf("Updated At: %s (%s)\n", repo.GetUpdatedAt().Format(time.DateTime), humanize.Time(repo.GetUpdatedAt().Time))
sess.Println("URL: ", repo.GetHTMLURL())
sess.Println()
sess.Printf("🚀 Install via: %s\n", color.Green.Sprintf("ignite app install github.com/%s", repo.GetFullName()))
}
94 changes: 48 additions & 46 deletions marketplace/cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,97 +1,99 @@
package cmd

import (
"context"
"fmt"

"github.com/charmbracelet/lipgloss"
"github.com/dustin/go-humanize"
"github.com/google/go-github/v56/github"
"github.com/ignite/apps/marketplace/pkg/apps"
"github.com/ignite/apps/marketplace/pkg/tree"
"github.com/ignite/apps/marketplace/pkg/xgithub"
"github.com/ignite/cli/ignite/pkg/cliui"
"github.com/spf13/cobra"
)

const (
minStarsFlag = "min-stars"
igniteAppTopic = "ignite-cli-app"
descriptionLimit = 50
queryFlag = "query"
descriptionLimit = 75
)

var (
starsCountStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
updatedAtStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12"))
)

// NewList creates a new list command that searches all the ignite apps in GitHub.
func NewList() *cobra.Command {
c := &cobra.Command{
Use: "list [query]",
Use: "list",
Short: "List all the ignite apps",
Args: cobra.MaximumNArgs(1),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
query := ""
if len(args) > 0 {
query = args[0]
}
githubToken, _ := cmd.Flags().GetString(githubTokenFlag)
query, _ := cmd.Flags().GetString(queryFlag)
minStars, _ := cmd.Flags().GetUint(minStarsFlag)

session := cliui.New(cliui.StartSpinner())
defer session.End()

session.StartSpinner("🔎 Searching for ignite apps on GitHub...")
repos, total, err := searchIgniteApps(cmd.Context(), query, minStars)
client := xgithub.NewClient(githubToken)
repos, err := apps.Search(cmd.Context(), client, query, minStars)
if err != nil {
return err
}
session.StopSpinner()

session.Printf("🎉 Found %d results\n", total)

if total > 0 {
session.Println()
printRepoList(session, repos)
if len(repos) < 1 {
session.Println("❌ No ignite application were found")
return nil
}

printRepoTree(session, repos)

return nil
},
}

c.Flags().StringP(queryFlag, "q", "", "Query string to search for")
c.Flags().Uint(minStarsFlag, 10, "Minimum number of stars to search for")

return c
}

func searchIgniteApps(ctx context.Context, query string, minStars uint) ([]*github.Repository, int, error) {
client := xgithub.NewClient(githubToken)

opts := &github.SearchOptions{
Sort: "stars",
Order: "desc",
}
repos, total, err := client.SearchRepositories(ctx, opts,
xgithub.StringQuery(query),
xgithub.LanguageQuery("go"),
xgithub.TopicQuery(igniteAppTopic),
xgithub.MinStarsQuery(int(minStars)))
if err != nil {
return nil, 0, err
func printRepoTree(sess *cliui.Session, repos []apps.AppRepository) {
for i, repo := range repos {
node := tree.NewNode(fmt.Sprintf(
"📦 %-50s %s %s",
repo.PackageURL,
starsCountStyle.Render(humanizeInt(repo.Stars, "⭐️")),
updatedAtStyle.Render("("+humanize.Time(repo.UpdatedAt)+")"),
))
node.AddChild(nil)
for _, app := range repo.Apps {
node.AddChild(tree.NewNode(fmt.Sprintf(
"🔥 %s\t%s",
app.Name,
limitTextlength(app.Description, descriptionLimit),
)))
}
sess.Print(node)

if i < len(repos)-1 {
sess.Println()
}
}

return repos, total, nil
}

func printRepoList(sess *cliui.Session, repos []*github.Repository) {
header := []string{"Name", "Description", "Stars ⭐️", "Updated At"}
rows := make([][]string, 0, len(repos))
for _, repo := range repos {
rows = append(rows, []string{
repo.GetFullName(),
limitTextlength(repo.GetDescription(), descriptionLimit),
humanize.SIWithDigits(float64(repo.GetStargazersCount()), 1, ""),
humanize.Time(repo.GetPushedAt().Time),
})
}

sess.PrintTable(header, rows...)
func humanizeInt(n int, unit string) string {
value, suffix := humanize.ComputeSI(float64(n))
return humanize.FtoaWithDigits(value, 1) + suffix + " " + unit
}

func limitTextlength(text string, limit int) string {
if len(text) > limit {
return text[:limit] + "..."
return text[:limit-3] + "..."
}

return text
Expand Down
8 changes: 5 additions & 3 deletions marketplace/cmd/marketplace.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

var githubToken = os.Getenv("GITHUB_TOKEN")
const (
githubTokenFlag = "github-token"
)

// NewMarketplace creates a new marketplace command that holds
// some other sub commands related to running marketplace like
Expand All @@ -31,5 +31,7 @@ func NewMarketplace() *cobra.Command {
NewInfo(),
)

c.Flags().String(githubTokenFlag, "", "GitHub access token")

return c
}
Loading

0 comments on commit 449bf15

Please sign in to comment.