Compare commits

...

2 Commits

Author SHA1 Message Date
Peter Steinberger
ced43a5a70 docs: update drive ls --all docs/changelog (#107) (thanks @struong)
Some checks failed
ci / test (push) Has been cancelled
ci / worker (push) Has been cancelled
ci / darwin-cgo-build (push) Has been cancelled
ci / windows-build (push) Has been cancelled
2026-03-03 05:00:19 +00:00
Steven Truong
515bf1ad69 feat(drive): add --all flag to ls for global file listing 2026-03-03 04:58:48 +00:00
6 changed files with 51 additions and 2 deletions

View File

@ -6,6 +6,7 @@
- Sheets: add `sheets insert` to insert rows/columns into a sheet. (#203) — thanks @andybergon.
- Gmail: add `watch serve --history-types` filtering (`messageAdded|messageDeleted|labelAdded|labelRemoved`) and include `deletedMessageIds` in webhook payloads. (#168) — thanks @salmonumbrella.
- Contacts: support `--org`, `--title`, `--url`, `--note`, and `--custom` on create/update; include custom fields in get output with deterministic ordering. (#199) — thanks @phuctm97.
- Drive: add `drive ls --all` (alias `--global`) to list across all accessible files; make `--all` and `--parent` mutually exclusive. (#107) — thanks @struong.
### Fixed
- Calendar: respond patches only attendees to avoid custom reminders validation errors. (#265) — thanks @sebasrodriguez.

View File

@ -833,6 +833,7 @@ gog time now --timezone UTC
# List and search
gog drive ls --max 20
gog drive ls --parent <folderId> --max 20
gog drive ls --all --max 20 # List across all accessible files (cannot combine with --parent)
gog drive ls --no-all-drives # Only list from "My Drive"
gog drive search "invoice" --max 20
gog drive search "invoice" --no-all-drives

View File

@ -178,7 +178,7 @@ Flag aliases:
- `gog config set <key> <value>`
- `gog config unset <key>`
- `gog version`
- `gog drive ls [--parent ID] [--max N] [--page TOKEN] [--query Q] [--[no-]all-drives]`
- `gog drive ls [--all] [--parent ID] [--max N] [--page TOKEN] [--query Q] [--[no-]all-drives]` (`--all` and `--parent` are mutually exclusive)
- `gog drive search <text> [--raw-query] [--max N] [--page TOKEN] [--[no-]all-drives]`
- `gog drive get <fileId>`
- `gog drive download <fileId> [--out PATH] [--format F]` (`--format` only applies to Google Workspace files)

View File

@ -84,10 +84,15 @@ type DriveLsCmd struct {
Page string `name:"page" aliases:"cursor" help:"Page token"`
Query string `name:"query" help:"Drive query filter"`
Parent string `name:"parent" help:"Folder ID to list (default: root)"`
All bool `name:"all" aliases:"global" help:"List all accessible files (mutually exclusive with --parent)"`
AllDrives bool `name:"all-drives" help:"Include shared drives (default: true; use --no-all-drives for My Drive only)" default:"true" negatable:"_"`
}
func (c *DriveLsCmd) Run(ctx context.Context, flags *RootFlags) error {
if c.All && strings.TrimSpace(c.Parent) != "" {
return usage("--all cannot be combined with --parent")
}
u := ui.FromContext(ctx)
account, err := requireAccount(flags)
if err != nil {
@ -104,7 +109,12 @@ func (c *DriveLsCmd) Run(ctx context.Context, flags *RootFlags) error {
return err
}
q := buildDriveListQuery(folderID, c.Query)
var q string
if c.All {
q = buildDriveAllListQuery(c.Query)
} else {
q = buildDriveListQuery(folderID, c.Query)
}
// Include files from shared drives, not just personal "My Drive"
call := svc.Files.List().
@ -988,6 +998,17 @@ func buildDriveListQuery(folderID string, userQuery string) string {
return q
}
func buildDriveAllListQuery(userQuery string) string {
q := strings.TrimSpace(userQuery)
if q == "" {
return "trashed = false"
}
if !hasDriveTrashedPredicate(q) {
q += " and trashed = false"
}
return q
}
func buildDriveSearchQuery(text string, rawQuery bool) string {
q := strings.TrimSpace(text)
if q == "" {

View File

@ -14,6 +14,11 @@ func TestDriveCommand_ValidationErrors(t *testing.T) {
t.Fatalf("expected parent error, got %v", err)
}
lsCmd := &DriveLsCmd{}
if err := runKong(t, lsCmd, []string{"--all", "--parent", "p1"}, context.Background(), flags); err == nil || !strings.Contains(err.Error(), "--all cannot be combined with --parent") {
t.Fatalf("expected mutually exclusive error, got %v", err)
}
shareCmd := &DriveShareCmd{}
if err := runKong(t, shareCmd, []string{"file1"}, context.Background(), flags); err == nil || !strings.Contains(err.Error(), "must specify --to") {
t.Fatalf("expected share target error, got %v", err)

View File

@ -32,6 +32,27 @@ func TestBuildDriveListQuery(t *testing.T) {
})
}
func TestBuildDriveAllListQuery(t *testing.T) {
tests := []struct {
name string
query string
expected string
}{
{"empty query", "", "trashed = false"},
{"with query", "mimeType='image/png'", "mimeType='image/png' and trashed = false"},
{"query mentions trashed", "trashed = true", "trashed = true"},
{"quoted trashed string", "name contains 'trashed'", "name contains 'trashed' and trashed = false"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := buildDriveAllListQuery(tt.query)
if got != tt.expected {
t.Errorf("buildDriveAllListQuery(%q) = %q, want %q", tt.query, got, tt.expected)
}
})
}
}
func TestBuildDriveSearchQuery(t *testing.T) {
got := buildDriveSearchQuery("hello world", false)
if got != "fullText contains 'hello world' and trashed = false" {