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
5 changes: 5 additions & 0 deletions .commitlintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extends:
- '@commitlint/config-conventional'

rules:
header-max-length: [0, 'always', 100]
48 changes: 48 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
version: 2

updates:
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "weekly"
groups:
uv-minor-patch:
applies-to: "version-updates"
patterns:
- "*"
update-types:
- "minor"
- "patch"
uv-major:
applies-to: "version-updates"
patterns:
- "*"
update-types:
- "major"
uv-security:
applies-to: "security-updates"
patterns:
- "*"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions-minor-patch:
applies-to: "version-updates"
patterns:
- "*"
update-types:
- "minor"
- "patch"
actions-major:
applies-to: "version-updates"
patterns:
- "*"
update-types:
- "major"
actions-security:
applies-to: "security-updates"
patterns:
- "*"
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI

on:
push:
branches:
- main
paths-ignore:
- "data/**"
pull_request:
branches:
- main
paths-ignore:
- "data/**"

permissions:
contents: read

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: .python-version

- name: Set up uv
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
version: "0.12.18"
enable-cache: true
cache-dependency-glob: uv.lock

- name: Run tests
run: uv run --frozen pytest

- name: Check formatting and lint
run: |
uv run --frozen ruff check .
uv run --frozen ruff format --check .

- name: Check types
run: uv run --frozen mypy src tests

- name: Check complexity
run: uv run --frozen complexipy src/github_trending --max-complexity-allowed 15 --sort desc

- name: Check dependencies and imports
run: |
uv run --frozen deptry .
uv run --frozen lint-imports
61 changes: 61 additions & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Commit checks

on:
push:
branches:
- main
paths-ignore:
- "data/**"
pull_request:
branches:
- main
types:
- opened
- edited
- synchronize
- reopened

concurrency:
group: commitlint-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
commitlint:
if: >-
(github.event_name == 'pull_request' && github.event.pull_request.user.login != 'dependabot[bot]')
|| (github.event_name == 'push' && github.event.head_commit.author.name != 'dependabot[bot]')
runs-on: ubuntu-latest

steps:
- name: Enforce single-commit PRs
if: github.event_name == 'pull_request'
env:
PR_COMMIT_COUNT: ${{ github.event.pull_request.commits }}
run: test "$PR_COMMIT_COUNT" -eq 1

- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
persist-credentials: false

- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
package-manager-cache: false

- name: Install commitlint
run: npm install --ignore-scripts --no-save --no-package-lock @commitlint/cli@21.2.3 @commitlint/config-conventional@21.2.3

- name: Validate PR title
if: github.event_name == 'pull_request'
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: printf '%s\n' "$PR_TITLE" | ./node_modules/.bin/commitlint --verbose

- name: Validate last commit
run: ./node_modules/.bin/commitlint --last --verbose
64 changes: 64 additions & 0 deletions .github/workflows/update-data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Update data

on:
schedule:
- cron: "17 */6 * * *"
workflow_dispatch:

permissions:
contents: write

concurrency:
group: update-github-trending-data
cancel-in-progress: false

jobs:
update:
runs-on: ubuntu-latest
env:
UV_PYTHON_PREFERENCE: only-system
UV_PYTHON_DOWNLOADS: never
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: .python-version

- name: Set up uv
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
version: "0.12.18"
enable-cache: true
cache-dependency-glob: uv.lock

- name: Generate dataset
id: generate
shell: bash
run: |
set +e
uv run --frozen github-trending --verbose
exit_code=$?
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
if [[ "$exit_code" != "0" && "$exit_code" != "2" ]]; then
exit "$exit_code"
fi

- name: Commit generated data
if: steps.generate.outputs.exit_code == '0' || steps.generate.outputs.exit_code == '2'
shell: bash
run: |
git add data
if git diff --cached --quiet; then
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -m "chore(data): update $(date -u +'%Y-%m-%dT%H:%M:%SZ') [skip ci]"
git push

- name: Mark degraded update as failed
if: steps.generate.outputs.exit_code == '2'
run: exit 1
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.venv/
.mypy_cache/
.pytest_cache/
.ruff_cache/
.complexipy_cache/
.import_linter_cache/
dist/
__pycache__/
*.py[cod]
.DS_Store

.idea/
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Agent skills

### Issue tracker

Issues and specs are tracked as local Markdown files under `.scratch/`. See `docs/agents/issue-tracker.md`.

### Domain docs

This repository uses a single-context domain documentation layout. See `docs/agents/domain.md`.
56 changes: 56 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# GitHub Trending Dataset

This context describes the vocabulary of observed GitHub Trending rankings and their history.

## Language

**Feed**:
A single GitHub Trending ranking for one language filter and one period.
_Avoid_: Endpoint, channel

**Observation**:
One repository's appearance at a particular rank in a feed at a point in time.
_Avoid_: Record, event

**Repository Identity**:
The case-insensitive owner and repository name that relates observations of the same repository.
_Avoid_: URL, GUID

**Period Metric**:
The number of stars GitHub reports for a repository within a feed's period. It is optional because
GitHub may omit it from an otherwise valid observation.
_Avoid_: Total stars, growth rate

**Snapshot**:
The ordered observations obtained from one successful reading of a feed.
_Avoid_: Current archive, batch

**Snapshot Issue**:
A structured description of an unexpectedly missing or malformed field at its original source rank.
_Avoid_: Feed failure, validation error

**Current Dataset**:
The latest successfully published snapshot of each feed.
_Avoid_: Cache, latest archive

**Daily Rollup**:
The unique repositories observed in one feed during a UTC day, together with their latest values and daily rank summary.
_Avoid_: Daily snapshot, cumulative current

**Archive**:
The date-addressed collection of daily rollups.
_Avoid_: Backup, snapshot history

**Degraded Snapshot**:
A snapshot containing every identifiable observation from a recognized ranking while identifying
unexpectedly missing or malformed fields. An absent optional period metric does not cause
degradation; only source positions without repository identity are skipped.
_Avoid_: Partial failure, incomplete feed

**Stale Feed**:
A feed whose latest read failed entirely, leaving its previously published snapshot unchanged.
_Avoid_: Empty feed, degraded snapshot

**Update Run**:
One attempt to read every configured feed and publish each snapshot that was obtained successfully.
_Avoid_: Snapshot, deployment
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# GitHub Trending API

Static JSON and RSS snapshots of GitHub Trending, refreshed four times per day by GitHub Actions.
The dataset covers `daily`, `weekly`, and `monthly` periods for `all`, `python`, `rust`, `go`,
`javascript`, and `typescript`.

## Data

`current` contains the latest published snapshot. `archive` contains one accumulated UTC daily
rollup per feed.

```text
https://raw.githubusercontent.com/<owner>/<repo>/main/data/current/{period}/{language}.{json|xml}
https://raw.githubusercontent.com/<owner>/<repo>/main/data/archive/{YYYY}/{MM}/{DD}/{period}/{language}.{json|xml}
```

## Documentation

- [Dataset behavior](docs/product/dataset.md)
- [JSON and RSS data contract](docs/product/data-contract.md)
- [Documentation index](docs/README.md)
21 changes: 21 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Documentation

This directory is the entrypoint for durable documentation of the implemented system.

## Product

- [Product documentation](product/README.md)
- [Dataset behavior](product/dataset.md)
- [JSON and RSS data contract](product/data-contract.md)

## Architecture and operations

- [Architecture overview](architecture/overview.md)
- [Deployment and automation](architecture/deployment.md)
- [ADR-0001: Static dataset via GitHub Actions](adr/0001-static-dataset-via-github-actions.md)

## Domain language

- [GitHub Trending Dataset glossary](../CONTEXT.md)

The project landing page remains in the root [README](../README.md).
6 changes: 6 additions & 0 deletions docs/adr/0001-static-dataset-via-github-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Static dataset via GitHub Actions

GitHub Trending API is delivered as generated JSON and RSS committed by a scheduled GitHub Actions
job and served through repository files and GitHub Raw, rather than through an application server
and database. This keeps operation minimal and makes every published change visible in Git history,
at the cost of update latency, repository write access for Actions, and no dynamic query interface.
Loading
Loading