Files
QuantEngineByItz/.gitea/workflows/prepare-release.yml
T
kjh2064 a8e6479193
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 13s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 20s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
Workflow Lint & Validation / Notify Lint Results (push) Failing after 1s
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 12s
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 12s
Workflow Lint & Validation / Validate Secrets Contract (push) Successful in 7s
Workflow Lint & Validation / Lint All Workflow Files (push) Failing after 14s
ci(wbs-ux): inject Vue 3 frontend build task to release compilation pipeline
2026-07-25 11:36:58 +09:00

308 lines
11 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Prepare Release
on:
workflow_run:
workflows: ["Validators (Pushes and Pull Requests)"]
types: [completed]
workflow_dispatch:
inputs:
version:
description: 'Release version (auto-generated if empty, e.g. quant_20260711.0.abc1234 for the first deploy that day)'
required: false
type: string
env:
DOTNET_VERSION: '10.0.x'
concurrency:
group: prepare-release-${{ github.event.workflow_run.head_sha || github.sha }}
cancel-in-progress: false
jobs:
upstream-gate:
name: "Upstream CI Success Gate"
runs-on: ubuntu-latest
steps:
- name: Check CI Pipeline Status
run: |
if [ "${{ github.event_name }}" = "workflow_run" ]; then
if [ "${{ github.event.workflow_run.conclusion }}" != "success" ]; then
echo "❌ ERROR: CI pipeline failed — release preparation blocked"
exit 1
fi
echo "✓ CI pipeline succeeded — proceeding to release"
else
echo " Release triggered manually — skipping upstream CI check"
fi
build-and-release:
name: Build & Create Release
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
timeout-minutes: 30
needs: upstream-gate
outputs:
version: ${{ steps.metadata.outputs.version }}
commit: ${{ steps.metadata.outputs.commit }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Generate Metadata
id: metadata
run: |
VERSION_INPUT="${{ github.event.inputs.version }}"
COMMIT=$(git rev-parse --short HEAD)
# Auto-generate version if not provided
if [ -z "$VERSION_INPUT" ]; then
# Simple, reliable version scheme: timestamp + commit hash
# Avoids unreliable Gitea API calls (network failures, timeouts)
# Format: vYYYY.MM.DD.HHMMSS.COMMIT
TIMESTAMP=$(TZ=Asia/Seoul date +%Y.%m.%d.%H%M%S)
VERSION="v${TIMESTAMP}.${COMMIT}"
else
VERSION="$VERSION_INPUT"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "commit=${COMMIT}" >> $GITHUB_OUTPUT
echo "Version: $VERSION"
echo "Commit: $COMMIT"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Frontend Dependencies & Build
run: |
cd src/frontend
npm install
npm run build
cd ../..
- name: Copy Built Frontend to wwwroot
run: |
mkdir -p src/dotnet/QuantEngine.Web/wwwroot
cp -r src/frontend/dist/* src/dotnet/QuantEngine.Web/wwwroot/
echo "✓ Frontend assets copied to BFF wwwroot"
- name: Restore
run: |
dotnet restore src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj
- name: Build (Release)
run: |
dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \
-c Release \
--no-restore \
-p:ContinuousIntegrationBuild=true
- name: Publish
run: |
dotnet publish src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \
-c Release \
-o ./publish \
--no-restore \
--no-build
- name: Write Version Text
run: |
echo "${{ steps.metadata.outputs.version }}" > ./publish/version.txt
- name: Write Production Config
run: |
mkdir -p ./publish
VERSION="${{ steps.metadata.outputs.version }}"
python3 -c '
import json
import pathlib
# NOTE: No ConnectionStrings here on purpose. The real DB
# password lives only in /home/kjh2064/.config/quantengine.env
# on the production server and is injected via systemd
# EnvironmentFile (ConnectionStrings__DefaultConnection),
# which overrides this file at runtime. Never bake secrets
# into a build artifact that ends up in a Gitea Release.
config = {
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AppVersion": "'$VERSION'"
}
pathlib.Path("./publish/appsettings.Production.json").write_text(
json.dumps(config, ensure_ascii=False, indent=2),
encoding="utf-8"
)'
test -s ./publish/appsettings.Production.json || { echo "ERROR: appsettings.Production.json is empty"; exit 1; }
echo "✓ Production config created (version: $VERSION)"
- name: Package Artifact
run: |
VERSION="${{ steps.metadata.outputs.version }}"
ARTIFACT="quantengine_${VERSION}.tar.gz"
tar -czf "$ARTIFACT" -C ./publish .
echo "artifact=${ARTIFACT}" >> $GITHUB_OUTPUT
echo "✓ Package: $(du -sh $ARTIFACT | cut -f1)"
file "$ARTIFACT"
- name: Generate Artifact Checksum
run: |
VERSION="${{ steps.metadata.outputs.version }}"
ARTIFACT="quantengine_${VERSION}.tar.gz"
sha256sum "$ARTIFACT" | awk '{print $1}' > "${ARTIFACT}.sha256"
echo "✓ Checksum created: ${ARTIFACT}.sha256"
cat "${ARTIFACT}.sha256"
- name: Generate Release Manifest
run: |
VERSION="${{ steps.metadata.outputs.version }}"
COMMIT="${{ steps.metadata.outputs.commit }}"
ARTIFACT="quantengine_${VERSION}.tar.gz"
CHECKSUM=$(cat "${ARTIFACT}.sha256")
python3 - <<PY
import json
import pathlib
payload = {
"version": "${VERSION}",
"commit": "${COMMIT}",
"artifact": "${ARTIFACT}",
"sha256": "${CHECKSUM}",
}
pathlib.Path("${ARTIFACT}.manifest.json").write_text(
json.dumps(payload, ensure_ascii=False, indent=2),
encoding="utf-8",
)
PY
echo "✓ Manifest created"
- name: Validate Release Manifest
run: |
ARTIFACT="quantengine_${{ steps.metadata.outputs.version }}.tar.gz"
MANIFEST="${ARTIFACT}.manifest.json"
python3 - <<PY
import json
import sys
import pathlib
try:
data = json.loads(pathlib.Path("${MANIFEST}").read_text(encoding="utf-8"))
required_fields = ["version", "commit", "artifact", "sha256"]
for field in required_fields:
if field not in data or not data[field]:
print(f"ERROR: Manifest missing or empty '{field}'")
sys.exit(1)
print(f"✓ Manifest validated: {data['version']}")
except Exception as e:
print(f"ERROR: {e}")
sys.exit(1)
PY
- name: Create Git Tag
run: |
VERSION="${{ steps.metadata.outputs.version }}"
COMMIT="${{ steps.metadata.outputs.commit }}"
git config user.name "Gitea Actions"
git config user.email "actions@gitea.local"
git tag -a "$VERSION" -m "Release $VERSION (commit: $COMMIT)" HEAD
echo "✓ Local tag created: $VERSION"
git push origin "$VERSION"
echo "✓ Tag pushed: $VERSION"
- name: Create Gitea Release
env:
VERSION: ${{ steps.metadata.outputs.version }}
COMMIT: ${{ steps.metadata.outputs.commit }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
ARTIFACT="quantengine_${VERSION}.tar.gz"
API="https://gitea.taxbaik.com/api/v1"
REPO="kjh2064/QuantEngineByItz"
test -s "$ARTIFACT" || { echo "ERROR: artifact missing: $ARTIFACT"; exit 1; }
echo "Creating release $VERSION via Gitea API..."
RELEASE_JSON=$(curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"${VERSION}\",\"name\":\"Release ${VERSION}\",\"body\":\"Release Version: ${VERSION} | Commit: ${COMMIT}\",\"target_commitish\":\"main\"}" \
"${API}/repos/${REPO}/releases")
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
echo "ERROR: Failed to create release"
echo "$RELEASE_JSON"
exit 1
fi
echo "✓ Release created: $VERSION (id: $RELEASE_ID)"
echo "Uploading artifact..."
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: multipart/form-data" \
-F "attachment=@${ARTIFACT}" \
"${API}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${ARTIFACT}" \
-o /dev/null
echo "✓ Artifact attached: $ARTIFACT"
echo "Uploading checksum..."
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: multipart/form-data" \
-F "attachment=@${ARTIFACT}.sha256" \
"${API}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${ARTIFACT}.sha256" \
-o /dev/null
echo "✓ Checksum attached: ${ARTIFACT}.sha256"
echo "Uploading manifest..."
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: multipart/form-data" \
-F "attachment=@${ARTIFACT}.manifest.json" \
"${API}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${ARTIFACT}.manifest.json" \
-o /dev/null
echo "✓ Manifest attached: ${ARTIFACT}.manifest.json"
notification:
name: Release Notification
runs-on: ubuntu-latest
if: always()
needs: [upstream-gate, build-and-release]
steps:
- name: Notify Release Ready
if: needs.build-and-release.result == 'success'
run: |
echo "════════════════════════════════════════"
echo "✅ Release Ready for Deployment"
echo "════════════════════════════════════════"
echo "Version: ${{ needs.build-and-release.outputs.version }}"
echo "Commit: ${{ needs.build-and-release.outputs.commit }}"
echo ""
echo "Next: Use deploy-prod.yml to deploy this release"
echo "════════════════════════════════════════"