afterpython 0.1.0.dev7__py3-none-any.whl → 0.1.0.dev8__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.
- afterpython/cli/commands/build.py +1 -1
- afterpython/cli/commands/init.py +22 -8
- afterpython/cli/commands/init_branch_rules.py +9 -0
- afterpython/cli/main.py +3 -0
- afterpython/templates/ci-workflow-template.yml +197 -0
- afterpython/templates/dependabot-template.yml +30 -0
- afterpython/templates/deploy-workflow-template.yml +5 -5
- afterpython/templates/release-workflow-template.yml +3 -3
- afterpython/tools/_git.py +28 -2
- afterpython/tools/branch_rules.py +107 -0
- afterpython/tools/github_actions.py +23 -53
- afterpython/utils.py +5 -0
- {afterpython-0.1.0.dev7.dist-info → afterpython-0.1.0.dev8.dist-info}/METADATA +10 -2
- {afterpython-0.1.0.dev7.dist-info → afterpython-0.1.0.dev8.dist-info}/RECORD +16 -14
- {afterpython-0.1.0.dev7.dist-info → afterpython-0.1.0.dev8.dist-info}/WHEEL +1 -1
- afterpython/.pre-commit-config.yaml +0 -48
- afterpython/cz.toml +0 -27
- {afterpython-0.1.0.dev7.dist-info → afterpython-0.1.0.dev8.dist-info}/entry_points.txt +0 -0
afterpython/cli/commands/init.py
CHANGED
|
@@ -47,8 +47,14 @@ def init_website():
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
@click.command()
|
|
50
|
+
@click.option(
|
|
51
|
+
"--yes",
|
|
52
|
+
"-y",
|
|
53
|
+
is_flag=True,
|
|
54
|
+
help="Automatically answer yes to all prompts",
|
|
55
|
+
)
|
|
50
56
|
@click.pass_context
|
|
51
|
-
def init(ctx):
|
|
57
|
+
def init(ctx, yes):
|
|
52
58
|
"""Initialize afterpython with MyST Markdown (by default) and project website template"""
|
|
53
59
|
from afterpython.tools.pyproject import init_pyproject
|
|
54
60
|
from afterpython.tools._afterpython import init_afterpython
|
|
@@ -56,8 +62,8 @@ def init(ctx):
|
|
|
56
62
|
from afterpython.tools.pre_commit import init_pre_commit
|
|
57
63
|
from afterpython.tools.commitizen import init_commitizen
|
|
58
64
|
from afterpython.tools.github_actions import (
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
create_workflow,
|
|
66
|
+
create_dependabot,
|
|
61
67
|
)
|
|
62
68
|
|
|
63
69
|
paths = ctx.obj["paths"]
|
|
@@ -79,20 +85,28 @@ def init(ctx):
|
|
|
79
85
|
|
|
80
86
|
init_website()
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
create_workflow("deploy")
|
|
89
|
+
create_workflow("ci")
|
|
90
|
+
|
|
91
|
+
if yes or click.confirm(
|
|
83
92
|
f"\nCreate .pre-commit-config.yaml in {afterpython_path}?", default=True
|
|
84
93
|
):
|
|
85
94
|
init_pre_commit()
|
|
86
95
|
|
|
87
|
-
if click.confirm(f"\nCreate ruff.toml in {afterpython_path}?", default=True):
|
|
96
|
+
if yes or click.confirm(f"\nCreate ruff.toml in {afterpython_path}?", default=True):
|
|
88
97
|
init_ruff_toml()
|
|
89
98
|
|
|
90
|
-
if click.confirm(
|
|
99
|
+
if yes or click.confirm(
|
|
91
100
|
f"\nCreate commitizen configuration (cz.toml) in {afterpython_path} "
|
|
92
101
|
f"and release workflow in .github/workflows/release.yml?",
|
|
93
102
|
default=True,
|
|
94
103
|
):
|
|
95
104
|
init_commitizen()
|
|
96
|
-
|
|
105
|
+
create_workflow("release")
|
|
97
106
|
|
|
98
|
-
|
|
107
|
+
if yes or click.confirm(
|
|
108
|
+
"\nCreate Dependabot configuration (.github/dependabot.yml) "
|
|
109
|
+
"to auto-update GitHub Actions versions?",
|
|
110
|
+
default=True,
|
|
111
|
+
):
|
|
112
|
+
create_dependabot()
|
afterpython/cli/main.py
CHANGED
|
@@ -23,6 +23,7 @@ from afterpython.cli.commands.commitizen import commitizen
|
|
|
23
23
|
from afterpython.cli.commands.commit import commit
|
|
24
24
|
from afterpython.cli.commands.bump import bump
|
|
25
25
|
from afterpython.cli.commands.release import release
|
|
26
|
+
from afterpython.cli.commands.init_branch_rules import init_branch_rules
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@tui(command="tui", help="Open terminal UI")
|
|
@@ -50,6 +51,7 @@ afterpython_group.add_command(build)
|
|
|
50
51
|
afterpython_group.add_command(dev)
|
|
51
52
|
afterpython_group.add_command(update)
|
|
52
53
|
afterpython_group.add_command(check)
|
|
54
|
+
afterpython_group.add_command(check, name="lint")
|
|
53
55
|
afterpython_group.add_command(format)
|
|
54
56
|
afterpython_group.add_command(sync)
|
|
55
57
|
afterpython_group.add_command(start)
|
|
@@ -69,3 +71,4 @@ afterpython_group.add_command(commitizen, name="cz")
|
|
|
69
71
|
afterpython_group.add_command(commit)
|
|
70
72
|
afterpython_group.add_command(bump)
|
|
71
73
|
afterpython_group.add_command(release)
|
|
74
|
+
afterpython_group.add_command(init_branch_rules)
|
|
@@ -0,0 +1,197 @@
|
|
|
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.59.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:
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
steps:
|
|
37
37
|
- name: Checkout code
|
|
38
|
-
uses: actions/checkout@
|
|
38
|
+
uses: actions/checkout@v6
|
|
39
39
|
|
|
40
40
|
- name: Install pnpm
|
|
41
41
|
uses: pnpm/action-setup@v4
|
|
@@ -43,19 +43,19 @@ jobs:
|
|
|
43
43
|
version: 10
|
|
44
44
|
|
|
45
45
|
- name: Set up Node.js
|
|
46
|
-
uses: actions/setup-node@
|
|
46
|
+
uses: actions/setup-node@v6
|
|
47
47
|
with:
|
|
48
48
|
node-version: '24'
|
|
49
49
|
cache: 'pnpm'
|
|
50
50
|
cache-dependency-path: './afterpython/_website/pnpm-lock.yaml'
|
|
51
51
|
|
|
52
52
|
- name: Set up Python
|
|
53
|
-
uses: actions/setup-python@
|
|
53
|
+
uses: actions/setup-python@v6
|
|
54
54
|
with:
|
|
55
55
|
python-version: '3.11'
|
|
56
56
|
|
|
57
57
|
- name: Install uv
|
|
58
|
-
uses: astral-sh/setup-uv@
|
|
58
|
+
uses: astral-sh/setup-uv@v7
|
|
59
59
|
with:
|
|
60
60
|
version: "latest"
|
|
61
61
|
|
|
@@ -71,7 +71,7 @@ jobs:
|
|
|
71
71
|
ap build
|
|
72
72
|
|
|
73
73
|
- name: Upload artifact
|
|
74
|
-
uses: actions/upload-pages-artifact@
|
|
74
|
+
uses: actions/upload-pages-artifact@v4
|
|
75
75
|
with:
|
|
76
76
|
path: './afterpython/_website/build'
|
|
77
77
|
|
|
@@ -14,15 +14,15 @@ jobs:
|
|
|
14
14
|
|
|
15
15
|
steps:
|
|
16
16
|
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@
|
|
17
|
+
uses: actions/checkout@v6
|
|
18
18
|
|
|
19
19
|
- name: Set up Python
|
|
20
|
-
uses: actions/setup-python@
|
|
20
|
+
uses: actions/setup-python@v6
|
|
21
21
|
with:
|
|
22
22
|
python-version: '3.11'
|
|
23
23
|
|
|
24
24
|
- name: Install uv
|
|
25
|
-
uses: astral-sh/setup-uv@
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
26
|
with:
|
|
27
27
|
version: "latest"
|
|
28
28
|
|
afterpython/tools/_git.py
CHANGED
|
@@ -58,7 +58,7 @@ def get_github_url() -> str | None:
|
|
|
58
58
|
return None
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
def
|
|
61
|
+
def is_gh_authenticated():
|
|
62
62
|
"""Guide user through GitHub authentication."""
|
|
63
63
|
if not has_gh():
|
|
64
64
|
print("""
|
|
@@ -89,7 +89,6 @@ Please authenticate with GitHub:
|
|
|
89
89
|
""")
|
|
90
90
|
return False
|
|
91
91
|
|
|
92
|
-
print("✓ GitHub authentication verified")
|
|
93
92
|
return True
|
|
94
93
|
|
|
95
94
|
|
|
@@ -107,5 +106,32 @@ def get_github_username() -> str | None:
|
|
|
107
106
|
return result.stdout.strip()
|
|
108
107
|
|
|
109
108
|
|
|
109
|
+
def get_current_user_id() -> int | None:
|
|
110
|
+
"""
|
|
111
|
+
Get the GitHub user ID of the currently authenticated user.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
User ID or None if error
|
|
115
|
+
"""
|
|
116
|
+
if not is_gh_authenticated():
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
result = subprocess.run(
|
|
120
|
+
["gh", "api", "user", "--jq", ".id"],
|
|
121
|
+
capture_output=True,
|
|
122
|
+
text=True,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if result.returncode != 0:
|
|
126
|
+
print(f"Error fetching user ID: {result.stderr}")
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
return int(result.stdout.strip())
|
|
131
|
+
except ValueError:
|
|
132
|
+
print("Error: Failed to parse user ID")
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
|
|
110
136
|
# TODO: use gh's token for pygithub to get repo issues
|
|
111
137
|
# def get_repo_issues(owner: str, repo: str) -> list[dict]:
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Branch protection rules for AfterPython projects.
|
|
3
|
+
Uses gh CLI to create GitHub rulesets.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import subprocess
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
|
|
10
|
+
from afterpython.tools._git import is_gh_authenticated
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
DEFAULT_RULESET = {
|
|
14
|
+
"name": "afterpython-default", # The ruleset identifier in GitHub
|
|
15
|
+
"target": "branch", # This ruleset applies to branches (not tags)
|
|
16
|
+
"enforcement": "active", # Rules are enforced (vs "disabled" or "evaluate")
|
|
17
|
+
"conditions": { # Which branches this ruleset applies to
|
|
18
|
+
"ref_name": {
|
|
19
|
+
"include": ["refs/heads/main"], # Only protect the 'main' branch
|
|
20
|
+
"exclude": [], # No exclusions
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"bypass_actors": [
|
|
24
|
+
{
|
|
25
|
+
"actor_id": 5, # Repository admin role
|
|
26
|
+
"actor_type": "RepositoryRole",
|
|
27
|
+
"bypass_mode": "always",
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"rules": [ # Array of protection rules
|
|
31
|
+
# Rule 1: No Force Pushes
|
|
32
|
+
{"type": "non_fast_forward"}, # Prevents git push --force
|
|
33
|
+
# Rule 2: No Branch Deletion
|
|
34
|
+
{"type": "deletion"}, # Prevents branch from being deleted
|
|
35
|
+
# Rule 3: CI Status Checks
|
|
36
|
+
{
|
|
37
|
+
"type": "required_status_checks",
|
|
38
|
+
"parameters": {
|
|
39
|
+
"required_status_checks": [
|
|
40
|
+
{"context": "lint"},
|
|
41
|
+
{"context": "test"},
|
|
42
|
+
{"context": "build"},
|
|
43
|
+
],
|
|
44
|
+
# The PR branch must be up to date with the base branch (main) before merging
|
|
45
|
+
"strict_required_status_checks_policy": True,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def list_rulesets() -> list[dict] | None:
|
|
53
|
+
"""
|
|
54
|
+
List existing rulesets for the current repository.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
List of rulesets or None if error
|
|
58
|
+
"""
|
|
59
|
+
if not is_gh_authenticated():
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
result = subprocess.run(
|
|
63
|
+
["gh", "api", "repos/{owner}/{repo}/rulesets"],
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
print(f"Error listing rulesets: {result.stderr}")
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
return json.loads(result.stdout)
|
|
74
|
+
except json.JSONDecodeError:
|
|
75
|
+
print("Error: Failed to parse rulesets JSON")
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def create_default_branch_rules(branch: str = "main") -> bool:
|
|
80
|
+
if not is_gh_authenticated():
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
# Check if ruleset already exists
|
|
84
|
+
existing_rulesets = list_rulesets()
|
|
85
|
+
if existing_rulesets:
|
|
86
|
+
print(f"Ruleset '{DEFAULT_RULESET['name']}' already exists.")
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
# Build payload
|
|
90
|
+
payload = deepcopy(DEFAULT_RULESET)
|
|
91
|
+
if branch != "main":
|
|
92
|
+
payload["conditions"]["ref_name"]["include"] = [f"refs/heads/{branch}"]
|
|
93
|
+
|
|
94
|
+
# Create ruleset
|
|
95
|
+
result = subprocess.run(
|
|
96
|
+
["gh", "api", "-X", "POST", "repos/{owner}/{repo}/rulesets", "--input", "-"],
|
|
97
|
+
input=json.dumps(payload),
|
|
98
|
+
capture_output=True,
|
|
99
|
+
text=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if result.returncode != 0:
|
|
103
|
+
print(f"Error creating ruleset: {result.stderr}")
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
print(f"✓ Created branch ruleset '{DEFAULT_RULESET['name']}' for {branch=}")
|
|
107
|
+
return True
|
|
@@ -1,78 +1,48 @@
|
|
|
1
1
|
import shutil
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import click
|
|
4
5
|
|
|
5
6
|
import afterpython as ap
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
def
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
This workflow triggers on version tags and:
|
|
13
|
-
- Builds the package with uv
|
|
14
|
-
- Publishes to PyPI using trusted publishing
|
|
15
|
-
- Creates GitHub releases (with pre-release detection)
|
|
16
|
-
"""
|
|
17
|
-
user_path = ap.paths.user_path
|
|
18
|
-
workflow_dir = user_path / ".github" / "workflows"
|
|
19
|
-
workflow_path = workflow_dir / "release.yml"
|
|
20
|
-
|
|
21
|
-
if workflow_path.exists():
|
|
22
|
-
click.echo(f"GitHub Actions release workflow {workflow_path} already exists")
|
|
9
|
+
def _copy_github_template(template_name: str, target_path: Path):
|
|
10
|
+
"""Helper to copy GitHub-related templates"""
|
|
11
|
+
if target_path.exists():
|
|
12
|
+
click.echo(f"{target_path} already exists")
|
|
23
13
|
return
|
|
24
14
|
|
|
25
|
-
# Create
|
|
26
|
-
|
|
15
|
+
# Create parent directory if it doesn't exist
|
|
16
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
27
17
|
|
|
28
18
|
# Copy template from package
|
|
29
|
-
template_path = ap.paths.templates_path /
|
|
19
|
+
template_path = ap.paths.templates_path / template_name
|
|
30
20
|
if not template_path.exists():
|
|
31
21
|
raise FileNotFoundError(
|
|
32
22
|
f"Template file not found: {template_path}\n"
|
|
33
23
|
"This might indicate a corrupted installation. Please reinstall afterpython."
|
|
34
24
|
)
|
|
35
25
|
|
|
36
|
-
shutil.copy(template_path,
|
|
37
|
-
|
|
38
|
-
click.echo(
|
|
39
|
-
"\n📋 Next steps to enable releases:\n"
|
|
40
|
-
" 1. Enable PyPI trusted publishing:\n"
|
|
41
|
-
" - Go to https://pypi.org/manage/account/publishing/\n"
|
|
42
|
-
" - Add your repository and workflow file: release.yml\n"
|
|
43
|
-
" 2. Push tags to trigger releases:\n"
|
|
44
|
-
" - Use 'ap bump --release' for stable releases (auto-pushes tag)\n"
|
|
45
|
-
" - Use 'ap bump --pre' then 'ap release' for pre-releases\n"
|
|
46
|
-
)
|
|
26
|
+
shutil.copy(template_path, target_path)
|
|
27
|
+
print(f"Created {target_path}")
|
|
47
28
|
|
|
48
29
|
|
|
49
|
-
def
|
|
50
|
-
"""
|
|
30
|
+
def create_workflow(workflow_name: str):
|
|
31
|
+
"""Create a GitHub Actions workflow from template"""
|
|
32
|
+
if ".yml" in workflow_name:
|
|
33
|
+
workflow_name = workflow_name.replace(".yml", "")
|
|
51
34
|
|
|
52
|
-
Creates .github/workflows/deploy.yml in the user's project root.
|
|
53
|
-
This workflow triggers on pushes to main branch and:
|
|
54
|
-
- Builds the project website with 'ap build'
|
|
55
|
-
- Deploys to GitHub Pages
|
|
56
|
-
- Allows manual deployment via workflow_dispatch
|
|
57
|
-
"""
|
|
58
35
|
user_path = ap.paths.user_path
|
|
59
|
-
|
|
60
|
-
|
|
36
|
+
workflow_path = user_path / ".github" / "workflows" / f"{workflow_name}.yml"
|
|
37
|
+
template_name = f"{workflow_name}-workflow-template.yml"
|
|
61
38
|
|
|
62
|
-
|
|
63
|
-
click.echo(f"GitHub Actions deploy workflow {workflow_path} already exists")
|
|
64
|
-
return
|
|
39
|
+
_copy_github_template(template_name, workflow_path)
|
|
65
40
|
|
|
66
|
-
# Create .github/workflows directory if it doesn't exist
|
|
67
|
-
workflow_dir.mkdir(parents=True, exist_ok=True)
|
|
68
41
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"This might indicate a corrupted installation. Please reinstall afterpython."
|
|
75
|
-
)
|
|
42
|
+
def create_dependabot():
|
|
43
|
+
"""Create Dependabot configuration for GitHub Actions updates"""
|
|
44
|
+
user_path = ap.paths.user_path
|
|
45
|
+
dependabot_path = user_path / ".github" / "dependabot.yml"
|
|
46
|
+
template_name = "dependabot-template.yml"
|
|
76
47
|
|
|
77
|
-
|
|
78
|
-
click.echo(f"Created {workflow_path}")
|
|
48
|
+
_copy_github_template(template_name, dependabot_path)
|
afterpython/utils.py
CHANGED
|
@@ -35,6 +35,11 @@ def has_uv() -> bool:
|
|
|
35
35
|
return shutil.which("uv") is not None
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
def has_pixi() -> bool:
|
|
39
|
+
"""Check if pixi is installed"""
|
|
40
|
+
return shutil.which("pixi") is not None
|
|
41
|
+
|
|
42
|
+
|
|
38
43
|
def has_gh() -> bool:
|
|
39
44
|
"""Check if gh is installed"""
|
|
40
45
|
return shutil.which("gh") is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: afterpython
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev8
|
|
4
4
|
Summary: CLI tool for AfterPython
|
|
5
5
|
Keywords: package-maintenance,project-website,static-site-generator,developer-tools,documentation,cli-tool,ci/cd,mystmd,semantic-release,python-packaging
|
|
6
6
|
Author: Stephen Yau
|
|
@@ -13,7 +13,6 @@ Classifier: Topic :: Software Development :: Documentation
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
17
16
|
Requires-Dist: click>=8.3.1
|
|
18
17
|
Requires-Dist: trogon>=0.6.0
|
|
19
18
|
Requires-Dist: httpx>=0.28.1
|
|
@@ -91,16 +90,20 @@ First-time maintainers must learn multiple tools and concepts, e.g. [MyST], [Sem
|
|
|
91
90
|
<img alt="Project Website" src="afterpython/static/website-light.png">
|
|
92
91
|
</picture>
|
|
93
92
|
|
|
93
|
+
You can create your own website too and deploy it to GitHub Pages in **less than a minute**! See [Quickstart](https://afterpython.afterpython.org/doc/quickstart).
|
|
94
|
+
|
|
94
95
|
---
|
|
95
96
|
## Installation
|
|
96
97
|
```bash
|
|
97
98
|
# install afterpython as a dev dependency
|
|
98
99
|
uv add --dev afterpython
|
|
100
|
+
|
|
99
101
|
# initialize afterpython
|
|
100
102
|
ap init
|
|
101
103
|
```
|
|
102
104
|
|
|
103
105
|
|
|
106
|
+
---
|
|
104
107
|
## Tech Stack
|
|
105
108
|
- [MyST]
|
|
106
109
|
- [project-website-template]
|
|
@@ -114,3 +117,8 @@ ap init
|
|
|
114
117
|
- [WebLLM]
|
|
115
118
|
<!-- - ty -->
|
|
116
119
|
<!-- - [pixi] -->
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
## *Our Mission*
|
|
124
|
+
> Only by making package maintenance and documentation easy can we encourage more Python developers to publish their own packages and grow the ecosystem even further.
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
afterpython/.pre-commit-config.yaml,sha256=7mpSRHaFcG2M6SOY-5Sbs9WxN8UISnZ2g0NwCGsLNCA,915
|
|
2
1
|
afterpython/__init__.py,sha256=aNochs72gU2NR1cBzIkk3NxSsdJ7ceHluI5gdYwaFpI,289
|
|
3
2
|
afterpython/_io/toml.py,sha256=nrx0CFPONgmkz5WDCSMyr4caic6nzu0uCd33qOmhhF0,3408
|
|
4
3
|
afterpython/_io/yaml.py,sha256=raksve_gaIFJim8lQrq-kQHkRjTloed7CT2FY0oUJSg,654
|
|
@@ -8,7 +7,7 @@ afterpython/builders/__init__.py,sha256=MOv3spIh-ABwyUtvQAHhPZ2horWb0D93WNmOPNAz
|
|
|
8
7
|
afterpython/builders/metadata.py,sha256=fj7rlawZCh43aJrBBfcmOTlYew1aW-om3QTpVulKbOk,1273
|
|
9
8
|
afterpython/builders/molab.py,sha256=Qji8piWJB1tbzhgtld0pQWIsUA7d7RsGCfnoLVKd5EA,3714
|
|
10
9
|
afterpython/cli/__init__.py,sha256=1vLZylRMnGaV7cJ-kHO96dChp33_P4fBIJ_Vi-yyZg4,85
|
|
11
|
-
afterpython/cli/commands/build.py,sha256=
|
|
10
|
+
afterpython/cli/commands/build.py,sha256=14C30vDU1SaR_5RVnA62lAAzX_eSRnlEfZI5h5AIrsk,8051
|
|
12
11
|
afterpython/cli/commands/bump.py,sha256=Wg-q3UQIkIRGT3umZCUBPpwIQTAHwQZVs1yHSZhmzKE,3088
|
|
13
12
|
afterpython/cli/commands/check.py,sha256=cLP4Vle3ENQHCXBv1okDlWK-L1XK-fv80m66xW3LQkg,1097
|
|
14
13
|
afterpython/cli/commands/clean.py,sha256=dCEkkWOTn93758wGTrWJG9V6c-lv2Z59CYfoP3i3rJE,2531
|
|
@@ -16,7 +15,8 @@ afterpython/cli/commands/commit.py,sha256=yRLOBs6JetZSGkFy9_uLzgR8yAX9djeUF291ga
|
|
|
16
15
|
afterpython/cli/commands/commitizen.py,sha256=naI8j4pfXIMsiOLmPMeZTGh831I3665_1_Sbn7yoKyE,811
|
|
17
16
|
afterpython/cli/commands/dev.py,sha256=yI1g0v7HlVaVH6HwcHyukLYMyUbZjAd0BiCYk9QGdGw,6752
|
|
18
17
|
afterpython/cli/commands/format.py,sha256=cXvuc-6XwULM1VJjS2B2bJBvnV1TVHFl1CeSs0SYQ24,738
|
|
19
|
-
afterpython/cli/commands/init.py,sha256=
|
|
18
|
+
afterpython/cli/commands/init.py,sha256=EDX6ojHJyQzaYTef2BjaWoy4_yL-bf6DAnCKa-ylfTU,3354
|
|
19
|
+
afterpython/cli/commands/init_branch_rules.py,sha256=fzAm8D5qbW3u4bEMpqPuRgO-0akuCGG7pu09JlKhYn4,243
|
|
20
20
|
afterpython/cli/commands/install.py,sha256=wgH9DEuN7hsA6BslNJASqOBn4VHJrYHBvowXDHi4smE,573
|
|
21
21
|
afterpython/cli/commands/pre_commit.py,sha256=DdmbkcZgJ7QArAY1y5vODYZmHUXWEIuXRyp69AS-pn0,1981
|
|
22
22
|
afterpython/cli/commands/preview.py,sha256=EbuB-dFcgonmqumTb2aHlLpXRiXkGE4DI3ddJdHwcaM,619
|
|
@@ -24,24 +24,26 @@ afterpython/cli/commands/release.py,sha256=6SDEnPtuCL0_XUqWUlvRSKxAv011QqOD0kc5p
|
|
|
24
24
|
afterpython/cli/commands/start.py,sha256=PnO1ECXnYtJxTOoDgG2ZoiVnkJVYNhPT63rabronjZ0,3992
|
|
25
25
|
afterpython/cli/commands/sync.py,sha256=epgD8VvrkYB1GSKMu4UFQb3-uGjyiLzw8CjtjaGB6zs,4669
|
|
26
26
|
afterpython/cli/commands/update.py,sha256=f6dzoJIiEod7j44dgnaFe-v7INVdUbopVoWPxv7-Mpo,5491
|
|
27
|
-
afterpython/cli/main.py,sha256=
|
|
27
|
+
afterpython/cli/main.py,sha256=_M5Z3msEZEZ4sIWeM8hvEmnrt9Qd2PHbC_GjibdKVfk,2832
|
|
28
28
|
afterpython/const.py,sha256=KsALiC1kERK9BQQdYRXSHdYosxVExxgDN7iGYMAJrZE,158
|
|
29
|
-
afterpython/cz.toml,sha256=JlenGROat8jvxvqRH6KluDs6f7w0JAy8Skd3ak7sGLY,1506
|
|
30
29
|
afterpython/main.py,sha256=w0z6mTib3u4p2HxMrk-tIJlZtur7uRaqsbE0ewlYlSs,490
|
|
31
30
|
afterpython/pcu.py,sha256=RWgPcdAFyNBVhWbQPuL1seji9uyT8Pqz-zE6jCf_Qb8,6091
|
|
32
|
-
afterpython/templates/
|
|
33
|
-
afterpython/templates/
|
|
31
|
+
afterpython/templates/ci-workflow-template.yml,sha256=2L-SRPB2GKlfR4bQAgpdq4r9bFdT9vCYo4oWjnIzKfg,5933
|
|
32
|
+
afterpython/templates/dependabot-template.yml,sha256=CBQEgh8EsXw2X7IqzGtFI7lVT9liF6PW4DvGLB0X2LY,1136
|
|
33
|
+
afterpython/templates/deploy-workflow-template.yml,sha256=2W4K3lKMYjSTPrlXIsMweBzqP9IoLtZXAAcUu5FA5NA,2365
|
|
34
|
+
afterpython/templates/release-workflow-template.yml,sha256=3YBkgrqmi--uznslpMxPz7Vj7L4_NPlhDxgwYBt-Ui8,1606
|
|
34
35
|
afterpython/templates/ruff-template.toml,sha256=_yTtZ0YPsJiCxy66ZDfYaStTJ9aXXW-JXy-KW6l2bBE,1010
|
|
35
36
|
afterpython/tools/_afterpython.py,sha256=W88GhtQADB09DV4A24GOYBeYrHsnVVzllLdWFiKgS1A,1904
|
|
36
|
-
afterpython/tools/_git.py,sha256=
|
|
37
|
+
afterpython/tools/_git.py,sha256=aO-qDEQ4OevD_B74DYKK4nQKYeiaS1BXmYc8paJRfbQ,3772
|
|
38
|
+
afterpython/tools/branch_rules.py,sha256=Tn6PdiZjj3duQd2u2wa89Cgbkun1lT4tGbbK9Eb71Ck,3160
|
|
37
39
|
afterpython/tools/commitizen.py,sha256=9aGXsO4tTyDs3s8qS_fiskdSabHqc9XjHwePThybJU0,1469
|
|
38
|
-
afterpython/tools/github_actions.py,sha256=
|
|
40
|
+
afterpython/tools/github_actions.py,sha256=zVmg9aqUg-EO0CnbRHl9i8TmFtXpt7nd0VjzckqqE30,1527
|
|
39
41
|
afterpython/tools/myst.py,sha256=w24zqWRUOLaZIC0twpGM4BF__wldmrgIvbns0FFdunA,6601
|
|
40
42
|
afterpython/tools/pre_commit.py,sha256=stXUQfR0A6nPMCSuuKO-Icjc5F2z9VsZu2mKkIW1vWI,2193
|
|
41
43
|
afterpython/tools/pyproject.py,sha256=YwJJAB3lIqYK9wt8UtL4dfCli9UN7uzi3e-vtycB0HE,2325
|
|
42
|
-
afterpython/utils.py,sha256=
|
|
44
|
+
afterpython/utils.py,sha256=LcQCXUw3OlgSeSliRm_ivq4kt7EX-_Nh7YunrYD7TqA,7041
|
|
43
45
|
afterpython/version.py,sha256=hihRV1S-gc1m46OaXD32ikkEkqzs-Gtq7AcAqOQV-wY,1603
|
|
44
|
-
afterpython-0.1.0.
|
|
45
|
-
afterpython-0.1.0.
|
|
46
|
-
afterpython-0.1.0.
|
|
47
|
-
afterpython-0.1.0.
|
|
46
|
+
afterpython-0.1.0.dev8.dist-info/WHEEL,sha256=AaqHSNJgTyoT6I9ETCXrbV_7cVSjA_q07lkDGeNjGdQ,79
|
|
47
|
+
afterpython-0.1.0.dev8.dist-info/entry_points.txt,sha256=roa0PDgBueM1JPbRG0G2OSxzaN394OUL_oS9iEwVLBc,80
|
|
48
|
+
afterpython-0.1.0.dev8.dist-info/METADATA,sha256=qSdlGSV3R2ip84sSGFOR7tNGiOz4y2KPSmnHef0sZ1w,5604
|
|
49
|
+
afterpython-0.1.0.dev8.dist-info/RECORD,,
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
default_install_hook_types:
|
|
2
|
-
- pre-commit
|
|
3
|
-
- commit-msg
|
|
4
|
-
- pre-push
|
|
5
|
-
exclude: ^afterpython/_website/
|
|
6
|
-
repos:
|
|
7
|
-
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
8
|
-
rev: v6.0.0
|
|
9
|
-
hooks:
|
|
10
|
-
- id: trailing-whitespace
|
|
11
|
-
stages:
|
|
12
|
-
- pre-commit
|
|
13
|
-
- id: end-of-file-fixer
|
|
14
|
-
stages:
|
|
15
|
-
- pre-commit
|
|
16
|
-
- id: check-yaml
|
|
17
|
-
stages:
|
|
18
|
-
- pre-commit
|
|
19
|
-
- id: check-toml
|
|
20
|
-
stages:
|
|
21
|
-
- pre-commit
|
|
22
|
-
- id: check-added-large-files
|
|
23
|
-
stages:
|
|
24
|
-
- pre-commit
|
|
25
|
-
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
26
|
-
rev: v0.14.5
|
|
27
|
-
hooks:
|
|
28
|
-
- id: ruff-check
|
|
29
|
-
stages:
|
|
30
|
-
- pre-commit
|
|
31
|
-
args:
|
|
32
|
-
- --config
|
|
33
|
-
- ./afterpython/ruff.toml
|
|
34
|
-
- id: ruff-format
|
|
35
|
-
stages:
|
|
36
|
-
- pre-commit
|
|
37
|
-
args:
|
|
38
|
-
- --config
|
|
39
|
-
- ./afterpython/ruff.toml
|
|
40
|
-
- repo: https://github.com/commitizen-tools/commitizen
|
|
41
|
-
rev: v4.10.0
|
|
42
|
-
hooks:
|
|
43
|
-
- id: commitizen
|
|
44
|
-
stages:
|
|
45
|
-
- commit-msg
|
|
46
|
-
- id: commitizen-branch
|
|
47
|
-
stages:
|
|
48
|
-
- pre-push
|
afterpython/cz.toml
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
[tool.commitizen]
|
|
2
|
-
name = "cz_conventional_commits"
|
|
3
|
-
# name = "cz_customize"
|
|
4
|
-
tag_format = "v$version"
|
|
5
|
-
version_scheme = "pep440"
|
|
6
|
-
version_provider = "uv"
|
|
7
|
-
update_changelog_on_bump = false
|
|
8
|
-
major_version_zero = true
|
|
9
|
-
|
|
10
|
-
# FIXME: commitizen can't even add a few custom types like "chore" and "wip", skip it for now
|
|
11
|
-
# [[tool.commitizen.customize.questions]]
|
|
12
|
-
# type = "list"
|
|
13
|
-
# name = "change_type"
|
|
14
|
-
# choices = [
|
|
15
|
-
# {value = "fix", name = "fix: A bug fix. Correlates with PATCH in SemVer"},
|
|
16
|
-
# {value = "feat", name = "feat: A new feature. Correlates with MINOR in SemVer"},
|
|
17
|
-
# {value = "docs", name = "docs: Documentation only changes"},
|
|
18
|
-
# {value = "style", name = "style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"},
|
|
19
|
-
# {value = "refactor", name = "refactor: A code change that neither fixes a bug nor adds a feature"},
|
|
20
|
-
# {value = "perf", name = "perf: A code change that improves performance"},
|
|
21
|
-
# {value = "test", name = "test: Adding missing or correcting existing tests"},
|
|
22
|
-
# {value = "build", name = "build: Changes that affect the build system or external dependencies (example scopes: pip, docker, npm)"},
|
|
23
|
-
# {value = "ci", name = "ci: Changes to CI configuration files and scripts (example scopes: GitLabCI)"},
|
|
24
|
-
# {value = "chore", name = "chore: Other changes that don't modify src or test files"},
|
|
25
|
-
# {value = "wip", name = "wip: Work in progress"}
|
|
26
|
-
# ]
|
|
27
|
-
# message = "Select the type of change you are committing"
|
|
File without changes
|