mirror of
https://github.com/tiennm99/ghstats.git
synced 2026-05-23 00:25:23 +00:00
94e13d2c65
- design-guidelines: every dimension was stale — card frame 340x200 (was 500x220), corner radius 6, title 15px at (20,30), row y0/dy, donut centre (250,110) r=55/30, topN=5, legend y0=55 dy=20, bar chart area [35,325]x[45,155], area chart [28,312]x[45,150], icon scale 0.75. - code-standards: FetchContributionsAllTime signature now ctx-first, viewbox 500x220 → 340x200. - codebase-summary: test coverage lists main_test.go + TestDonutSingleSlice/Empty; filename convention says plain kebab-case (no numeric prefix). - project-overview-pdr: forks/private defaults now on, not off. - project-roadmap: add Phase 7 (Marketplace polish — resize, numeric- prefix drop, v1 floating tag, rename-rollback). Renumber planned phases 8-11. Fix "hard width 500 px" limitation. - deployment-guide: document update-major-tag job; note Marketplace listing name is `ghstats-cards`.
155 lines
6.1 KiB
Markdown
155 lines
6.1 KiB
Markdown
# Deployment Guide
|
||
|
||
Three consumption paths: **GitHub Action**, **prebuilt binaries**, **go install**.
|
||
|
||
## 1. GitHub Action (recommended for README auto-updates)
|
||
|
||
### Workflow template
|
||
|
||
File: `.github/workflows/ghstats.yml` in your profile repo.
|
||
|
||
```yaml
|
||
name: ghstats
|
||
|
||
on:
|
||
schedule:
|
||
- cron: "0 0 * * *" # daily at 00:00 UTC
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: write # needed for commit_changes
|
||
|
||
jobs:
|
||
cards:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v5
|
||
- uses: tiennm99/ghstats@v1
|
||
with:
|
||
user: ${{ github.repository_owner }}
|
||
token: ${{ secrets.GHSTATS_TOKEN }}
|
||
themes: dracula,github_dark,tokyonight
|
||
tz: Asia/Saigon
|
||
include_forks: "false"
|
||
include_private: "false"
|
||
commit_changes: "true"
|
||
```
|
||
|
||
### Required secrets
|
||
|
||
`GHSTATS_TOKEN`: a **classic** personal access token with at minimum:
|
||
|
||
| Scope | Needed for |
|
||
| --- | --- |
|
||
| `read:user` | Basic profile fields, contribution calendar |
|
||
| `repo` | Only if `include_private: "true"` |
|
||
|
||
Fine-grained PATs and the default `${{ github.token }}` lack the introspection scope for contribution calendars in many orgs, so a classic PAT is recommended.
|
||
|
||
Create one at <https://github.com/settings/tokens> → "Generate new token (classic)" → select `read:user` (+ `repo` if needed) → save as repo secret `GHSTATS_TOKEN`.
|
||
|
||
### Embedding in README
|
||
|
||
```md
|
||

|
||

|
||

|
||

|
||

|
||

|
||

|
||

|
||

|
||
```
|
||
|
||
The Action commits SVGs to `output/<theme>/` on the default branch. GitHub serves them from the raw URL the README references.
|
||
|
||
## 2. Prebuilt binaries
|
||
|
||
Each tag under `v*` publishes:
|
||
- Linux `amd64`, `arm64`
|
||
- macOS `amd64`, `arm64`
|
||
- Windows `amd64`
|
||
|
||
Released via `.github/workflows/release.yml` which matrixes `GOOS` × `GOARCH`, strips symbols (`-ldflags="-s -w"`), and uploads tar.gz / zip to the GitHub Release.
|
||
|
||
Install:
|
||
|
||
```sh
|
||
# Linux x86_64 example
|
||
curl -L https://github.com/tiennm99/ghstats/releases/latest/download/ghstats_linux_amd64.tar.gz \
|
||
| tar xz
|
||
./ghstats -user YOUR_USERNAME
|
||
```
|
||
|
||
## 3. go install
|
||
|
||
```sh
|
||
go install github.com/tiennm99/ghstats@latest
|
||
```
|
||
|
||
Requires Go 1.26+. Puts the binary in `$(go env GOPATH)/bin`.
|
||
|
||
## Docker image
|
||
|
||
Published to `ghcr.io/tiennm99/ghstats:<tag>` on each `v*` release via `.github/workflows/release.yml` (buildx, multi-tag: exact version, major.minor, major, latest).
|
||
|
||
The Action itself uses a runner-built image by default (`image: Dockerfile` in `action.yml`). To switch to the pre-built image for faster cold starts, edit `action.yml`:
|
||
|
||
```yaml
|
||
runs:
|
||
using: docker
|
||
image: docker://ghcr.io/tiennm99/ghstats:v1
|
||
```
|
||
|
||
## Release process
|
||
|
||
1. Tag: `git tag -a v1.2.0 -m "..." && git push origin v1.2.0`.
|
||
2. `release.yml` runs `go vet` + `go test` as a gate before the docker and
|
||
binaries jobs. If tests fail, no artifacts ship.
|
||
3. On green, GHCR push + cross-platform binary artifacts happen automatically.
|
||
4. The `update-major-tag` job force-moves the floating major tag (e.g. `v1`)
|
||
to this release's commit after test + docker + binaries all pass.
|
||
Consumers pinned to `tiennm99/ghstats@v1` pick up the release on their
|
||
next Action run without a workflow edit.
|
||
5. Docker base images and third-party actions are SHA-pinned (with version
|
||
comments) so mutable-tag changes upstream can't rewrite a released image.
|
||
6. **Marketplace publishing (one-time per repo):** GitHub only exposes the
|
||
"Publish this Action to the GitHub Marketplace" toggle on the Release
|
||
web UI — there is no CLI flag. Open the newly created release at
|
||
`https://github.com/tiennm99/ghstats/releases/tag/vX.Y.Z/edit`, tick the
|
||
marketplace checkbox, accept the terms, and re-publish. Subsequent
|
||
releases inherit marketplace visibility automatically. The Marketplace
|
||
listing name is `ghstats-cards` (set in `action.yml`) because the bare
|
||
`ghstats` is already taken on the Marketplace.
|
||
|
||
## Rollback
|
||
|
||
- Revert the tag: `git push --delete origin v1.2.0`, delete GitHub release, delete GHCR tag.
|
||
- Users pinned to `@v1` keep working because the previous patch is still tagged.
|
||
|
||
## Rate limit considerations
|
||
|
||
| Scenario | GraphQL calls per run | Notes |
|
||
| --- | --- | --- |
|
||
| Typical user, defaults | 15–40 | Well under 5000 pts/hr |
|
||
| Active user (8 years, 30+ seed repos) | 40–80 | Still comfortable |
|
||
| `-include-private=true` with 100+ work repos | 80–200 | Fine for daily cron |
|
||
| Adversarial user with 500+ committed repos/year | Capped by `maxRepositories: 100` per year query | Long tail drops silently |
|
||
|
||
No REST calls today. Future `-accurate-languages` mode will push toward 1000+ REST per run; schedule that mode less frequently (weekly, not daily).
|
||
|
||
The client auto-handles rate-limit responses: on 429 or 403 with `X-RateLimit-Remaining: 0`, it sleeps up to 5 minutes (honoring `Retry-After` / `X-RateLimit-Reset`) and retries once. A reset window longer than 5 min surfaces as an error so CI can reschedule instead of burning runner time. Use the `-timeout` flag (default 30m) to cap total fetch duration; `SIGINT`/`SIGTERM` cancels in-flight requests cleanly.
|
||
|
||
## Troubleshooting
|
||
|
||
| Symptom | Check |
|
||
| --- | --- |
|
||
| "error: fetch profile: graphql: Could not resolve to a User" | Username typo |
|
||
| "http 401" | Token expired or lacks `read:user` |
|
||
| "rate limit resets in 42m (>5m0s max wait)" | Client refused to sleep through a long window; reschedule the Action |
|
||
| "http 403" on non-rate-limit path | PAT scope too narrow |
|
||
| Blank contribution chart | User has 0 contributions in their window; expected |
|
||
| Private repo data missing | `-include-private=true` not set, or PAT lacks `repo` |
|
||
| Nothing committed by the Action | Check `permissions: contents: write` in the workflow |
|