feat(ci/cd): Implement release-based deployment with two-workflow architecture
- Add prepare-release.yml: Manual release creation workflow * Builds code, generates appsettings.Production.json * Packages artifact (.tar.gz) * Creates git tag and Gitea Release with attached artifact - Refactor deploy-prod.yml: Release-based deployment workflow * Fetch Release stage: Query Gitea Releases, download artifact * Pre-Check stage: Verify SSH credentials and release integrity * Deploy stage: Upload, extract, symlink, restart service * Health Check stage: 5-point verification (HTTP, CSS, login, service, release) * Report stage: Final deployment status * Now triggered via workflow_dispatch with release version input * Removes on:push trigger (manual release selection required) - Update CLAUDE.md: * Document two-workflow architecture * Add release creation and deployment procedures * Update SSH key configuration with GITEA_TOKEN requirement * Clarify CI/CD-Only Deployment Mandate with release traceability * Add complete deployment flow documentation **Motivation**: - Separate build/release phase from deployment phase - Enable release tagging for version control and rollback - Reduce build time on re-deployments (use cached releases) - Improve deployment auditability via git tags and Gitea Releases - Match taxbaik-pattern release management strategy Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
name: Prepare Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version (e.g., v0.1.20260711 or v1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: '10.0.x'
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
name: Build & Create Release
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
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="${{ github.event.inputs.version }}"
|
||||
COMMIT=$(git rev-parse --short HEAD)
|
||||
TIMESTAMP=$(TZ=UTC date +%Y%m%d_%H%M%S)
|
||||
ARTIFACT="quantengine_${VERSION}_${COMMIT}.tar.gz"
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "artifact=${ARTIFACT}" >> $GITHUB_OUTPUT
|
||||
echo "commit=${COMMIT}" >> $GITHUB_OUTPUT
|
||||
echo "timestamp=${TIMESTAMP}" >> $GITHUB_OUTPUT
|
||||
|
||||
- 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 Production Config
|
||||
run: |
|
||||
mkdir -p ./publish
|
||||
python3 -c '
|
||||
import json
|
||||
import pathlib
|
||||
|
||||
config = {
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=quantengine_app;Search Path=quantengine;"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
- name: Package Artifact
|
||||
run: |
|
||||
ARTIFACT="${{ steps.metadata.outputs.artifact }}"
|
||||
tar -czf "$ARTIFACT" -C ./publish .
|
||||
echo "✓ Package: $(du -sh $ARTIFACT | cut -f1)"
|
||||
file "$ARTIFACT"
|
||||
|
||||
- name: Create Git Tag
|
||||
run: |
|
||||
VERSION="${{ steps.metadata.outputs.version }}"
|
||||
COMMIT="${{ steps.metadata.outputs.commit }}"
|
||||
git tag -a "$VERSION" -m "Release $VERSION (commit: $COMMIT)" HEAD
|
||||
git push origin "$VERSION"
|
||||
echo "✓ Tag created: $VERSION"
|
||||
|
||||
- name: Create Gitea Release
|
||||
run: |
|
||||
VERSION="${{ steps.metadata.outputs.version }}"
|
||||
ARTIFACT="${{ steps.metadata.outputs.artifact }}"
|
||||
COMMIT="${{ steps.metadata.outputs.commit }}"
|
||||
TOKEN="${{ secrets.GITEA_TOKEN }}"
|
||||
REPO="kjh2064/QuantEngineByItz"
|
||||
|
||||
# Create release
|
||||
gh release create "$VERSION" "$ARTIFACT" \
|
||||
--title "Release $VERSION" \
|
||||
--notes "Commit: $COMMIT
|
||||
Platform: .NET 10
|
||||
Build: $(date '+%Y-%m-%d %H:%M:%S UTC')
|
||||
|
||||
## Files
|
||||
- quantengine_release.tar.gz
|
||||
- QuantEngine.Web.dll
|
||||
- appsettings.Production.json
|
||||
- All dependencies
|
||||
|
||||
## Deployment
|
||||
Use deploy-prod.yml with release: \`$VERSION\`"
|
||||
|
||||
echo "✓ Release created: $VERSION"
|
||||
echo "✓ Artifact attached"
|
||||
|
||||
notification:
|
||||
name: Release Notification
|
||||
runs-on: ubuntu-latest
|
||||
if: success()
|
||||
needs: build-and-release
|
||||
|
||||
steps:
|
||||
- name: Notify Release Ready
|
||||
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 "════════════════════════════════════════"
|
||||
Reference in New Issue
Block a user