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
27 changes: 27 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Lint

on:
push:
branches: [main]
pull_request:

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

permissions:
contents: read

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Install
run: uv sync --python 3.11

- name: Ruff
run: uv run ruff check .
69 changes: 69 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Release

# Publishes to PyPI when a version tag such as v0.2.0 is pushed.
# Needs a PYPI_API_TOKEN secret (Settings > Secrets and variables > Actions).
on:
push:
tags: ["v*.*.*"]

permissions:
contents: read

jobs:
check:
name: Check version and tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Tag must match the package version
shell: bash
run: |
tag="${GITHUB_REF_NAME#v}"
project=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
module=$(python3 -c "import re; print(re.search(r'__version__ = \"(.+?)\"', open('src/commitrocket/__init__.py').read()).group(1))")
echo "tag=$tag pyproject=$project __init__=$module"
if [ "$tag" != "$project" ] || [ "$tag" != "$module" ]; then
echo "::error::Tag v$tag must match the version in pyproject.toml ($project) and src/commitrocket/__init__.py ($module)."
exit 1
fi

- name: Install
run: uv sync --python 3.11

- name: Lint
run: uv run ruff check .

- name: Unit tests
run: uv run pytest -m "not integration"

- name: Integration tests
run: uv run pytest -m integration

publish:
name: Build and publish
needs: check
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Build
run: uv build

- name: Publish to PyPI
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
run: uv publish

- name: GitHub release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: dist/*
45 changes: 45 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Tests

on:
push:
branches: [main]
pull_request:

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

permissions:
contents: read

jobs:
test:
name: ${{ matrix.os }} / Python ${{ matrix.python }}
runs-on: ${{ matrix.os }}
# Python 3.15 may still be a pre-release; don't let it block the build.
continue-on-error: ${{ matrix.python == '3.15' }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, python: "3.11" }
- { os: ubuntu-latest, python: "3.12" }
- { os: ubuntu-latest, python: "3.13" }
- { os: ubuntu-latest, python: "3.14" }
- { os: ubuntu-latest, python: "3.15" }
- { os: windows-latest, python: "3.11" }
- { os: macos-latest, python: "3.11" }

steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Install
run: uv sync --python ${{ matrix.python }}

- name: Unit tests
run: uv run pytest -m "not integration" -n auto

- name: Integration tests
run: uv run pytest -m integration -n auto
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,6 @@ __marimo__/

# Streamlit
.streamlit/secrets.toml

CLAUDE.md
.temp/
17 changes: 17 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Install once with: uv run pre-commit install
# Integration tests (marker "integration") are slower and run only in CI.
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.17.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

- repo: local
hooks:
- id: pytest
name: pytest (unit tests)
entry: uv run pytest -m "not integration" -n auto -q
language: system
types: [python]
pass_filenames: false
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Changelog

## [Unreleased]

## [0.1.0] - 2026-10-24

### Added
- CommitRocket is now an installable package with a `commitrocket` command.
- Files over 100 MiB are detected up front, and the run stops with a hint to use `--use-lfs` instead of failing at push time.
- The overall progress bar shows an ETA based on the average speed of the whole run so far, updating live during each upload.
- `--use-lfs` stores files over 100 MiB with Git LFS during the run, without committing any LFS config, and removes the local setup afterwards.
- `--report FILE` writes a machine-readable JSON summary of every run.
- `--notify` and `--notify-webhook` tell you when a run ends, via a desktop notification or a web hook.
- `commitrocket doctor` checks Git, git-lfs, your settings, the remote and the repository before a run.
- Settings can be saved in `commitrocket.toml` or `[tool.commitrocket]` in `pyproject.toml`.
- `--include`, `--exclude`, `--include-from`, `--exclude-from` and `.commitrocketignore` choose which files are handled, using `.gitignore`-style patterns.
- `--remote` and `--branch` choose where to push, `--no-push` only commits, and `--message-template` customises commit messages.
- `--lfs-commit-rules` commits LFS rules per file type so clones get the real files.
- A failed `--use-lfs` run now keeps the LFS hooks until its commits are pushed, so LFS files are never published as bare pointers.
- `--repo` now defaults to the current folder.
- A `--log-file` or `--report` inside the repository is no longer committed, which previously made a run commit its own log forever.
- `--dry-run` shows the planned batches and commit messages without changing anything.
- Failed pushes are retried with growing waits (`--retries`, default 3); rejections are not retried.
- Interrupted or failed runs can be resumed by running the same command again.
- `--post-buffer-mib` raises Git's HTTP buffer for large pushes over HTTPS.
- Each push is checked against the remote, and LFS files are confirmed as pointers before upload.
- `--lfs-threshold-mib` sets the size above which `--use-lfs` applies (default 100); `0` sends every file through LFS.
- Each run writes a log file to the system's standard log folder; `--level` sets the detail and `--log-file` overrides the location.
- `--batch-type` chooses how files are grouped: `deterministic` (default, unchanged), `sequential` or `soft`.
- `--compression-threads`, `--lfs-threads` and `--lfs-batch-mib` speed up pushes; the thread settings apply to the repository only and are restored afterwards.
- Leftover local commits containing files over 100 MiB are detected at startup, with the command to clean them up.
Loading
Loading