Files
weekly-activity/README.md
T
kosmosandvhaudiquet 6d8cc3d817 Add config onboarding wizard and aggregated report
- `weekly-activity config`: interactive wizard writing
  ~/.config/weekly-activity.toml (XDG-aware, --config override), one
  section per source, 0600 permissions, tokens never echoed; re-runs show
  current settings and pre-fill defaults
- `weekly-activity report` (and bare invocation): loads enabled sources,
  collects each independently, joins blocks under one header; a failing
  source renders as [skipped: <source> — error] without aborting
- config.py: typed schema, tomllib reader with strict validation,
  hand-formatted TOML writer (stdlib-only, no new dependency)
- aggregate.py: source spec building + failure-isolated collection +
  combined rendering
- README: document config/report usage and config schema
- tests/: 16 stdlib-unittest cases (config round-trip/escaping/validation,
  aggregation mapping/isolation)
2026-08-26 20:18:41 +00:00

154 lines
6.2 KiB
Markdown

# weekly-activity
Aggregate weekly activity across development platforms (Launchpad, GitHub, GitLab, Debian BTS) into a single text report.
## Usage
```bash
# Interactive setup: pick sources, store identities/tokens once
uv run weekly-activity config
# Aggregated report across every configured source
uv run weekly-activity report # bare `weekly-activity` does the same
```
### Single sources (ad-hoc, no config needed)
```bash
# Launchpad (uses system keyring for OAuth; --anonymous for public data only)
uv run weekly-activity launchpad <username>
uv run weekly-activity launchpad --anonymous <username>
# GitHub (uses GITHUB_TOKEN env var or `gh auth token`; anonymous works but rate-limited)
uv run weekly-activity github <username>
uv run weekly-activity github --token ghp_xxx <username>
# GitLab (gitlab.com by default; any self-hosted instance via --url, e.g. Debian Salsa;
# uses GITLAB_TOKEN / SALSA_TOKEN env vars, anonymous works but rate-limited)
uv run weekly-activity gitlab <username>
uv run weekly-activity gitlab --url https://salsa.debian.org <username>
uv run weekly-activity gitlab --url https://salsa.debian.org --token glpat-xxx <username>
# Debian BTS (bugs.debian.org; identify by the email used on bugs)
uv run weekly-activity bts <email>
# Custom date range (ISO dates, UTC)
uv run weekly-activity launchpad --since 2025-08-01 --until 2025-08-15 <username>
uv run weekly-activity github --since 2025-08-01 --until 2025-08-15 <username>
uv run weekly-activity gitlab --since 2025-08-01 --until 2025-08-15 <username>
uv run weekly-activity bts --since 2025-08-01 --until 2025-08-15 <email>
```
### GitLab instances
Any GitLab instance works via `--url`. Token discovery order:
1. `--token` flag
2. env var named by `--token-env`
3. `<HOST>_TOKEN` derived from the instance host (e.g. `SALSA_TOKEN` for `salsa.debian.org`)
4. `GITLAB_TOKEN`
## What it reports
| Section | Launchpad | GitHub | GitLab | Debian BTS |
|---|---|---|---|---|
| Merge proposals / PRs authored | `getMergeProposals` (created in range) | `/search/issues` (`author:` + `type:pr`) | `/merge_requests` (`author_id`, created range) | — |
| Review requests received | `getRequestedReviews` (filtered by `date_review_requested`) | `/search/issues` (`reviewed-by:` + `type:pr`) | — | — |
| Reviews performed | `getRequestedReviews` (filtered by `date_reviewed`) | (same query) | events (`action=approved`) | — |
| Issues / Bugs | `searchTasks` (reporter, commenter, assignee) | `/search/issues` (author, commenter, assignee) | `/issues` (`author_id`, `assignee_id`) | `get_bugs` (`submitter`) + `get_status` (created in range) |
| Bugs owned, updated | — | — | — | `get_bugs` (`owner`) + `get_status` (`log_modified`) |
| Repositories modified | `git_repositories.getRepositories` (`modified_since_date`) | `/users/{user}/repos` (filtered by `pushed_at`) | — (covered by push events) | — |
| Commits pushed | — (not in Launchpad REST API) | `/repos/{owner}/{repo}/commits` (per active repo) | events (`action=pushed`) | — |
### Default time window
Rolling 7 days ending today (inclusive). Override with `--since` / `--until` (ISO dates, UTC).
## Configuration
`weekly-activity config` walks through each known source and writes a TOML
file. Tokens are stored as provided (plaintext), but the file is created with
owner-only permissions (`0600`) and secrets are never echoed back. Use
`--config <path>` (also accepted by `report`) to keep configs elsewhere.
Default location: `${XDG_CONFIG_HOME:-~/.config}/weekly-activity.toml`.
```toml
[github]
username = "octocat"
token = "" # empty -> fall back to $GITHUB_TOKEN / `gh auth token`
[launchpad]
username = "jane"
mode = "credentials" # "anonymous" (public data only) | "credentials"
credentials_file = "" # empty -> system keyring; OAuth runs at report time
[gitlab]
url = "https://salsa.debian.org"
username = "jane"
token_env = "SALSA_TOKEN"
[bts]
email = "jane@example.org"
```
An absent `[section]` disables that source. Re-running `weekly-activity
config` shows the current settings and offers to redo the wizard with the
existing values as defaults.
## Architecture
```
src/weekly_activity/
model.py ActivityReport, Section, last_week_window
report.py format_report() — source-agnostic text renderer
cli.py subcommand dispatch (launchpad | github | gitlab | bts | report | config)
aggregate.py collect_specs()/format_combined() — one text report across sources
config.py ActivityConfig schema + TOML load/save (tomllib read, hand-written)
wizard.py interactive `config` onboarding
sources/
__init__.py ActivitySource protocol
launchpad.py LaunchpadSource (launchpadlib)
github.py GitHubSource (httpx)
gitlab.py GitLabSource (httpx, REST v4 — gitlab.com or self-hosted)
debian_bts.py DebianBtsSource (python-debianbts SOAP)
```
Each source implements `ActivitySource` — a `name` and a `collect(username, since, until) -> ActivityReport` method. Sources keep their own dataclasses internally; the shared contract is `Section` (title + pre-formatted lines) and `ActivityReport` (metadata + sections + warnings). The report formatter (`report.py`) is source-agnostic.
Per-query failures (rate limits, server timeouts) are caught per-section — a failing endpoint records a warning and degrades to an empty section rather than killing the whole report.
## Development
```bash
uv sync # install deps + dev tooling
uv run ruff format src # format
uv run ruff check src # lint
uv run ty check # type check
```
## CI / releases
Gitea Actions (`.gitea/workflows/ci.yml`) runs two jobs:
- **check** — format, lint, and type check on every push to `main`
- **release** — on `v*` tags: builds a standalone Linux executable with
PyInstaller, smoke-tests it, creates a Gitea release, and uploads the
binary as an asset
Cut a release with:
```bash
git tag vX.Y.Z && git push origin vX.Y.Z
```
## Dependencies
- **launchpadlib** — Launchpad REST API client
- **httpx** — GitHub & GitLab REST API client
- **python-debianbts** — Debian BTS SOAP client
- **ruff** — format + lint (dev)
- **ty** — type check (dev)