rlsbl 0.8.2 → 0.9.0
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.
- package/package.json +3 -5
- package/rlsbl/__init__.py +0 -247
- package/rlsbl/__main__.py +0 -4
- package/rlsbl/commands/__init__.py +0 -0
- package/rlsbl/commands/check.py +0 -229
- package/rlsbl/commands/config.py +0 -67
- package/rlsbl/commands/discover.py +0 -198
- package/rlsbl/commands/init_cmd.py +0 -518
- package/rlsbl/commands/pre_push_check.py +0 -46
- package/rlsbl/commands/record_gif.py +0 -92
- package/rlsbl/commands/release.py +0 -287
- package/rlsbl/commands/status.py +0 -76
- package/rlsbl/commands/undo.py +0 -74
- package/rlsbl/commands/watch.py +0 -122
- package/rlsbl/config.py +0 -57
- package/rlsbl/registries/__init__.py +0 -5
- package/rlsbl/registries/go.py +0 -123
- package/rlsbl/registries/npm.py +0 -119
- package/rlsbl/registries/pypi.py +0 -171
- package/rlsbl/tagging.py +0 -207
- package/rlsbl/templates/go/VERSION.tpl +0 -1
- package/rlsbl/templates/go/ci.yml.tpl +0 -21
- package/rlsbl/templates/go/goreleaser.yml.tpl +0 -25
- package/rlsbl/templates/go/publish.yml.tpl +0 -25
- package/rlsbl/templates/merged/publish.yml.tpl +0 -30
- package/rlsbl/templates/npm/ci.yml.tpl +0 -22
- package/rlsbl/templates/npm/publish.yml.tpl +0 -22
- package/rlsbl/templates/pypi/ci.yml.tpl +0 -20
- package/rlsbl/templates/pypi/publish.yml.tpl +0 -18
- package/rlsbl/templates/shared/CHANGELOG.md.tpl +0 -5
- package/rlsbl/templates/shared/CLAUDE.md.tpl +0 -20
- package/rlsbl/templates/shared/LICENSE.tpl +0 -21
- package/rlsbl/templates/shared/claude-settings.json.tpl +0 -3
- package/rlsbl/templates/shared/gitignore.tpl +0 -14
- package/rlsbl/templates/shared/hooks/post-release.sh.tpl +0 -8
- package/rlsbl/templates/shared/hooks/pre-release.sh.tpl +0 -31
- package/rlsbl/utils.py +0 -131
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: write
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
goreleaser:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v6
|
|
15
|
-
with:
|
|
16
|
-
fetch-depth: 0
|
|
17
|
-
- uses: actions/setup-go@v6
|
|
18
|
-
with:
|
|
19
|
-
go-version-file: go.mod
|
|
20
|
-
- uses: goreleaser/goreleaser-action@v7
|
|
21
|
-
with:
|
|
22
|
-
version: "~> v2"
|
|
23
|
-
args: release --clean
|
|
24
|
-
env:
|
|
25
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
id-token: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
npm:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v6
|
|
16
|
-
- uses: actions/setup-node@v6
|
|
17
|
-
with:
|
|
18
|
-
node-version: 22
|
|
19
|
-
registry-url: https://registry.npmjs.org
|
|
20
|
-
- run: npm publish --provenance --access public
|
|
21
|
-
env:
|
|
22
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
23
|
-
|
|
24
|
-
pypi:
|
|
25
|
-
runs-on: ubuntu-latest
|
|
26
|
-
steps:
|
|
27
|
-
- uses: actions/checkout@v6
|
|
28
|
-
- uses: astral-sh/setup-uv@v7
|
|
29
|
-
- run: uv build
|
|
30
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
strategy:
|
|
13
|
-
matrix:
|
|
14
|
-
node-version: [18, 20, 22]
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v6
|
|
17
|
-
- uses: actions/setup-node@v6
|
|
18
|
-
with:
|
|
19
|
-
node-version: ${{ matrix.node-version }}
|
|
20
|
-
- run: node -e "require('./package.json')"
|
|
21
|
-
- run: npm test --if-present
|
|
22
|
-
- run: npm audit --audit-level=moderate || true
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
id-token: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v6
|
|
16
|
-
- uses: actions/setup-node@v6
|
|
17
|
-
with:
|
|
18
|
-
node-version: 22
|
|
19
|
-
registry-url: https://registry.npmjs.org
|
|
20
|
-
- run: npm publish --provenance --access public
|
|
21
|
-
env:
|
|
22
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
strategy:
|
|
13
|
-
matrix:
|
|
14
|
-
python-version: ["3.12", "3.13", "3.14"]
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v6
|
|
17
|
-
- uses: astral-sh/setup-uv@v7
|
|
18
|
-
- run: uv python install ${{ matrix.python-version }}
|
|
19
|
-
- run: uv sync
|
|
20
|
-
- run: uv run python -c "import {{importName}}"
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
id-token: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v6
|
|
16
|
-
- uses: astral-sh/setup-uv@v7
|
|
17
|
-
- run: uv build
|
|
18
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# {{name}}
|
|
2
|
-
|
|
3
|
-
## Release workflow
|
|
4
|
-
|
|
5
|
-
This project uses [rlsbl](https://github.com/smm-h/rlsbl) for release orchestration.
|
|
6
|
-
|
|
7
|
-
- Update CHANGELOG.md with a `## X.Y.Z` entry describing changes
|
|
8
|
-
- Run `rlsbl release [patch|minor|major]` to bump version and create a GitHub Release
|
|
9
|
-
- CI handles publishing automatically via the publish workflow
|
|
10
|
-
- Never publish manually — always use `rlsbl release`
|
|
11
|
-
- {{publishSetup}}
|
|
12
|
-
- Use `rlsbl release --dry-run` to preview a release without making changes
|
|
13
|
-
|
|
14
|
-
## Conventions
|
|
15
|
-
|
|
16
|
-
- No tokens or secrets in command-line arguments (use env vars or config files)
|
|
17
|
-
- All file writes to shared state should be atomic (write to tmp, then rename)
|
|
18
|
-
- External calls (APIs, CLI tools) must have timeouts and graceful fallbacks
|
|
19
|
-
- Use `npm link` (npm) or `uv pip install -e .` (Python) for local development
|
|
20
|
-
- CI runs smoke tests on every push; manual testing for UI/UX changes
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) {{year}} {{author}}
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Post-release hook. Runs after a successful release (non-fatal).
|
|
3
|
-
# Environment: RLSBL_VERSION is set to the released version.
|
|
4
|
-
# Customize this for your project (e.g., local install, deploy, notify).
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
echo "Post-release: v$RLSBL_VERSION"
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Pre-release validation hook.
|
|
3
|
-
# Runs before rlsbl creates a release. Exit non-zero to abort.
|
|
4
|
-
# Detects project type and runs appropriate checks automatically.
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
echo "Running pre-release checks..."
|
|
9
|
-
|
|
10
|
-
if [ -f go.mod ]; then
|
|
11
|
-
echo " Go: vet + build + test"
|
|
12
|
-
go vet ./...
|
|
13
|
-
go build ./...
|
|
14
|
-
go test ./... -race -short -count=1
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
if [ -f package.json ] && node -e "process.exit(require('./package.json').scripts?.test ? 0 : 1)" 2>/dev/null; then
|
|
18
|
-
echo " npm: test"
|
|
19
|
-
npm test
|
|
20
|
-
fi
|
|
21
|
-
|
|
22
|
-
if [ -f pyproject.toml ]; then
|
|
23
|
-
echo " Python: pytest"
|
|
24
|
-
if command -v uv &>/dev/null; then
|
|
25
|
-
uv run pytest
|
|
26
|
-
elif command -v pytest &>/dev/null; then
|
|
27
|
-
pytest
|
|
28
|
-
fi
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
echo "Pre-release checks passed."
|
package/rlsbl/utils.py
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
"""Git helpers, version bump, changelog extraction, and other shared utilities."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import re
|
|
5
|
-
import shutil
|
|
6
|
-
import subprocess
|
|
7
|
-
import sys
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def run(cmd, args=None, timeout=120, env=None):
|
|
11
|
-
"""Run a command with args, return trimmed stdout. Raise on failure."""
|
|
12
|
-
full_cmd = [cmd] + (args or [])
|
|
13
|
-
result = subprocess.run(full_cmd, capture_output=True, text=True, check=True, timeout=timeout, env=env)
|
|
14
|
-
return result.stdout.strip()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def is_clean_tree():
|
|
19
|
-
"""Returns True if the git working tree is clean (no uncommitted changes)."""
|
|
20
|
-
status = run("git", ["status", "--porcelain"])
|
|
21
|
-
return len(status) == 0
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def get_current_branch():
|
|
25
|
-
"""Returns the current git branch name."""
|
|
26
|
-
return run("git", ["rev-parse", "--abbrev-ref", "HEAD"])
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def get_push_timeout():
|
|
30
|
-
"""Return the push timeout in seconds, from RLSBL_PUSH_TIMEOUT or default 120."""
|
|
31
|
-
raw = os.environ.get("RLSBL_PUSH_TIMEOUT")
|
|
32
|
-
if raw is None:
|
|
33
|
-
return 120
|
|
34
|
-
try:
|
|
35
|
-
val = int(raw)
|
|
36
|
-
if val <= 0:
|
|
37
|
-
raise ValueError
|
|
38
|
-
return val
|
|
39
|
-
except ValueError:
|
|
40
|
-
print(f'Warning: invalid RLSBL_PUSH_TIMEOUT="{raw}", using default 120s', file=sys.stderr)
|
|
41
|
-
return 120
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def push_if_needed(branch):
|
|
45
|
-
"""Push the branch to origin if local is ahead of remote."""
|
|
46
|
-
timeout = get_push_timeout()
|
|
47
|
-
local = run("git", ["rev-parse", branch])
|
|
48
|
-
try:
|
|
49
|
-
remote = run("git", ["rev-parse", f"origin/{branch}"])
|
|
50
|
-
except subprocess.CalledProcessError:
|
|
51
|
-
# Remote branch doesn't exist yet; push it
|
|
52
|
-
run("git", ["push", "-u", "origin", branch], timeout=timeout)
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
if local != remote:
|
|
56
|
-
run("git", ["push", "origin", branch], timeout=timeout)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def extract_changelog_entry(changelog_path, version):
|
|
60
|
-
"""Extract a changelog entry for a specific version.
|
|
61
|
-
|
|
62
|
-
Looks for a heading like '## 1.2.3' and captures everything
|
|
63
|
-
until the next heading or EOF.
|
|
64
|
-
"""
|
|
65
|
-
with open(changelog_path, "r", encoding="utf-8") as f:
|
|
66
|
-
content = f.read()
|
|
67
|
-
|
|
68
|
-
escaped_version = re.escape(version)
|
|
69
|
-
header_pattern = re.compile(r"^## " + escaped_version + r"\s*$", re.MULTILINE)
|
|
70
|
-
match = header_pattern.search(content)
|
|
71
|
-
if not match:
|
|
72
|
-
return None
|
|
73
|
-
|
|
74
|
-
# Start after the matched header line
|
|
75
|
-
start_idx = match.end()
|
|
76
|
-
# Find the next "## " heading or use end of string
|
|
77
|
-
next_heading_idx = content.find("\n## ", start_idx)
|
|
78
|
-
end_idx = len(content) if next_heading_idx == -1 else next_heading_idx
|
|
79
|
-
entry = content[start_idx:end_idx].strip()
|
|
80
|
-
return entry or None
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def check_gh_installed():
|
|
84
|
-
"""Check that the gh CLI is installed."""
|
|
85
|
-
try:
|
|
86
|
-
run("gh", ["--version"])
|
|
87
|
-
return True
|
|
88
|
-
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
89
|
-
return False
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def check_gh_auth():
|
|
93
|
-
"""Check that the gh CLI is authenticated."""
|
|
94
|
-
try:
|
|
95
|
-
run("gh", ["auth", "status"])
|
|
96
|
-
return True
|
|
97
|
-
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def find_commit_tool():
|
|
102
|
-
"""Detect safegit or fall back to git for committing.
|
|
103
|
-
|
|
104
|
-
Returns "safegit" if available on PATH, otherwise "git".
|
|
105
|
-
"""
|
|
106
|
-
if shutil.which("safegit"):
|
|
107
|
-
return "safegit"
|
|
108
|
-
return "git"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def bump_version(version, bump_type):
|
|
112
|
-
"""Bump a semver version string by the given type (patch, minor, major).
|
|
113
|
-
|
|
114
|
-
Returns the new version string.
|
|
115
|
-
"""
|
|
116
|
-
parts = version.split(".")
|
|
117
|
-
if len(parts) != 3:
|
|
118
|
-
raise ValueError(f'Invalid semver version: "{version}"')
|
|
119
|
-
try:
|
|
120
|
-
major, minor, patch = (int(p) for p in parts)
|
|
121
|
-
except ValueError:
|
|
122
|
-
raise ValueError(f'Invalid semver version: "{version}"')
|
|
123
|
-
|
|
124
|
-
if bump_type == "major":
|
|
125
|
-
return f"{major + 1}.0.0"
|
|
126
|
-
elif bump_type == "minor":
|
|
127
|
-
return f"{major}.{minor + 1}.0"
|
|
128
|
-
elif bump_type == "patch":
|
|
129
|
-
return f"{major}.{minor}.{patch + 1}"
|
|
130
|
-
else:
|
|
131
|
-
raise ValueError(f'Invalid bump type: "{bump_type}". Use patch, minor, or major.')
|