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
22 changes: 22 additions & 0 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Auto Release

on:
push:
branches: [main]
workflow_dispatch:
inputs:
dry-run:
description: "Compute the tag but do not push it"
type: boolean
default: true

permissions:
contents: read

jobs:
auto-release:
uses: open-cli-collective/.github/.github/workflows/auto-release.yml@v1
with:
dry-run: ${{ github.event_name == 'workflow_dispatch' && (inputs.dry-run == true || inputs.dry-run == 'true') }}
secrets:
tag-token: ${{ secrets.TAP_GITHUB_TOKEN }}
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ jobs:
go-version-file: go.mod
- run: make test-cover-check

identity-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: open-cli-collective/.github/actions/identity-check@v1

pr-title:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Release

on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
dry-run:
description: "Build + render but skip publishing (only meaningful from a tag ref)"
type: boolean
default: true

permissions:
contents: write

jobs:
release:
uses: open-cli-collective/.github/.github/workflows/release.yml@v1
with:
dry-run: ${{ github.event_name == 'workflow_dispatch' && (inputs.dry-run == true || inputs.dry-run == 'true') }}
secrets:
homebrew-tap-token: ${{ secrets.TAP_GITHUB_TOKEN }}
chocolatey-api-key: ${{ secrets.CHOCOLATEY_API_KEY }}
winget-token: ${{ secrets.WINGET_GITHUB_TOKEN }}
linux-dispatch-token: ${{ secrets.LINUX_PACKAGES_DISPATCH_TOKEN }}
macos-cert-p12: ${{ secrets.MACOS_CERT_P12 }}
macos-cert-password: ${{ secrets.MACOS_CERT_PASSWORD }}
macos-cert-cn: ${{ secrets.MACOS_CERT_CN }}
macos-cert-leaf-sha: ${{ secrets.MACOS_CERT_LEAF_SHA }}
196 changes: 196 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
version: 2

project_name: google-cli

before:
hooks:
- sh -c "go mod tidy && git diff --exit-code go.mod go.sum"
- go test ./...

builds:
- id: gro-darwin
main: ./cmd/gro
binary: gro
flags: ["-tags=keyring_no1password,keyring_nopassage"]
env: [CGO_ENABLED=1]
goos: [darwin]
goarch: [amd64, arm64]
overrides:
- goos: darwin
goarch: amd64
goamd64: v1
env:
- CGO_ENABLED=1
- "CC=xcrun clang -arch x86_64"
- goos: darwin
goarch: arm64
goarm64: v8.0
env:
- CGO_ENABLED=1
- "CC=xcrun clang -arch arm64"
ldflags:
- -s -w
- -X github.com/open-cli-collective/google-cli/internal/version.Version={{.Version}}
- -X github.com/open-cli-collective/google-cli/internal/version.Commit={{.Commit}}
- -X github.com/open-cli-collective/google-cli/internal/version.Date={{.Date}}
hooks:
post:
- cmd: bash -c 'f="${CODESIGN_DARWIN_SCRIPT:-}"; if [ -z "$f" ]; then echo "skip codesign (CODESIGN_DARWIN_SCRIPT unset, local build)"; exit 0; fi; [ -x "$f" ] || { echo "CODESIGN_DARWIN_SCRIPT not executable ($f)" >&2; exit 1; }; exec "$f" "$0" "$1"' "{{ .Path }}" "{{ .Os }}"
- id: gro-unix-win
main: ./cmd/gro
binary: gro
flags: ["-tags=keyring_no1password,keyring_nopassage"]
env: [CGO_ENABLED=0]
goos: [linux, windows]
goarch: [amd64, arm64]
ldflags:
- -s -w
- -X github.com/open-cli-collective/google-cli/internal/version.Version={{.Version}}
- -X github.com/open-cli-collective/google-cli/internal/version.Commit={{.Commit}}
- -X github.com/open-cli-collective/google-cli/internal/version.Date={{.Date}}
- id: grw-darwin
main: ./cmd/grw
binary: grw
flags: ["-tags=keyring_no1password,keyring_nopassage"]
env: [CGO_ENABLED=1]
goos: [darwin]
goarch: [amd64, arm64]
overrides:
- goos: darwin
goarch: amd64
goamd64: v1
env:
- CGO_ENABLED=1
- "CC=xcrun clang -arch x86_64"
- goos: darwin
goarch: arm64
goarm64: v8.0
env:
- CGO_ENABLED=1
- "CC=xcrun clang -arch arm64"
ldflags:
- -s -w
- -X github.com/open-cli-collective/google-cli/internal/version.Version={{.Version}}
- -X github.com/open-cli-collective/google-cli/internal/version.Commit={{.Commit}}
- -X github.com/open-cli-collective/google-cli/internal/version.Date={{.Date}}
hooks:
post:
- cmd: bash -c 'f="${CODESIGN_DARWIN_SCRIPT:-}"; if [ -z "$f" ]; then echo "skip codesign (CODESIGN_DARWIN_SCRIPT unset, local build)"; exit 0; fi; [ -x "$f" ] || { echo "CODESIGN_DARWIN_SCRIPT not executable ($f)" >&2; exit 1; }; exec "$f" "$0" "$1"' "{{ .Path }}" "{{ .Os }}"
- id: grw-unix-win
main: ./cmd/grw
binary: grw
flags: ["-tags=keyring_no1password,keyring_nopassage"]
env: [CGO_ENABLED=0]
goos: [linux, windows]
goarch: [amd64, arm64]
ldflags:
- -s -w
- -X github.com/open-cli-collective/google-cli/internal/version.Version={{.Version}}
- -X github.com/open-cli-collective/google-cli/internal/version.Commit={{.Commit}}
- -X github.com/open-cli-collective/google-cli/internal/version.Date={{.Date}}

archives:
- id: gro
ids: [gro-darwin, gro-unix-win]
formats: [tar.gz]
format_overrides:
- goos: windows
formats: [zip]
name_template: "gro_v{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files: [LICENSE, README.md]
- id: grw
ids: [grw-darwin, grw-unix-win]
formats: [tar.gz]
format_overrides:
- goos: windows
formats: [zip]
name_template: "grw_v{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files: [LICENSE, README.md]

nfpms:
- id: google-readonly
ids: [gro-unix-win]
package_name: google-readonly
vendor: Open CLI Collective
homepage: https://github.com/open-cli-collective/google-cli
maintainer: Open CLI Collective <https://github.com/open-cli-collective>
description: Read-only command-line interface for Google services
license: MIT
formats: [deb, rpm]
bindir: /usr/bin
contents:
- src: LICENSE
dst: /usr/share/licenses/google-readonly/LICENSE
- id: google-readwrite
ids: [grw-unix-win]
package_name: google-readwrite
vendor: Open CLI Collective
homepage: https://github.com/open-cli-collective/google-cli
maintainer: Open CLI Collective <https://github.com/open-cli-collective>
description: Read-write command-line interface for Google services
license: MIT
formats: [deb, rpm]
bindir: /usr/bin
contents:
- src: LICENSE
dst: /usr/share/licenses/google-readwrite/LICENSE

homebrew_casks:
- name: gro
ids: [gro]
skip_upload: true
repository:
owner: open-cli-collective
name: homebrew-tap
homepage: https://github.com/open-cli-collective/google-cli
description: "Read-only command-line interface for Google services"
binaries: [gro]
hooks:
post:
install: |
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/gro"]
caveats: |
gro has been installed. Run 'gro init' to configure.
On macOS, your token is stored securely in the system Keychain.
- name: grw
ids: [grw]
skip_upload: true
repository:
owner: open-cli-collective
name: homebrew-tap
homepage: https://github.com/open-cli-collective/google-cli
description: "Read-write command-line interface for Google services"
binaries: [grw]
hooks:
post:
install: |
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/grw"]
caveats: |
grw has been installed. Run 'grw init' to configure.
On macOS, your token is stored securely in the system Keychain.

checksum:
name_template: checksums.txt

changelog:
sort: asc
use: github
filters:
exclude:
- "^docs:"
- "^test:"
- "^ci:"
- "^chore:"
- "Merge pull request"
groups:
- title: Features
regexp: '^feat:'
order: 0
- title: Bug Fixes
regexp: '^fix:'
order: 1
- title: Other
order: 999

release:
replace_existing_artifacts: true
18 changes: 18 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,22 @@ There is one release stream for both binaries. `version.txt` contains the major/

Each tag publishes both binaries and their platform archives through the shared release automation. Homebrew, Chocolatey, WinGet, and Linux package publication fan out from that release. Follow the [release](https://github.com/open-cli-collective/cli-common/blob/main/docs/release.md) and [distribution](https://github.com/open-cli-collective/cli-common/blob/main/docs/distribution.md) standards rather than duplicating workflow policy here.

### Packaging identity

`packaging/identity.yml` (schema `open-cli-identity/v1`, described in the cli-common
[distribution](https://github.com/open-cli-collective/cli-common/blob/main/docs/distribution.md)
standard) declares both binaries once so the shared automation can validate, build, sign, and
publish them without per-repo workflow logic. Naming follows one rule: `gro` keeps every identifier
it shipped under before the merge (`google-readonly` on Chocolatey, WinGet, Linux, and as a tap
alias) because package registries cannot rename an existing package without breaking upgrades;
`grw` is new, so it is canonical under its short name and only carries `google-readwrite` as a tap
alias. Each binary's `keychain_probe` runs the freshly built macOS binary against a seeded config
and asserts it selects the Keychain backend, which catches a static or mis-tagged build before it
is published.

`version.txt` holds only `MAJOR.MINOR`; the `major_minor_run_patch` scheme appends the workflow
run number, so tags are `v1.2.N` and never collide or need a bump commit. The stream starts at
`1.2` because `gro` had already released `1.1.x`; continuing its line keeps upgrades monotonic for
existing installs.

Use a focused branch, run `make check`, and open a pull request. Keep the pull-request title in conventional-commit form because squash merge makes that title the commit on `main` and therefore the release signal.
24 changes: 24 additions & 0 deletions packaging/chocolatey/google-readonly/google-readonly.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
<metadata>
<id>google-readonly</id>
<version>0.0.0</version>
<title>Google Readonly CLI</title>
<authors>Open CLI Collective</authors>
<owners>rianjs</owners>
<licenseUrl>https://github.com/open-cli-collective/google-cli/blob/main/LICENSE</licenseUrl>
<projectUrl>https://github.com/open-cli-collective/google-cli#readme</projectUrl>
<projectSourceUrl>https://github.com/open-cli-collective/google-cli</projectSourceUrl>
<packageSourceUrl>https://github.com/open-cli-collective/google-cli/tree/main/packaging/chocolatey/google-readonly</packageSourceUrl>
<bugTrackerUrl>https://github.com/open-cli-collective/google-cli/issues</bugTrackerUrl>
<copyright>Copyright (c) 2026 Open CLI Collective</copyright>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A read-only Google CLI for Gmail, Calendar, Contacts, and Drive.</description>
<summary>Read-only Google CLI for Gmail, Calendar, Contacts, and Drive</summary>
<releaseNotes>https://github.com/open-cli-collective/google-cli/releases</releaseNotes>
<tags>google gmail calendar contacts drive cli api readonly automation</tags>
</metadata>
<files>
<file src="tools\**" target="tools" />
</files>
</package>
25 changes: 25 additions & 0 deletions packaging/chocolatey/google-readonly/tools/chocolateyInstall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
$ErrorActionPreference = 'Stop'

$version = $env:ChocolateyPackageVersion
$toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition

$checksumAmd64 = 'CHECKSUM_AMD64_PLACEHOLDER'
$checksumArm64 = 'CHECKSUM_ARM64_PLACEHOLDER'

if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {
$arch = 'arm64'
$checksum = $checksumArm64
} elseif ([Environment]::Is64BitOperatingSystem) {
$arch = 'amd64'
$checksum = $checksumAmd64
} else {
throw "32-bit Windows is not supported. gro requires 64-bit Windows."
}

$url = "https://github.com/open-cli-collective/google-cli/releases/download/v${version}/gro_v${version}_windows_${arch}.zip"

Install-ChocolateyZipPackage -PackageName $env:ChocolateyPackageName `
-Url $url `
-UnzipLocation $toolsDir `
-Checksum $checksum `
-ChecksumType 'sha256'
24 changes: 24 additions & 0 deletions packaging/chocolatey/grw/grw.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
<metadata>
<id>grw</id>
<version>0.0.0</version>
<title>Google Read-Write CLI</title>
<authors>Open CLI Collective</authors>
<owners>rianjs</owners>
<licenseUrl>https://github.com/open-cli-collective/google-cli/blob/main/LICENSE</licenseUrl>
<projectUrl>https://github.com/open-cli-collective/google-cli#readme</projectUrl>
<projectSourceUrl>https://github.com/open-cli-collective/google-cli</projectSourceUrl>
<packageSourceUrl>https://github.com/open-cli-collective/google-cli/tree/main/packaging/chocolatey/grw</packageSourceUrl>
<bugTrackerUrl>https://github.com/open-cli-collective/google-cli/issues</bugTrackerUrl>
<copyright>Copyright (c) 2026 Open CLI Collective</copyright>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A read-write Google CLI: everything gro does plus Gmail delete and restore, folders, and filters.</description>
<summary>Read-write Google CLI with Gmail cleanup, folders, and filters</summary>
<releaseNotes>https://github.com/open-cli-collective/google-cli/releases</releaseNotes>
<tags>google gmail calendar contacts drive cli api readwrite automation</tags>
</metadata>
<files>
<file src="tools\**" target="tools" />
</files>
</package>
25 changes: 25 additions & 0 deletions packaging/chocolatey/grw/tools/chocolateyInstall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
$ErrorActionPreference = 'Stop'

$version = $env:ChocolateyPackageVersion
$toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition

$checksumAmd64 = 'CHECKSUM_AMD64_PLACEHOLDER'
$checksumArm64 = 'CHECKSUM_ARM64_PLACEHOLDER'

if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {
$arch = 'arm64'
$checksum = $checksumArm64
} elseif ([Environment]::Is64BitOperatingSystem) {
$arch = 'amd64'
$checksum = $checksumAmd64
} else {
throw "32-bit Windows is not supported. grw requires 64-bit Windows."
}

$url = "https://github.com/open-cli-collective/google-cli/releases/download/v${version}/grw_v${version}_windows_${arch}.zip"

Install-ChocolateyZipPackage -PackageName $env:ChocolateyPackageName `
-Url $url `
-UnzipLocation $toolsDir `
-Checksum $checksum `
-ChecksumType 'sha256'
Loading
Loading