Skip to content
135 changes: 135 additions & 0 deletions .github/workflows/auto-bump-version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: Auto Bump Version on Merge to main

on:
pull_request:
types: [closed]

permissions:
contents: write

jobs:
bump-version:
if: >
github.event.pull_request.merged == true &&
github.event.pull_request.base.ref == 'main' &&
github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
with:
ref: main

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Detect if package.json version changed in PR
id: ver_changed
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request.number;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr,
per_page: 100
});
const touched = files.some(f => f.filename === 'package.json' && /"version"\s*:/.test(f.patch || ''));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

버전 변경 감지 로직이 키 존재 여부만 확인 - 실제 값 변경 미감지

현재 정규식 /"version"\s*:/.test(f.patch || '')"version" 키가 있는지만 확인하고, 실제로 버전 이 변경되었는지는 검증하지 않습니다. JSON 포매팅 변경이나 다른 필드 수정으로도 거짓 양성이 발생할 수 있습니다.

patch 컨텐츠에서 이전/새 버전값을 직접 추출하여 비교하도록 개선하세요:

const versionMatch = (f.patch || '').match(/^-.*"version"\s*:\s*"([^"]+)"/m);
const newVersionMatch = (f.patch || '').match(/^\+.*"version"\s*:\s*"([^"]+)"/m);
const touched = versionMatch && newVersionMatch && versionMatch[1] !== newVersionMatch[1];

🏁 Script executed:

#!/bin/bash
# Examine the workflow file to verify the version detection logic
cat .github/workflows/auto-bump-version.yaml | head -60

Length of output: 1827


🏁 Script executed:

#!/bin/bash
# Search for context around the version detection logic
rg -n "touched.*files.some" -A 5 -B 5 .github/workflows/auto-bump-version.yaml

Length of output: 479


🏁 Script executed:

#!/bin/bash
# Look for any other version detection or comparison logic in the workflow
rg -n "version" -i .github/workflows/auto-bump-version.yaml | head -20

Length of output: 769


라인 42의 버전 변경 감지 로직이 키 존재 여부만 확인 - 실제 값 변경 미감지

현재 정규식 /"version"\s*:/.test(f.patch || '')"version" 키가 diff의 어디든 나타나면 참을 반환합니다. GitHub API의 patch 형식은 변경사항(-, +)뿐만 아니라 컨텍스트 라인(변경 없는 라인)도 포함하므로, 버전 필드가 diff 컨텍스트에 나타나기만 해도 거짓 양성이 발생합니다.

실제 버전 값 변경을 감지하도록 개선하세요:

const versionMatch = (f.patch || '').match(/^-.*"version"\s*:\s*"([^"]+)"/m);
const newVersionMatch = (f.patch || '').match(/^\+.*"version"\s*:\s*"([^"]+)"/m);
const touched = versionMatch && newVersionMatch && versionMatch[1] !== newVersionMatch[1];
🤖 Prompt for AI Agents
.github/workflows/auto-bump-version.yaml lines 42: the current check only tests
for the presence of a "version" key in the patch and can produce false positives
because GitHub patch includes context lines; update the logic to extract the old
and new version strings from lines that start with '-' and '+' respectively
(using regex anchored to those prefixes), then set touched to true only when
both matches exist and the extracted versions differ, and ensure you safely
handle empty or undefined f.patch before matching.

core.setOutput('changed', touched ? 'true' : 'false');
Comment on lines +30 to +43
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Line 41: 버전 변경 감지 로직 개선 - 정확성 고려

현재 정규식 패턴 /"version"\s*:/.test(f.patch || '')"version" 키의 존재 여부만 확인하며, 실제 버전 이 변경되었는지는 검증하지 않습니다. JSON 포매팅 변경이나 다른 필드 수정으로도 거짓 양성(false positive)이 발생할 수 있습니다.

patch 컨텐츠에서 이전 버전과 새 버전의 실제 semver 문자열을 추출하여 비교하면 더 정확합니다:

const versionMatch = (f.patch || '').match(/^-.*"version"\s*:\s*"([^"]+)"[\s,]/m);
const newVersionMatch = (f.patch || '').match(/^\+.*"version"\s*:\s*"([^"]+)"[\s,]/m);
const touched = versionMatch && newVersionMatch && versionMatch[1] !== newVersionMatch[1];
🤖 Prompt for AI Agents
In .github/workflows/auto-bump-version.yaml around lines 29 to 42, the current
regex only detects the "version" key and can yield false positives; instead
parse the patch to extract the old and new version values and compare them.
Update the script to search the patch for a line removed (starts with '-')
containing "version": "oldVersion" and a line added (starts with '+') containing
"version": "newVersion", ensure both matches are found and non-null, compare
oldVersion !== newVersion, and set the 'changed' output to 'true' only if they
differ; include safe null checks to avoid runtime errors.


- name: Bump patch version (+0.0.1) if not changed in PR
if: steps.ver_changed.outputs.changed != 'true'
run: |
node -e "
const fs = require('fs');
const pr_title = context.payload.pull_request.title;
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
const [a,b,c] = pkg.version.split('.').map(Number);
let new_version;

if (pr_title.toLowerCase().startsWith('feat')) {
new_version = [a,b+1,0].join('.');
} else {
new_version = [a,b,c+1].join('.');
}

pkg.version = new_version;
fs.writeFileSync('package.json', JSON.stringify(pkg,null,2)+'\n');
console.log('Bumped to', pkg.version);
"

- name: Install dependencies
run: npm ci

- name: Sync exports to src/shared/index.ts (Revised)
run: |
node -e "
const fs = require('fs');
const path = require('path');
const root = 'src/shared';
const indexPath = path.join(root, 'index.ts');
const indexContent = fs.existsSync(indexPath) ? fs.readFileSync(indexPath,'utf8') : '';
const existingExports = new Set((indexContent.match(/from\\s+['\\\"](\\.\\/|\\.\\.\\/)([^'\\\"]+)['\\\"]/g) || [])
.map(line => line.match(/from\\s+['\\\"]([^'\\\"]+)['\\\"]/)[1]));
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Lines 76-77: 정규식 패턴 개선 - 다양한 export 형식 지원

현재 정규식이 기존 export를 추출할 때 모든 형식을 완벽히 지원하지 않을 수 있습니다. 큰따옴표와 작은따옴표 모두, 다양한 whitespace 패턴을 수용하도록 개선하세요:

-            const existingExports = new Set((indexContent.match(/from\\s+['\\\"](\\.\\/|\\.\\.\\/)([^'\\\"]+)['\\\"]/g) || [])
-                                  .map(line => line.match(/from\\s+['\\\"]([^'\\\"]+)['\\\"]/)[1]));
+            const existingExports = new Set((indexContent.match(/from\s+['"]([^'"]+)['"]/g) || [])
+                                  .map(line => {
+                                    const match = line.match(/from\s+['"]([^'"]+)['"]/);
+                                    return match ? match[1] : null;
+                                  }).filter(Boolean));

이렇게 수정하면 작은따옴표/큰따옴표 혼용, 다양한 whitespace를 지원하며, 매칭 실패 시 안전하게 처리합니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In .github/workflows/auto-bump-version.yaml around lines 76-77, the current
regex used to collect existing exports is brittle and may fail on different
quote styles, whitespace variations, or when match returns null; update the
pattern to accept both single and double quotes, allow optional whitespace
around tokens and relative path prefixes, and change the mapping to safely guard
against null matches (skip non-matches) before accessing capture groups so you
don't attempt to index undefined matches.

const adds = [];
const uiRoot = path.join(root, 'ui');
const componentFiles = [];
if (fs.existsSync(uiRoot)) {
fs.readdirSync(uiRoot, { withFileTypes: true })
.filter(d => d.isDirectory())
.forEach(dir => {
const dirPath = path.join(uiRoot, dir.name);
const innerItems = fs.readdirSync(dirPath, { withFileTypes: true });

for (const item of innerItems) {
if (item.isFile() && (item.name.endsWith('.ts') || item.name.endsWith('.tsx')) && item.name !== 'index.ts') {
componentFiles.push(path.join(dir.name, item.name));
}
}
});
}

for (const relativeFilePath of componentFiles) {
const componentName = path.basename(relativeFilePath, path.extname(relativeFilePath));
const exportPath = './ui/' + relativeFilePath.replace(path.extname(relativeFilePath), '');

if (existingExports.has(exportPath)) {
continue;
}
const line = \`export { \${componentName} } from '\${exportPath}'\`;
adds.push(line);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Line 103: export 라인 템플릿에 세미콜론 누락

export 문 끝에 세미콜론이 없습니다:

const line = \`export { \${componentName} } from '\${exportPath}'\`;
//                                                              ↑ 세미콜론 필요

Line 109에서 adds.join(';\\n')으로 결합하므로, 각 라인 끝에 세미콜론이 있어야 합니다:

-               const line = \`export { \${componentName} } from '\${exportPath}'\`;
+               const line = \`export { \${componentName} } from '\${exportPath}';\`;
🤖 Prompt for AI Agents
.github/workflows/auto-bump-version.yaml around lines 103-105: the export line
template currently misses a trailing semicolon which is required because later
code joins entries with ';\\n'; update the template to include a semicolon at
the end of the string (i.e., ensure the exported line ends with ';') so the
final joined output has correctly terminated export statements.



if (adds.length) {
const next = (indexContent.trim() ? indexContent.trim()+'\\n' : '') + adds.join(';\\n') + ';\\n';
fs.writeFileSync(indexPath, next);
console.log('Added exports to index.ts:', adds);
} else {
console.log('No new files found to export.');
}
"

- name: Build package
run: npm run build

- name: Commit & Push
run: |
if git diff --quiet; then
echo "No changes to commit."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add package.json src/shared/index.ts || true
git commit -m "chore: bump version and sync shared exports [skip ci]"
git push

- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Comment on lines +165 to +168
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Lines 132-135: npm publish 조건 검토 - 변경사항 없을 때 동작

npm publish 단계가 이전 "Commit & Push" 단계의 조건부 로직과 독립적으로 항상 실행됩니다. 변경사항이 없어서 Commit & Push에서 exit 0으로 조용히 종료되어도, npm publish는 시도되어 이미 배포된 버전 재배포 오류를 유발할 수 있습니다.

변경사항이 있을 때만 publish하도록 보호하세요. 예를 들어, Commit & Push에서 성공 여부를 변수로 저장 후 publish 단계에서 조건 확인:

      - name: Commit & Push
        id: commit_push
        run: |
          if git diff --quiet; then
            echo "changed=false" >> $GITHUB_OUTPUT
            exit 0
          fi
          git config user.name  "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add package.json src/shared/index.ts || true
          git commit -m "chore: bump version and sync shared exports [skip ci]"
          git push
          echo "changed=true" >> $GITHUB_OUTPUT

      - name: Publish to npm
        if: steps.commit_push.outputs.changed == 'true'
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
🤖 Prompt for AI Agents
.github/workflows/auto-bump-version.yaml around lines 132-135: the "Publish to
npm" step always runs even when the prior "Commit & Push" step did nothing,
which can cause re-publish errors; modify the workflow so the "Commit & Push"
step sets an output flag (e.g., id: commit_push and echo "changed=true" or
"changed=false" to GITHUB_OUTPUT based on git diff) and then add a conditional
to the "Publish to npm" step (if: steps.commit_push.outputs.changed == 'true')
so npm publish only runs when changes were pushed.