afterpython 0.1.0__py3-none-any.whl → 0.1.0.dev4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. afterpython/{templates/pre-commit-config-template.yaml → .pre-commit-config.yaml} +1 -1
  2. afterpython/_io/toml.py +3 -5
  3. afterpython/_paths.py +1 -1
  4. afterpython/_typing.py +2 -1
  5. afterpython/builders/__init__.py +3 -12
  6. afterpython/builders/metadata.py +3 -7
  7. afterpython/builders/molab.py +99 -0
  8. afterpython/cli/__init__.py +1 -0
  9. afterpython/cli/commands/build.py +63 -136
  10. afterpython/cli/commands/bump.py +0 -30
  11. afterpython/cli/commands/check.py +1 -1
  12. afterpython/cli/commands/clean.py +3 -4
  13. afterpython/cli/commands/commit.py +3 -21
  14. afterpython/cli/commands/commitizen.py +1 -1
  15. afterpython/cli/commands/dev.py +13 -80
  16. afterpython/cli/commands/format.py +1 -1
  17. afterpython/cli/commands/init.py +39 -48
  18. afterpython/cli/commands/install.py +2 -8
  19. afterpython/cli/commands/pre_commit.py +1 -1
  20. afterpython/cli/commands/preview.py +1 -1
  21. afterpython/cli/commands/start.py +4 -8
  22. afterpython/cli/commands/sync.py +21 -65
  23. afterpython/cli/commands/update.py +8 -31
  24. afterpython/cli/main.py +14 -75
  25. afterpython/const.py +2 -1
  26. afterpython/cz.toml +27 -0
  27. afterpython/pcu.py +1 -3
  28. afterpython/templates/deploy-workflow-template.yml +5 -22
  29. afterpython/templates/release-workflow-template.yml +3 -3
  30. afterpython/templates/ruff-template.toml +1 -1
  31. afterpython/tools/_afterpython.py +10 -73
  32. afterpython/tools/_git.py +2 -28
  33. afterpython/tools/commitizen.py +45 -5
  34. afterpython/tools/github_actions.py +53 -23
  35. afterpython/tools/myst.py +38 -82
  36. afterpython/tools/pre_commit.py +31 -6
  37. afterpython/tools/pyproject.py +2 -40
  38. afterpython/utils.py +3 -87
  39. {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev4.dist-info}/METADATA +13 -39
  40. afterpython-0.1.0.dev4.dist-info/RECORD +47 -0
  41. {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev4.dist-info}/WHEEL +1 -1
  42. afterpython/builders/content_json.py +0 -131
  43. afterpython/builders/index_md.py +0 -94
  44. afterpython/builders/jupyter_notebook.py +0 -293
  45. afterpython/builders/markdown.py +0 -271
  46. afterpython/cli/commands/add.py +0 -67
  47. afterpython/cli/commands/init_branch_rules.py +0 -9
  48. afterpython/cli/commands/lock.py +0 -23
  49. afterpython/cli/commands/remove.py +0 -67
  50. afterpython/templates/ci-workflow-template.yml +0 -197
  51. afterpython/templates/cz-template.toml +0 -7
  52. afterpython/templates/dependabot-template.yml +0 -30
  53. afterpython/tools/branch_rules.py +0 -106
  54. afterpython-0.1.0.dist-info/RECORD +0 -57
  55. {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev4.dist-info}/entry_points.txt +0 -0
@@ -1,271 +0,0 @@
1
- from pathlib import Path
2
-
3
- import click
4
-
5
- import afterpython as ap
6
- from afterpython.const import CONTENT_TYPES
7
-
8
-
9
- def _read_markdown(markdown_path: Path, content_path: Path) -> str | None:
10
- """Read and validate a markdown file.
11
-
12
- Args:
13
- markdown_path: Absolute path to the markdown file
14
- content_path: Path relative to afterpython/ for logging
15
-
16
- Returns:
17
- Markdown content as a string if valid, None if invalid or error occurred
18
- """
19
- try:
20
- with open(markdown_path, encoding="utf-8") as f:
21
- content = f.read()
22
- return content
23
- except FileNotFoundError:
24
- click.echo(f"✗ Skipping {content_path} - file not found")
25
- return None
26
- except Exception as e:
27
- click.echo(f"✗ Error reading {content_path}: {e}")
28
- return None
29
-
30
-
31
- def _write_markdown(content: str, markdown_path: Path):
32
- """Write markdown content to file.
33
-
34
- Args:
35
- content: The markdown content to write
36
- markdown_path: Absolute path to the markdown file
37
- """
38
- with open(markdown_path, "w", encoding="utf-8") as f:
39
- f.write(content)
40
-
41
-
42
- def _has_frontmatter(content: str) -> bool:
43
- """Check if markdown content has frontmatter.
44
-
45
- Args:
46
- content: The markdown file content as a string
47
-
48
- Returns:
49
- True if the content starts with ---, False otherwise
50
- """
51
- return content.strip().startswith("---")
52
-
53
-
54
- def _read_frontmatter(content: str) -> str | None:
55
- """Read frontmatter content from markdown.
56
-
57
- Args:
58
- content: The markdown file content as a string
59
-
60
- Returns:
61
- Frontmatter content as a string (including --- delimiters) if it exists, None otherwise
62
- """
63
- if not _has_frontmatter(content):
64
- return None
65
-
66
- lines = content.split("\n")
67
-
68
- # Find the closing --- of frontmatter
69
- closing_index = -1
70
- for i in range(1, len(lines)):
71
- if lines[i].strip() == "---":
72
- closing_index = i
73
- break
74
-
75
- if closing_index == -1:
76
- return None
77
-
78
- # Return frontmatter including both --- delimiters
79
- return "\n".join(lines[: closing_index + 1])
80
-
81
-
82
- def _write_frontmatter(content: str, frontmatter: str) -> str:
83
- """Write frontmatter content to markdown.
84
-
85
- Low-level function that handles frontmatter replacement.
86
- If frontmatter exists in content, replaces it. If not, prepends it.
87
-
88
- Args:
89
- content: The markdown file content as a string
90
- frontmatter: The complete frontmatter content as a string (should include --- delimiters)
91
-
92
- Returns:
93
- The updated markdown content with the new frontmatter
94
- """
95
- if _has_frontmatter(content):
96
- # Replace existing frontmatter
97
- lines = content.split("\n")
98
-
99
- # Find the closing --- of existing frontmatter
100
- closing_index = -1
101
- for i in range(1, len(lines)):
102
- if lines[i].strip() == "---":
103
- closing_index = i
104
- break
105
-
106
- if closing_index > -1:
107
- # Remove old frontmatter and prepend new one
108
- body = "\n".join(lines[closing_index + 1 :])
109
- return frontmatter + "\n" + body
110
- else:
111
- # Malformed frontmatter, just prepend new frontmatter
112
- return frontmatter + "\n" + content
113
- else:
114
- # No frontmatter exists, prepend it
115
- return frontmatter + "\n" + content
116
-
117
-
118
- def _ensure_blank_line_after_frontmatter(content: str) -> str:
119
- """Ensure there's a blank line between frontmatter and content.
120
-
121
- Args:
122
- content: The markdown content
123
-
124
- Returns:
125
- Content with blank line after frontmatter if frontmatter exists
126
- """
127
- if not _has_frontmatter(content):
128
- return content
129
-
130
- lines = content.split("\n")
131
-
132
- # Find the closing --- of frontmatter
133
- closing_index = -1
134
- for i in range(1, len(lines)):
135
- if lines[i].strip() == "---":
136
- closing_index = i
137
- break
138
-
139
- if closing_index == -1:
140
- return content
141
-
142
- # Check if there's already a blank line after the closing ---, and if the next line is not empty, insert a blank line
143
- if closing_index + 1 < len(lines) and lines[closing_index + 1].strip() != "":
144
- lines.insert(closing_index + 1, "")
145
-
146
- return "\n".join(lines)
147
-
148
-
149
- def _add_fields_to_frontmatter(content: str, fields: dict[str, str]) -> str:
150
- """Add or update fields in frontmatter.
151
-
152
- High-level function that handles frontmatter field manipulation.
153
- If frontmatter exists, adds new fields to it. If not, creates new frontmatter with those fields.
154
-
155
- Args:
156
- content: The markdown file content as a string
157
- fields: A dict of fields to add/update (e.g., {"thumbnail": "null"})
158
-
159
- Returns:
160
- The updated markdown content with the new fields in frontmatter
161
- """
162
- existing_frontmatter = _read_frontmatter(content)
163
-
164
- if existing_frontmatter:
165
- # Parse existing frontmatter and add new fields
166
- lines = existing_frontmatter.split("\n")
167
-
168
- # Find the closing --- of frontmatter
169
- closing_index = -1
170
- for i in range(1, len(lines)):
171
- if lines[i].strip() == "---":
172
- closing_index = i
173
- break
174
-
175
- if closing_index > 0:
176
- # Insert new fields before the closing ---
177
- for key, value in fields.items():
178
- # Check if field already exists
179
- if not any(line.strip().startswith(f"{key}:") for line in lines):
180
- lines.insert(closing_index, f"{key}: {value}")
181
- closing_index += 1 # Adjust index for next insertion
182
-
183
- new_frontmatter = "\n".join(lines)
184
- return _write_frontmatter(content, new_frontmatter)
185
- else:
186
- # Create new frontmatter with the provided fields
187
- field_lines = [f"{key}: {value}" for key, value in fields.items()]
188
- new_frontmatter = "---\n" + "\n".join(field_lines) + "\n---"
189
- return _write_frontmatter(content, new_frontmatter)
190
-
191
- return content
192
-
193
-
194
- def _add_thumbnail_to_markdown(
195
- content: str, thumbnail: str, content_path: Path
196
- ) -> tuple[str, bool]:
197
- """Add thumbnail field to a markdown file's frontmatter.
198
-
199
- Args:
200
- content: The markdown content
201
- thumbnail: The thumbnail value to add
202
- content_path: Path for logging purposes
203
-
204
- Returns:
205
- Tuple of (modified_content, was_modified)
206
- """
207
- # Check if thumbnail is already set in frontmatter
208
- frontmatter_content = _read_frontmatter(content)
209
- if frontmatter_content and "thumbnail:" in frontmatter_content:
210
- return content, False
211
-
212
- # Add thumbnail using the fields parameter
213
- modified_content = _add_fields_to_frontmatter(
214
- content, fields={"thumbnail": thumbnail}
215
- )
216
-
217
- if frontmatter_content:
218
- click.echo(
219
- f" ↳ Added 'thumbnail: {thumbnail}' to frontmatter in: {content_path}"
220
- )
221
- else:
222
- click.echo(
223
- f" ↳ Created frontmatter with 'thumbnail: {thumbnail}' in: {content_path}"
224
- )
225
-
226
- return modified_content, True
227
-
228
-
229
- def build_markdown():
230
- """Build markdown files for all content types"""
231
- from afterpython.tools._afterpython import get_default_thumbnail
232
-
233
- for content_type in CONTENT_TYPES:
234
- # Skip doc content type - docs don't need default thumbnails
235
- if content_type == "doc":
236
- continue
237
-
238
- click.echo(f"Building markdown files for {content_type}/...")
239
-
240
- path = ap.paths.afterpython_path / content_type.lower()
241
-
242
- # Iterate over all .md files
243
- for markdown_path in path.rglob("*.md"):
244
- # Skip files in _build directory
245
- if "_build" in markdown_path.parts:
246
- continue
247
-
248
- # Get path relative to afterpython/
249
- content_path = markdown_path.relative_to(ap.paths.afterpython_path)
250
-
251
- # Get default thumbnail for this content type
252
- default_thumbnail = get_default_thumbnail(content_type, markdown_path)
253
-
254
- # Read the markdown file
255
- content = _read_markdown(markdown_path, content_path)
256
- if content is None:
257
- continue
258
-
259
- # Ensure blank line after frontmatter (fixes existing files)
260
- original_content = content
261
- content = _ensure_blank_line_after_frontmatter(content)
262
- blank_line_added = content != original_content
263
-
264
- # Add thumbnail to frontmatter
265
- modified_content, was_modified = _add_thumbnail_to_markdown(
266
- content, default_thumbnail, content_path
267
- )
268
-
269
- # Write back if modified (either blank line or thumbnail)
270
- if was_modified or blank_line_added:
271
- _write_markdown(modified_content, markdown_path)
@@ -1,67 +0,0 @@
1
- import subprocess
2
-
3
- import click
4
- from click.exceptions import Exit
5
-
6
- from afterpython.utils import has_pixi, has_uv
7
-
8
-
9
- @click.command()
10
- @click.option(
11
- "--optional",
12
- type=str,
13
- default=None,
14
- required=False,
15
- help="Add to an optional dependency group (pixi: mapped to 'optional' feature)",
16
- )
17
- @click.option(
18
- "--group",
19
- type=str,
20
- default=None,
21
- required=False,
22
- help="Add to a dependency group (pixi: mapped to same-named feature)",
23
- )
24
- @click.argument("lib", type=str, required=True)
25
- def add(optional: str | None, group: str | None, lib: str):
26
- """Add a new dependency to the project (manages both uv and pixi if present)"""
27
- if not has_uv():
28
- click.echo("uv not found. Please install uv first.")
29
- return
30
-
31
- if optional and group:
32
- click.echo("Error: Cannot specify both --optional and --group")
33
- raise Exit(1)
34
-
35
- result = subprocess.run(
36
- [
37
- "uv",
38
- "add",
39
- *(["--optional", optional] if optional else []),
40
- *(["--group", group] if group else []),
41
- lib,
42
- ],
43
- check=False,
44
- )
45
- if result.returncode != 0:
46
- raise Exit(result.returncode)
47
-
48
- if has_pixi():
49
- # NOTE: pixi doesn't support --optional, so we need to use --feature instead
50
- if optional:
51
- feature_name = "optional"
52
- elif group:
53
- feature_name = group
54
- else:
55
- feature_name = None
56
- result = subprocess.run(
57
- [
58
- "pixi",
59
- "add",
60
- "--pypi",
61
- *(["--feature", feature_name] if feature_name else []),
62
- lib,
63
- ],
64
- check=False,
65
- )
66
- if result.returncode != 0:
67
- raise Exit(result.returncode)
@@ -1,9 +0,0 @@
1
- import click
2
-
3
-
4
- @click.command()
5
- def init_branch_rules():
6
- """Create default branch protection rules for the current repository"""
7
- from afterpython.tools.branch_rules import create_default_branch_rules
8
-
9
- create_default_branch_rules()
@@ -1,23 +0,0 @@
1
- import subprocess
2
-
3
- import click
4
- from click.exceptions import Exit
5
-
6
- from afterpython.utils import has_pixi, has_uv
7
-
8
-
9
- @click.command()
10
- def lock():
11
- """Lock project dependencies (manages both uv and pixi if present)"""
12
- if not has_uv():
13
- click.echo("uv not found. Please install uv first.")
14
- return
15
-
16
- result = subprocess.run(["uv", "lock"], check=False)
17
- if result.returncode != 0:
18
- raise Exit(result.returncode)
19
-
20
- if has_pixi():
21
- result = subprocess.run(["pixi", "lock"], check=False)
22
- if result.returncode != 0:
23
- raise Exit(result.returncode)
@@ -1,67 +0,0 @@
1
- import subprocess
2
-
3
- import click
4
- from click.exceptions import Exit
5
-
6
- from afterpython.utils import has_pixi, has_uv
7
-
8
-
9
- @click.command()
10
- @click.option(
11
- "--optional",
12
- type=str,
13
- default=None,
14
- required=False,
15
- help="Remove from an optional dependency group (pixi: mapped to 'optional' feature)",
16
- )
17
- @click.option(
18
- "--group",
19
- type=str,
20
- default=None,
21
- required=False,
22
- help="Remove from a dependency group (pixi: mapped to same-named feature)",
23
- )
24
- @click.argument("lib", type=str, required=True)
25
- def remove(optional: str | None, group: str | None, lib: str):
26
- """Remove a dependency from the project (manages both uv and pixi if present)"""
27
- if not has_uv():
28
- click.echo("uv not found. Please install uv first.")
29
- return
30
-
31
- if optional and group:
32
- click.echo("Error: Cannot specify both --optional and --group")
33
- raise Exit(1)
34
-
35
- result = subprocess.run(
36
- [
37
- "uv",
38
- "remove",
39
- *(["--optional", optional] if optional else []),
40
- *(["--group", group] if group else []),
41
- lib,
42
- ],
43
- check=False,
44
- )
45
- if result.returncode != 0:
46
- raise Exit(result.returncode)
47
-
48
- if has_pixi():
49
- # NOTE: pixi doesn't support --optional, so we need to use --feature instead
50
- if optional:
51
- feature_name = "optional"
52
- elif group:
53
- feature_name = group
54
- else:
55
- feature_name = None
56
- result = subprocess.run(
57
- [
58
- "pixi",
59
- "remove",
60
- "--pypi",
61
- *(["--feature", feature_name] if feature_name else []),
62
- lib,
63
- ],
64
- check=False,
65
- )
66
- if result.returncode != 0:
67
- raise Exit(result.returncode)
@@ -1,197 +0,0 @@
1
- name: CI
2
-
3
- # Trigger CI on pushes to main and all pull requests
4
- # This ensures every code change is validated before merging
5
- on:
6
- push:
7
- branches:
8
- - main
9
- pull_request:
10
- # Run on all PRs regardless of target branch
11
- branches:
12
- - '**'
13
-
14
- jobs:
15
- # Job 1: Lint and Format Check
16
- # Runs ruff to check code quality and formatting
17
- lint:
18
- runs-on: ubuntu-latest
19
- steps:
20
- - name: Checkout code
21
- uses: actions/checkout@v6
22
-
23
- - name: Set up Python
24
- uses: actions/setup-python@v6
25
- with:
26
- python-version: '3.11'
27
-
28
- - name: Install uv
29
- uses: astral-sh/setup-uv@v7
30
- with:
31
- version: "latest"
32
-
33
- - name: Install dependencies
34
- # Install the package with uv in system mode
35
- # This installs ruff and other tools defined in dependencies
36
- run: uv pip install --system .
37
-
38
- - name: Run ruff check
39
- run: ruff check --config ./afterpython/ruff.toml .
40
-
41
- - name: Run ruff format check
42
- # --check flag ensures it only validates, doesn't reformat
43
- run: ruff format --check --config ./afterpython/ruff.toml .
44
-
45
- # Job 2: Detect Test Strategy
46
- # Determines whether to use pixi or uv based on pixi.toml presence
47
- detect-test-strategy:
48
- runs-on: ubuntu-latest
49
- outputs:
50
- use_pixi: ${{ steps.check.outputs.use_pixi }}
51
- steps:
52
- - name: Checkout code
53
- uses: actions/checkout@v6
54
-
55
- - name: Check for pixi.toml
56
- id: check
57
- run: |
58
- if [ -f "pixi.toml" ]; then
59
- echo "use_pixi=true" >> $GITHUB_OUTPUT
60
- else
61
- echo "use_pixi=false" >> $GITHUB_OUTPUT
62
- fi
63
-
64
- # Job 3.1: Test Suite - UV Workflow
65
- # Traditional Python testing with uv for projects without pixi
66
- test-uv:
67
- needs: detect-test-strategy
68
- if: needs.detect-test-strategy.outputs.use_pixi == 'false'
69
- runs-on: ubuntu-latest
70
- strategy:
71
- matrix:
72
- # TODO: support python 3.14
73
- python-version: ['3.11', '3.12', '3.13']
74
- fail-fast: false
75
-
76
- steps:
77
- - name: Checkout code
78
- uses: actions/checkout@v6
79
-
80
- - name: Set up Python ${{ matrix.python-version }}
81
- uses: actions/setup-python@v6
82
- with:
83
- python-version: ${{ matrix.python-version }}
84
-
85
- - name: Install uv
86
- uses: astral-sh/setup-uv@v7
87
- with:
88
- version: "latest"
89
-
90
- - name: Install dependencies
91
- run: |
92
- # Install package, main dependencies, and test dependencies
93
- # If no [dependency-groups] test exists, only the package and main dependencies are installed
94
- uv pip install --system . --group test || uv pip install --system .
95
-
96
- - name: Run tests with pytest
97
- # Run pytest with verbose output
98
- # Exit code 5 (no tests collected) is treated as success
99
- run: |
100
- pytest -v || if [ $? -eq 5 ]; then exit 0; else exit $?; fi
101
-
102
- # Job 3.2: Test Suite - Pixi Workflow
103
- # Pixi-based testing for projects using pixi.toml
104
- test-pixi:
105
- needs: detect-test-strategy
106
- if: needs.detect-test-strategy.outputs.use_pixi == 'true'
107
- runs-on: ubuntu-latest
108
- strategy:
109
- matrix:
110
- # TODO: support python 3.14
111
- environment: ['py311', 'py312', 'py313']
112
- fail-fast: false
113
-
114
- steps:
115
- - name: Checkout code
116
- uses: actions/checkout@v6
117
-
118
- - name: Set up pixi
119
- uses: prefix-dev/setup-pixi@v0.9.3
120
- with:
121
- pixi-version: v0.60.0
122
- cache: true
123
- # Optional: Uncomment if you need prefix.dev authentication
124
- # auth-host: prefix.dev
125
- # auth-token: ${{ secrets.PREFIX_DEV_TOKEN }}
126
-
127
- - name: Run tests with pixi
128
- # Runs test in specific Python environment (py311, py312, py313)
129
- # Assumes you have environments defined in pixi.toml with a "test" task
130
- # Example pixi.toml:
131
- # [environments]
132
- # py311 = ["py311", "test"]
133
- # [feature.test.tasks]
134
- # test = "pytest -v"
135
- # Note: Exit code 5 (no tests collected) is treated as success
136
- run: |
137
- pixi run -e ${{ matrix.environment }} test || if [ $? -eq 5 ]; then exit 0; else exit $?; fi
138
-
139
- # Job 3.3: Test Suite - Complete
140
- # Unified test status for branch protection
141
- test:
142
- if: always()
143
- needs: [detect-test-strategy, test-uv, test-pixi]
144
- runs-on: ubuntu-latest
145
- steps:
146
- - name: Check test results
147
- run: |
148
- uv_result="${{ needs.test-uv.result }}"
149
- pixi_result="${{ needs.test-pixi.result }}"
150
- # One should succeed, the other should be skipped
151
- if [ "$uv_result" == "success" ] || [ "$uv_result" == "skipped" ]; then
152
- if [ "$pixi_result" == "success" ] || [ "$pixi_result" == "skipped" ]; then
153
- echo "All tests passed!"
154
- exit 0
155
- fi
156
- fi
157
- echo "Tests failed: uv=$uv_result, pixi=$pixi_result"
158
- exit 1
159
-
160
- # Job 4: Build Verification
161
- # Ensures the package can be built successfully
162
- build:
163
- runs-on: ubuntu-latest
164
- steps:
165
- - name: Checkout code
166
- uses: actions/checkout@v6
167
-
168
- - name: Set up Python
169
- uses: actions/setup-python@v6
170
- with:
171
- python-version: '3.11'
172
-
173
- - name: Install uv
174
- uses: astral-sh/setup-uv@v7
175
- with:
176
- version: "latest"
177
-
178
- - name: Build package
179
- run: uv build
180
-
181
- - name: List build artifacts
182
- # Show what was built (wheel + sdist)
183
- # Useful for debugging build issues
184
- run: ls -lh dist/
185
-
186
- - name: Install built package
187
- # Test that the built wheel can be installed
188
- # This catches packaging issues like missing files
189
- run: uv pip install --system dist/*.whl
190
-
191
- - name: Verify installation
192
- # Confirm the CLI entry point works
193
- # This ensures the package is usable after installation
194
- run: ap --help
195
-
196
- # Job 5: Type Check
197
- # typecheck:
@@ -1,7 +0,0 @@
1
- [tool.commitizen]
2
- name = "cz_conventional_commits"
3
- tag_format = "v$version"
4
- version_scheme = "pep440"
5
- version_provider = "uv"
6
- update_changelog_on_bump = false
7
- major_version_zero = true
@@ -1,30 +0,0 @@
1
- # Dependabot configuration for automatic dependency updates
2
- # See: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
3
-
4
- version: 2
5
- updates:
6
- # Update GitHub Actions versions
7
- # This keeps your workflow actions secure and up-to-date
8
- - package-ecosystem: "github-actions"
9
- directory: "/"
10
- schedule:
11
- # Check for updates monthly (less noisy than weekly)
12
- interval: "monthly"
13
- labels:
14
- - "dependencies"
15
- - "github-actions"
16
- # Group all GitHub Actions updates into a single PR
17
- # This reduces PR noise and makes reviewing easier
18
- groups:
19
- github-actions:
20
- patterns:
21
- - "*"
22
- # Automatically add reviewers (optional - uncomment and customize)
23
- # reviewers:
24
- # - "your-username"
25
- # Limit how many Dependabot PRs can be open at once (optional)
26
- # Default is 5, increase if you want more concurrent PRs
27
- # open-pull-requests-limit: 10
28
- #
29
- # Note: Auto-merge is configured in GitHub repo settings, not here.
30
- # Go to: Settings → General → Pull Requests → Allow auto-merge