ruff-sync 0.0.3.dev1__tar.gz → 0.0.4.dev1__tar.gz
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-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.agents/TESTING.md +16 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.github/workflows/ci.yaml +26 -1
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/PKG-INFO +47 -43
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/README.md +46 -42
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/pyproject.toml +1 -1
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/ruff_sync.py +268 -39
- ruff_sync-0.0.4.dev1/scripts/gitclone_dogfood.sh +46 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_basic.py +2 -2
- ruff_sync-0.0.4.dev1/tests/test_config_validation.py +91 -0
- ruff_sync-0.0.4.dev1/tests/test_git_fetch.py +155 -0
- ruff_sync-0.0.4.dev1/tests/test_scaffold.py +257 -0
- ruff_sync-0.0.4.dev1/tests/test_url_parsing.py +31 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/uv.lock +1 -1
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.agents/workflows/add-test-case.md +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.git-blame-ignore-revs +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.github/dependabot.yml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.github/workflows/complexity.yaml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.gitignore +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/.pre-commit-config.yaml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/AGENTS.md +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/LICENSE.md +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/codecov.yml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/ruff_sync_banner.png +0 -0
- /ruff_sync-0.0.3.dev1/scripts/dogfood_check.sh → /ruff_sync-0.0.4.dev1/scripts/check_dogfood.sh +0 -0
- /ruff_sync-0.0.3.dev1/scripts/dogfood.sh → /ruff_sync-0.0.4.dev1/scripts/pull_dogfood.sh +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tasks.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/__init__.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_changes_final.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_changes_initial.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_changes_upstream.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_dotted_keys_final.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_dotted_keys_initial.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_ruff_cfg_final.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/readme_excludes_final.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/readme_excludes_initial.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/readme_excludes_upstream.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/standard_final.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/standard_initial.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/lifecycle_tomls/standard_upstream.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/ruff.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_check.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_corner_cases.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_e2e.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_project.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_toml_operations.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_url_handling.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/test_whitespace.py +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/w_ruff_sync_cfg/pyproject.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/wo_ruff_cfg/pyproject.toml +0 -0
- {ruff_sync-0.0.3.dev1 → ruff_sync-0.0.4.dev1}/tests/wo_ruff_sync_cfg/pyproject.toml +0 -0
|
@@ -48,6 +48,22 @@ def test_merge_scenarios(source, upstream, expected_keys):
|
|
|
48
48
|
# ... test logic ...
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
### 3.3 No Autouse Fixtures
|
|
52
|
+
`autouse=True` fixtures are **never allowed**. They hide setup logic and can cause non-obvious side effects or dependencies between tests. All fixtures used by a test must be explicitly requested in the test function's arguments.
|
|
53
|
+
|
|
54
|
+
### 3.4 Main Entry Point
|
|
55
|
+
Every test file **must** end with a main entry point block. This ensures each file is independently executable as a script (`python tests/test_foo.py`).
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
pytest.main([__file__, "-vv"])
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Why this matters:**
|
|
63
|
+
1. **Direct Execution**: Developers can run a single test file using standard Python without needing to remember complex `pytest` filter flags.
|
|
64
|
+
2. **IDE Workflow Integration**: Many IDEs (like VS Code or PyCharm) allow you to run the "Current File" with a single click or keyboard shortcut. Having a main block ensures this works out of the box with the correct verbosity and scope.
|
|
65
|
+
3. **Cleaner Diffs**: By terminating the file with this standard block, it prevents "no newline at end of file" warnings and ensures that new tests added above it produce clean, isolated diff segments. It also ensures that when debugging with `--icdiff` or similar tools, the output is scoped correctly to the specific file.
|
|
66
|
+
|
|
51
67
|
## 4. Handling TOML and `tomlkit`
|
|
52
68
|
|
|
53
69
|
`tomlkit` is central to this project but its dynamic type system can be tricky for mypy.
|
|
@@ -64,10 +64,35 @@ jobs:
|
|
|
64
64
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
65
65
|
slug: Kilo59/ruff-sync
|
|
66
66
|
|
|
67
|
+
pre-publish:
|
|
68
|
+
name: Test package installation
|
|
69
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
70
|
+
needs: [static-analysis, tests]
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
steps:
|
|
73
|
+
- name: Checkout
|
|
74
|
+
uses: actions/checkout@v4
|
|
75
|
+
|
|
76
|
+
- name: Install uv
|
|
77
|
+
uses: astral-sh/setup-uv@v5
|
|
78
|
+
|
|
79
|
+
- name: Set up Python
|
|
80
|
+
run: uv python install 3.10
|
|
81
|
+
|
|
82
|
+
- name: Build package
|
|
83
|
+
run: uv build
|
|
84
|
+
|
|
85
|
+
- name: Install and test packaged program
|
|
86
|
+
run: |
|
|
87
|
+
uv tool install $(ls dist/*.whl)
|
|
88
|
+
ruff-sync --version
|
|
89
|
+
ruff-sync https://github.com/Kilo59/ruff-sync
|
|
90
|
+
ruff-sync check https://github.com/Kilo59/ruff-sync
|
|
91
|
+
|
|
67
92
|
publish:
|
|
68
93
|
name: Build and publish to PyPI
|
|
69
94
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
70
|
-
needs: [
|
|
95
|
+
needs: [pre-publish]
|
|
71
96
|
runs-on: ubuntu-latest
|
|
72
97
|
permissions:
|
|
73
98
|
# This permission is required for trusted publishing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ruff-sync
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4.dev1
|
|
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://github.com/Kilo59/ruff-sync#readme
|
|
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
|
|
43
43
|
**Keep your Ruff config consistent across multiple projects.**
|
|
44
44
|
|
|
45
|
-
`ruff-sync` is a CLI tool that pulls a canonical [Ruff](https://docs.astral.sh/ruff/) configuration from an upstream `pyproject.toml` (hosted anywhere — GitHub, GitLab, or any raw URL) and merges it into your local project, preserving your comments, formatting, and project-specific overrides.
|
|
45
|
+
`ruff-sync` is a CLI tool that pulls a canonical [Ruff](https://docs.astral.sh/ruff/) configuration from an upstream `pyproject.toml` or `ruff.toml` (hosted anywhere — GitHub, GitLab, or any raw URL) and merges it into your local project, preserving your comments, formatting, and project-specific overrides.
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
@@ -141,21 +141,20 @@ uv tool install git+https://github.com/Kilo59/ruff-sync
|
|
|
141
141
|
### Usage
|
|
142
142
|
|
|
143
143
|
```console
|
|
144
|
-
# Sync from a GitHub repository (defaults to main/pyproject.toml)
|
|
144
|
+
# Sync from a GitHub/GitLab repository (defaults to main/pyproject.toml)
|
|
145
145
|
ruff-sync https://github.com/my-org/standards
|
|
146
146
|
|
|
147
147
|
# Or a direct blob/file URL (auto-converts to raw)
|
|
148
148
|
ruff-sync https://github.com/my-org/standards/blob/main/pyproject.toml
|
|
149
149
|
|
|
150
|
-
#
|
|
151
|
-
|
|
150
|
+
# Clone from any git repository (using SSH or HTTP, defaults to --depth 1)
|
|
151
|
+
# You can use the --branch flag to specify a branch (default: main)
|
|
152
|
+
ruff-sync git@github.com:my-org/standards.git
|
|
153
|
+
ruff-sync ssh://git@gitlab.com/my-org/standards.git
|
|
152
154
|
|
|
153
|
-
#
|
|
155
|
+
# Or if configured in pyproject.toml (see Configuration), simply run:
|
|
154
156
|
ruff-sync
|
|
155
157
|
|
|
156
|
-
# Sync into a specific project directory
|
|
157
|
-
ruff-sync --source ./my-project
|
|
158
|
-
|
|
159
158
|
# Exclude specific sections from being overwritten using dotted paths
|
|
160
159
|
ruff-sync --exclude lint.per-file-ignores lint.ignore
|
|
161
160
|
|
|
@@ -170,12 +169,13 @@ Run `ruff-sync --help` for full details on all available options.
|
|
|
170
169
|
|
|
171
170
|
## Key Features
|
|
172
171
|
|
|
173
|
-
- **Format-preserving merges** — Uses [tomlkit](https://github.com/sdispater/tomlkit) under the hood, so your comments, whitespace, and TOML structure are preserved. No reformatting surprises.
|
|
174
|
-
- **GitHub & GitLab URL support** — Automatically converts GitHub/GitLab repository URLs or blob URLs to raw content URLs.
|
|
175
|
-
- **
|
|
176
|
-
- **
|
|
177
|
-
- **
|
|
178
|
-
- **
|
|
172
|
+
- 🏗️ **Format-preserving merges** — Uses [tomlkit](https://github.com/sdispater/tomlkit) under the hood, so your comments, whitespace, and TOML structure are preserved. No reformatting surprises.
|
|
173
|
+
- 🌐 **GitHub & GitLab URL support** — Automatically converts GitHub/GitLab repository URLs or blob URLs to raw content URLs.
|
|
174
|
+
- 📥 **Git clone support** — If the URL starts with `git@` or uses the `ssh://`, `git://`, or `git+ssh://` schemes, `ruff-sync` will perform an efficient shallow clone (using `--filter=blob:none` and `--no-checkout`) to safely extract the configuration with minimal network traffic.
|
|
175
|
+
- 🛡️ **Selective exclusions** — Keep project-specific overrides (like `per-file-ignores` or `target-version`) from being clobbered by the upstream config.
|
|
176
|
+
- 🌍 **Works with any host** — GitHub, GitLab, Bitbucket, private SSH servers, or any raw URL that serves a `pyproject.toml` or `ruff.toml`.
|
|
177
|
+
- 🤖 **CI-ready `check` command** — Verify that your local config is in sync without modifying anything. Exits 1 if out of sync, making it perfect for pre-merge gates. ([See detailed logic](#detailed-check-logic))
|
|
178
|
+
- 🧠 **Semantic mode** — Use `--semantic` to ignore cosmetic differences (comments, whitespace) and only fail on real value changes.
|
|
179
179
|
|
|
180
180
|
## Configuration
|
|
181
181
|
|
|
@@ -202,16 +202,25 @@ This sets the default upstream and exclusions so you don't need to pass them on
|
|
|
202
202
|
|
|
203
203
|
### Advanced Configuration
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
Here are all the possible values that can be provided in `[tool.ruff-sync]` along with their explanations and defaults:
|
|
206
206
|
|
|
207
207
|
```toml
|
|
208
208
|
[tool.ruff-sync]
|
|
209
|
+
# The source of truth URL for your Ruff configuration. (Required, unless passed via CLI)
|
|
209
210
|
upstream = "https://github.com/my-org/standards"
|
|
210
211
|
|
|
211
|
-
#
|
|
212
|
+
# A list of config keys to exclude from being synced. (Default: ["lint.per-file-ignores"])
|
|
213
|
+
# Use simple names for top-level keys, and dotted paths for nested keys.
|
|
214
|
+
exclude = [
|
|
215
|
+
"target-version",
|
|
216
|
+
"lint.per-file-ignores",
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
# The branch, tag, or commit hash to use when resolving a Git repository URL. (Default: "main")
|
|
212
220
|
branch = "develop"
|
|
213
221
|
|
|
214
|
-
#
|
|
222
|
+
# A directory prefix to use when looking for a configuration file in a repository. (Default: "")
|
|
223
|
+
# Useful if the upstream pyproject.toml is not at the repository root.
|
|
215
224
|
path = "config/ruff"
|
|
216
225
|
```
|
|
217
226
|
|
|
@@ -259,6 +268,18 @@ git diff pyproject.toml # review the changes
|
|
|
259
268
|
git commit -am "sync ruff config from upstream"
|
|
260
269
|
```
|
|
261
270
|
|
|
271
|
+
## Bootstrapping a New Project
|
|
272
|
+
|
|
273
|
+
By default, `ruff-sync` requires an existing configuration file (`pyproject.toml` or `ruff.toml`) to merge into. If you are starting a fresh project and want to initialize it with your organization's Ruff settings, you can use the `--init` flag to scaffold a new file automatically.
|
|
274
|
+
|
|
275
|
+
```console
|
|
276
|
+
# Create a new pyproject.toml (or ruff.toml) pre-configured with upstream settings
|
|
277
|
+
ruff-sync pull https://github.com/my-org/standards --init
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
`ruff-sync` seamlessly supports both `pyproject.toml` and standalone `ruff.toml` (or `.ruff.toml`) files. If your upstream source or your local target is a `ruff.toml`, it will automatically adapt and sync the root configuration rather than looking for a `[tool.ruff]` section.
|
|
281
|
+
|
|
282
|
+
|
|
262
283
|
## Detailed Check Logic
|
|
263
284
|
|
|
264
285
|
When you run `ruff-sync check`, it follows this process to determine if your project has drifted from the upstream source:
|
|
@@ -297,40 +318,23 @@ flowchart TD
|
|
|
297
318
|
style SemanticNode fill:#f4f4f4,color:#363636,stroke:#dbdbdb
|
|
298
319
|
```
|
|
299
320
|
|
|
300
|
-
## Contributing
|
|
301
|
-
|
|
302
|
-
This project uses:
|
|
303
|
-
|
|
304
|
-
- [uv](https://docs.astral.sh/uv/) for dependency management
|
|
305
|
-
- [Ruff](https://docs.astral.sh/ruff/) for linting and formatting
|
|
306
|
-
- [mypy](https://mypy-lang.org/) for type checking (strict mode)
|
|
307
|
-
- [pytest](https://docs.pytest.org/) for testing
|
|
308
|
-
|
|
309
|
-
```console
|
|
310
|
-
# Setup
|
|
311
|
-
uv sync --group dev
|
|
312
|
-
|
|
313
|
-
# Run checks
|
|
314
|
-
uv run ruff check . --fix # lint
|
|
315
|
-
uv run ruff format . # format
|
|
316
|
-
uv run mypy . # type check
|
|
317
|
-
uv run pytest -vv # test
|
|
318
|
-
```
|
|
319
|
-
|
|
320
321
|
## Dogfooding
|
|
321
322
|
|
|
322
|
-
To see `ruff-sync` in action, you can "dogfood" it on this project's own config.
|
|
323
|
+
To see `ruff-sync` in action, you can ["dogfood" it on this project's own config](./scripts).
|
|
323
324
|
|
|
324
|
-
**Check if this project is in sync with its upstream:**
|
|
325
|
+
[**Check if this project is in sync with its upstream:**](./scripts/check_dogfood.sh)
|
|
325
326
|
|
|
326
327
|
```console
|
|
327
|
-
./scripts/
|
|
328
|
+
./scripts/check_dogfood.sh
|
|
328
329
|
```
|
|
329
330
|
|
|
330
|
-
**Or sync from a large upstream like Pydantic's config:**
|
|
331
|
+
[**Or sync from a large upstream like Pydantic's config:**](./scripts/pull_dogfood.sh)
|
|
331
332
|
|
|
332
333
|
```console
|
|
333
|
-
|
|
334
|
+
# Using a HTTP URL
|
|
335
|
+
./scripts/pull_dogfood.sh
|
|
336
|
+
# Using a Git URL
|
|
337
|
+
./scripts/gitclone_dogfood.sh
|
|
334
338
|
```
|
|
335
339
|
|
|
336
340
|
This will download Pydantic's Ruff configuration and merge it into the local `pyproject.toml`. You can then use `git diff` to see how it merged the keys while preserving the existing structure and comments.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
**Keep your Ruff config consistent across multiple projects.**
|
|
14
14
|
|
|
15
|
-
`ruff-sync` is a CLI tool that pulls a canonical [Ruff](https://docs.astral.sh/ruff/) configuration from an upstream `pyproject.toml` (hosted anywhere — GitHub, GitLab, or any raw URL) and merges it into your local project, preserving your comments, formatting, and project-specific overrides.
|
|
15
|
+
`ruff-sync` is a CLI tool that pulls a canonical [Ruff](https://docs.astral.sh/ruff/) configuration from an upstream `pyproject.toml` or `ruff.toml` (hosted anywhere — GitHub, GitLab, or any raw URL) and merges it into your local project, preserving your comments, formatting, and project-specific overrides.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -111,21 +111,20 @@ uv tool install git+https://github.com/Kilo59/ruff-sync
|
|
|
111
111
|
### Usage
|
|
112
112
|
|
|
113
113
|
```console
|
|
114
|
-
# Sync from a GitHub repository (defaults to main/pyproject.toml)
|
|
114
|
+
# Sync from a GitHub/GitLab repository (defaults to main/pyproject.toml)
|
|
115
115
|
ruff-sync https://github.com/my-org/standards
|
|
116
116
|
|
|
117
117
|
# Or a direct blob/file URL (auto-converts to raw)
|
|
118
118
|
ruff-sync https://github.com/my-org/standards/blob/main/pyproject.toml
|
|
119
119
|
|
|
120
|
-
#
|
|
121
|
-
|
|
120
|
+
# Clone from any git repository (using SSH or HTTP, defaults to --depth 1)
|
|
121
|
+
# You can use the --branch flag to specify a branch (default: main)
|
|
122
|
+
ruff-sync git@github.com:my-org/standards.git
|
|
123
|
+
ruff-sync ssh://git@gitlab.com/my-org/standards.git
|
|
122
124
|
|
|
123
|
-
#
|
|
125
|
+
# Or if configured in pyproject.toml (see Configuration), simply run:
|
|
124
126
|
ruff-sync
|
|
125
127
|
|
|
126
|
-
# Sync into a specific project directory
|
|
127
|
-
ruff-sync --source ./my-project
|
|
128
|
-
|
|
129
128
|
# Exclude specific sections from being overwritten using dotted paths
|
|
130
129
|
ruff-sync --exclude lint.per-file-ignores lint.ignore
|
|
131
130
|
|
|
@@ -140,12 +139,13 @@ Run `ruff-sync --help` for full details on all available options.
|
|
|
140
139
|
|
|
141
140
|
## Key Features
|
|
142
141
|
|
|
143
|
-
- **Format-preserving merges** — Uses [tomlkit](https://github.com/sdispater/tomlkit) under the hood, so your comments, whitespace, and TOML structure are preserved. No reformatting surprises.
|
|
144
|
-
- **GitHub & GitLab URL support** — Automatically converts GitHub/GitLab repository URLs or blob URLs to raw content URLs.
|
|
145
|
-
- **
|
|
146
|
-
- **
|
|
147
|
-
- **
|
|
148
|
-
- **
|
|
142
|
+
- 🏗️ **Format-preserving merges** — Uses [tomlkit](https://github.com/sdispater/tomlkit) under the hood, so your comments, whitespace, and TOML structure are preserved. No reformatting surprises.
|
|
143
|
+
- 🌐 **GitHub & GitLab URL support** — Automatically converts GitHub/GitLab repository URLs or blob URLs to raw content URLs.
|
|
144
|
+
- 📥 **Git clone support** — If the URL starts with `git@` or uses the `ssh://`, `git://`, or `git+ssh://` schemes, `ruff-sync` will perform an efficient shallow clone (using `--filter=blob:none` and `--no-checkout`) to safely extract the configuration with minimal network traffic.
|
|
145
|
+
- 🛡️ **Selective exclusions** — Keep project-specific overrides (like `per-file-ignores` or `target-version`) from being clobbered by the upstream config.
|
|
146
|
+
- 🌍 **Works with any host** — GitHub, GitLab, Bitbucket, private SSH servers, or any raw URL that serves a `pyproject.toml` or `ruff.toml`.
|
|
147
|
+
- 🤖 **CI-ready `check` command** — Verify that your local config is in sync without modifying anything. Exits 1 if out of sync, making it perfect for pre-merge gates. ([See detailed logic](#detailed-check-logic))
|
|
148
|
+
- 🧠 **Semantic mode** — Use `--semantic` to ignore cosmetic differences (comments, whitespace) and only fail on real value changes.
|
|
149
149
|
|
|
150
150
|
## Configuration
|
|
151
151
|
|
|
@@ -172,16 +172,25 @@ This sets the default upstream and exclusions so you don't need to pass them on
|
|
|
172
172
|
|
|
173
173
|
### Advanced Configuration
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Here are all the possible values that can be provided in `[tool.ruff-sync]` along with their explanations and defaults:
|
|
176
176
|
|
|
177
177
|
```toml
|
|
178
178
|
[tool.ruff-sync]
|
|
179
|
+
# The source of truth URL for your Ruff configuration. (Required, unless passed via CLI)
|
|
179
180
|
upstream = "https://github.com/my-org/standards"
|
|
180
181
|
|
|
181
|
-
#
|
|
182
|
+
# A list of config keys to exclude from being synced. (Default: ["lint.per-file-ignores"])
|
|
183
|
+
# Use simple names for top-level keys, and dotted paths for nested keys.
|
|
184
|
+
exclude = [
|
|
185
|
+
"target-version",
|
|
186
|
+
"lint.per-file-ignores",
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
# The branch, tag, or commit hash to use when resolving a Git repository URL. (Default: "main")
|
|
182
190
|
branch = "develop"
|
|
183
191
|
|
|
184
|
-
#
|
|
192
|
+
# A directory prefix to use when looking for a configuration file in a repository. (Default: "")
|
|
193
|
+
# Useful if the upstream pyproject.toml is not at the repository root.
|
|
185
194
|
path = "config/ruff"
|
|
186
195
|
```
|
|
187
196
|
|
|
@@ -229,6 +238,18 @@ git diff pyproject.toml # review the changes
|
|
|
229
238
|
git commit -am "sync ruff config from upstream"
|
|
230
239
|
```
|
|
231
240
|
|
|
241
|
+
## Bootstrapping a New Project
|
|
242
|
+
|
|
243
|
+
By default, `ruff-sync` requires an existing configuration file (`pyproject.toml` or `ruff.toml`) to merge into. If you are starting a fresh project and want to initialize it with your organization's Ruff settings, you can use the `--init` flag to scaffold a new file automatically.
|
|
244
|
+
|
|
245
|
+
```console
|
|
246
|
+
# Create a new pyproject.toml (or ruff.toml) pre-configured with upstream settings
|
|
247
|
+
ruff-sync pull https://github.com/my-org/standards --init
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`ruff-sync` seamlessly supports both `pyproject.toml` and standalone `ruff.toml` (or `.ruff.toml`) files. If your upstream source or your local target is a `ruff.toml`, it will automatically adapt and sync the root configuration rather than looking for a `[tool.ruff]` section.
|
|
251
|
+
|
|
252
|
+
|
|
232
253
|
## Detailed Check Logic
|
|
233
254
|
|
|
234
255
|
When you run `ruff-sync check`, it follows this process to determine if your project has drifted from the upstream source:
|
|
@@ -267,40 +288,23 @@ flowchart TD
|
|
|
267
288
|
style SemanticNode fill:#f4f4f4,color:#363636,stroke:#dbdbdb
|
|
268
289
|
```
|
|
269
290
|
|
|
270
|
-
## Contributing
|
|
271
|
-
|
|
272
|
-
This project uses:
|
|
273
|
-
|
|
274
|
-
- [uv](https://docs.astral.sh/uv/) for dependency management
|
|
275
|
-
- [Ruff](https://docs.astral.sh/ruff/) for linting and formatting
|
|
276
|
-
- [mypy](https://mypy-lang.org/) for type checking (strict mode)
|
|
277
|
-
- [pytest](https://docs.pytest.org/) for testing
|
|
278
|
-
|
|
279
|
-
```console
|
|
280
|
-
# Setup
|
|
281
|
-
uv sync --group dev
|
|
282
|
-
|
|
283
|
-
# Run checks
|
|
284
|
-
uv run ruff check . --fix # lint
|
|
285
|
-
uv run ruff format . # format
|
|
286
|
-
uv run mypy . # type check
|
|
287
|
-
uv run pytest -vv # test
|
|
288
|
-
```
|
|
289
|
-
|
|
290
291
|
## Dogfooding
|
|
291
292
|
|
|
292
|
-
To see `ruff-sync` in action, you can "dogfood" it on this project's own config.
|
|
293
|
+
To see `ruff-sync` in action, you can ["dogfood" it on this project's own config](./scripts).
|
|
293
294
|
|
|
294
|
-
**Check if this project is in sync with its upstream:**
|
|
295
|
+
[**Check if this project is in sync with its upstream:**](./scripts/check_dogfood.sh)
|
|
295
296
|
|
|
296
297
|
```console
|
|
297
|
-
./scripts/
|
|
298
|
+
./scripts/check_dogfood.sh
|
|
298
299
|
```
|
|
299
300
|
|
|
300
|
-
**Or sync from a large upstream like Pydantic's config:**
|
|
301
|
+
[**Or sync from a large upstream like Pydantic's config:**](./scripts/pull_dogfood.sh)
|
|
301
302
|
|
|
302
303
|
```console
|
|
303
|
-
|
|
304
|
+
# Using a HTTP URL
|
|
305
|
+
./scripts/pull_dogfood.sh
|
|
306
|
+
# Using a Git URL
|
|
307
|
+
./scripts/gitclone_dogfood.sh
|
|
304
308
|
```
|
|
305
309
|
|
|
306
310
|
This will download Pydantic's Ruff configuration and merge it into the local `pyproject.toml`. You can then use `git diff` to see how it merged the keys while preserving the existing structure and comments.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ruff-sync"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.4.dev1"
|
|
4
4
|
description = "Synchronize Ruff linter configuration across projects"
|
|
5
5
|
keywords = ["ruff", "linter", "config", "synchronize", "python", "linting", "automation", "tomlkit"]
|
|
6
6
|
authors = [
|