ci: auto-release on merge to main - #4
Conversation
Extract the kernel HTTP layer into a standalone MIT-licensed package: immutable Request/Response value objects, PSR-7 Uri, SiteUri, content negotiation, Method enum, UserAgent, and FPM-/Swoole-safe UploadedFile. Add community health files (README, LICENSE, CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, SUPPORT, issue/PR templates, CODEOWNERS, dependabot), CI matrix (PHP 8.2/8.3/8.4 -> validate + PHPStan + PHPUnit), phpunit + phpstan config, tests, and a kernel-styled .gitignore.
… kernel baseline)
# Conflicts: # .github/workflows/ci.yml # .github/workflows/release.yml # CHANGELOG.md # composer.json
📝 WalkthroughWalkthroughThe change adds automatic release handling for changelog version updates on ChangesRelease automation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant MainPush
participant AutoRelease
participant Changelog
participant ReleaseWorkflow
participant GitHubRelease
MainPush->>AutoRelease: Push to main with CHANGELOG.md change
AutoRelease->>Changelog: Read latest non-Unreleased version
AutoRelease->>AutoRelease: Check and create vX.Y.Z tag
AutoRelease->>ReleaseWorkflow: Call with detected version
ReleaseWorkflow->>GitHubRelease: Check release existence
ReleaseWorkflow->>GitHubRelease: Create release when absent
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8).github/workflows/auto-release.ymlTraceback (most recent call last): .github/workflows/release.ymlTraceback (most recent call last): Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
.github/workflows/auto-release.yml (2)
15-16: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winScope
contents: writeto the jobs that require it.Keep
contents: readat workflow scope and grant write access explicitly todetectandrelease. This limits privilege inheritance for future jobs.Proposed permission scope
permissions: - contents: write + contents: read jobs: detect: + permissions: + contents: write🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/auto-release.yml around lines 15 - 16, Update the workflow-level permissions in auto-release.yml to keep contents: read, then add job-level contents: write permissions only to the detect and release jobs. Ensure other and future jobs inherit only read access.Source: Linters/SAST tools
30-32: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAvoid persisting the write token in the checkout.
git pushlater requires authentication, sopersist-credentials: falsecannot be added alone. Disable persistence and provide the token only to the push command, or explicitly justify retaining it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/auto-release.yml around lines 30 - 32, Update the actions/checkout@v4 step to avoid persisting credentials by setting persist-credentials to false, then provide the required write token explicitly only for the later git push command. Preserve the existing full fetch-depth configuration and ensure authentication is not retained beyond that push.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/auto-release.yml:
- Around line 45-47: Update the existing tag-existence check in the release
workflow to verify only the exact tag reference, using the fully qualified
refs/tags/v$VERSION form with git show-ref --verify --quiet. Preserve the
current skip message and release=false output behavior when that tag exists.
- Around line 45-51: Update the version-check flow around the release output to
always set release=true and invoke release.yml, including when the v$VERSION tag
already exists. Remove the existing release=false skip path while preserving the
informational tag-exists logging.
In @.github/workflows/release.yml:
- Around line 49-56: Update the “Resolve tag” step to pass inputs.version
through the step environment instead of interpolating it in the shell. Validate
the environment value before use, then write the tag output with printf so
caller-supplied shell syntax or extra GITHUB_OUTPUT lines cannot be interpreted.
---
Nitpick comments:
In @.github/workflows/auto-release.yml:
- Around line 15-16: Update the workflow-level permissions in auto-release.yml
to keep contents: read, then add job-level contents: write permissions only to
the detect and release jobs. Ensure other and future jobs inherit only read
access.
- Around line 30-32: Update the actions/checkout@v4 step to avoid persisting
credentials by setting persist-credentials to false, then provide the required
write token explicitly only for the later git push command. Preserve the
existing full fetch-depth configuration and ensure authentication is not
retained beyond that push.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 32fbcd62-5607-412d-98bd-554ea467e604
📒 Files selected for processing (3)
.github/workflows/auto-release.yml.github/workflows/release.ymlCHANGELOG.md
| if git rev-parse "v$VERSION" >/dev/null 2>&1; then | ||
| echo "Tag v$VERSION already exists — skipping." | ||
| echo "release=false" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- .github/workflows/auto-release.yml (around lines 35-55) ---\n'
sed -n '35,55p' .github/workflows/auto-release.yml
printf '\n--- search for v$VERSION / rev-parse / show-ref usage ---\n'
rg -n 'rev-parse|show-ref|v\$VERSION|refs/tags/v' .github/workflows -SRepository: AlfaCode-Team/http
Length of output: 247
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import subprocess, tempfile, os, textwrap, json, sys
# Probe git ref resolution behavior in a scratch repo to test the claim.
repo = tempfile.mkdtemp(prefix="git-ref-probe-")
def run(cmd, cwd=repo):
return subprocess.run(cmd, cwd=cwd, text=True, capture_output=True)
steps = [
["git", "init", "-q"],
["git", "config", "user.email", "a@example.com"],
["git", "config", "user.name", "a"],
["bash", "-lc", "printf x > f && git add f && git commit -q -m init"],
["git", "branch", "v1.2.3"],
["git", "tag", "v9.9.9"],
]
for cmd in steps:
r = run(cmd)
if r.returncode != 0:
print("FAILED", cmd, r.stderr, file=sys.stderr)
sys.exit(1)
checks = {
'branch ref': ['git', 'rev-parse', '--verify', 'v1.2.3^{commit}'],
'branch name': ['git', 'rev-parse', 'v1.2.3'],
'exact tag ref existence': ['git', 'show-ref', '--verify', '--quiet', 'refs/tags/v1.2.3'],
'exact tag ref existence (tag)': ['git', 'show-ref', '--verify', '--quiet', 'refs/tags/v9.9.9'],
'rev-parse tag': ['git', 'rev-parse', 'v9.9.9'],
}
for label, cmd in checks.items():
r = run(cmd)
print(f'## {label}')
print('cmd:', ' '.join(cmd))
print('rc:', r.returncode)
if r.stdout:
print('stdout:', r.stdout.strip())
if r.stderr:
print('stderr:', r.stderr.strip())
print()
PYRepository: AlfaCode-Team/http
Length of output: 644
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- .github/workflows/auto-release.yml (around lines 35-55) ---'
sed -n '35,55p' .github/workflows/auto-release.yml
echo
echo '--- search for ref checks in .github/workflows ---'
rg -n 'rev-parse|show-ref|v\$VERSION|refs/tags/v' .github/workflows -SRepository: AlfaCode-Team/http
Length of output: 1576
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/auto-release.yml')
for i, line in enumerate(p.read_text().splitlines(), 1):
if 35 <= i <= 55:
print(f"{i:>4}: {line}")
PYRepository: AlfaCode-Team/http
Length of output: 1130
Check the exact tag ref. git rev-parse "v$VERSION" matches any ref named v$VERSION, including branches, so a real release can be skipped. Use git show-ref --verify --quiet "refs/tags/v$VERSION" instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/auto-release.yml around lines 45 - 47, Update the existing
tag-existence check in the release workflow to verify only the exact tag
reference, using the fully qualified refs/tags/v$VERSION form with git show-ref
--verify --quiet. Preserve the current skip message and release=false output
behavior when that tag exists.
| if git rev-parse "v$VERSION" >/dev/null 2>&1; then | ||
| echo "Tag v$VERSION already exists — skipping." | ||
| echo "release=false" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "New version detected: v$VERSION" | ||
| echo "release=true" >> "$GITHUB_OUTPUT" | ||
| fi |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== auto-release workflow ==\n'
ast-grep outline .github/workflows/auto-release.yml --view expanded || true
printf '\n== release workflow references ==\n'
rg -n "release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\\$VERSION" .github/workflows -n
printf '\n== file snippets ==\n'
nl -ba .github/workflows/auto-release.yml | sed -n '1,160p'
printf '\n---- release workflow ----\n'
nl -ba .github/workflows/release.yml | sed -n '1,220p'Repository: AlfaCode-Team/http
Length of output: 309
🏁 Script executed:
#!/bin/bash
set -euo pipefail
nl -ba .github/workflows/auto-release.yml | sed -n '1,120p'
echo '----'
nl -ba .github/workflows/release.yml | sed -n '1,220p'Repository: AlfaCode-Team/http
Length of output: 196
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== auto-release ==\n'
sed -n '1,220p' .github/workflows/auto-release.yml
printf '\n== release ==\n'
sed -n '1,260p' .github/workflows/release.yml
printf '\n== references ==\n'
rg -n 'release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\$VERSION|VERSION' .github/workflowsRepository: AlfaCode-Team/http
Length of output: 5960
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in .github/workflows/auto-release.yml .github/workflows/release.yml; do
echo "===== $f ====="
cat -n "$f" | sed -n '1,220p'
doneRepository: AlfaCode-Team/http
Length of output: 5382
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== auto-release =='
sed -n '1,220p' .github/workflows/auto-release.yml
echo
echo '== release =='
sed -n '1,260p' .github/workflows/release.yml
echo
echo '== matches =='
rg -n 'release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\$VERSION|VERSION' .github/workflows/auto-release.yml .github/workflows/release.ymlRepository: AlfaCode-Team/http
Length of output: 5957
Always call release.yml even when v$VERSION already exists. release.yml is idempotent, so skipping it here makes a failed first run unrecoverable: reruns will hit release=false and never recreate the missing GitHub Release.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/auto-release.yml around lines 45 - 51, Update the
version-check flow around the release output to always set release=true and
invoke release.yml, including when the v$VERSION tag already exists. Remove the
existing release=false skip path while preserving the informational tag-exists
logging.
| - name: Resolve tag | ||
| id: tag | ||
| run: | | ||
| if [ -n "${{ inputs.version }}" ]; then | ||
| echo "tag=v${{ inputs.version }}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | ||
| fi |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the workflow and any callers first.
git ls-files '.github/workflows/*' '.*' | sed -n '1,200p'Repository: AlfaCode-Team/http
Length of output: 462
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-files .github/workflows | sed -n '1,200p'Repository: AlfaCode-Team/http
Length of output: 246
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the relevant workflow section with line numbers.
cat -n .github/workflows/release.yml | sed -n '1,140p'Repository: AlfaCode-Team/http
Length of output: 2526
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find workflow callers and references to the release workflow.
rg -n "release\.yml|workflow_call|inputs\.version|Resolve tag" .github/workflows -SRepository: AlfaCode-Team/http
Length of output: 871
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== workflow files ==="
git ls-files .github/workflows
echo "=== release.yml lines 1-180 ==="
cat -n .github/workflows/release.yml | sed -n '1,180p'Repository: AlfaCode-Team/http
Length of output: 2671
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== search for reusable workflow declaration and callers ==="
rg -n "workflow_call|uses: \.\/\.github\/workflows\/release\.yml|inputs\.version|version:" .github/workflows -SRepository: AlfaCode-Team/http
Length of output: 1199
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n .github/workflows/release.yml | sed -n '1,180p'Repository: AlfaCode-Team/http
Length of output: 2526
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/release.yml')
print(p.read_text())
PYRepository: AlfaCode-Team/http
Length of output: 2044
Don't interpolate inputs.version directly into this shell step. In .github/workflows/release.yml:49-56, a caller can inject shell syntax or extra $GITHUB_OUTPUT lines here. Pass it through env, validate it, and write it with printf.
🧰 Tools
🪛 zizmor (1.26.1)
[error] 52-52: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[error] 53-53: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml around lines 49 - 56, Update the “Resolve tag”
step to pass inputs.version through the step environment instead of
interpolating it in the shell. Validate the environment value before use, then
write the tag output with printf so caller-supplied shell syntax or extra
GITHUB_OUTPUT lines cannot be interpreted.
Source: Linters/SAST tools
Lands the auto-release pipeline on
main:auto-release.yml— on a merge tomainthat bumpsCHANGELOG.md, tagsvX.Y.Z(if new) and calls the release build.release.yml— madeworkflow_call-able and idempotent (skips if the release already exists).CHANGELOG.md— record1.0.0(its tag already exists, so the merge auto-release is a safe no-op).Follow-up to #1, whose squash landed before these commits.
Summary by CodeRabbit
New Features
Documentation