Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions cmd/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/massdriver-cloud/mass/docs/helpdocs"
"github.com/massdriver-cloud/mass/pkg/api"
"github.com/massdriver-cloud/mass/pkg/bundle"
"github.com/massdriver-cloud/mass/pkg/cli"
cmdbundle "github.com/massdriver-cloud/mass/pkg/commands/bundle"
"github.com/massdriver-cloud/mass/pkg/commands/bundle/templates"
"github.com/massdriver-cloud/mass/pkg/params"
Expand Down Expand Up @@ -44,13 +45,38 @@ type bundleNew struct {
paramsDir string
}

type bundleList struct {
search string
sortField string
sortOrder string
limit int
output string
}

func NewCmdBundle() *cobra.Command {
bundleCmd := &cobra.Command{
Use: "bundle",
Short: "Generate and publish bundles",
Long: helpdocs.MustRender("bundle"),
}

var bundleListInput bundleList

bundleListCmd := &cobra.Command{
Use: "list",
Short: "List bundles in your organization",
Long: helpdocs.MustRender("bundle/list"),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
return runBundleList(&bundleListInput)
},
}
bundleListCmd.Flags().StringVarP(&bundleListInput.search, "search", "s", "", "Search bundles (supports AND, OR, -, quotes)")
bundleListCmd.Flags().StringVar(&bundleListInput.sortField, "sort", "name", "Sort field (name, created_at)")
bundleListCmd.Flags().StringVar(&bundleListInput.sortOrder, "order", "asc", "Sort order (asc, desc)")
bundleListCmd.Flags().IntVarP(&bundleListInput.limit, "limit", "l", 0, "Maximum number of results to return")
bundleListCmd.Flags().StringVarP(&bundleListInput.output, "output", "o", "table", "Output format (table, json)")

bundleBuildCmd := &cobra.Command{
Use: "build",
Short: "Build schemas and generate IaC files from massdriver.yaml file",
Expand Down Expand Up @@ -143,6 +169,7 @@ func NewCmdBundle() *cobra.Command {
RunE: runBundleTemplateRefresh,
}

bundleCmd.AddCommand(bundleListCmd)
bundleCmd.AddCommand(bundleBuildCmd)
bundleCmd.AddCommand(bundleImportCmd)
bundleCmd.AddCommand(bundleLintCmd)
Expand Down Expand Up @@ -456,6 +483,54 @@ func runBundlePull(cmd *cobra.Command, args []string) error {
return nil
}

func runBundleList(input *bundleList) error {
ctx := context.Background()

mdClient, err := client.New()
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}

opts := api.ReposListOptions{
Search: input.search,
SortField: input.sortField,
SortOrder: input.sortOrder,
Limit: input.limit,
}

page, err := api.ListRepos(ctx, mdClient, opts)
if err != nil {
return fmt.Errorf("failed to list bundles: %w", err)
}

switch input.output {
case "json":
jsonBytes, err := json.MarshalIndent(page, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal bundles to JSON: %w", err)
}
fmt.Println(string(jsonBytes))
case "table":
tbl := cli.NewTable("Name", "Latest", "Created At")
for _, repo := range page.Items {
latest := ""
for _, rc := range repo.ReleaseChannels {
if rc.Name == "latest" {
latest = rc.Tag
break
}
}
createdAt := repo.CreatedAt.Format("2006-01-02 15:04:05")
tbl.AddRow(repo.Name, latest, createdAt)
}
tbl.Print()
default:
return fmt.Errorf("unsupported output format: %s", input.output)
}

return nil
}

func runBundleGet(cmd *cobra.Command, args []string) error {
ctx := context.Background()

Expand Down
1 change: 1 addition & 0 deletions docs/generated/mass_bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Generate and publish bundles
* [mass bundle get](/cli/commands/mass_bundle_get) - Get bundle information from Massdriver
* [mass bundle import](/cli/commands/mass_bundle_import) - Import declared variables from IaC into massdriver.yaml params
* [mass bundle lint](/cli/commands/mass_bundle_lint) - Check massdriver.yaml file for common errors
* [mass bundle list](/cli/commands/mass_bundle_list) - List bundles in your organization
* [mass bundle new](/cli/commands/mass_bundle_new) - Create a new bundle from a template
* [mass bundle publish](/cli/commands/mass_bundle_publish) - Publish bundle to Massdriver's package manager
* [mass bundle pull](/cli/commands/mass_bundle_pull) - Pull bundle from Massdriver to local directory
Expand Down
71 changes: 71 additions & 0 deletions docs/generated/mass_bundle_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
id: mass_bundle_list.md
slug: /cli/commands/mass_bundle_list
title: Mass Bundle List
sidebar_label: Mass Bundle List
---
## mass bundle list

List bundles in your organization

### Synopsis

# List bundles in your organization

List all bundle repositories with optional search, sort, and limit.

## Usage

```bash
mass bundle list [flags]
```

## Flags

- `--search, -s`: Search bundles using Google-style operators (AND, OR, -, quotes)
- `--sort`: Sort field (name, created_at). Defaults to "name"
- `--order`: Sort order (asc, desc). Defaults to "asc"
- `--limit, -l`: Maximum number of results to return
- `--output, -o`: Output format (table or json). Defaults to "table"

## Examples

```bash
# List all bundles
mass bundle list

# Search for postgres bundles
mass bundle list --search postgres

# Search with operators
mass bundle list --search "postgres AND aws -aurora"

# Sort by creation date, newest first
mass bundle list --sort created_at --order desc

# Limit results
mass bundle list --limit 10

# Output as JSON
mass bundle list -o json
```


```
mass bundle list [flags]
```

### Options

```
-h, --help help for list
-l, --limit int Maximum number of results to return
--order string Sort order (asc, desc) (default "asc")
-o, --output string Output format (table, json) (default "table")
-s, --search string Search bundles (supports AND, OR, -, quotes)
--sort string Sort field (name, created_at) (default "name")
```

### SEE ALSO

* [mass bundle](/cli/commands/mass_bundle) - Generate and publish bundles
39 changes: 39 additions & 0 deletions docs/helpdocs/bundle/list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# List bundles in your organization

List all bundle repositories with optional search, sort, and limit.

## Usage

```bash
mass bundle list [flags]
```

## Flags

- `--search, -s`: Search bundles using Google-style operators (AND, OR, -, quotes)
- `--sort`: Sort field (name, created_at). Defaults to "name"
- `--order`: Sort order (asc, desc). Defaults to "asc"
- `--limit, -l`: Maximum number of results to return
- `--output, -o`: Output format (table or json). Defaults to "table"

## Examples

```bash
# List all bundles
mass bundle list

# Search for postgres bundles
mass bundle list --search postgres

# Search with operators
mass bundle list --search "postgres AND aws -aurora"

# Sort by creation date, newest first
mass bundle list --sort created_at --order desc

# Limit results
mass bundle list --limit 10

# Output as JSON
mass bundle list -o json
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/manifoldco/promptui v0.9.0
github.com/massdriver-cloud/airlock v0.0.9
github.com/massdriver-cloud/massdriver-sdk-go v0.0.8
github.com/mattn/go-runewidth v0.0.16
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/moby v27.3.1+incompatible
github.com/moby/term v0.5.0
Expand Down Expand Up @@ -102,7 +103,6 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
Expand Down
31 changes: 30 additions & 1 deletion pkg/api/genqlient.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -624,9 +624,38 @@ mutation deployPreviewEnvironment($organizationId: ID!, $projectId: ID!, $input:
}


# REPOS (BUNDLES)

query listRepos(
$organizationId: ID!,
# @genqlient(omitempty: true, pointer: true)
$sort: ReposSort,
# @genqlient(omitempty: true, pointer: true)
$cursor: Cursor,
# @genqlient(omitempty: true, pointer: true)
$search: String
) {
repos(organizationId: $organizationId, sort: $sort, cursor: $cursor, search: $search) {
cursor {
next
previous
}
items {
id
name
createdAt
releaseChannels {
name
tag
}
}
}
}


# SERVER

query getServer() {
query getServer {
server {
appUrl
mode
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/genqlient.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ bindings:
type: string
Markdown:
type: string
Cursor:
type: github.com/massdriver-cloud/mass/pkg/api/scalars.Cursor
2 changes: 1 addition & 1 deletion pkg/api/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package api

//go:generate go run github.com/Khan/genqlient@v0.6.0
//go:generate genqlient
89 changes: 89 additions & 0 deletions pkg/api/repo.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,94 @@
package api

import (
"context"
"time"

"github.com/massdriver-cloud/mass/pkg/api/scalars"
"github.com/massdriver-cloud/massdriver-sdk-go/massdriver/client"
)

// Repo represents a bundle repository
type Repo struct {
ID string `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"`
ReleaseChannels []ReleaseChannel `json:"releaseChannels"`
}

// ReleaseChannel represents a release channel
type ReleaseChannel struct {
Name string `json:"name"`
Tag string `json:"tag"`
}

// ReposPage represents a page of repos with pagination info
type ReposPage struct {
Items []Repo `json:"items"`
NextCursor string `json:"nextCursor,omitempty"`
PrevCursor string `json:"prevCursor,omitempty"`
}

// ReposListOptions contains options for listing repos
type ReposListOptions struct {
Search string
SortField string // "name" or "created_at"
SortOrder string // "asc" or "desc"
Limit int
}

// ListRepos lists bundle repositories with optional search, sort, and pagination
func ListRepos(ctx context.Context, mdClient *client.Client, opts ReposListOptions) (*ReposPage, error) {
var sort *ReposSort
if opts.SortField != "" || opts.SortOrder != "" {
s := ReposSort{
Field: ReposSortFieldName,
Order: SortOrderAsc,
}
if opts.SortField == "created_at" {
s.Field = ReposSortFieldCreatedAt
}
if opts.SortOrder == "desc" {
s.Order = SortOrderDesc
}
sort = &s
}

var cursor *scalars.Cursor
if opts.Limit > 0 {
cursor = &scalars.Cursor{
Limit: opts.Limit,
}
}

var search *string
if opts.Search != "" {
search = &opts.Search
}

response, err := listRepos(ctx, mdClient.GQL, mdClient.Config.OrganizationID, sort, cursor, search)
if err != nil {
return nil, err
}

page := &ReposPage{
Items: make([]Repo, 0, len(response.Repos.Items)),
NextCursor: response.Repos.Cursor.Next,
PrevCursor: response.Repos.Cursor.Previous,
}

for _, item := range response.Repos.Items {
repo := Repo{
ID: item.Id,
Name: item.Name,
CreatedAt: item.CreatedAt,
ReleaseChannels: make([]ReleaseChannel, 0, len(item.ReleaseChannels)),
}
for _, rc := range item.ReleaseChannels {
repo.ReleaseChannels = append(repo.ReleaseChannels, ReleaseChannel(rc))
}
page.Items = append(page.Items, repo)
}

return page, nil
}
Loading
Loading