From cea58108c1d1ffda87ce5a6d862992b8ee2fc0bd Mon Sep 17 00:00:00 2001 From: Subin Lee Date: Fri, 8 May 2026 10:37:55 +0900 Subject: [PATCH] feat(release): add preview build artifacts and guide to release-please PRs When release-please opens or updates a release PR, build snapshot binaries for every supported OS/arch via GoReleaser, upload them as a workflow artifact, and post (or idempotently update) a Korean download/usage guide as a PR comment. Reviewers can verify the next version end-to-end before merging the release PR. - Add preview-release-pr job to .github/workflows/release-please.yml - Add comment body template at .github/templates/preview-build-comment.md.tmpl - Add snapshot.version_template to .goreleaser.yaml so the binary version matches the preview tag and resolves the v2.2 deprecation Co-Authored-By: Claude Opus 4.7 (1M context) --- .../templates/preview-build-comment.md.tmpl | 71 +++++++++ .github/workflows/release-please.yml | 135 ++++++++++++++++++ .goreleaser.yaml | 3 + 3 files changed, 209 insertions(+) create mode 100644 .github/templates/preview-build-comment.md.tmpl diff --git a/.github/templates/preview-build-comment.md.tmpl b/.github/templates/preview-build-comment.md.tmpl new file mode 100644 index 0000000..c9286bb --- /dev/null +++ b/.github/templates/preview-build-comment.md.tmpl @@ -0,0 +1,71 @@ + +## πŸ“¦ v${VERSION} Preview Build + +Release Pleaseκ°€ λ‹€μŒ 릴리즈λ₯Ό μ€€λΉ„ μ€‘μž…λ‹ˆλ‹€: **v${VERSION}** (commit `${SHORT_SHA}`). +이 PR이 λ¨Έμ§€λ˜λ©΄ 정식 λ¦΄λ¦¬μ¦ˆκ°€ μžλ™μœΌλ‘œ μƒμ„±λ©λ‹ˆλ‹€. λ¨Έμ§€ 전에 μ•„λž˜ 미리보기 λ°”μ΄λ„ˆλ¦¬λ‘œ μƒˆ 버전을 검증할 수 μžˆμŠ΅λ‹ˆλ‹€. + +> [!IMPORTANT] +> 이 λ°”μ΄λ„ˆλ¦¬λŠ” **곡식 λ¦΄λ¦¬μ¦ˆκ°€ μ•„λ‹™λ‹ˆλ‹€.** GitHub Actions ArtifactλŠ” μ•½ **14일 ν›„ μžλ™ μ‚­μ œ**되며 λ‹€μš΄λ‘œλ“œμ—λŠ” GitHub 둜그인이 ν•„μš”ν•©λ‹ˆλ‹€. + +### λ‹€μš΄λ‘œλ“œ + +**μ˜΅μ…˜ A β€” GitHub CLI (ꢌμž₯)** + +```bash +gh run download ${RUN_ID} \ + --repo ${REPO} \ + --name ${ARTIFACT_NAME} \ + --dir solactl-preview +cd solactl-preview +``` + +**μ˜΅μ…˜ B β€” μ›Ή λΈŒλΌμš°μ €** + +[Workflow Run #${RUN_ID}](${RUN_URL}) νŽ˜μ΄μ§€ ν•˜λ‹¨ _Artifacts_ μ„Ήμ…˜μ—μ„œ [`${ARTIFACT_NAME}`](${ARTIFACT_URL}) 을 λ°›μ•„ 압좕을 ν’‰λ‹ˆλ‹€. λ‹€μš΄λ‘œλ“œ 받은 zip μ•ˆμ—λŠ” OS/μ•„ν‚€ν…μ²˜λ³„ tarballΒ·zip κ³Ό `checksums.txt` κ°€ λ“€μ–΄ μžˆμŠ΅λ‹ˆλ‹€. + +### μ‹€ν–‰ + +#### Linux / macOS + +ν”Œλž«νΌμ— λ§žλŠ” tarball을 ν’‰λ‹ˆλ‹€ (`` = `linux` λ˜λŠ” `darwin`, `` = `amd64` λ˜λŠ” `arm64`): + +```bash +tar -xzf solactl_${VERSION}-preview-${SHORT_SHA}__.tar.gz +chmod +x solactl +./solactl version +# μ˜ˆμƒ 좜λ ₯: solactl ${VERSION}-preview-${SHORT_SHA} (commit: ..., date: ...) +``` + +> [!NOTE] +> macOSμ—μ„œ _"ν™•μΈλ˜μ§€ μ•Šμ€ 개발자"_ κ²½κ³ κ°€ 뜨면 quarantine 속성을 μ œκ±°ν•˜μ„Έμš”: +> ```bash +> xattr -d com.apple.quarantine ./solactl +> ``` + +#### Windows + +```powershell +Expand-Archive solactl_${VERSION}-preview-${SHORT_SHA}_windows_amd64.zip -DestinationPath . +.\solactl_${VERSION}-preview-${SHORT_SHA}_windows_amd64\solactl.exe version +``` + +### 무결성 검증 (선택) + +```bash +sha256sum -c checksums.txt --ignore-missing +``` + +### 검증 포인트 + +λ¨Έμ§€ 전에 μ•„λž˜ ν•­λͺ©λ“€μ„ 확인해 μ£Όμ„Έμš”: + +- 이 PR μƒλ‹¨μ˜ _Release notes_ 에 λ‚˜μ—΄λœ λ³€κ²½ 사항이 μ˜λ„λŒ€λ‘œ λ™μž‘ν•˜λŠ”μ§€ +- `solactl version` 좜λ ₯이 μœ„ μ˜ˆμƒ 좜λ ₯κ³Ό μΌμΉ˜ν•˜λŠ”μ§€ +- νšŒκ·€ κ°€λŠ₯성이 μžˆλŠ” κΈ°μ‘΄ λͺ…λ Ήλ“€ (`solactl configure`, `solactl send sms`, `solactl quota`, `solactl kakao` λ“±) +- 자주 μ“°λŠ” μ›Œν¬ν”Œλ‘œ (μ„€μ • 파일 μƒμ„±Β·λ‘œλ“œ, `--profile` μ „ν™˜, `--debug` 좜λ ₯) + +λ¬Έμ œκ°€ μžˆλ‹€λ©΄ 이 PR에 μ½”λ©˜νŠΈλ‘œ μ•Œλ €μ£Όμ„Έμš”. λ¨Έμ§€ ν›„ release μ›Œν¬ν”Œλ‘œκ°€ μžλ™μœΌλ‘œ 정식 λ°”μ΄λ„ˆλ¦¬λ₯Ό λΉŒλ“œΒ·λ°°ν¬ν•©λ‹ˆλ‹€. + +--- + +이 λŒ“κΈ€μ€ .github/workflows/release-please.yml 의 preview-release-pr job 에 μ˜ν•΄ μžλ™μœΌλ‘œ μƒμ„±Β·κ°±μ‹ λ©λ‹ˆλ‹€ Β· build commit ${SHA} Β· run [#${RUN_ID}](${RUN_URL}) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 140c0fc..d24d88d 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -145,6 +145,141 @@ jobs: gh api "repos/$REPO/statuses/$SHA" \ -f state=failure -f context="Lint" -f description="Lint failed" + preview-release-pr: + name: Preview Build (Release PR) + needs: release-please + if: ${{ !needs.release-please.outputs.release_created && needs.release-please.outputs.pr_head_sha != '' }} + runs-on: ubuntu-latest + env: + ARTIFACT_NAME_PREFIX: solactl-preview + steps: + - name: Set pending status + continue-on-error: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SHA: ${{ needs.release-please.outputs.pr_head_sha }} + REPO: ${{ github.repository }} + run: | + gh api "repos/$REPO/statuses/$SHA" \ + -f state=pending -f context="Preview Build" -f description="Building preview binaries..." + + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ needs.release-please.outputs.pr_head_sha }} + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: '1.26.1' + + - name: Resolve preview version + id: version + run: | + VERSION=$(jq -r '."."' .release-please-manifest.json) + if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then + echo "::error::Failed to read version from .release-please-manifest.json" + exit 1 + fi + SHORT_SHA="${GITHUB_SHA::7}" + TAG="v${VERSION}-preview-${SHORT_SHA}" + ARTIFACT_NAME="${ARTIFACT_NAME_PREFIX}-v${VERSION}-${SHORT_SHA}" + { + echo "version=${VERSION}" + echo "short_sha=${SHORT_SHA}" + echo "tag=${TAG}" + echo "artifact_name=${ARTIFACT_NAME}" + } >> "$GITHUB_OUTPUT" + echo "GORELEASER_CURRENT_TAG=${TAG}" >> "$GITHUB_ENV" + + - name: Run GoReleaser snapshot + uses: goreleaser/goreleaser-action@v7 + with: + distribution: goreleaser + version: '~> v2' + args: release --snapshot --skip=publish --clean + + - name: Upload preview artifacts + id: artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.version.outputs.artifact_name }} + path: | + dist/solactl_*.tar.gz + dist/solactl_*.zip + dist/checksums.txt + retention-days: 14 + if-no-files-found: error + compression-level: 0 + + - name: Comment preview guide on PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + VERSION: ${{ steps.version.outputs.version }} + SHORT_SHA: ${{ steps.version.outputs.short_sha }} + TAG: ${{ steps.version.outputs.tag }} + SHA: ${{ needs.release-please.outputs.pr_head_sha }} + ARTIFACT_URL: ${{ steps.artifact.outputs.artifact-url }} + ARTIFACT_NAME: ${{ steps.version.outputs.artifact_name }} + RUN_ID: ${{ github.run_id }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + TEMPLATE_PATH: .github/templates/preview-build-comment.md.tmpl + run: | + set -euo pipefail + + if [ ! -f "$TEMPLATE_PATH" ]; then + echo "::error::Comment template not found at $TEMPLATE_PATH" + exit 1 + fi + + PR_NUMBER=$(gh pr list --repo "$REPO" --head release-please--branches--main --state open --json number --jq '.[0].number') + if [ -z "$PR_NUMBER" ]; then + echo "::warning::No open release-please PR found; skipping comment" + exit 0 + fi + + export VERSION SHORT_SHA TAG SHA ARTIFACT_NAME ARTIFACT_URL RUN_ID RUN_URL REPO + + BODY_FILE="$(mktemp)" + envsubst '${VERSION} ${SHORT_SHA} ${TAG} ${SHA} ${ARTIFACT_NAME} ${ARTIFACT_URL} ${RUN_ID} ${RUN_URL} ${REPO}' \ + < "$TEMPLATE_PATH" > "$BODY_FILE" + + PAYLOAD_FILE="$(mktemp)" + jq -Rs '{body: .}' "$BODY_FILE" > "$PAYLOAD_FILE" + + EXISTING_ID=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" --paginate \ + --jq '.[] | select(.body | startswith("")) | .id' | head -n 1) + + if [ -n "$EXISTING_ID" ]; then + echo "Updating existing preview comment $EXISTING_ID on PR #$PR_NUMBER" + gh api -X PATCH "repos/$REPO/issues/comments/$EXISTING_ID" --input "$PAYLOAD_FILE" > /dev/null + else + echo "Creating new preview comment on PR #$PR_NUMBER" + gh api "repos/$REPO/issues/$PR_NUMBER/comments" --input "$PAYLOAD_FILE" > /dev/null + fi + + - name: Report success + if: success() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SHA: ${{ needs.release-please.outputs.pr_head_sha }} + REPO: ${{ github.repository }} + run: | + gh api "repos/$REPO/statuses/$SHA" \ + -f state=success -f context="Preview Build" -f description="Preview binaries ready" + + - name: Report failure + if: failure() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SHA: ${{ needs.release-please.outputs.pr_head_sha }} + REPO: ${{ github.repository }} + run: | + gh api "repos/$REPO/statuses/$SHA" \ + -f state=failure -f context="Preview Build" -f description="Preview build failed" + goreleaser: name: Release Binaries needs: release-please diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 3f509d2..4691211 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -31,6 +31,9 @@ archives: checksum: name_template: checksums.txt +snapshot: + version_template: '{{ .Version }}' + changelog: disable: true