ruff-sync 0.1.3.dev1__tar.gz → 0.1.3.dev2__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.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/ruff-sync-usage/SKILL.md +12 -2
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/ruff-sync-usage/references/ci-integration.md +4 -3
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/ruff-sync-usage/references/configuration.md +1 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.github/workflows/ci.yaml +39 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/AGENTS.md +2 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/PKG-INFO +6 -3
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/README.md +5 -2
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/codecov.yml +1 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/ci-integration.md +5 -2
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/usage.md +5 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/pyproject.toml +7 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/cli.py +21 -5
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/constants.py +17 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/core.py +60 -32
- ruff_sync-0.1.3.dev2/src/ruff_sync/formatters.py +243 -0
- ruff_sync-0.1.3.dev2/tests/conftest.py +64 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_basic.py +157 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_check.py +230 -8
- ruff_sync-0.1.3.dev2/tests/test_formatters.py +154 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_scaffold.py +19 -7
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_serialization.py +2 -1
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/uv.lock +4 -4
- ruff_sync-0.1.3.dev1/tests/conftest.py +0 -12
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/TESTING.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/SKILL.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/examples.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/templates/api-reference.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/templates/getting-started.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/templates/index.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/mkdocs-generation/templates/mkdocs.yml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/release-notes-generation/SKILL.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/skills/ruff-sync-usage/references/troubleshooting.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.agents/workflows/add-test-case.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.git-blame-ignore-revs +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.github/dependabot.yml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.github/workflows/complexity.yaml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.github/workflows/docs.yaml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.gitignore +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.pre-commit-config.yaml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/.pre-commit-hooks.yaml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/CONTRIBUTING.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/LICENSE.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/configs/data-science-engineering/ruff.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/configs/fastapi/ruff.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/configs/kitchen-sink/ruff.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/agent-skill.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/assets/favicon.png +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/assets/logo.png +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/assets/ruff_sync_banner.png +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/best-practices.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/configuration.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/contributing.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/examples/advanced-config.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/examples/basic-config.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/gen_ref_pages.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/index.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/installation.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/pre-commit.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/pre-defined-configs.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/troubleshooting.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/docs/url-resolution.md +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/mkdocs.yml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/scripts/check_dogfood.sh +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/scripts/gitclone_dogfood.sh +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/scripts/pull_dogfood.sh +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/skills-lock.json +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/__init__.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/__main__.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/src/ruff_sync/pre_commit.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tasks.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/__init__.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/multi_upstream_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/multi_upstream_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/multi_upstream_up1.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/multi_upstream_up2.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_changes_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_changes_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_changes_upstream.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_dotted_keys_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_dotted_keys_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_ruff_cfg_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/readme_excludes_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/readme_excludes_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/readme_excludes_upstream.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/standard_final.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/standard_initial.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/lifecycle_tomls/standard_upstream.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/ruff.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_config_validation.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_constants.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_corner_cases.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_deprecation.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_e2e.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_git_fetch.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_pre_commit.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_project.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_toml_operations.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_url_handling.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/test_whitespace.py +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/w_ruff_sync_cfg/pyproject.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/wo_ruff_cfg/pyproject.toml +0 -0
- {ruff_sync-0.1.3.dev1 → ruff_sync-0.1.3.dev2}/tests/wo_ruff_sync_cfg/pyproject.toml +0 -0
|
@@ -77,8 +77,9 @@ upstream = [
|
|
|
77
77
|
CI Setup Progress:
|
|
78
78
|
- [ ] 1. Add ruff-sync check step to CI workflow (see references/ci-integration.md)
|
|
79
79
|
- [ ] 2. Decide: --semantic for value-only checks, or full string comparison
|
|
80
|
-
- [ ] 3. Set
|
|
81
|
-
- [ ] 4.
|
|
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`
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
Keep the `ruff-pre-commit` hook version in `.pre-commit-config.yaml` aligned with the project's Ruff version.
|
|
@@ -112,6 +113,15 @@ ruff-sync https://raw.githubusercontent.com/my-org/standards/main/pyproject.toml
|
|
|
112
113
|
ruff-sync git@github.com:my-org/standards.git # SSH (shallow clone)
|
|
113
114
|
```
|
|
114
115
|
|
|
116
|
+
## CLI Reference (Short)
|
|
117
|
+
|
|
118
|
+
| Flag | Meaning |
|
|
119
|
+
|------|---------|
|
|
120
|
+
| `--output-format` | `text` (default), `json`, `github` (PR annotations) |
|
|
121
|
+
| `--semantic` | Ignore whitespace/comments in `check` |
|
|
122
|
+
| `--pre-commit` | Sync `.pre-commit-config.yaml` hook version |
|
|
123
|
+
| `--save` | Persist CLI args to `pyproject.toml` |
|
|
124
|
+
|
|
115
125
|
## Gotchas
|
|
116
126
|
|
|
117
127
|
- **`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`.
|
|
@@ -8,10 +8,11 @@ Add this step to any existing workflow (e.g., `.github/workflows/ci.yaml`):
|
|
|
8
8
|
|
|
9
9
|
```yaml
|
|
10
10
|
- name: Check Ruff config is in sync
|
|
11
|
-
run: ruff-sync check --semantic
|
|
11
|
+
run: ruff-sync check --semantic --output-format github
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
`--semantic` ignores cosmetic differences (comments, whitespace) — only real value or rule changes cause failure.
|
|
15
|
+
`--output-format github` creates inline PR annotations for errors and warnings.
|
|
15
16
|
|
|
16
17
|
### Full Workflow Example
|
|
17
18
|
|
|
@@ -40,7 +41,7 @@ jobs:
|
|
|
40
41
|
run: uv tool install ruff-sync
|
|
41
42
|
|
|
42
43
|
- name: Check Ruff config is in sync with upstream
|
|
43
|
-
run: ruff-sync check --semantic
|
|
44
|
+
run: ruff-sync check --semantic --output-format github
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
### With Pre-commit Sync Check
|
|
@@ -49,7 +50,7 @@ To also verify the pre-commit hook version, add the `--pre-commit` flag. Any non
|
|
|
49
50
|
|
|
50
51
|
```yaml
|
|
51
52
|
- name: Check Ruff config and pre-commit hook
|
|
52
|
-
run: ruff-sync check --semantic --pre-commit
|
|
53
|
+
run: ruff-sync check --semantic --pre-commit --output-format github
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
(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.)
|
|
@@ -127,7 +127,7 @@ pre-commit-version-sync = true
|
|
|
127
127
|
All config keys have CLI equivalents. CLI values always win over `pyproject.toml`:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
-
ruff-sync --exclude lint.ignore --branch develop
|
|
130
|
+
ruff-sync https://github.com/my-org/standards --exclude lint.ignore --branch develop --output-format github
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
## Config Discovery for `ruff.toml` Projects
|
|
@@ -31,6 +31,26 @@ jobs:
|
|
|
31
31
|
|
|
32
32
|
- run: uv run invoke ${{ matrix.task }} --check
|
|
33
33
|
|
|
34
|
+
validate-docs-build:
|
|
35
|
+
name: Validate documentation build
|
|
36
|
+
if: github.event_name == 'pull_request'
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout
|
|
40
|
+
uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- name: Install uv
|
|
43
|
+
uses: astral-sh/setup-uv@v5
|
|
44
|
+
|
|
45
|
+
- name: Set up Python
|
|
46
|
+
run: uv python install 3.10
|
|
47
|
+
|
|
48
|
+
- name: Install dependencies
|
|
49
|
+
run: uv sync --group docs --frozen
|
|
50
|
+
|
|
51
|
+
- name: Build documentation
|
|
52
|
+
run: uv run mkdocs build --strict
|
|
53
|
+
|
|
34
54
|
tests:
|
|
35
55
|
strategy:
|
|
36
56
|
fail-fast: ${{ github.event.pull_request.draft == true }}
|
|
@@ -102,6 +122,13 @@ jobs:
|
|
|
102
122
|
echo "Testing ruff-sync check against Kilo59/ruff-sync..."
|
|
103
123
|
ruff-sync check https://github.com/Kilo59/ruff-sync
|
|
104
124
|
|
|
125
|
+
- name: Dogfood Ruff-Sync Check (GitHub Format)
|
|
126
|
+
run: |
|
|
127
|
+
echo "Dogfooding ruff-sync check with GitHub annotations..."
|
|
128
|
+
# This will produce annotations if the current branch's ruff config
|
|
129
|
+
# has drifted from the upstream (main branch).
|
|
130
|
+
ruff-sync check https://github.com/Kilo59/ruff-sync --output-format github
|
|
131
|
+
|
|
105
132
|
- name: Verify semantic check failure
|
|
106
133
|
run: |
|
|
107
134
|
echo "Verifying that --semantic check fails for kitchen-sink config (expected failure)..."
|
|
@@ -131,4 +158,15 @@ jobs:
|
|
|
131
158
|
run: uv build
|
|
132
159
|
|
|
133
160
|
- name: Publish package
|
|
134
|
-
run:
|
|
161
|
+
run: |
|
|
162
|
+
# Capture stderr to a file so we can check for specific error strings
|
|
163
|
+
uv publish 2> publish_err.log || {
|
|
164
|
+
exit_code=$?
|
|
165
|
+
# Check for common "version already exists" markers in the output
|
|
166
|
+
if grep -qi "already exists" publish_err.log; then
|
|
167
|
+
echo "::warning title=Ruff Sync Publish::Version already exists on PyPI. Skipping upload."
|
|
168
|
+
else
|
|
169
|
+
cat publish_err.log
|
|
170
|
+
exit $exit_code
|
|
171
|
+
fi
|
|
172
|
+
}
|
|
@@ -158,6 +158,7 @@ uv run coverage run -m pytest -vv
|
|
|
158
158
|
- Prefer f-strings for logging (we ignore `G004`).
|
|
159
159
|
- Do not create custom exception classes for simple errors (`TRY003` is ignored).
|
|
160
160
|
- **Prefer `NamedTuple` for return types** over plain tuples to improve readability and type safety.
|
|
161
|
+
- **Prefer `typing.Protocol` over `abc.ABC`** for abstract base classes to promote structural subtyping.
|
|
161
162
|
|
|
162
163
|
### TOML Handling
|
|
163
164
|
|
|
@@ -219,3 +220,4 @@ CI is defined in `.github/workflows/ci.yaml`:
|
|
|
219
220
|
2. **`cast(Any, ...)` in tests**: Use `cast(Any, tomlkit.parse(...))["tool"]["ruff"]` pattern in tests to avoid mypy complaints about `tomlkit`'s `Item | Container` return types.
|
|
220
221
|
3. **Pre-commit ruff version**: The ruff version in `.pre-commit-config.yaml` must stay in sync with the version in `pyproject.toml`. The test `test_pre_commit_versions_are_in_sync` enforces this.
|
|
221
222
|
4. **Keep the ruff-sync-usage skill current**: After any change to CLI behavior (new flags, changed exit codes, new configuration keys, updated URL handling, etc.), update `.agents/skills/ruff-sync-usage/` accordingly. The `SKILL.md` covers quick start, workflows, exit codes, and gotchas. Detailed references live in `references/configuration.md`, `references/troubleshooting.md`, and `references/ci-integration.md`.
|
|
223
|
+
5. **No `autouse=True` fixtures**: NEVER use `autouse=True` for pytest fixtures. All fixtures must be explicitly requested by the test functions that require them. This ensures dependencies are explicit and avoids hidden side effects.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ruff-sync
|
|
3
|
-
Version: 0.1.3.
|
|
3
|
+
Version: 0.1.3.dev2
|
|
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/
|
|
@@ -208,6 +208,7 @@ See the [Usage documentation](https://kilo59.github.io/ruff-sync/usage/) for mor
|
|
|
208
208
|
- 🧠 **Semantic mode** — Use `--semantic` to ignore cosmetic differences (comments, whitespace) and only fail on real value changes.
|
|
209
209
|
- 🔗 **Pre-commit hook sync** — Use `--pre-commit` to automatically keep your `ruff-pre-commit` hook version in `.pre-commit-config.yaml` matching your project's Ruff version.
|
|
210
210
|
- 🦾 **Agent Skill** — Ships a bundled [Agent Skill](https://kilo59.github.io/ruff-sync/agent-skill/) so AI coding agents can guide you through setup, configuration, and troubleshooting automatically.
|
|
211
|
+
- 📊 **Multiple Output Formats** — Supports `text`, `json`, and GitHub Actions `github` (inline annotations) formats for seamless integration with both human developers and CI/CD pipelines.
|
|
211
212
|
|
|
212
213
|
## Configuration
|
|
213
214
|
|
|
@@ -289,7 +290,7 @@ The `check` command is designed for use in CI pipelines. Add it as a step to cat
|
|
|
289
290
|
# .github/workflows/ci.yaml
|
|
290
291
|
- name: Check ruff config is in sync
|
|
291
292
|
run: |
|
|
292
|
-
ruff-sync check --semantic
|
|
293
|
+
ruff-sync check --semantic --output-format github
|
|
293
294
|
```
|
|
294
295
|
|
|
295
296
|
With `--semantic`, minor reformatting of your local file won't cause a false positive — only actual rule or value differences will fail the check.
|
|
@@ -442,7 +443,9 @@ flowchart TD
|
|
|
442
443
|
|
|
443
444
|
## Dogfooding
|
|
444
445
|
|
|
445
|
-
To see `ruff-sync` in action,
|
|
446
|
+
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.
|
|
447
|
+
|
|
448
|
+
You can also run these checks manually or experiment with syncing:
|
|
446
449
|
|
|
447
450
|
[**Check if this project is in sync with its upstream:**](./scripts/check_dogfood.sh)
|
|
448
451
|
|
|
@@ -177,6 +177,7 @@ See the [Usage documentation](https://kilo59.github.io/ruff-sync/usage/) for mor
|
|
|
177
177
|
- 🧠 **Semantic mode** — Use `--semantic` to ignore cosmetic differences (comments, whitespace) and only fail on real value changes.
|
|
178
178
|
- 🔗 **Pre-commit hook sync** — Use `--pre-commit` to automatically keep your `ruff-pre-commit` hook version in `.pre-commit-config.yaml` matching your project's Ruff version.
|
|
179
179
|
- 🦾 **Agent Skill** — Ships a bundled [Agent Skill](https://kilo59.github.io/ruff-sync/agent-skill/) so AI coding agents can guide you through setup, configuration, and troubleshooting automatically.
|
|
180
|
+
- 📊 **Multiple Output Formats** — Supports `text`, `json`, and GitHub Actions `github` (inline annotations) formats for seamless integration with both human developers and CI/CD pipelines.
|
|
180
181
|
|
|
181
182
|
## Configuration
|
|
182
183
|
|
|
@@ -258,7 +259,7 @@ The `check` command is designed for use in CI pipelines. Add it as a step to cat
|
|
|
258
259
|
# .github/workflows/ci.yaml
|
|
259
260
|
- name: Check ruff config is in sync
|
|
260
261
|
run: |
|
|
261
|
-
ruff-sync check --semantic
|
|
262
|
+
ruff-sync check --semantic --output-format github
|
|
262
263
|
```
|
|
263
264
|
|
|
264
265
|
With `--semantic`, minor reformatting of your local file won't cause a false positive — only actual rule or value differences will fail the check.
|
|
@@ -411,7 +412,9 @@ flowchart TD
|
|
|
411
412
|
|
|
412
413
|
## Dogfooding
|
|
413
414
|
|
|
414
|
-
To see `ruff-sync` in action,
|
|
415
|
+
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.
|
|
416
|
+
|
|
417
|
+
You can also run these checks manually or experiment with syncing:
|
|
415
418
|
|
|
416
419
|
[**Check if this project is in sync with its upstream:**](./scripts/check_dogfood.sh)
|
|
417
420
|
|
|
@@ -25,10 +25,13 @@ jobs:
|
|
|
25
25
|
steps:
|
|
26
26
|
- uses: actions/checkout@v4
|
|
27
27
|
- uses: astral-sh/setup-uv@v5
|
|
28
|
-
-
|
|
28
|
+
- name: Check Ruff Config
|
|
29
|
+
run: uvx ruff-sync check --semantic --output-format github
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
By using `--output-format github`, `ruff-sync` will emit special workflow commands that GitHub translates into inline annotations directly on your Pull Request's file diff.
|
|
33
|
+
|
|
34
|
+
### Automated Sync PRs
|
|
32
35
|
|
|
33
36
|
Instead of just checking, you can have a bot automatically open a PR when the upstream configuration changes.
|
|
34
37
|
|
|
@@ -165,6 +165,10 @@ ruff-sync [UPSTREAM_URL...] [--to PATH] [--exclude KEY...] [--init] [--pre-commi
|
|
|
165
165
|
* **`--exclude KEY...`**: Dotted paths of keys to keep local and never overwrite (e.g., `lint.isort`).
|
|
166
166
|
* **`--init`**: Create a new `pyproject.toml` with the upstream configuration if it doesn't already exist. This automatically saves the upstream source and any other CLI flags into the `[tool.ruff-sync]` section.
|
|
167
167
|
* **`--save` / `--no-save`**: Force serialization (or prevent serialization) of the provided CLI arguments (like `upstream`, `exclude`, etc.) directly into the `[tool.ruff-sync]` section of the target `pyproject.toml` for future use. Note: any credentials present in the upstream URL will cause this operation to safely abort.
|
|
168
|
+
* **`--output-format [text|json|github]`**: Specify the output format for synchronization results.
|
|
169
|
+
- `text` (default): Human-readable terminal output.
|
|
170
|
+
- `json`: Machine-readable JSON output for tool integration.
|
|
171
|
+
- `github`: GitHub Actions workflow commands (`::error`, `::warning`) for inline PR annotations.
|
|
168
172
|
* **`--pre-commit`**: Sync the `astral-sh/ruff-pre-commit` hook version inside `.pre-commit-config.yaml` with the project's Ruff version.
|
|
169
173
|
|
|
170
174
|
### `check`
|
|
@@ -182,6 +186,7 @@ ruff-sync check [UPSTREAM_URL...] [--semantic] [--diff] [--pre-commit]
|
|
|
182
186
|
* **`UPSTREAM_URL...`**: The source URL(s). Optional if defined locally.
|
|
183
187
|
* **`--semantic`**: Ignore "non-functional" differences like whitespace, comments, or key order. Only errors if the actual Python-level data differs.
|
|
184
188
|
* **`--diff` / `--no-diff`**: Control the display of the unified diff in the terminal.
|
|
189
|
+
* **`--output-format [text|json|github]`**: Specify the output format for check results. Defaults to `text`.
|
|
185
190
|
* **`--pre-commit`**: Verify that the `astral-sh/ruff-pre-commit` hook version matches the project's Ruff version in addition to checking configuration drift. If you have `pre-commit-version-sync = true` configured in your `pyproject.toml`, the `check` command will automatically respect this setting and you do not need to pass this flag.
|
|
186
191
|
|
|
187
192
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ruff-sync"
|
|
3
|
-
version = "0.1.3.
|
|
3
|
+
version = "0.1.3.dev2"
|
|
4
4
|
description = "Synchronize Ruff linter configuration across projects"
|
|
5
5
|
keywords = ["ruff", "linter", "config", "synchronize", "python", "linting", "automation", "tomlkit", "pre-commit"]
|
|
6
6
|
authors = [
|
|
@@ -162,6 +162,8 @@ select = [
|
|
|
162
162
|
"TID", # flake8-tidy-imports
|
|
163
163
|
# https://docs.astral.sh/ruff/rules/#tryceratops-try
|
|
164
164
|
"TRY", # tryceratops - exception handling
|
|
165
|
+
# https://docs.astral.sh/ruff/rules/#flake8-print-t20
|
|
166
|
+
"T20", # flake8-print
|
|
165
167
|
# https://beta.ruff.rs/docs/rules/#pyupgrade-up
|
|
166
168
|
"UP", # pyupgrade
|
|
167
169
|
]
|
|
@@ -173,8 +175,12 @@ ignore = [
|
|
|
173
175
|
]
|
|
174
176
|
|
|
175
177
|
[tool.ruff.lint.per-file-ignores]
|
|
178
|
+
"src/ruff_sync/formatters.py" = ["T20"]
|
|
179
|
+
"tasks.py" = ["T20"]
|
|
176
180
|
"tests/**/*.py" = [
|
|
181
|
+
"T20", # allow print in tests
|
|
177
182
|
"D100", # missing docstring in module
|
|
183
|
+
"D101", # missing docstring in class
|
|
178
184
|
"D103", # missing docstring in function
|
|
179
185
|
"D400", # first line should end with a period
|
|
180
186
|
"D401", # first line of docstring should be in imperative mood
|
|
@@ -33,6 +33,7 @@ from ruff_sync.constants import (
|
|
|
33
33
|
DEFAULT_PATH,
|
|
34
34
|
MISSING,
|
|
35
35
|
MissingType,
|
|
36
|
+
OutputFormat,
|
|
36
37
|
resolve_defaults,
|
|
37
38
|
)
|
|
38
39
|
from ruff_sync.core import (
|
|
@@ -102,6 +103,7 @@ class Arguments(NamedTuple):
|
|
|
102
103
|
init: bool = False
|
|
103
104
|
pre_commit: bool | MissingType = MISSING
|
|
104
105
|
save: bool | None = None
|
|
106
|
+
output_format: OutputFormat = OutputFormat.TEXT
|
|
105
107
|
|
|
106
108
|
@property
|
|
107
109
|
@deprecated("Use 'to' instead")
|
|
@@ -249,6 +251,13 @@ def _get_cli_parser() -> ArgumentParser:
|
|
|
249
251
|
default=None,
|
|
250
252
|
help="Sync the pre-commit Ruff hook version with the project's Ruff version.",
|
|
251
253
|
)
|
|
254
|
+
common_parser.add_argument(
|
|
255
|
+
"--output-format",
|
|
256
|
+
type=OutputFormat,
|
|
257
|
+
choices=list(OutputFormat),
|
|
258
|
+
default=OutputFormat.TEXT,
|
|
259
|
+
help="Format for output. Default: text.",
|
|
260
|
+
)
|
|
252
261
|
|
|
253
262
|
# Pull subcommand (the default action)
|
|
254
263
|
pull_parser = subparsers.add_parser(
|
|
@@ -433,11 +442,17 @@ def main() -> int:
|
|
|
433
442
|
1: logging.INFO,
|
|
434
443
|
}.get(args.verbose, logging.DEBUG)
|
|
435
444
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
445
|
+
# Configure logging for the entire ruff_sync package
|
|
446
|
+
root_logger = logging.getLogger("ruff_sync")
|
|
447
|
+
root_logger.setLevel(log_level)
|
|
448
|
+
|
|
449
|
+
# Avoid adding multiple handlers if main() is called multiple times (e.g. in tests)
|
|
450
|
+
if not root_logger.handlers:
|
|
451
|
+
handler = logging.StreamHandler()
|
|
452
|
+
handler.setFormatter(ColoredFormatter())
|
|
453
|
+
root_logger.addHandler(handler)
|
|
454
|
+
|
|
455
|
+
root_logger.propagate = "PYTEST_CURRENT_TEST" in os.environ
|
|
441
456
|
|
|
442
457
|
# Determine target 'to' from CLI or use default '.'
|
|
443
458
|
# Defer Path conversion to avoid pyfakefs issues with captured Path class
|
|
@@ -473,6 +488,7 @@ def main() -> int:
|
|
|
473
488
|
init=getattr(args, "init", False),
|
|
474
489
|
pre_commit=pre_commit_val,
|
|
475
490
|
save=getattr(args, "save", None),
|
|
491
|
+
output_format=getattr(args, "output_format", OutputFormat.TEXT),
|
|
476
492
|
)
|
|
477
493
|
|
|
478
494
|
# Use the shared helper from constants so the MISSING→default logic for
|
|
@@ -5,6 +5,8 @@ from __future__ import annotations
|
|
|
5
5
|
import enum
|
|
6
6
|
from typing import TYPE_CHECKING, Final
|
|
7
7
|
|
|
8
|
+
from typing_extensions import override
|
|
9
|
+
|
|
8
10
|
if TYPE_CHECKING:
|
|
9
11
|
from collections.abc import Iterable
|
|
10
12
|
|
|
@@ -14,6 +16,7 @@ __all__: Final[list[str]] = [
|
|
|
14
16
|
"DEFAULT_PATH",
|
|
15
17
|
"MISSING",
|
|
16
18
|
"MissingType",
|
|
19
|
+
"OutputFormat",
|
|
17
20
|
"resolve_defaults",
|
|
18
21
|
]
|
|
19
22
|
|
|
@@ -42,6 +45,20 @@ class MissingType(enum.Enum):
|
|
|
42
45
|
MISSING: Final[MissingType] = MissingType.SENTINEL
|
|
43
46
|
|
|
44
47
|
|
|
48
|
+
@enum.unique
|
|
49
|
+
class OutputFormat(str, enum.Enum):
|
|
50
|
+
"""Output formats for the CLI."""
|
|
51
|
+
|
|
52
|
+
TEXT = "text"
|
|
53
|
+
JSON = "json"
|
|
54
|
+
GITHUB = "github"
|
|
55
|
+
|
|
56
|
+
@override
|
|
57
|
+
def __str__(self) -> str:
|
|
58
|
+
"""Return the string value for argparse help."""
|
|
59
|
+
return self.value
|
|
60
|
+
|
|
61
|
+
|
|
45
62
|
def resolve_defaults(
|
|
46
63
|
branch: str | MissingType,
|
|
47
64
|
path: str | MissingType,
|
|
@@ -38,6 +38,7 @@ from ruff_sync.constants import (
|
|
|
38
38
|
MISSING,
|
|
39
39
|
resolve_defaults,
|
|
40
40
|
)
|
|
41
|
+
from ruff_sync.formatters import ResultFormatter, get_formatter
|
|
41
42
|
from ruff_sync.pre_commit import sync_pre_commit
|
|
42
43
|
|
|
43
44
|
if TYPE_CHECKING:
|
|
@@ -116,6 +117,16 @@ class UpstreamError(Exception):
|
|
|
116
117
|
super().__init__(msg)
|
|
117
118
|
|
|
118
119
|
|
|
120
|
+
class DiffContext(NamedTuple):
|
|
121
|
+
"""Context for printing a diff between local and merged configurations."""
|
|
122
|
+
|
|
123
|
+
source_toml_path: pathlib.Path
|
|
124
|
+
source_doc: TOMLDocument
|
|
125
|
+
merged_doc: TOMLDocument
|
|
126
|
+
source_val: Any
|
|
127
|
+
merged_val: Any
|
|
128
|
+
|
|
129
|
+
|
|
119
130
|
class Config(TypedDict, total=False):
|
|
120
131
|
"""Configuration schema for [tool.ruff-sync] in pyproject.toml."""
|
|
121
132
|
|
|
@@ -837,25 +848,22 @@ async def _merge_multiple_upstreams(
|
|
|
837
848
|
|
|
838
849
|
def _print_diff(
|
|
839
850
|
args: Arguments,
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
merged_doc: tomlkit.TOMLDocument,
|
|
843
|
-
source_val: Any,
|
|
844
|
-
merged_val: Any,
|
|
851
|
+
fmt: ResultFormatter,
|
|
852
|
+
ctx: DiffContext,
|
|
845
853
|
) -> None:
|
|
846
854
|
"""Print the unified diff between the local and expected configurations."""
|
|
847
855
|
if args.semantic:
|
|
848
856
|
# Semantic diff of the managed section
|
|
849
|
-
from_lines = json.dumps(source_val, indent=2, sort_keys=True).splitlines(keepends=True)
|
|
850
|
-
to_lines = json.dumps(merged_val, indent=2, sort_keys=True).splitlines(keepends=True)
|
|
857
|
+
from_lines = json.dumps(ctx.source_val, indent=2, sort_keys=True).splitlines(keepends=True)
|
|
858
|
+
to_lines = json.dumps(ctx.merged_val, indent=2, sort_keys=True).splitlines(keepends=True)
|
|
851
859
|
from_file = "local (semantic)"
|
|
852
860
|
to_file = "upstream (semantic)"
|
|
853
861
|
else:
|
|
854
862
|
# Full text diff of the file
|
|
855
|
-
from_lines = source_doc.as_string().splitlines(keepends=True)
|
|
856
|
-
to_lines = merged_doc.as_string().splitlines(keepends=True)
|
|
857
|
-
from_file = f"local/{source_toml_path.name}"
|
|
858
|
-
to_file = f"upstream/{source_toml_path.name}"
|
|
863
|
+
from_lines = ctx.source_doc.as_string().splitlines(keepends=True)
|
|
864
|
+
to_lines = ctx.merged_doc.as_string().splitlines(keepends=True)
|
|
865
|
+
from_file = f"local/{ctx.source_toml_path.name}"
|
|
866
|
+
to_file = f"upstream/{ctx.source_toml_path.name}"
|
|
859
867
|
|
|
860
868
|
diff = difflib.unified_diff(
|
|
861
869
|
from_lines,
|
|
@@ -863,16 +871,23 @@ def _print_diff(
|
|
|
863
871
|
fromfile=from_file,
|
|
864
872
|
tofile=to_file,
|
|
865
873
|
)
|
|
866
|
-
|
|
874
|
+
fmt.diff("".join(diff))
|
|
867
875
|
|
|
868
876
|
|
|
869
|
-
def _check_pre_commit_sync(args: Arguments) -> int | None:
|
|
877
|
+
def _check_pre_commit_sync(args: Arguments, fmt: ResultFormatter) -> int | None:
|
|
870
878
|
"""Return exit code 2 if pre-commit hook version is out of sync, otherwise None.
|
|
871
879
|
|
|
872
880
|
Shared helper to avoid duplicating the pre-commit synchronization logic.
|
|
873
881
|
"""
|
|
874
882
|
if getattr(args, "pre_commit", False) and not sync_pre_commit(pathlib.Path.cwd(), dry_run=True):
|
|
875
|
-
|
|
883
|
+
repo_root = pathlib.Path.cwd()
|
|
884
|
+
pre_commit_config = repo_root / ".pre-commit-config.yaml"
|
|
885
|
+
file_path = pre_commit_config if pre_commit_config.exists() else repo_root
|
|
886
|
+
fmt.warning(
|
|
887
|
+
"⚠️ Pre-commit hook version is out of sync!",
|
|
888
|
+
logger=LOGGER,
|
|
889
|
+
file_path=file_path,
|
|
890
|
+
)
|
|
876
891
|
return 2
|
|
877
892
|
return None
|
|
878
893
|
|
|
@@ -898,13 +913,16 @@ async def check(
|
|
|
898
913
|
... )
|
|
899
914
|
>>> # asyncio.run(check(args))
|
|
900
915
|
"""
|
|
901
|
-
|
|
916
|
+
fmt = get_formatter(args.output_format)
|
|
917
|
+
fmt.note("🔍 Checking Ruff sync status...")
|
|
902
918
|
|
|
903
919
|
_source_toml_path = resolve_target_path(args.to, args.upstream).resolve(strict=False)
|
|
904
920
|
if not _source_toml_path.exists():
|
|
905
|
-
|
|
921
|
+
fmt.error(
|
|
906
922
|
f"❌ Configuration file {_source_toml_path} does not exist. "
|
|
907
|
-
"Run 'ruff-sync pull' to create it."
|
|
923
|
+
"Run 'ruff-sync pull' to create it.",
|
|
924
|
+
file_path=_source_toml_path,
|
|
925
|
+
logger=LOGGER,
|
|
908
926
|
)
|
|
909
927
|
return 1
|
|
910
928
|
|
|
@@ -939,14 +957,14 @@ async def check(
|
|
|
939
957
|
merged_val = merged_ruff.unwrap() if merged_ruff is not None else None
|
|
940
958
|
|
|
941
959
|
if source_val == merged_val:
|
|
942
|
-
|
|
943
|
-
exit_code = _check_pre_commit_sync(args)
|
|
960
|
+
fmt.success("✅ Ruff configuration is semantically in sync.")
|
|
961
|
+
exit_code = _check_pre_commit_sync(args, fmt)
|
|
944
962
|
if exit_code is not None:
|
|
945
963
|
return exit_code
|
|
946
964
|
return 0
|
|
947
965
|
elif source_doc.as_string() == merged_doc.as_string():
|
|
948
|
-
|
|
949
|
-
exit_code = _check_pre_commit_sync(args)
|
|
966
|
+
fmt.success("✅ Ruff configuration is in sync.")
|
|
967
|
+
exit_code = _check_pre_commit_sync(args, fmt)
|
|
950
968
|
if exit_code is not None:
|
|
951
969
|
return exit_code
|
|
952
970
|
return 0
|
|
@@ -955,16 +973,23 @@ async def check(
|
|
|
955
973
|
rel_path = _source_toml_path.relative_to(pathlib.Path.cwd())
|
|
956
974
|
except ValueError:
|
|
957
975
|
rel_path = _source_toml_path
|
|
958
|
-
|
|
976
|
+
fmt.error(
|
|
977
|
+
f"❌ Ruff configuration at {rel_path} is out of sync!",
|
|
978
|
+
file_path=rel_path,
|
|
979
|
+
logger=LOGGER,
|
|
980
|
+
)
|
|
959
981
|
|
|
960
982
|
if args.diff:
|
|
961
983
|
_print_diff(
|
|
962
984
|
args=args,
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
985
|
+
fmt=fmt,
|
|
986
|
+
ctx=DiffContext(
|
|
987
|
+
source_toml_path=_source_toml_path,
|
|
988
|
+
source_doc=source_doc,
|
|
989
|
+
merged_doc=merged_doc,
|
|
990
|
+
source_val=source_val,
|
|
991
|
+
merged_val=merged_val,
|
|
992
|
+
),
|
|
968
993
|
)
|
|
969
994
|
return 1
|
|
970
995
|
|
|
@@ -1059,7 +1084,8 @@ async def pull(
|
|
|
1059
1084
|
... )
|
|
1060
1085
|
>>> # asyncio.run(pull(args))
|
|
1061
1086
|
"""
|
|
1062
|
-
|
|
1087
|
+
fmt = get_formatter(args.output_format)
|
|
1088
|
+
fmt.note("🔄 Syncing Ruff...")
|
|
1063
1089
|
_source_toml_path = resolve_target_path(args.to, args.upstream).resolve(strict=False)
|
|
1064
1090
|
|
|
1065
1091
|
source_toml_file = TOMLFile(_source_toml_path)
|
|
@@ -1073,12 +1099,14 @@ async def pull(
|
|
|
1073
1099
|
_source_toml_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1074
1100
|
_source_toml_path.touch()
|
|
1075
1101
|
except OSError as e:
|
|
1076
|
-
|
|
1102
|
+
fmt.error(f"❌ Failed to create {_source_toml_path}: {e}", logger=LOGGER)
|
|
1077
1103
|
return 1
|
|
1078
1104
|
else:
|
|
1079
|
-
|
|
1105
|
+
fmt.error(
|
|
1080
1106
|
f"❌ Configuration file {_source_toml_path} does not exist. "
|
|
1081
|
-
"Pass the '--init' flag to create it."
|
|
1107
|
+
"Pass the '--init' flag to create it.",
|
|
1108
|
+
file_path=_source_toml_path,
|
|
1109
|
+
logger=LOGGER,
|
|
1082
1110
|
)
|
|
1083
1111
|
return 1
|
|
1084
1112
|
|
|
@@ -1105,7 +1133,7 @@ async def pull(
|
|
|
1105
1133
|
rel_path = _source_toml_path.resolve().relative_to(pathlib.Path.cwd())
|
|
1106
1134
|
except ValueError:
|
|
1107
1135
|
rel_path = _source_toml_path.resolve()
|
|
1108
|
-
|
|
1136
|
+
fmt.success(f"✅ Updated {rel_path}")
|
|
1109
1137
|
|
|
1110
1138
|
if args.pre_commit is not MISSING and args.pre_commit:
|
|
1111
1139
|
sync_pre_commit(pathlib.Path.cwd(), dry_run=False)
|