ruff-sync 0.1.0.dev2__tar.gz → 0.1.1.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.
Files changed (85) hide show
  1. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.pre-commit-config.yaml +2 -1
  2. ruff_sync-0.1.1.dev1/.pre-commit-hooks.yaml +15 -0
  3. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/PKG-INFO +56 -16
  4. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/README.md +55 -15
  5. ruff_sync-0.1.1.dev1/docs/assets/favicon.png +0 -0
  6. ruff_sync-0.1.1.dev1/docs/assets/logo.png +0 -0
  7. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/ci-integration.md +7 -18
  8. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/configuration.md +6 -3
  9. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/index.md +19 -7
  10. ruff_sync-0.1.1.dev1/docs/pre-commit.md +69 -0
  11. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/troubleshooting.md +39 -0
  12. ruff_sync-0.1.1.dev1/docs/usage.md +145 -0
  13. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/mkdocs.yml +7 -3
  14. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/pyproject.toml +2 -2
  15. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/src/ruff_sync/cli.py +14 -4
  16. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/src/ruff_sync/core.py +99 -5
  17. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_basic.py +169 -1
  18. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/uv.lock +141 -125
  19. ruff_sync-0.1.0.dev2/docs/usage.md +0 -100
  20. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/TESTING.md +0 -0
  21. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/SKILL.md +0 -0
  22. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/examples.md +0 -0
  23. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/templates/api-reference.md +0 -0
  24. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/templates/getting-started.md +0 -0
  25. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/templates/index.md +0 -0
  26. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/mkdocs-generation/templates/mkdocs.yml +0 -0
  27. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/skills/release-notes-generation/SKILL.md +0 -0
  28. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.agents/workflows/add-test-case.md +0 -0
  29. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.git-blame-ignore-revs +0 -0
  30. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.github/dependabot.yml +0 -0
  31. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.github/workflows/ci.yaml +0 -0
  32. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.github/workflows/complexity.yaml +0 -0
  33. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.github/workflows/docs.yaml +0 -0
  34. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/.gitignore +0 -0
  35. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/AGENTS.md +0 -0
  36. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/LICENSE.md +0 -0
  37. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/codecov.yml +0 -0
  38. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/configs/fastapi/ruff.toml +0 -0
  39. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/configs/kitchen-sink/ruff.toml +0 -0
  40. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/assets/ruff_sync_banner.png +0 -0
  41. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/gen_ref_pages.py +0 -0
  42. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/docs/installation.md +0 -0
  43. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/scripts/check_dogfood.sh +0 -0
  44. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/scripts/gitclone_dogfood.sh +0 -0
  45. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/scripts/pull_dogfood.sh +0 -0
  46. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/skills-lock.json +0 -0
  47. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/src/ruff_sync/__init__.py +0 -0
  48. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/src/ruff_sync/__main__.py +0 -0
  49. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tasks.py +0 -0
  50. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/__init__.py +0 -0
  51. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/conftest.py +0 -0
  52. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/multi_upstream_final.toml +0 -0
  53. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/multi_upstream_initial.toml +0 -0
  54. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/multi_upstream_up1.toml +0 -0
  55. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/multi_upstream_up2.toml +0 -0
  56. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_changes_final.toml +0 -0
  57. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_changes_initial.toml +0 -0
  58. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_changes_upstream.toml +0 -0
  59. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_dotted_keys_final.toml +0 -0
  60. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_dotted_keys_initial.toml +0 -0
  61. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +0 -0
  62. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_ruff_cfg_final.toml +0 -0
  63. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +0 -0
  64. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +0 -0
  65. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/readme_excludes_final.toml +0 -0
  66. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/readme_excludes_initial.toml +0 -0
  67. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/readme_excludes_upstream.toml +0 -0
  68. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/standard_final.toml +0 -0
  69. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/standard_initial.toml +0 -0
  70. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/lifecycle_tomls/standard_upstream.toml +0 -0
  71. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/ruff.toml +0 -0
  72. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_check.py +0 -0
  73. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_config_validation.py +0 -0
  74. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_corner_cases.py +0 -0
  75. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_deprecation.py +0 -0
  76. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_e2e.py +0 -0
  77. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_git_fetch.py +0 -0
  78. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_project.py +0 -0
  79. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_scaffold.py +0 -0
  80. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_toml_operations.py +0 -0
  81. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_url_handling.py +0 -0
  82. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/test_whitespace.py +0 -0
  83. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/w_ruff_sync_cfg/pyproject.toml +0 -0
  84. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/wo_ruff_cfg/pyproject.toml +0 -0
  85. {ruff_sync-0.1.0.dev2 → ruff_sync-0.1.1.dev1}/tests/wo_ruff_sync_cfg/pyproject.toml +0 -0
@@ -7,12 +7,13 @@ repos:
7
7
  - id: check-yaml
8
8
  args: ["--unsafe"]
9
9
  exclude: .agents/skills/mkdocs-generation/templates/mkdocs.yml
10
+ - id: check-toml
10
11
  - id: end-of-file-fixer
11
12
  - id: trailing-whitespace
12
13
  - id: no-commit-to-branch
13
14
  args: [--branch, develop, --branch, main]
14
15
  - repo: https://github.com/astral-sh/ruff-pre-commit
15
- rev: "v0.15.5"
16
+ rev: "v0.15.6"
16
17
  hooks:
17
18
  - id: ruff-check
18
19
  args: ["--fix"]
@@ -0,0 +1,15 @@
1
+ - id: ruff-sync-pull
2
+ name: ruff-sync-pull
3
+ description: Pull and apply upstream ruff configuration.
4
+ entry: ruff-sync pull
5
+ language: python
6
+ files: ^(\.ruff\.toml|ruff\.toml|pyproject\.toml)$
7
+ pass_filenames: false
8
+
9
+ - id: ruff-sync-check
10
+ name: ruff-sync-check
11
+ description: Check if ruff configuration is in sync with upstream.
12
+ entry: ruff-sync check --semantic
13
+ language: python
14
+ files: ^(\.ruff\.toml|ruff\.toml|pyproject\.toml)$
15
+ pass_filenames: false
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ruff-sync
3
- Version: 0.1.0.dev2
3
+ Version: 0.1.1.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://kilo59.github.io/ruff-sync/
@@ -54,6 +54,7 @@ Description-Content-Type: text/markdown
54
54
  - [Quick Start](#quick-start)
55
55
  - [Key Features](#key-features)
56
56
  - [Configuration](#configuration)
57
+ - [Pre-commit Integration](#pre-commit-integration)
57
58
  - [CI Integration](#ci-integration)
58
59
  - [Example Workflow](#example-workflow)
59
60
  - [Detailed Check Logic](#detailed-check-logic)
@@ -132,33 +133,59 @@ pip install ruff-sync
132
133
 
133
134
  ### Usage
134
135
 
136
+ **The Basic Sync**
137
+
138
+ ```console
139
+ # Pull rules from a central repository into your current project
140
+ ruff-sync pull https://github.com/my-org/standards
141
+ ```
142
+
143
+ **Persistent Configuration**
144
+
145
+ ```console
146
+ # If configured in pyproject.toml (see Configuration), simply run:
147
+ ruff-sync pull
148
+ ```
149
+
150
+ **Initializing a New Project**
151
+
135
152
  ```console
136
- # Sync from a GitHub/GitLab repository (root or specific directory)
137
- ruff-sync https://github.com/my-org/standards
138
- ruff-sync https://github.com/my-org/standards/tree/main/configs/shared
153
+ # Scaffold a new pyproject.toml if your directory is empty
154
+ ruff-sync pull https://github.com/my-org/standards --init
155
+ ```
139
156
 
140
- # Or a direct blob/file URL (auto-converts to raw)
141
- ruff-sync https://github.com/my-org/standards/blob/main/pyproject.toml
157
+ **Syncing Subdirectories or Specific Files**
142
158
 
143
- # Clone from any git repository (using SSH or HTTP, defaults to --depth 1)
144
- # You can use the --branch flag to specify a branch (default: main)
145
- ruff-sync git@github.com:my-org/standards.git
146
- ruff-sync ssh://git@gitlab.com/my-org/standards.git
159
+ ```console
160
+ ruff-sync pull https://github.com/my-org/standards/tree/main/configs/shared
161
+ ruff-sync pull https://github.com/my-org/standards/blob/main/pyproject.toml
162
+ ```
147
163
 
148
- # Or if configured in pyproject.toml (see Configuration), simply run:
149
- ruff-sync
164
+ **Using Git (SSH/HTTP)**
150
165
 
166
+ ```console
167
+ # Clones efficiently (depth 1, blob:none) to extract the config
168
+ ruff-sync pull git@github.com:my-org/standards.git
169
+ ```
170
+
171
+ **Excluding Specific Rules**
172
+
173
+ ```console
151
174
  # Exclude specific sections from being overwritten using dotted paths
152
- ruff-sync --exclude lint.per-file-ignores lint.ignore
175
+ ruff-sync pull --exclude lint.ignore
176
+ ```
177
+
178
+ **Checking for Drift (CI)**
153
179
 
154
- # Check if your local config is in sync (useful in CI)
180
+ ```console
181
+ # Verify local config matches upstream. Exits 1 if out of sync.
155
182
  ruff-sync check https://github.com/my-org/standards
156
183
 
157
- # Semantic check — ignore cosmetic differences like comments and whitespace
184
+ # Semantic check — ignores cosmetic differences like comments and whitespace
158
185
  ruff-sync check --semantic
159
186
  ```
160
187
 
161
- Run `ruff-sync --help` for full details on all available options.
188
+ See the [Usage documentation](https://kilo59.github.io/ruff-sync/usage/) for more detailed examples and advanced workflows.
162
189
 
163
190
  ## Key Features
164
191
 
@@ -223,6 +250,19 @@ path = "config/ruff"
223
250
  to = "."
224
251
  ```
225
252
 
253
+ ## Pre-commit Integration
254
+
255
+ Ensure your configuration is always in sync before every commit. Add this to your `.pre-commit-config.yaml`:
256
+
257
+ ```yaml
258
+ - repo: https://github.com/Kilo59/ruff-sync
259
+ rev: v0.1.0 # Use the latest version
260
+ hooks:
261
+ - id: ruff-sync-check
262
+ ```
263
+
264
+ See the [Pre-commit Guide](https://kilo59.github.io/ruff-sync/pre-commit/) for more details.
265
+
226
266
  ## CI Integration
227
267
 
228
268
  The `check` command is designed for use in CI pipelines. Add it as a step to catch config drift before it merges:
@@ -23,6 +23,7 @@
23
23
  - [Quick Start](#quick-start)
24
24
  - [Key Features](#key-features)
25
25
  - [Configuration](#configuration)
26
+ - [Pre-commit Integration](#pre-commit-integration)
26
27
  - [CI Integration](#ci-integration)
27
28
  - [Example Workflow](#example-workflow)
28
29
  - [Detailed Check Logic](#detailed-check-logic)
@@ -101,33 +102,59 @@ pip install ruff-sync
101
102
 
102
103
  ### Usage
103
104
 
105
+ **The Basic Sync**
106
+
107
+ ```console
108
+ # Pull rules from a central repository into your current project
109
+ ruff-sync pull https://github.com/my-org/standards
110
+ ```
111
+
112
+ **Persistent Configuration**
113
+
114
+ ```console
115
+ # If configured in pyproject.toml (see Configuration), simply run:
116
+ ruff-sync pull
117
+ ```
118
+
119
+ **Initializing a New Project**
120
+
104
121
  ```console
105
- # Sync from a GitHub/GitLab repository (root or specific directory)
106
- ruff-sync https://github.com/my-org/standards
107
- ruff-sync https://github.com/my-org/standards/tree/main/configs/shared
122
+ # Scaffold a new pyproject.toml if your directory is empty
123
+ ruff-sync pull https://github.com/my-org/standards --init
124
+ ```
108
125
 
109
- # Or a direct blob/file URL (auto-converts to raw)
110
- ruff-sync https://github.com/my-org/standards/blob/main/pyproject.toml
126
+ **Syncing Subdirectories or Specific Files**
111
127
 
112
- # Clone from any git repository (using SSH or HTTP, defaults to --depth 1)
113
- # You can use the --branch flag to specify a branch (default: main)
114
- ruff-sync git@github.com:my-org/standards.git
115
- ruff-sync ssh://git@gitlab.com/my-org/standards.git
128
+ ```console
129
+ ruff-sync pull https://github.com/my-org/standards/tree/main/configs/shared
130
+ ruff-sync pull https://github.com/my-org/standards/blob/main/pyproject.toml
131
+ ```
116
132
 
117
- # Or if configured in pyproject.toml (see Configuration), simply run:
118
- ruff-sync
133
+ **Using Git (SSH/HTTP)**
119
134
 
135
+ ```console
136
+ # Clones efficiently (depth 1, blob:none) to extract the config
137
+ ruff-sync pull git@github.com:my-org/standards.git
138
+ ```
139
+
140
+ **Excluding Specific Rules**
141
+
142
+ ```console
120
143
  # Exclude specific sections from being overwritten using dotted paths
121
- ruff-sync --exclude lint.per-file-ignores lint.ignore
144
+ ruff-sync pull --exclude lint.ignore
145
+ ```
146
+
147
+ **Checking for Drift (CI)**
122
148
 
123
- # Check if your local config is in sync (useful in CI)
149
+ ```console
150
+ # Verify local config matches upstream. Exits 1 if out of sync.
124
151
  ruff-sync check https://github.com/my-org/standards
125
152
 
126
- # Semantic check — ignore cosmetic differences like comments and whitespace
153
+ # Semantic check — ignores cosmetic differences like comments and whitespace
127
154
  ruff-sync check --semantic
128
155
  ```
129
156
 
130
- Run `ruff-sync --help` for full details on all available options.
157
+ See the [Usage documentation](https://kilo59.github.io/ruff-sync/usage/) for more detailed examples and advanced workflows.
131
158
 
132
159
  ## Key Features
133
160
 
@@ -192,6 +219,19 @@ path = "config/ruff"
192
219
  to = "."
193
220
  ```
194
221
 
222
+ ## Pre-commit Integration
223
+
224
+ Ensure your configuration is always in sync before every commit. Add this to your `.pre-commit-config.yaml`:
225
+
226
+ ```yaml
227
+ - repo: https://github.com/Kilo59/ruff-sync
228
+ rev: v0.1.0 # Use the latest version
229
+ hooks:
230
+ - id: ruff-sync-check
231
+ ```
232
+
233
+ See the [Pre-commit Guide](https://kilo59.github.io/ruff-sync/pre-commit/) for more details.
234
+
195
235
  ## CI Integration
196
236
 
197
237
  The `check` command is designed for use in CI pipelines. Add it as a step to catch config drift before it merges:
@@ -72,26 +72,9 @@ ruff-sync-check:
72
72
 
73
73
  ---
74
74
 
75
- ## 🛠️ Pre-commit Integration
76
-
77
75
  You can use `ruff-sync` with `pre-commit` to ensure your configuration is always in sync before pushing.
78
76
 
79
- Add this to your `.pre-commit-config.yaml`:
80
-
81
- ```yaml
82
- repos:
83
- - repo: local
84
- hooks:
85
- - id: ruff-sync-check
86
- name: ruff-sync-check
87
- entry: uvx ruff-sync check --semantic
88
- language: system
89
- files: ^pyproject\.toml$
90
- pass_filenames: false
91
- ```
92
-
93
- !!! note
94
- Running `ruff-sync check` in pre-commit is fast because it only performs a network request if the local `pyproject.toml` is older than the upstream or if no cache exists.
77
+ See the [Pre-commit Guide](pre-commit.md) for details on using the official hooks.
95
78
 
96
79
  ---
97
80
 
@@ -101,6 +84,12 @@ repos:
101
84
 
102
85
  In CI, you usually only care about the functional configuration. Using `--semantic` ensures that minor formatting changes don't break your builds, while still guaranteeing that the actual rules are identical.
103
86
 
87
+ ### Handle Exclusions Properly
88
+
89
+ If your project intentionally diverges from the upstream (e.g., using different `per-file-ignores` or ignoring a specific rule), ensure those overrides are listed in the `[tool.ruff-sync]` `exclude` list in your `pyproject.toml`.
90
+
91
+ The `check` command respects your local `exclude` list. If you exclude a setting, `ruff-sync check` will completely ignore it when comparing against the upstream, ensuring that intended deviations never cause CI to fail!
92
+
104
93
  ### Use a Dedicated Workflow
105
94
 
106
95
  Running `ruff-sync` as a separate job in your linting workflow makes it easy to identify when a failure is due to configuration drift rather than a code quality issue.
@@ -60,16 +60,19 @@ exclude = ["target-version"]
60
60
 
61
61
  #### Sequential merging of multiple sources
62
62
 
63
- You can specify multiple upstream sources as a list. They will be merged in order, with later sources overriding earlier ones.
63
+ You can specify multiple upstream sources as a list. They will be merged in order—from top to bottom—with later sources overriding or extending earlier ones.
64
64
 
65
65
  ```toml
66
66
  [tool.ruff-sync]
67
67
  upstream = [
68
- "https://github.com/my-org/shared-config",
69
- "https://github.com/my-org/team-overrides",
68
+ "https://github.com/my-org/shared-config", # 1. Base rules
69
+ "https://github.com/my-org/team-overrides", # 2. Team-specific tweaks (wins)
70
70
  ]
71
71
  ```
72
72
 
73
+ !!! tip "Last One Wins"
74
+ The merge logic follows a "last one wins" approach for simple keys (like `line-length`), while performing a deep merge for configuration tables like `lint.per-file-ignores`.
75
+
73
76
  ## Deprecation Notes
74
77
 
75
78
  - The key `source` in `[tool.ruff-sync]` is deprecated and will be removed in a future version. Use `to` instead.
@@ -13,11 +13,13 @@
13
13
  ## 🚀 Key Features
14
14
 
15
15
  * **⚡ Fast & Lightweight**: Zero-config needed for most projects.
16
- * **✨ Formatting Preserved**: Uses `tomlkit` to keep your comments, indentation, and whitespace exactly as they are.
17
- * **🛡️ Smart Merging**: Safely merges nested tables (like `lint.per-file-ignores`) without overwriting local overrides.
16
+ * **✨ Formatting Preserved**: Keeps all comments and whitespace via `tomlkit`.
17
+ * **🛡️ Smart Merging**: Safely merges nested tables without overwriting local overrides.
18
18
  * **📂 Upstream Layers**: Combine and merge configurations from several sources sequentially.
19
- * **🔗 Flexible Sources**: Sync from GitHub, GitLab, raw URLs, or local files.
20
- * **✅ CI Ready**: Built-in `check` command with semantic diffs for automated pipelines.
19
+ * **🌐 Flexible Sources**: Sync from GitHub, GitLab, raw URLs, or local files.
20
+ * **📥 Efficient Git Support**: Shallow clones and sparse checkouts for fast extraction.
21
+ * **🚀 Zero-Config Bootstrapping**: Use `--init` to scaffold a new project in one command.
22
+ * **✅ CI Ready**: Built-in `check` command with semantic comparison logic.
21
23
 
22
24
  ---
23
25
 
@@ -38,16 +40,26 @@ Internal "base" configurations or shared presets often fall out of sync, or requ
38
40
 
39
41
  ## 🏁 Quick Start
40
42
 
41
- ### 1. Configure your project
43
+ ### 1. Initialize a new project (Optional)
42
44
 
43
- Add the upstream URL to your `pyproject.toml`:
45
+ If your local directory doesn't have a configuration file yet, you can fetch the standard and create one instantly:
46
+
47
+ ```bash
48
+ uv run ruff-sync pull https://github.com/my-org/standards --init
49
+ ```
50
+
51
+ ### 2. Configure an existing project
52
+
53
+ Add the upstream URL to your `pyproject.toml` to make it the default:
44
54
 
45
55
  ```toml
46
56
  [tool.ruff-sync]
47
57
  upstream = "https://github.com/my-org/standards/blob/main/pyproject.toml"
48
58
  ```
49
59
 
50
- ### 2. Pull the configuration
60
+ ### 3. Pull the configuration
61
+
62
+ Once configured, simply run:
51
63
 
52
64
  ```bash
53
65
  uv run ruff-sync pull
@@ -0,0 +1,69 @@
1
+ # Pre-commit Integration
2
+
3
+ Using `ruff-sync` with [pre-commit](https://pre-commit.com/) ensures that your Ruff configuration stays in sync with your organization's standards automatically.
4
+
5
+ ## Official Hooks
6
+
7
+ `ruff-sync` provides two official hooks:
8
+
9
+ ### `ruff-sync-check`
10
+
11
+ Verifies that your local `pyproject.toml` or `ruff.toml` matches the upstream configuration. It is recommended to use this hook to prevent accidental drift.
12
+
13
+ ```yaml
14
+ - repo: https://github.com/Kilo59/ruff-sync
15
+ rev: v0.1.0 # Use the latest version
16
+ hooks:
17
+ - id: ruff-sync-check
18
+ ```
19
+
20
+ ### `ruff-sync-pull`
21
+
22
+ Automatically pulls and applies the upstream configuration if a drift is detected.
23
+
24
+ ```yaml
25
+ - repo: https://github.com/Kilo59/ruff-sync
26
+ rev: v0.1.0 # Use the latest version
27
+ hooks:
28
+ - id: ruff-sync-pull
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ The hooks will automatically respect the configuration defined in your `pyproject.toml` under `[tool.ruff-sync]`. Any arguments passed via `args` in `.pre-commit-config.yaml` will override these settings.
34
+
35
+ > [!NOTE]
36
+ > For a full list of configuration options, see the [Configuration Guide](configuration.md).
37
+
38
+ ### Example `.pre-commit-config.yaml`
39
+
40
+ ```yaml
41
+ repos:
42
+ - repo: https://github.com/Kilo59/ruff-sync
43
+ rev: v0.1.0
44
+ hooks:
45
+ - id: ruff-sync-check
46
+ # Common arguments:
47
+ # --semantic: ignore cosmetic changes (default in check hook)
48
+ # --no-diff: hide the unified diff
49
+ # --to PATH: sync to a specific file or directory
50
+ args: ["--semantic", "--no-diff"]
51
+ ```
52
+
53
+ ## Why use `ruff-sync-check`?
54
+
55
+ Running `ruff-sync check` in pre-commit is fast because:
56
+
57
+ 1. It only checks the `[tool.ruff]` section of the configuration.
58
+ 2. It minimizes network overhead by only fetching exactly what it needs (e.g., using direct HTTP requests for single files or partial git cloning for repositories).
59
+ 3. By default, it uses `--semantic` to ignore formatting-only differences, reducing false positives.
60
+
61
+ For more complex scenarios, such as syncing from multiple upstreams or using directory prefixes, see [Advanced Usage](usage.md#advanced-usage).
62
+
63
+ ## Manual Execution
64
+
65
+ You can always run the hooks manually using:
66
+
67
+ ```bash
68
+ pre-commit run ruff-sync-check --all-files
69
+ ```
@@ -4,6 +4,21 @@ Common issues and questions when using `ruff-sync`.
4
4
 
5
5
  ## Common Issues
6
6
 
7
+ ### Debug Logging
8
+
9
+ If `ruff-sync` is not behaving as expected, you can increase the verbosity of the logs to see what's happening under the hood.
10
+
11
+ **Usage**:
12
+
13
+ - `-v`: Shows `INFO` level logs (e.g., which configuration file is being used, where upstreams are being sourced from).
14
+ - `-vv`: Shows `DEBUG` level logs (e.g., detailed TOML merging operations and raw HTTP/Git requests).
15
+
16
+ Example:
17
+
18
+ ```bash
19
+ ruff-sync pull -vv
20
+ ```
21
+
7
22
  ### Upstream URL not found
8
23
 
9
24
  **Error**: `Error: Upstream Required. No upstream URL found in pyproject.toml or provided as argument.`
@@ -31,6 +46,30 @@ Use the `--exclude` flag to keep your local settings:
31
46
  ruff-sync pull --exclude lint.line-length
32
47
  ```
33
48
 
49
+ ### Multi-upstream Fetch Failures
50
+
51
+ **Error**: `❌ <N> upstream fetches failed`
52
+
53
+ This happens when one or more of the specified upstream URLs cannot be reached, do not exist, or return an error (e.g., 404 or 403). `ruff-sync` fetches all upstreams concurrently for speed, but requires ALL of them to succeed before it will attempt to merge.
54
+
55
+ **Solution**:
56
+ 1. Check each URL in the terminal output to see which specific one failed.
57
+ 2. Verify you have network access and the correct permissions for each source.
58
+ 3. If an HTTP source is blocked or private, consider using a Git SSH URL instead.
59
+
60
+ ### Git SSH Workaround for Fetch Errors
61
+
62
+ If you see an HTTP `403 Forbidden` or `404 Not Found` when trying to fetch from GitHub or GitLab, it might be due to authentication requirements.
63
+
64
+ **Solution**:
65
+ Use the git-clone alternative suggested in the error message:
66
+
67
+ ```bash
68
+ ruff-sync pull git@github.com:org/repo.git
69
+ ```
70
+
71
+ This uses your local SSH keys and is often more reliable for internal or private repositories.
72
+
34
73
  ## FAQ
35
74
 
36
75
  ### Does it support `ruff.toml`?
@@ -0,0 +1,145 @@
1
+ # Usage
2
+
3
+ `ruff-sync` provides two main commands—`pull` and `check`—designed to keep your Ruff configuration synchronized across projects.
4
+
5
+ This guide covers common daily workflows, explains how `ruff-sync` merges configuration, and provides a full command reference.
6
+
7
+ ---
8
+
9
+ ## 🌟 Common Workflows
10
+
11
+ ### The Basic Sync
12
+
13
+ If you want to pull rules from a central repository into your current project, run:
14
+
15
+ ```bash
16
+ ruff-sync pull https://github.com/my-org/standards
17
+ ```
18
+
19
+ This fetches the `pyproject.toml` from the `main` branch of `my-org/standards`, extracts the `[tool.ruff]` section, and surgically merges it into your local `pyproject.toml`.
20
+
21
+ ### Persistent Configuration
22
+
23
+ Instead of passing the URL every time, you can save the upstream URL in your project's `pyproject.toml`:
24
+
25
+ ```toml
26
+ [tool.ruff-sync]
27
+ upstream = "https://github.com/my-org/standards"
28
+ ```
29
+
30
+ Now, you can simply run:
31
+
32
+ ```bash
33
+ ruff-sync pull
34
+ ```
35
+
36
+ ### Initializing a New Project
37
+
38
+ If your local directory doesn't have a `pyproject.toml` yet, you can scaffold one:
39
+
40
+ ```bash
41
+ ruff-sync pull https://github.com/my-org/standards --init
42
+ ```
43
+
44
+ This creates a new `pyproject.toml` populated with the upstream configuration and automatically adds a `[tool.ruff-sync]` block so you won't need to specify the URL again.
45
+
46
+ ### Syncing Subdirectories
47
+
48
+ If the upstream repository stores its Python configuration in a specific subdirectory (like a `backend/` folder in a monorepo), use the `--path` argument:
49
+
50
+ ```bash
51
+ ruff-sync pull https://github.com/my-org/standards --path backend
52
+ ```
53
+
54
+ ### Excluding Specific Rules
55
+
56
+ Sometimes your project needs to deviate slightly from the upstream standard. You can exclude specific dotted paths to preserve your local settings:
57
+
58
+ ```bash
59
+ ruff-sync pull --exclude lint.ignore lint.select
60
+ ```
61
+
62
+ *(By default, `lint.per-file-ignores` is always excluded so your local file-specific ignores are safe).*
63
+
64
+ ---
65
+
66
+ ## 🔍 Checking for Drift
67
+
68
+ To ensure your repository hasn't drifted from your organization's unified standards, use the `check` command. It compares your local config to the upstream and warns you of any divergence.
69
+
70
+ ```bash
71
+ ruff-sync check https://github.com/my-org/standards
72
+ ```
73
+
74
+ *(If you have `upstream` configured in your `pyproject.toml`, you can just run `ruff-sync check`.)*
75
+
76
+ ### Semantic Checking
77
+
78
+ Often, the exact ordering of keys, whitespace, or comments might slightly differ from the upstream, even though the actual rules are identical. Use the `--semantic` flag to ignore functional equivalents:
79
+
80
+ ```bash
81
+ ruff-sync check --semantic
82
+ ```
83
+
84
+ *(This is heavily recommended for CI pipelines.)*
85
+
86
+ ---
87
+
88
+ ## ✨ Artisanal Merging
89
+
90
+ One of the core features of `ruff-sync` is its ability to respect your file's existing structure.
91
+
92
+ Unlike other tools that might blindly overwrite your file, strip away comments, or change indentation, `ruff-sync` uses `tomlkit` to perform a **lossless merge**.
93
+
94
+ !!! info "What is preserved?"
95
+ * **Comments**: All comments in your local file are kept exactly where they are.
96
+ * **Whitespace**: Your indentation and line breaks are respected.
97
+ * **Key Order**: The order of your existing keys in `[tool.ruff]` is preserved where possible.
98
+ * **Non-Ruff Configs**: Any other sections in your `pyproject.toml` (like `[project]` or `[tool.pytest]`) are completely untouched.
99
+
100
+ ---
101
+
102
+ ## 📚 Command Reference
103
+
104
+ ### `pull`
105
+
106
+ Downloads the upstream configuration and merges it into your local file.
107
+
108
+ ```bash
109
+ ruff-sync pull [UPSTREAM_URL...] [--to PATH] [--exclude KEY...] [--init]
110
+ ```
111
+
112
+ * **`UPSTREAM_URL...`**: One or more URLs to the source `pyproject.toml` or `ruff.toml`. Optional if defined in your local `[tool.ruff-sync]` config. Multiple URLs form a fallback/merge chain. All upstreams are fetched **concurrently**, but they are merged sequentially in the order they are defined. If any upstream fails to fetch, the entire operation will fail.
113
+ * **`--to PATH`**: Where to save the merged config (defaults to the current directory `.`).
114
+ * **`--exclude KEY...`**: Dotted paths of keys to keep local and never overwrite (e.g., `lint.isort`).
115
+ * **`--init`**: Create a new `pyproject.toml` with the upstream configuration if it doesn't already exist.
116
+
117
+ ### `check`
118
+
119
+ Verifies if your local configuration matches what the upstream would produce. It exits with a non-zero code if differences are found.
120
+
121
+ ```bash
122
+ ruff-sync check [UPSTREAM_URL...] [--semantic] [--diff]
123
+ ```
124
+
125
+ * **`UPSTREAM_URL...`**: The source URL(s). Optional if defined locally.
126
+ * **`--semantic`**: Ignore "non-functional" differences like whitespace, comments, or key order. Only errors if the actual Python-level data differs.
127
+ * **`--diff` / `--no-diff`**: Control the display of the unified diff in the terminal.
128
+
129
+ ---
130
+
131
+ ## 🗺️ Logic Flow
132
+
133
+ The following diagram illustrates how `ruff-sync` handles the synchronization process under the hood:
134
+
135
+ ```mermaid
136
+ graph TD
137
+ A[Start] --> B[Resolve all Upstream URLs]
138
+ B --> C[Fetch all Upstreams Concurrently]
139
+ C --> D{Any Failures?}
140
+ D -- Yes --> E[Raise UpstreamError]
141
+ D -- No --> F[Initialize Target Doc]
142
+ F --> G[Merge Upstreams Sequentially]
143
+ G --> H[Save Final Configuration]
144
+ H --> I[End]
145
+ ```
@@ -8,6 +8,8 @@ edit_uri: edit/main/docs/
8
8
 
9
9
  theme:
10
10
  name: material
11
+ logo: assets/logo.png
12
+ favicon: assets/favicon.png
11
13
  palette:
12
14
  - media: "(prefers-color-scheme: light)"
13
15
  scheme: default
@@ -105,8 +107,10 @@ plugins:
105
107
  nav:
106
108
  - Home: index.md
107
109
  - Installation: installation.md
108
- - Usage: usage.md
109
- - Configuration: configuration.md
110
- - CI Integration: ci-integration.md
110
+ - Usage:
111
+ - Usage: usage.md
112
+ - Configuration: configuration.md
113
+ - Pre-commit: pre-commit.md
114
+ - CI Integration: ci-integration.md
111
115
  - Troubleshooting: troubleshooting.md
112
116
  - API Reference: reference/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ruff-sync"
3
- version = "0.1.0.dev2"
3
+ version = "0.1.1.dev1"
4
4
  description = "Synchronize Ruff linter configuration across projects"
5
5
  keywords = ["ruff", "linter", "config", "synchronize", "python", "linting", "automation", "tomlkit"]
6
6
  authors = [
@@ -121,7 +121,6 @@ select = [
121
121
  # https://beta.ruff.rs/docs/rules/#flake8-datetimez-dtz
122
122
  "DTZ", # flake8-datetimez-dtz - prevent use of tz naive datetimes
123
123
  "EM", # flake8-errmsg - raw string literals in error messages
124
- "ERA", # eradicate - commented-out code
125
124
  # https://beta.ruff.rs/docs/rules/#pyflakes-f
126
125
  "F", # Pyflakes
127
126
  # https://beta.ruff.rs/docs/rules/#pycodestyle-e-w
@@ -197,6 +196,7 @@ ignore = [
197
196
  "TRY003", # don't care about long exception messages in tests
198
197
  "PLW1510", # subprocess check not needed in tests
199
198
  "PT013", # pytest import style, prevents importing param and or types in from style
199
+ "TC002", # Move third-party import into type-checking block
200
200
  ]
201
201
 
202
202
  [tool.ruff.lint.pydocstyle]