ruff-sync 0.1.7.dev2__py3-none-any.whl → 0.1.9.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ruff_sync/.agents/skills/ruff-sync/SKILL.md +147 -0
- ruff_sync/.agents/skills/ruff-sync/references/ci-integration.md +233 -0
- ruff_sync/.agents/skills/ruff-sync/references/configuration.md +164 -0
- ruff_sync/.agents/skills/ruff-sync/references/troubleshooting.md +157 -0
- ruff_sync/config_io.py +1 -1
- ruff_sync/constants.py +3 -3
- ruff_sync/core.py +17 -44
- ruff_sync/types_.py +1 -3
- {ruff_sync-0.1.7.dev2.dist-info → ruff_sync-0.1.9.dev0.dist-info}/METADATA +32 -6
- {ruff_sync-0.1.7.dev2.dist-info → ruff_sync-0.1.9.dev0.dist-info}/RECORD +13 -9
- {ruff_sync-0.1.7.dev2.dist-info → ruff_sync-0.1.9.dev0.dist-info}/WHEEL +1 -1
- {ruff_sync-0.1.7.dev2.dist-info → ruff_sync-0.1.9.dev0.dist-info}/entry_points.txt +0 -0
- {ruff_sync-0.1.7.dev2.dist-info → ruff_sync-0.1.9.dev0.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ruff-sync
|
|
3
|
+
description: >-
|
|
4
|
+
Configure and operate ruff-sync to synchronize Ruff linter settings across Python projects.
|
|
5
|
+
Use when the user wants to set up ruff-sync, sync Ruff config from an upstream source,
|
|
6
|
+
check for configuration drift, integrate ruff-sync into CI, troubleshoot sync issues,
|
|
7
|
+
or keep Ruff rules consistent across multiple repositories.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# ruff-sync Usage
|
|
11
|
+
|
|
12
|
+
`ruff-sync` pulls a canonical Ruff configuration from an upstream URL and merges it into your local project, preserving comments, whitespace, and per-project overrides.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 1. Install
|
|
18
|
+
uv tool install ruff-sync
|
|
19
|
+
|
|
20
|
+
# 2. Sync from an upstream repo (extracts [tool.ruff] / ruff.toml automatically)
|
|
21
|
+
ruff-sync https://github.com/my-org/standards
|
|
22
|
+
|
|
23
|
+
# 3. Review the changes before committing
|
|
24
|
+
git diff pyproject.toml
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Persist Configuration
|
|
28
|
+
|
|
29
|
+
Add to `pyproject.toml` so you don't need to pass CLI args every time:
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[tool.ruff-sync]
|
|
33
|
+
upstream = "https://github.com/my-org/standards"
|
|
34
|
+
exclude = [
|
|
35
|
+
"target-version", # each project uses its own Python version
|
|
36
|
+
"lint.per-file-ignores", # project-specific suppressions
|
|
37
|
+
"lint.ignore",
|
|
38
|
+
"lint.isort.known-first-party",
|
|
39
|
+
]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then just run `ruff-sync` (no arguments needed).
|
|
43
|
+
|
|
44
|
+
See [references/configuration.md](references/configuration.md) for all config keys and defaults.
|
|
45
|
+
|
|
46
|
+
## Common Workflows
|
|
47
|
+
|
|
48
|
+
### Initial Project Setup
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Setup Progress:
|
|
52
|
+
- [ ] 1. Install ruff-sync (uv tool install ruff-sync)
|
|
53
|
+
- [ ] 2. Check for `.pre-commit-config.yaml` — if present, ensure the `ruff` hook is used
|
|
54
|
+
- [ ] 3. Add `[tool.ruff-sync]` to `pyproject.toml` with upstream URL and exclusions
|
|
55
|
+
- [ ] 4. If `.pre-commit-config.yaml` exists, set `pre-commit-version-sync = true` in `[tool.ruff-sync]`
|
|
56
|
+
- [ ] 5. Run `ruff-sync` to pull the upstream config
|
|
57
|
+
- [ ] 6. Review `git diff`
|
|
58
|
+
- [ ] 7. Fix any new lint errors: `uv run ruff check . --fix`
|
|
59
|
+
- [ ] 8. Commit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Upstream Layers (multi-source)
|
|
63
|
+
|
|
64
|
+
Stack multiple upstream sources — later entries win on conflict:
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[tool.ruff-sync]
|
|
68
|
+
upstream = [
|
|
69
|
+
"https://github.com/my-org/python-standards", # base company rules
|
|
70
|
+
"https://github.com/my-org/ml-team-tweaks", # team-specific overrides
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### CI Drift Check
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
CI Setup Progress:
|
|
78
|
+
- [ ] 1. Add ruff-sync check step to CI workflow (see references/ci-integration.md)
|
|
79
|
+
- [ ] 2. Decide: --semantic for value-only checks, or full string comparison
|
|
80
|
+
- [ ] 3. Set output format: --output-format github for PR annotations
|
|
81
|
+
- [ ] 4. Set exit-code expectations (0 = in sync, 1 = config drift, 2 = pre-commit only)
|
|
82
|
+
- [ ] 5. Verify locally: `ruff-sync check --semantic`
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Keep the `ruff-pre-commit` hook version in `.pre-commit-config.yaml` aligned with the project's Ruff version.
|
|
86
|
+
|
|
87
|
+
**Recommendation:** Always prefer the persistent TOML configuration over the ephemeral `--pre-commit` CLI flag.
|
|
88
|
+
|
|
89
|
+
```toml
|
|
90
|
+
[tool.ruff-sync]
|
|
91
|
+
pre-commit-version-sync = true
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then run `ruff-sync` — it updates the hook rev automatically. Exit code 2 means only the hook version is out of sync (Ruff config itself is fine).
|
|
95
|
+
|
|
96
|
+
## Exit Codes
|
|
97
|
+
|
|
98
|
+
| Code | Meaning |
|
|
99
|
+
|------|---------|
|
|
100
|
+
| `0` | In sync — no action needed |
|
|
101
|
+
| `1` | Ruff config is out of sync with upstream |
|
|
102
|
+
| `2` | Config is in sync, but pre-commit hook version is stale (only when `--pre-commit` is active) |
|
|
103
|
+
|
|
104
|
+
## URL Formats Supported
|
|
105
|
+
|
|
106
|
+
All of these work as the `upstream` value:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ruff-sync https://github.com/my-org/standards # repo root
|
|
110
|
+
ruff-sync https://github.com/my-org/standards/tree/main/cfg # subdirectory
|
|
111
|
+
ruff-sync https://github.com/my-org/standards/blob/main/ruff.toml # specific file
|
|
112
|
+
ruff-sync https://raw.githubusercontent.com/my-org/standards/main/pyproject.toml
|
|
113
|
+
ruff-sync git@github.com:my-org/standards.git # SSH (shallow clone)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## CLI Reference (Short)
|
|
117
|
+
|
|
118
|
+
| Flag | Meaning |
|
|
119
|
+
|------|---------|
|
|
120
|
+
| `--validate` | Validate merged config with Ruff before writing; aborts if Ruff rejects it |
|
|
121
|
+
| `--strict` | Like `--validate` but also treats warnings (version mismatch, deprecated rules) as failures. Implies `--validate` |
|
|
122
|
+
| `--output-format` | `text` (default), `json`, `github`, `gitlab`, `sarif` (auto-detected in CI) |
|
|
123
|
+
| `--semantic` | Ignore whitespace/comments in `check` |
|
|
124
|
+
| `--pre-commit` | Sync `.pre-commit-config.yaml` hook version |
|
|
125
|
+
| `--save` | Persist CLI args to `pyproject.toml` |
|
|
126
|
+
|
|
127
|
+
## Gotchas
|
|
128
|
+
|
|
129
|
+
- **`exclude` uses dotted paths, not TOML paths.** `lint.per-file-ignores` refers to the `per-file-ignores` key inside `[tool.ruff.lint]`. Do NOT write `tool.ruff.lint.per-file-ignores`.
|
|
130
|
+
- **`--validate` is opt-in.** Validation is off by default. Pass `--validate` (or `--strict`) to run the merged config through Ruff before writing. The sync is aborted if Ruff rejects the config, leaving the local file untouched. This includes a **Python version consistency check** that compares upstream `target-version` against local `requires-python`.
|
|
131
|
+
- **Excluding `target-version` skips consistency validation.** If `target-version` (or `tool.ruff.target-version`) is in the `exclude` list, `ruff-sync` will skip the version consistency check and log a warning. This is useful for projects that intentionally deviate from upstream Python versions.
|
|
132
|
+
- **`--strict` implies `--validate`.** If you want warnings (like version mismatches or deprecated rules) treated as failures, only `--strict` is needed — don't pass both.
|
|
133
|
+
- **Validation soft-fails if `ruff` is not on PATH.** If the `ruff` binary can't be found, a warning is logged and the sync continues normally.
|
|
134
|
+
- **Use `--init` only for new projects.** `ruff-sync` requires an existing `pyproject.toml` or `ruff.toml`. Pass `--init` to scaffold one if the directory is empty. This will automatically generate a `[tool.ruff-sync]` configuration block for future syncs.
|
|
135
|
+
- **Use `--save` to persist CLI arguments.** If you want to update an existing `pyproject.toml` with a new upstream URL or exclusion, pass `--save` to write the new configuration to the file.
|
|
136
|
+
- **`--semantic` ignores comments and whitespace.** Use it in CI to avoid false positives from cosmetic local edits. Omit it for strict byte-for-byte checks.
|
|
137
|
+
- **SSH URLs trigger a shallow clone.** `git@github.com:...` URLs use `git clone --filter=blob:none --depth=1` — no `git` credential issues as long as SSH auth is configured.
|
|
138
|
+
- **Later upstreams win in `upstream` lists.** In a multi-source list, keys set by entry 2 overwrite keys from entry 1.
|
|
139
|
+
- **Config discovery order matters.** When targeting a directory, `ruff-sync` looks for `ruff.toml` -> `.ruff.toml` -> `pyproject.toml` in that order.
|
|
140
|
+
- **Pre-commit exit code 2 is intentional.** A `2` exit from `ruff-sync check` means the Ruff _config_ is fine, only the pre-commit hook tag is stale. You may want to treat this differently from a full config drift (exit 1) in CI.
|
|
141
|
+
- **Prefer TOML for pre-commit sync.** While `--pre-commit` works on the CLI, setting `pre-commit-version-sync = true` in `pyproject.toml` is the recommended way to ensure hook versioning stays consistent for all contributors.
|
|
142
|
+
|
|
143
|
+
## References
|
|
144
|
+
|
|
145
|
+
- **[Configuration reference](references/configuration.md)** — All `[tool.ruff-sync]` keys, types, and defaults
|
|
146
|
+
- **[Troubleshooting](references/troubleshooting.md)** — Common errors and how to resolve them
|
|
147
|
+
- **[CI integration recipes](references/ci-integration.md)** — GitHub Actions, GitLab CI, pre-commit hook
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# CI Integration Recipes
|
|
2
|
+
|
|
3
|
+
## GitHub Actions
|
|
4
|
+
|
|
5
|
+
### Basic Drift Check
|
|
6
|
+
|
|
7
|
+
Add this step to any existing workflow (e.g., `.github/workflows/ci.yaml`):
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
- name: Check Ruff config is in sync
|
|
11
|
+
run: ruff-sync check --semantic --output-format github
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`--semantic` ignores cosmetic differences (comments, whitespace) — only real value or rule changes cause failure.
|
|
15
|
+
`--output-format github` creates inline PR annotations and a structured Job Summary report.
|
|
16
|
+
|
|
17
|
+
### With Strict Validation
|
|
18
|
+
|
|
19
|
+
To also catch deprecated rules and Python version mismatches in CI:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
- name: Check Ruff config (with validation)
|
|
23
|
+
run: ruff-sync check --semantic --strict --output-format github
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`--strict` implies `--validate`. Deprecated rules and version mismatches are upgraded to failures.
|
|
27
|
+
|
|
28
|
+
> [!TIP]
|
|
29
|
+
> `ruff-sync` automatically groups multiple drifts in the same file into a single annotation to reduce PR noise.
|
|
30
|
+
|
|
31
|
+
### Full Workflow Example
|
|
32
|
+
|
|
33
|
+
Uses [`astral-sh/setup-uv`](https://github.com/astral-sh/setup-uv) — the official action that installs uv, adds it to PATH, and handles caching. No separate `setup-python` step needed.
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
name: Ruff sync check
|
|
37
|
+
|
|
38
|
+
on:
|
|
39
|
+
push:
|
|
40
|
+
branches: [main]
|
|
41
|
+
pull_request:
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
ruff-sync-check:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Install uv
|
|
50
|
+
uses: astral-sh/setup-uv@v6
|
|
51
|
+
with:
|
|
52
|
+
version: "0.10.x" # pin to a minor range; Dependabot can keep this current
|
|
53
|
+
|
|
54
|
+
- name: Install ruff-sync
|
|
55
|
+
run: uv tool install ruff-sync
|
|
56
|
+
|
|
57
|
+
- name: Check Ruff config is in sync with upstream
|
|
58
|
+
run: ruff-sync check --semantic --output-format github
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With Pre-commit Sync Check
|
|
62
|
+
|
|
63
|
+
To also verify the pre-commit hook version, add the `--pre-commit` flag:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
- name: Check Ruff config and pre-commit hook
|
|
67
|
+
run: ruff-sync check --semantic --pre-commit --output-format github
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
(Note: For better consistency, you can instead set `pre-commit-version-sync = true` in your `pyproject.toml` — then `ruff-sync check --semantic` will automatically include this check.)
|
|
71
|
+
|
|
72
|
+
### SARIF Upload (GitHub Advanced Security)
|
|
73
|
+
|
|
74
|
+
For repositories with GitHub Advanced Security enabled, upload SARIF results to track drift findings in the **Security tab** and get per-key inline PR annotations that persist across runs:
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
- name: Check Ruff config (SARIF)
|
|
78
|
+
run: ruff-sync check --output-format sarif > ruff-sync.sarif || true
|
|
79
|
+
|
|
80
|
+
- name: Upload SARIF results
|
|
81
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
82
|
+
with:
|
|
83
|
+
sarif_file: ruff-sync.sarif
|
|
84
|
+
category: ruff-sync
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The `|| true` ensures the upload step always runs even when `ruff-sync` exits 1 (drift detected). Without it, GitHub Actions would skip the upload step on failure.
|
|
88
|
+
|
|
89
|
+
> **Why SARIF over `--output-format github`?**
|
|
90
|
+
>
|
|
91
|
+
> | Feature | `github` | `sarif` |
|
|
92
|
+
> |---------|----------|---------|
|
|
93
|
+
> | **PR Feedback** | Inline annotations (grouped) | Inline annotations (per-key) |
|
|
94
|
+
> | **Job Summary** | ✅ Markdown table | ❌ (requires separate parsing) |
|
|
95
|
+
> | **Persistence** | Ephemeral (until re-run) | Persistent (Security tab) |
|
|
96
|
+
> | **Tracking** | Manual | Automated "introduced/resolved" |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## GitLab CI
|
|
101
|
+
|
|
102
|
+
Use the official [`ghcr.io/astral-sh/uv`](https://docs.astral.sh/uv/guides/integration/gitlab/) image — uv is already on the `PATH`, no install step needed.
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
variables:
|
|
106
|
+
UV_VERSION: "0.10"
|
|
107
|
+
PYTHON_VERSION: "3.12"
|
|
108
|
+
BASE_LAYER: alpine
|
|
109
|
+
UV_LINK_MODE: copy # required: GitLab mounts build dir separately
|
|
110
|
+
|
|
111
|
+
ruff-sync-check:
|
|
112
|
+
stage: lint
|
|
113
|
+
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
|
|
114
|
+
script:
|
|
115
|
+
- uvx ruff-sync check --semantic --output-format gitlab > gl-code-quality-report.json
|
|
116
|
+
artifacts:
|
|
117
|
+
when: always
|
|
118
|
+
reports:
|
|
119
|
+
codequality: gl-code-quality-report.json
|
|
120
|
+
paths:
|
|
121
|
+
- gl-code-quality-report.json
|
|
122
|
+
expire_in: 1 week
|
|
123
|
+
rules:
|
|
124
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
125
|
+
- if: '$CI_COMMIT_BRANCH == "main"'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### GitLab SAST Report / SARIF (Ultimate tier)
|
|
129
|
+
|
|
130
|
+
Use `--output-format sarif` to feed the GitLab [Security & Compliance dashboard](https://docs.gitlab.com/user/application_security/) via the `sast` artifact report type:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
variables:
|
|
134
|
+
UV_VERSION: "0.10"
|
|
135
|
+
PYTHON_VERSION: "3.12"
|
|
136
|
+
BASE_LAYER: alpine
|
|
137
|
+
UV_LINK_MODE: copy # required: GitLab mounts build dir separately
|
|
138
|
+
|
|
139
|
+
ruff-sync-sarif:
|
|
140
|
+
stage: lint
|
|
141
|
+
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
|
|
142
|
+
script:
|
|
143
|
+
- uvx ruff-sync check --output-format sarif > ruff-sync.sarif
|
|
144
|
+
artifacts:
|
|
145
|
+
when: always # Upload even when ruff-sync exits 1 (drift detected)
|
|
146
|
+
reports:
|
|
147
|
+
sast: ruff-sync.sarif
|
|
148
|
+
paths:
|
|
149
|
+
- ruff-sync.sarif
|
|
150
|
+
expire_in: 1 week
|
|
151
|
+
rules:
|
|
152
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
> **Why SARIF over `--output-format gitlab` (codequality)?**
|
|
156
|
+
>
|
|
157
|
+
> | Concern | `codequality` | `sarif` |
|
|
158
|
+
> |---------|--------------|--------|
|
|
159
|
+
> | GitLab tier | Free (MR widget), Ultimate (inline diff) | Ultimate (Security dashboard) |
|
|
160
|
+
> | GitHub support | ❌ | ✅ via `upload-sarif` |
|
|
161
|
+
> | Per-key findings | ❌ one issue per file | ✅ one finding per drifted TOML key |
|
|
162
|
+
> | Finding persistence | MR widget only | Security tab, tracked across branches |
|
|
163
|
+
> | Portability | GitLab only | GitHub, GitLab, SonarQube, IDE extensions |
|
|
164
|
+
>
|
|
165
|
+
> **Rule of thumb**: use `codequality` for lightweight GitLab-native linting feedback; use `sarif` when you need cross-platform compatibility or want findings tracked in a security/code-scanning dashboard.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Pre-commit Hook
|
|
170
|
+
|
|
171
|
+
Run `ruff-sync check` as a pre-commit hook to catch drift before every commit:
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
# .pre-commit-config.yaml
|
|
175
|
+
- repo: https://github.com/Kilo59/ruff-sync
|
|
176
|
+
rev: v0.1.6 # pin to a release tag
|
|
177
|
+
hooks:
|
|
178
|
+
- id: ruff-sync-check
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The hook runs `ruff-sync check --semantic` automatically. Update `rev` to the latest ruff-sync version.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Makefile
|
|
186
|
+
|
|
187
|
+
```makefile
|
|
188
|
+
.PHONY: sync-check sync
|
|
189
|
+
|
|
190
|
+
sync-check:
|
|
191
|
+
ruff-sync check --semantic
|
|
192
|
+
|
|
193
|
+
sync:
|
|
194
|
+
ruff-sync
|
|
195
|
+
git diff pyproject.toml
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Deciding: `--semantic` vs. Full String Check
|
|
201
|
+
|
|
202
|
+
| Mode | Fails on | Use when |
|
|
203
|
+
|------|---------|---------|
|
|
204
|
+
| `ruff-sync check --semantic` | Value/rule differences only | CI — avoids false positives from local comment edits |
|
|
205
|
+
| `ruff-sync check` | Any string difference (comments, whitespace, values) | Enforcing exact config file consistency |
|
|
206
|
+
|
|
207
|
+
Recommendation: **use `--semantic` in CI** and save the full-string check for auditing purposes.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Dogfooding (Self-Check)
|
|
212
|
+
|
|
213
|
+
If `ruff-sync` is configured in the project's own `pyproject.toml` (the standard case), just run:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
ruff-sync check
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
No URL argument needed — it reads `upstream` from `[tool.ruff-sync]`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Exit Codes
|
|
224
|
+
|
|
225
|
+
| Code | Meaning |
|
|
226
|
+
|------|----------|
|
|
227
|
+
| **0** | In sync — no drift detected |
|
|
228
|
+
| **1** | Config drift (`check`), validation failure (`pull --validate`), or sync error |
|
|
229
|
+
| **2** | CLI usage error — invalid arguments (reserved by argparse) |
|
|
230
|
+
| **3** | Pre-commit hook drift — use `--pre-commit` flag to enable this check |
|
|
231
|
+
| **4** | Upstream unreachable — HTTP error or network failure |
|
|
232
|
+
|
|
233
|
+
All non-zero codes cause a CI step to fail, which is the desired behaviour. To diagnose which failure occurred, check the exit code with `echo $?` after the `ruff-sync check` call.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# ruff-sync Configuration Reference
|
|
2
|
+
|
|
3
|
+
All keys live under `[tool.ruff-sync]` in `pyproject.toml`.
|
|
4
|
+
|
|
5
|
+
## Keys
|
|
6
|
+
|
|
7
|
+
### `upstream` *(required unless passed on CLI)*
|
|
8
|
+
|
|
9
|
+
The URL(s) of your canonical Ruff configuration. Accepts a single string or a list. When a list is given, sources are merged in order — later entries win on conflict.
|
|
10
|
+
|
|
11
|
+
```toml
|
|
12
|
+
# Single source
|
|
13
|
+
upstream = "https://github.com/my-org/standards"
|
|
14
|
+
|
|
15
|
+
# Multiple sources (base + team overlay)
|
|
16
|
+
upstream = [
|
|
17
|
+
"https://github.com/my-org/python-standards",
|
|
18
|
+
"https://github.com/my-org/ml-team-tweaks",
|
|
19
|
+
]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Supported URL formats (with automatic browser link resolution):**
|
|
23
|
+
- GitHub/GitLab repo root: `https://github.com/<org>/<repo>`
|
|
24
|
+
- Subdirectory (tree): `https://github.com/<org>/<repo>/tree/main/configs/ruff`
|
|
25
|
+
- Specific file (blob): `https://github.com/<org>/<repo>/blob/main/pyproject.toml`
|
|
26
|
+
- Raw URL: `https://raw.githubusercontent.com/<org>/<repo>/main/pyproject.toml`
|
|
27
|
+
- SSH (triggers shallow clone): `git@github.com:<org>/<repo>.git`
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### `exclude` *(default: `["lint.per-file-ignores"]`)*
|
|
32
|
+
|
|
33
|
+
List of config keys to protect from being overwritten by upstream. Use dotted paths to reference nested keys.
|
|
34
|
+
|
|
35
|
+
```toml
|
|
36
|
+
exclude = [
|
|
37
|
+
"target-version", # keep per-project Python version
|
|
38
|
+
"lint.per-file-ignores", # keep per-file suppressions
|
|
39
|
+
"lint.ignore", # keep repo-specific rule suppressions
|
|
40
|
+
"lint.isort.known-first-party", # keep first-party package list
|
|
41
|
+
"lint.flake8-tidy-imports.banned-api", # keep banned API list
|
|
42
|
+
"lint.pydocstyle.convention", # keep docstring style choice
|
|
43
|
+
]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Key format:**
|
|
47
|
+
- Top-level keys: `"target-version"`, `"line-length"`
|
|
48
|
+
- Nested keys (dotted): `"lint.select"`, `"lint.per-file-ignores"`, `"format.quote-style"`
|
|
49
|
+
- These are ruff config key names, NOT TOML paths — do NOT include `tool.ruff.` prefix.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### `branch` *(default: `"main"`)*
|
|
54
|
+
|
|
55
|
+
The branch, tag, or commit hash to use when fetching from a Git repo URL.
|
|
56
|
+
|
|
57
|
+
```toml
|
|
58
|
+
branch = "develop"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### `path` *(default: `""`)*
|
|
64
|
+
|
|
65
|
+
Path inside the repository where the config lives, when it's not at the repo root.
|
|
66
|
+
|
|
67
|
+
```toml
|
|
68
|
+
path = "configs/ruff"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Useful when combined with a repo-root `upstream` URL:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
upstream = "git@github.com:my-org/standards.git"
|
|
75
|
+
path = "configs/strict"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### `to` *(default: `"."`)*
|
|
81
|
+
|
|
82
|
+
Local target directory or file path to sync into.
|
|
83
|
+
|
|
84
|
+
```toml
|
|
85
|
+
to = "services/api" # sync into a subdirectory of the monorepo
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### `pre-commit-version-sync` *(default: `false`)*
|
|
91
|
+
|
|
92
|
+
When `true`, `ruff-sync` also updates the `ruff-pre-commit` hook rev in `.pre-commit-config.yaml` to match the Ruff version installed in the project.
|
|
93
|
+
|
|
94
|
+
> [!TIP]
|
|
95
|
+
> This is the preferred way to enable pre-commit hook synchronization as it persists the setting in your project configuration.
|
|
96
|
+
|
|
97
|
+
```toml
|
|
98
|
+
pre-commit-version-sync = true
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Requires a `- repo: https://github.com/astral-sh/ruff-pre-commit` entry in `.pre-commit-config.yaml`.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### `validate` *(default: `false`)*
|
|
106
|
+
|
|
107
|
+
When `true`, `ruff-sync` validates the merged configuration by running it through Ruff before writing to disk. If Ruff rejects the config (e.g., due to an unknown key), the sync is aborted and the local file is left unchanged.
|
|
108
|
+
|
|
109
|
+
```toml
|
|
110
|
+
validate = true
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
> [!NOTE]
|
|
114
|
+
> Validation requires `ruff` to be available on PATH. If `ruff` is not found, validation is skipped with a warning.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### `strict` *(default: `false`)*
|
|
119
|
+
|
|
120
|
+
When `true`, all validation warnings (Python version mismatches, deprecated rules) are treated as hard failures. Implies `validate = true`.
|
|
121
|
+
|
|
122
|
+
```toml
|
|
123
|
+
strict = true
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Full Example
|
|
129
|
+
|
|
130
|
+
```toml
|
|
131
|
+
[tool.ruff-sync]
|
|
132
|
+
upstream = [
|
|
133
|
+
"https://github.com/my-org/python-standards",
|
|
134
|
+
"https://github.com/my-org/backend-team-rules",
|
|
135
|
+
]
|
|
136
|
+
exclude = [
|
|
137
|
+
"target-version",
|
|
138
|
+
"lint.per-file-ignores",
|
|
139
|
+
"lint.ignore",
|
|
140
|
+
"lint.isort.known-first-party",
|
|
141
|
+
]
|
|
142
|
+
branch = "main"
|
|
143
|
+
path = "ruff"
|
|
144
|
+
to = "."
|
|
145
|
+
pre-commit-version-sync = true
|
|
146
|
+
validate = true
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## CLI Overrides
|
|
150
|
+
|
|
151
|
+
All config keys have CLI equivalents. CLI values always win over `pyproject.toml`:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
ruff-sync https://github.com/my-org/standards --exclude lint.ignore --branch develop --output-format github
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Config Discovery for `ruff.toml` Projects
|
|
158
|
+
|
|
159
|
+
If the local target is a directory, ruff-sync looks for config in this order:
|
|
160
|
+
1. `ruff.toml`
|
|
161
|
+
2. `.ruff.toml`
|
|
162
|
+
3. `pyproject.toml`
|
|
163
|
+
|
|
164
|
+
If the upstream is a `ruff.toml`, it syncs the root config object (no `[tool.ruff]` section extraction needed).
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Troubleshooting ruff-sync
|
|
2
|
+
|
|
3
|
+
## Config Not Changing After Sync
|
|
4
|
+
|
|
5
|
+
**Symptom:** `ruff-sync` runs without error, but `git diff` shows no changes.
|
|
6
|
+
|
|
7
|
+
**Likely causes:**
|
|
8
|
+
1. The key is in `exclude`. Check `[tool.ruff-sync] exclude` in your `pyproject.toml`.
|
|
9
|
+
2. The local value already matches upstream — you're already in sync.
|
|
10
|
+
3. The upstream URL resolved to the wrong file. Verify with `ruff-sync check --semantic` and look at the diff output.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## `UpstreamError` / HTTP Failure
|
|
15
|
+
|
|
16
|
+
**Symptom:**
|
|
17
|
+
```
|
|
18
|
+
UpstreamError: Failed to fetch https://...
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Steps:**
|
|
22
|
+
1. Check the URL works in a browser or with `curl -I <url>`.
|
|
23
|
+
2. For GitHub URLs, make sure you're pointing at a _raw_ or _tree/blob_ URL, not an HTML page.
|
|
24
|
+
3. If using a private repo, the raw URL requires authentication. Use an SSH URL instead:
|
|
25
|
+
```bash
|
|
26
|
+
ruff-sync git@github.com:my-org/private-standards.git
|
|
27
|
+
```
|
|
28
|
+
4. Check network/proxy settings if in a corporate environment.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## HTTP 404 on GitHub URL
|
|
33
|
+
|
|
34
|
+
**Symptom:** 404 when fetching a GitHub tree or blob URL.
|
|
35
|
+
|
|
36
|
+
**Cause:** The branch or path doesn't exist, or the repo is private.
|
|
37
|
+
|
|
38
|
+
**Fix:**
|
|
39
|
+
```toml
|
|
40
|
+
[tool.ruff-sync]
|
|
41
|
+
upstream = "https://github.com/my-org/standards"
|
|
42
|
+
branch = "main" # make sure this branch exists
|
|
43
|
+
path = "configs" # make sure this path exists on that branch
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Validate: `curl https://github.com/my-org/standards/tree/main/configs` should return 200.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## `FileNotFoundError` — No Local Config
|
|
51
|
+
|
|
52
|
+
**Symptom:**
|
|
53
|
+
```
|
|
54
|
+
FileNotFoundError: No pyproject.toml or ruff.toml found in .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Fix:** Use `--init` to scaffold a new config file before syncing:
|
|
58
|
+
```bash
|
|
59
|
+
ruff-sync https://github.com/my-org/standards --init
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Pre-commit Version Mismatch (Exit Code 2)
|
|
65
|
+
|
|
66
|
+
**Symptom:** `ruff-sync check` exits with code 2 and a warning like:
|
|
67
|
+
```
|
|
68
|
+
⚠️ Pre-commit ruff hook version is out of sync: .pre-commit-config.yaml uses v0.9.3, project has ruff==0.10.0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**This is not a config drift.** The Ruff configuration is in sync. Only the pre-commit hook tag is stale.
|
|
72
|
+
|
|
73
|
+
**Fix:**
|
|
74
|
+
```bash
|
|
75
|
+
ruff-sync # pulls config AND updates the hook rev (if pre-commit-version-sync = true)
|
|
76
|
+
# or manually: update the 'rev:' line in .pre-commit-config.yaml
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
To suppress this check entirely, omit `--pre-commit` from `ruff-sync check` or set `pre-commit-version-sync = false`.
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Python Version Mismatch Warning
|
|
83
|
+
|
|
84
|
+
**Symptom:** Sync succeeds but logs a warning like:
|
|
85
|
+
```
|
|
86
|
+
⚠️ Version mismatch: upstream [tool.ruff] target-version='py39' targets Python 3.9, but local [project] requires-python='>=3.10' requires Python >= 3.10.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Cause:** The upstream configuration is targeting an older Python version than your project requires. This can lead to Ruff not using newer rules or features available to your project.
|
|
90
|
+
|
|
91
|
+
**Fix:**
|
|
92
|
+
1. **Update Upstream:** The ideal fix is to update the `target-version` in the upstream repository to a newer version (e.g., `py311`).
|
|
93
|
+
2. **Exclude the key:** If you need to stay on a specific version locally, add `target-version` to your `exclude` list:
|
|
94
|
+
```toml
|
|
95
|
+
[tool.ruff-sync]
|
|
96
|
+
exclude = ["target-version"]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
In **`--strict`** mode, this warning is upgraded to a hard failure and will abort the sync.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Merge Produces Unexpected `tomlkit` Structure
|
|
104
|
+
|
|
105
|
+
**Symptom:** Synced `pyproject.toml` has repeated sections or oddly formatted keys.
|
|
106
|
+
|
|
107
|
+
**Cause:** Mixing dotted-key style (`lint.select = [...]`) with explicit table header style (`[tool.ruff.lint]`) in the same file.
|
|
108
|
+
|
|
109
|
+
**Fix:** Pick one style consistently. `ruff-sync` uses `tomlkit` which preserves formatting, but mixing styles can produce unexpected output.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## SSH Clone Fails
|
|
114
|
+
|
|
115
|
+
**Symptom:** Hangs or fails when using `git@github.com:...` URL.
|
|
116
|
+
|
|
117
|
+
**Cause:** SSH key not configured or not added to the agent.
|
|
118
|
+
|
|
119
|
+
**Fix:** Verify SSH auth first:
|
|
120
|
+
```bash
|
|
121
|
+
ssh -T git@github.com
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Alternatively, switch to HTTPS:
|
|
125
|
+
```toml
|
|
126
|
+
upstream = "https://github.com/my-org/standards"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## `ruff-sync` Not Found After Install
|
|
132
|
+
|
|
133
|
+
**Symptom:** `ruff-sync: command not found`
|
|
134
|
+
|
|
135
|
+
**Fix:**
|
|
136
|
+
```bash
|
|
137
|
+
# If installed with uv tool:
|
|
138
|
+
uv tool list # confirm it appears
|
|
139
|
+
# Ensure uv tools bin dir is on PATH:
|
|
140
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
|
|
141
|
+
|
|
142
|
+
# If using pipx:
|
|
143
|
+
pipx ensurepath
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Getting More Debug Info
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Show what config would be merged without applying it
|
|
152
|
+
ruff-sync check https://github.com/my-org/standards
|
|
153
|
+
|
|
154
|
+
# Show a diff of what changed
|
|
155
|
+
ruff-sync check --semantic # value-only diff
|
|
156
|
+
ruff-sync check # full string diff (catches comment/whitespace changes too)
|
|
157
|
+
```
|
ruff_sync/config_io.py
CHANGED
ruff_sync/constants.py
CHANGED
|
@@ -47,7 +47,7 @@ MISSING: Final[MissingType] = MissingType.SENTINEL
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
@enum.unique
|
|
50
|
-
class OutputFormat(
|
|
50
|
+
class OutputFormat(enum.StrEnum):
|
|
51
51
|
"""Output formats for the CLI."""
|
|
52
52
|
|
|
53
53
|
TEXT = "text"
|
|
@@ -63,7 +63,7 @@ class OutputFormat(str, enum.Enum):
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
@enum.unique
|
|
66
|
-
class ConfKey(
|
|
66
|
+
class ConfKey(enum.StrEnum):
|
|
67
67
|
"""Centralized configuration keys for [tool.ruff-sync].
|
|
68
68
|
|
|
69
69
|
These are the canonical names used in the pyproject.toml configuration file.
|
|
@@ -129,7 +129,7 @@ class ConfKey(str, enum.Enum):
|
|
|
129
129
|
|
|
130
130
|
def resolve_defaults(
|
|
131
131
|
branch: str | MissingType,
|
|
132
|
-
path: str |
|
|
132
|
+
path: str | MissingType | None,
|
|
133
133
|
exclude: Iterable[str] | MissingType,
|
|
134
134
|
) -> tuple[str, str | None, Iterable[str]]:
|
|
135
135
|
"""Resolve MISSING sentinel values to their effective defaults.
|
ruff_sync/core.py
CHANGED
|
@@ -697,51 +697,24 @@ async def fetch_upstreams_concurrently(
|
|
|
697
697
|
UpstreamError: If one or more upstreams fail to fetch.
|
|
698
698
|
"""
|
|
699
699
|
upstream_list = list(upstreams)
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
tg.create_task(fetch_upstream_config(url, client, branch, path))
|
|
707
|
-
for url in upstream_list
|
|
708
|
-
]
|
|
709
|
-
return [t.result() for t in tasks]
|
|
710
|
-
except BaseException as eg:
|
|
711
|
-
if isinstance(eg, (asyncio.CancelledError, KeyboardInterrupt)):
|
|
712
|
-
raise
|
|
713
|
-
# TODO: Use `except*` once Python 3.11+ is the minimum supported version.
|
|
714
|
-
# On Python 3.11+, TaskGroup raises an ExceptionGroup.
|
|
715
|
-
# Catching it as Exception is safe and compatible with Python 3.10 syntax.
|
|
716
|
-
errors = [
|
|
717
|
-
(upstream_list[i], t.exception())
|
|
718
|
-
for i, t in enumerate(tasks)
|
|
719
|
-
if t.done() and t.exception() is not None
|
|
700
|
+
tasks: list[asyncio.Task[FetchResult]] = []
|
|
701
|
+
try:
|
|
702
|
+
async with asyncio.TaskGroup() as tg:
|
|
703
|
+
tasks = [
|
|
704
|
+
tg.create_task(fetch_upstream_config(url, client, branch, path))
|
|
705
|
+
for url in upstream_list
|
|
720
706
|
]
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
for i, res in enumerate(results):
|
|
733
|
-
if isinstance(res, BaseException):
|
|
734
|
-
errors_list.append((upstream_list[i], res))
|
|
735
|
-
elif isinstance(res, FetchResult):
|
|
736
|
-
fetch_results.append(res)
|
|
737
|
-
else:
|
|
738
|
-
msg = f"Unexpected result type from fetch: {type(res)}"
|
|
739
|
-
raise TypeError(msg)
|
|
740
|
-
|
|
741
|
-
if errors_list:
|
|
742
|
-
raise UpstreamError(errors_list)
|
|
743
|
-
|
|
744
|
-
return fetch_results
|
|
707
|
+
return [t.result() for t in tasks]
|
|
708
|
+
except* Exception as eg:
|
|
709
|
+
errors: list[tuple[URL, BaseException]] = []
|
|
710
|
+
for i, t in enumerate(tasks):
|
|
711
|
+
if t.done() and not t.cancelled():
|
|
712
|
+
exc = t.exception()
|
|
713
|
+
if exc is not None:
|
|
714
|
+
errors.append((upstream_list[i], exc))
|
|
715
|
+
if errors:
|
|
716
|
+
raise UpstreamError(errors) from eg
|
|
717
|
+
raise
|
|
745
718
|
|
|
746
719
|
|
|
747
720
|
async def _merge_multiple_upstreams(
|
ruff_sync/types_.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: ruff-sync
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9.dev0
|
|
4
4
|
Summary: Synchronize Ruff linter configuration across projects
|
|
5
5
|
Project-URL: Homepage, https://github.com/Kilo59/ruff-sync
|
|
6
6
|
Project-URL: Documentation, https://kilo59.github.io/ruff-sync/
|
|
@@ -17,14 +17,13 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: Programming Language :: Python
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.14
|
|
25
24
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
26
|
-
Requires-Python: >=3.
|
|
27
|
-
Requires-Dist: httpx2>=2.
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: httpx2>=2.9.1
|
|
28
27
|
Requires-Dist: tomlkit<2.0.0,>=0.12.3
|
|
29
28
|
Requires-Dist: typing-extensions>=4.5.0
|
|
30
29
|
Provides-Extra: tui
|
|
@@ -38,6 +37,7 @@ Description-Content-Type: text/markdown
|
|
|
38
37
|
<br>
|
|
39
38
|
<a href="https://kilo59.github.io/ruff-sync/"><img src="https://img.shields.io/badge/docs-MkDocs-blue.svg" alt="Documentation"></a>
|
|
40
39
|
<a href="https://pypi.org/project/ruff-sync/"><img src="https://img.shields.io/pypi/v/ruff-sync" alt="PyPI version"></a>
|
|
40
|
+
<a href="https://pepy.tech/projects/ruff-sync"><img src="https://static.pepy.tech/personalized-badge/ruff-sync?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads" alt="PyPI Downloads"></a>
|
|
41
41
|
<a href="https://codecov.io/gh/Kilo59/ruff-sync"><img src="https://codecov.io/gh/Kilo59/ruff-sync/graph/badge.svg?token=kMZw0XtoFW" alt="codecov"></a>
|
|
42
42
|
<a href="https://results.pre-commit.ci/latest/github/Kilo59/ruff-sync/main"><img src="https://results.pre-commit.ci/badge/github/Kilo59/ruff-sync/main.svg" alt="pre-commit.ci status"></a>
|
|
43
43
|
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
|
|
@@ -353,7 +353,15 @@ $ ruff-sync check --semantic
|
|
|
353
353
|
|
|
354
354
|
## Agent Skill
|
|
355
355
|
|
|
356
|
-
`ruff-sync`
|
|
356
|
+
`ruff-sync` supports the [Library Skills](https://library-skills.io/) specification. AI coding agents that support the [Agent Skills format](https://agentskills.io/what-are-skills) (GitHub Copilot, Claude Code, Cursor, etc.) can automatically load this skill to guide you through setup, configuration, CI integration, and troubleshooting.
|
|
357
|
+
|
|
358
|
+
You can install it automatically using `uvx` (or `npx` in a Node.js project):
|
|
359
|
+
|
|
360
|
+
```console
|
|
361
|
+
$ uvx library-skills
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
This will link the `ruff-sync` skill (bundled inside the installed package) into your project's `.agents/skills/ruff-sync` folder.
|
|
357
365
|
|
|
358
366
|
See the **[Agent Skill guide](https://kilo59.github.io/ruff-sync/stable/agent-skill/)** for details.
|
|
359
367
|
|
|
@@ -477,6 +485,24 @@ flowchart TD
|
|
|
477
485
|
style SemanticNode fill:#4b5563,color:#fff,stroke:#374151
|
|
478
486
|
```
|
|
479
487
|
|
|
488
|
+
## Development
|
|
489
|
+
|
|
490
|
+
For local development and testing:
|
|
491
|
+
|
|
492
|
+
```console
|
|
493
|
+
# Run test suite
|
|
494
|
+
uv run pytest -vv
|
|
495
|
+
|
|
496
|
+
# Run linter and formatter
|
|
497
|
+
uv run ruff check . --fix
|
|
498
|
+
uv run ruff format .
|
|
499
|
+
|
|
500
|
+
# Run type checker
|
|
501
|
+
uv run mypy .
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
> **Note on Test Environment**: Test mocking uses `respx` with `httpx2`. To ensure `respx` intercepts `httpx2` network calls during `pytest` runs before plugin entrypoints load, a guarded `src/sitecustomize.py` script is used in development. This script is strictly excluded from production wheel builds (`packages = ["src/ruff_sync"]`) and is never shipped to end users.
|
|
505
|
+
|
|
480
506
|
## Dogfooding
|
|
481
507
|
|
|
482
508
|
To see `ruff-sync` in action, this project automatically "dogfoods" its own configuration. Every pull request runs a `ruff-sync check` against the repository's own `pyproject.toml` using the `--output-format github` flag, providing real-time feedback and inline annotations whenever configuration drift is detected.
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
ruff_sync/__init__.py,sha256=M_1YK0BcPzlLlxlBOEPEBTCkAVm37r-yoQzGGZnfQ7Y,1206
|
|
2
2
|
ruff_sync/__main__.py,sha256=oMIbv9ywToleBKJrZ-GMo_KhM4lHg02nJe7t6neWzJE,179
|
|
3
3
|
ruff_sync/cli.py,sha256=IICm0f60_-fKRjFH3gMLUn3sK9yxB9auNglI7E6P-WU,25346
|
|
4
|
-
ruff_sync/config_io.py,sha256=
|
|
5
|
-
ruff_sync/constants.py,sha256=
|
|
6
|
-
ruff_sync/core.py,sha256=
|
|
4
|
+
ruff_sync/config_io.py,sha256=K8wVXRoJ6KYbS5TYs9ND2hWR7DggMl0UwX9QlZAdEnY,4347
|
|
5
|
+
ruff_sync/constants.py,sha256=FEJQjAABC2kJStmtjBf6FVpoxEmmgCCvof53DldwjXI,5818
|
|
6
|
+
ruff_sync/core.py,sha256=N353z7Die51b_CHhO5p5L05xWhFKWsogVcDwESrngHQ,43119
|
|
7
7
|
ruff_sync/dependencies.py,sha256=RpJXAsrB-Y-ol_ZH4U92XIuyq8_bWaYwp9sn9KpxraA,2096
|
|
8
8
|
ruff_sync/formatters.py,sha256=A4p2XAyc-xnteUmdtRXbp63fIjT9MdyKF6qKvcyNMho,29908
|
|
9
9
|
ruff_sync/pre_commit.py,sha256=0ltXUkmocbrSwwf6cPbNc_K5K9n-gvou98xJy9YUhr0,5303
|
|
10
10
|
ruff_sync/system.py,sha256=vF9Jjb-Z9MuLwo3wiOqcCDxniNtjvo3O-aFt4NJf-2Y,5715
|
|
11
|
-
ruff_sync/types_.py,sha256=
|
|
11
|
+
ruff_sync/types_.py,sha256=9gSZpsDXl40FfXCd95aBToZTjOm1vnBZmqaDKXL4sJA,794
|
|
12
12
|
ruff_sync/validation.py,sha256=OatdkWUKEyxw7CYTOFNpH6IRsbVfU5EHjt6Lu6nOO9U,11585
|
|
13
|
+
ruff_sync/.agents/skills/ruff-sync/SKILL.md,sha256=06D6Sw-WuWQNezRtce-Y724wJcfHmBUb66eA7sNYmWQ,7419
|
|
14
|
+
ruff_sync/.agents/skills/ruff-sync/references/ci-integration.md,sha256=s3CmTFM8uEJU00_Bt99wLGNt3GIadhidwxMW70XxsaY,7325
|
|
15
|
+
ruff_sync/.agents/skills/ruff-sync/references/configuration.md,sha256=xoF6DDbKz_eAipgm-iuwbo5QxM-_49rju8pxjbbIfBQ,4519
|
|
16
|
+
ruff_sync/.agents/skills/ruff-sync/references/troubleshooting.md,sha256=vQxMLg0DA3Hmd7jJAVcvTZFIis9Gg4mZDItRRMoHnw4,4537
|
|
13
17
|
ruff_sync/tui/__init__.py,sha256=DcwvE70ETjBcC6pQeHpjrYtkJp8z4StGM8L3EuaVcIo,635
|
|
14
18
|
ruff_sync/tui/app.py,sha256=soq0fkFsLeB7ZxJWNZM_H6bNj7H8p6nEYyirVcskN54,9317
|
|
15
19
|
ruff_sync/tui/constants.py,sha256=fEPyp2k817QLluyiVHqDObzDONlHz_L3Ec0SYAUzzMs,267
|
|
@@ -17,8 +21,8 @@ ruff_sync/tui/screens.py,sha256=NVIlqNIr64JrFFWeec7usqJCb1x41NEmSfRZGeEcwuo,5557
|
|
|
17
21
|
ruff_sync/tui/themes.py,sha256=-x9u_8iZPa1XZuo8O_tWVHyCImN9Qs9F7xPhl0VLwZw,654
|
|
18
22
|
ruff_sync/tui/types_.py,sha256=poNUBJotgUso2IkUi3nXUuxz6wv1goFWZimj4VttdJE,8271
|
|
19
23
|
ruff_sync/tui/widgets.py,sha256=2m3gyH4xDBpM0CK-5eQmmUCZXYKJujrbyVkFTxqmHcg,9760
|
|
20
|
-
ruff_sync-0.1.
|
|
21
|
-
ruff_sync-0.1.
|
|
22
|
-
ruff_sync-0.1.
|
|
23
|
-
ruff_sync-0.1.
|
|
24
|
-
ruff_sync-0.1.
|
|
24
|
+
ruff_sync-0.1.9.dev0.dist-info/METADATA,sha256=KL05bz9etJdfbrqobWgiibwOWrQR4j235ci1xDFAol0,24046
|
|
25
|
+
ruff_sync-0.1.9.dev0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
26
|
+
ruff_sync-0.1.9.dev0.dist-info/entry_points.txt,sha256=QQ0pjxMIN0vp5EmNFkyb-1Yk8JOIkid8zAPN3IpAExA,78
|
|
27
|
+
ruff_sync-0.1.9.dev0.dist-info/licenses/LICENSE.md,sha256=RcCP8t8xyCx2cvMZSLjBrPqJfctciWC6q85ceQAcEfA,1080
|
|
28
|
+
ruff_sync-0.1.9.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|