Skip to content

ci: auto-release on merge to main - #4

Merged
hakeemRash merged 6 commits into
mainfrom
master
Jul 22, 2026
Merged

ci: auto-release on merge to main#4
hakeemRash merged 6 commits into
mainfrom
master

Conversation

@hakeemRash

@hakeemRash hakeemRash commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Lands the auto-release pipeline on main:

  • auto-release.yml — on a merge to main that bumps CHANGELOG.md, tags vX.Y.Z (if new) and calls the release build.
  • release.yml — made workflow_call-able and idempotent (skips if the release already exists).
  • CHANGELOG.md — record 1.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

    • Added automatic release creation when a new version is added to the changelog.
    • Releases can now be triggered through both version tags and automated workflow runs.
    • Added safeguards to prevent duplicate releases.
  • Documentation

    • Added changelog entry for version 1.0.0, dated July 22, 2026.

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.
# Conflicts:
#	.github/workflows/ci.yml
#	.github/workflows/release.yml
#	CHANGELOG.md
#	composer.json
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds automatic release handling for changelog version updates on main. It creates missing version tags, invokes the reusable release workflow with the detected version, and makes release creation idempotent for both workflow-call and tag-triggered runs.

Changes

Release automation

Layer / File(s) Summary
Changelog version detection and tagging
.github/workflows/auto-release.yml, CHANGELOG.md
The new workflow parses the first non-Unreleased version from CHANGELOG.md, checks for its vX.Y.Z tag, and creates the tag when absent. The changelog adds version 1.0.0 dated 2026-07-22.
Reusable release creation
.github/workflows/release.yml
The release workflow accepts a required version input, resolves tags for both invocation modes, and skips creation when the GitHub Release already exists.

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
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: automatic release on merges to main.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch master

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.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

.github/workflows/release.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hakeemRash
hakeemRash merged commit e8e65d5 into main Jul 22, 2026
1 of 2 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
.github/workflows/auto-release.yml (2)

15-16: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Scope contents: write to the jobs that require it.

Keep contents: read at workflow scope and grant write access explicitly to detect and release. 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 win

Avoid persisting the write token in the checkout.

git push later requires authentication, so persist-credentials: false cannot 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

📥 Commits

Reviewing files that changed from the base of the PR and between 86bfee4 and 0da276b.

📒 Files selected for processing (3)
  • .github/workflows/auto-release.yml
  • .github/workflows/release.yml
  • CHANGELOG.md

Comment on lines +45 to +47
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists — skipping."
echo "release=false" >> "$GITHUB_OUTPUT"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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 -S

Repository: 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()
PY

Repository: 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 -S

Repository: 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}")
PY

Repository: 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.

Comment on lines +45 to +51
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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/workflows

Repository: 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'
done

Repository: 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.yml

Repository: 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.

Comment on lines +49 to +56
- 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 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 -S

Repository: 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 -S

Repository: 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())
PY

Repository: 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant