Skip to content

Commit 87c631e

Browse files
feat: add retry logic, concurrent fetching, and extended commands
Resilience: - RetryTransport with circuit breaker for 429/5xx resilience - Exponential backoff with jitter, respects Retry-After headers - Circuit breaker auto-resets after 30s of successful requests Performance: - Concurrent gmail thread fetching (fixes N+1 query pattern) - Bounded concurrency with semaphore (max 10 parallel) New calendar commands: - colors: list available event/calendar colors - conflicts: check availability across calendars - search: find events by text query - time: show current time in multiple timezones New gmail commands: - autoforward: get/enable/disable auto-forwarding - delegates: list/add/remove mail delegation - filters: list/create/delete inbox filters - forwarding: manage forwarding addresses - sendas: manage send-as aliases - vacation: get/enable/disable vacation responder - batch: bulk operations (mark-read, archive, label, delete) - watch: Pub/Sub push with webhook forwarding New services: - Sheets: read/write/append spreadsheet data - Tasks: manage tasklists and tasks Developer experience: - Shell completion (bash, zsh, fish, powershell) - version command with build info - --debug flag for verbose logging - lefthook for pre-commit hooks Documentation: - Expanded README with examples - Gmail watch/Pub/Sub guide (docs/watch.md) - Architecture spec (docs/spec.md) - Release process (docs/RELEASING.md)
1 parent e1043f2 commit 87c631e

86 files changed

Lines changed: 8720 additions & 4853 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ on:
44
push:
55
tags:
66
- "v*"
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: "Tag to (re)release (e.g. v0.1.0)"
11+
required: true
12+
type: string
713

814
permissions:
915
contents: write
@@ -12,21 +18,29 @@ jobs:
1218
goreleaser:
1319
runs-on: ubuntu-latest
1420
steps:
15-
- uses: actions/checkout@v4
21+
- name: Checkout
22+
uses: actions/checkout@v4
1623
with:
1724
fetch-depth: 0
1825

19-
- uses: actions/setup-go@v5
26+
- name: Setup Go
27+
uses: actions/setup-go@v5
2028
with:
2129
go-version-file: go.mod
2230
cache: true
2331

24-
- name: Run GoReleaser
32+
- name: Stash GoReleaser config
33+
run: cp .goreleaser.yaml /tmp/.goreleaser.yaml
34+
35+
- name: Checkout release tag
36+
if: ${{ github.event_name == 'workflow_dispatch' }}
37+
run: git checkout ${{ inputs.tag }}
38+
39+
- name: GoReleaser
2540
uses: goreleaser/goreleaser-action@v6
2641
with:
2742
distribution: goreleaser
28-
version: "~> v2"
29-
args: release --clean
43+
version: latest
44+
args: release --clean --config /tmp/.goreleaser.yaml
3045
env:
3146
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32-
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ go.work.sum
3636

3737
# Local build output
3838
bin/
39+
/gog
3940

4041
# Node (optional dev scripts)
4142
node_modules/

.goreleaser.yaml

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
21
version: 2
32

4-
project_name: gog-cli
3+
project_name: gogcli
54

6-
before:
7-
hooks:
8-
- go mod tidy
5+
changelog:
6+
disable: true
97

108
builds:
119
- id: gog
@@ -14,55 +12,24 @@ builds:
1412
env:
1513
- CGO_ENABLED=0
1614
goos:
17-
- linux
1815
- darwin
16+
- linux
1917
- windows
2018
goarch:
2119
- amd64
2220
- arm64
23-
ldflags:
24-
- -s -w
25-
- -X main.version={{.Version}}
26-
- -X main.commit={{.ShortCommit}}
27-
- -X main.date={{.Date}}
21+
ignore:
22+
- goos: windows
23+
goarch: arm64
2824

2925
archives:
30-
- id: default
31-
formats:
32-
- tar.gz
26+
- builds:
27+
- gog
28+
format: tar.gz
29+
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
3330
format_overrides:
3431
- goos: windows
35-
formats:
36-
- zip
37-
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
38-
files:
39-
- README.md
40-
- LICENSE
32+
format: zip
4133

4234
checksum:
43-
name_template: "checksums.txt"
44-
45-
changelog:
46-
sort: asc
47-
filters:
48-
exclude:
49-
- "^docs:"
50-
- "^test:"
51-
- "^ci:"
52-
- Merge pull request
53-
- Merge branch
54-
55-
brews:
56-
- name: gog-cli
57-
repository:
58-
owner: salmonumbrella
59-
name: homebrew-tap
60-
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
61-
directory: Formula
62-
homepage: "https://github.com/salmonumbrella/gog-cli"
63-
description: "CLI for Google Workspace to manage Gmail, Calendar, and Drive"
64-
license: "MIT"
65-
install: |
66-
bin.install "gog"
67-
test: |
68-
system "#{bin}/gog", "--help"
35+
name_template: checksums.txt

CHANGELOG.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Changelog
2+
3+
## 0.2.1 - Unreleased
4+
5+
## 0.2.0 - 2025-12-24
6+
7+
### Added
8+
9+
- Gmail: watch + Pub/Sub push handler (`gog gmail watch start|status|renew|stop|serve`) with optional webhook forwarding, include-body, and max-bytes.
10+
- Gmail: history listing via `gog gmail history --since <historyId>`.
11+
- Gmail: HTML bodies for `gmail send` and `gmail drafts create` via `--body-html` (multipart/alternative when combined with `--body`, PR #16 — thanks @shanelindsay).
12+
- Gmail: `--reply-to-address` (sets `Reply-To` header, PR #16 — thanks @shanelindsay).
13+
- Tasks: manage tasklists and tasks (`lists`, `list`, `add`, `update`, `done`, `undo`, `delete`, `clear`, PR #10 — thanks @shanelindsay).
14+
### Changed
15+
16+
- Build: `make` builds `./bin/gog` by default (adds `build` target, PR #12 — thanks @advait).
17+
- Docs: local build instructions now use `make` (PR #12 — thanks @advait).
18+
19+
### Fixed
20+
21+
- Secrets: keyring file-backend fallback now stores encrypted entries in `$(os.UserConfigDir())/gogcli/keyring/` and supports non-interactive via `GOG_KEYRING_PASSWORD` (PR #13 — thanks @advait).
22+
- Gmail: decode base64url attachment/message-part payloads (PR #15 — thanks @shanelindsay).
23+
- Auth: add `people` service (OIDC `profile` scope) so `gog people me` works with `gog auth add --services all`.
24+
25+
## 0.1.1 - 2025-12-17
26+
27+
### Added
28+
29+
- Calendar: respond to invites via `gog calendar respond <calendarId> <eventId> --status accepted|declined|tentative` (optional `--send-updates`).
30+
- People: `gog people me` (quick “me card” / `people/me`).
31+
- Gmail: message get via `gog gmail get <messageId> [--format full|metadata|raw]`.
32+
- Gmail: download a single attachment via `gog gmail attachment <messageId> <attachmentId> [--out PATH]`.
33+
34+
## 0.1.0 - 2025-12-12
35+
36+
Initial public release of `gog`: a single Go CLI that unifies Gmail, Calendar, Drive, and Contacts (People API).
37+
38+
### Added
39+
40+
- Unified CLI (`gog`) with service subcommands: `gmail`, `calendar`, `drive`, `contacts`, plus `auth`.
41+
- OAuth setup and account management:
42+
- Store OAuth client credentials: `gog auth credentials <credentials.json>`.
43+
- Authorize accounts and store refresh tokens securely via OS keychain using `github.com/99designs/keyring`.
44+
- List/remove accounts: `gog auth list`, `gog auth remove <email>`.
45+
- Token management helpers: `gog auth tokens list|delete|export|import`.
46+
- Consistently parseable output:
47+
- `--output=text` (tab-separated lists on stdout) and `--output=json` (JSON on stdout).
48+
- Human hints/progress/errors go to stderr.
49+
- Colorized output in rich TTY (`--color=auto|always|never`), automatically disabled for JSON output.
50+
- Gmail features:
51+
- Search threads, show thread, generate web URLs.
52+
- Label listing/get (including counts) and thread label modify.
53+
- Send mail (supports reply headers + attachments).
54+
- Drafts: list/get/create/send/delete.
55+
- Calendar features:
56+
- List calendars, list ACL rules.
57+
- List/get/create/update/delete events and free/busy queries.
58+
- Drive features:
59+
- List/search/get files, download (including Google Docs export), upload, mkdir, delete, move, rename.
60+
- Sharing helpers: share/unshare/permissions, and web URL output.
61+
- Contacts / People API features:
62+
- Contacts list/search/get/create/update/delete.
63+
- “Other contacts” list/search.
64+
- Workspace directory list/search (Workspace accounts only).
65+
- Developer experience:
66+
- Formatting via `gofumpt` + `goimports` (and `gofmt` implicitly) using `make fmt` / `make fmt-check`.
67+
- Linting via pinned `golangci-lint` with repo config.
68+
- Tests using stdlib `testing` + `httptest`, with steadily increased unit coverage.
69+
- GitHub Actions CI running format checks, tests, and lint.
70+
- `pnpm gog` helper to build+run (`pnpm gog auth add you@gmail.com`).
71+
72+
### Notes / Known Limitations
73+
74+
- Importing tokens into macOS Keychain may require a local (GUI) session; headless/SSH sessions can fail due to Keychain user-interaction restrictions.
75+
- Workspace directory commands require a Google Workspace account; `@gmail.com` accounts will not work for directory endpoints.

Makefile

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
SHELL := /bin/bash
22

3-
.PHONY: setup fmt fmt-check lint test ci tools
3+
# `make` should build the binary by default.
4+
.DEFAULT_GOAL := build
45

5-
setup:
6-
@command -v lefthook >/dev/null || (echo "Install lefthook: brew install lefthook" && exit 1)
7-
lefthook install
6+
.PHONY: build fmt fmt-check lint test ci tools
7+
8+
BIN_DIR := $(CURDIR)/bin
9+
BIN := $(BIN_DIR)/gog
10+
CMD := ./cmd/gog
811

912
TOOLS_DIR := $(CURDIR)/.tools
1013
GOFUMPT := $(TOOLS_DIR)/gofumpt
1114
GOIMPORTS := $(TOOLS_DIR)/goimports
1215
GOLANGCI_LINT := $(TOOLS_DIR)/golangci-lint
1316

17+
build:
18+
@mkdir -p $(BIN_DIR)
19+
@go build -o $(BIN) $(CMD)
20+
1421
tools:
1522
@mkdir -p $(TOOLS_DIR)
1623
@GOBIN=$(TOOLS_DIR) go install mvdan.cc/gofumpt@v0.9.2

0 commit comments

Comments
 (0)