Spaces:
Paused
Paused
| # Automated Release Workflow for AI Studio Proxy API | |
| # Creates GitHub releases with source code archives when version tags are pushed, | |
| # on pushes to main (nightly builds), or manually triggered via workflow_dispatch. | |
| # | |
| # Release Types: | |
| # - Stable: Push a tag (git tag v0.1.0 && git push origin v0.1.0) | |
| # - Nightly: Automatic on every push to main branch (rolling release) | |
| # - Manual: Actions -> Release -> Run workflow -> Enter version (e.g., v0.2.0) | |
| # The tag will be auto-created on the current HEAD if it doesn't exist. | |
| name: Release | |
| on: | |
| # Trigger on pushes to main branch for nightly builds | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - 'v*.*.*' # Matches v1.0.0, v2.1.3, etc. | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., v0.1.0 or 0.1.0)' | |
| required: true | |
| type: string | |
| # Ensure only one release workflow runs at a time | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write # Required for creating releases | |
| jobs: | |
| # =========================================================================== | |
| # Stable Release Job | |
| # =========================================================================== | |
| # Runs on tag pushes (v*.*.*) or manual workflow_dispatch | |
| # Creates versioned, stable releases | |
| release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| # Only run on tag pushes or manual triggers (not on main branch pushes) | |
| if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Validate version format (manual trigger) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| VERSION_RAW="${{ github.event.inputs.version }}" | |
| if [[ "$VERSION_RAW" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| VERSION="v$VERSION_RAW" | |
| else | |
| VERSION="$VERSION_RAW" | |
| fi | |
| if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| echo "::error::Invalid version format '$VERSION_RAW'. Expected format: v1.2.3, 1.2.3, or pre-release variants like v1.2.3-beta.1" | |
| exit 1 | |
| fi | |
| echo "Version format validated: $VERSION" | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for changelog generation | |
| # For workflow_dispatch, checkout default branch first, then verify/checkout tag | |
| # For tag pushes, checkout the tag directly | |
| ref: ${{ github.event_name == 'workflow_dispatch' && '' || github.ref }} | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| VERSION_RAW="${{ github.event.inputs.version }}" | |
| if [[ "$VERSION_RAW" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| VERSION="v$VERSION_RAW" | |
| else | |
| VERSION="$VERSION_RAW" | |
| fi | |
| else | |
| VERSION="${GITHUB_REF#refs/tags/}" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT | |
| echo "Release version: $VERSION" | |
| - name: Setup Git for tagging (manual trigger) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Create or verify tag (manual trigger) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| # Fetch all tags to ensure we have the latest | |
| git fetch --tags --force | |
| if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then | |
| echo "✓ Tag $VERSION already exists" | |
| echo "Checking out existing tag..." | |
| git checkout "refs/tags/$VERSION" | |
| else | |
| echo "Tag $VERSION does not exist, creating it on current HEAD..." | |
| CURRENT_SHA=$(git rev-parse HEAD) | |
| echo "Creating tag $VERSION at commit $CURRENT_SHA" | |
| # Create the tag locally | |
| git tag -a "$VERSION" -m "Release $VERSION" | |
| # Push the tag to remote | |
| git push origin "$VERSION" | |
| echo "✓ Tag $VERSION created and pushed successfully" | |
| fi | |
| - name: Generate changelog | |
| id: changelog | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| # Find the previous tag for comparison | |
| PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | grep -v "^$VERSION$" | head -n 1) | |
| if [ -n "$PREVIOUS_TAG" ]; then | |
| echo "Generating changelog from $PREVIOUS_TAG to $VERSION" | |
| # Generate commit log grouped by type | |
| CHANGELOG=$(cat << 'CHANGELOG_EOF' | |
| ## What's Changed | |
| CHANGELOG_EOF | |
| ) | |
| TEMP_FILE=$(mktemp) | |
| while IFS= read -r commit_sha || [ -n "$commit_sha" ]; do | |
| if [ -z "$commit_sha" ]; then | |
| continue | |
| fi | |
| commit_msg=$(git log -1 --pretty=format:"%s" "$commit_sha") | |
| short_sha=$(git rev-parse --short "$commit_sha") | |
| git_author=$(git log -1 --pretty=format:"%an" "$commit_sha") | |
| api_response=$(gh api "repos/${{ github.repository }}/commits/$commit_sha" 2>/dev/null || echo '{}') | |
| github_username=$(echo "$api_response" | jq -r '.author.login // empty') | |
| if [ -n "$github_username" ]; then | |
| echo "- ${commit_msg} by @${github_username} (${short_sha})" >> "$TEMP_FILE" | |
| else | |
| echo "- ${commit_msg} by ${git_author} (${short_sha})" >> "$TEMP_FILE" | |
| fi | |
| done < <(git log --pretty=format:"%H" "$PREVIOUS_TAG..$VERSION" 2>/dev/null || true) | |
| if [ -s "$TEMP_FILE" ]; then | |
| CHANGELOG="$CHANGELOG | |
| $(cat "$TEMP_FILE")" | |
| else | |
| CHANGELOG="$CHANGELOG | |
| - Various improvements and updates" | |
| fi | |
| rm -f "$TEMP_FILE" | |
| CHANGELOG="$CHANGELOG | |
| **Full Changelog**: https://github.com/${{ github.repository }}/compare/$PREVIOUS_TAG...$VERSION" | |
| else | |
| echo "No previous tag found, this appears to be the first release" | |
| CHANGELOG="## What's Changed | |
| This is the first automated release in this repository. | |
| See the commit history for details." | |
| fi | |
| # Write to file for use in release | |
| echo "$CHANGELOG" > CHANGELOG.md | |
| echo "Changelog generated successfully" | |
| - name: Build release body | |
| id: release_body | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| VERSION_NUMBER="${{ steps.version.outputs.version_number }}" | |
| cat > RELEASE_BODY.md << 'EOF' | |
| ${{ steps.version.outputs.version }} brings improvements and updates to the AI Studio Proxy API. | |
| EOF | |
| # Append the generated changelog | |
| cat CHANGELOG.md >> RELEASE_BODY.md | |
| cat >> RELEASE_BODY.md << 'EOF' | |
| --- | |
| ## Installation | |
| ### Quick Start | |
| ```bash | |
| # Clone the repository | |
| git clone https://github.com/${{ github.repository }}.git | |
| cd AIstudioProxyAPI | |
| # Install dependencies with Poetry | |
| poetry install | |
| # Run the server | |
| poetry run python server.py | |
| ``` | |
| ### Docker | |
| ```bash | |
| docker-compose -f docker/docker-compose.yml up -d | |
| ``` | |
| For full installation and configuration details, see the [README](https://github.com/${{ github.repository }}/blob/main/README.md). | |
| ## Source Code | |
| Source code archives (zip and tar.gz) are automatically attached below. | |
| --- | |
| **Thank you to all contributors!** | |
| EOF | |
| echo "Release body generated successfully" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "AI Studio Proxy API ${{ steps.version.outputs.version }}" | |
| tag_name: ${{ steps.version.outputs.version }} | |
| body_path: RELEASE_BODY.md | |
| draft: false | |
| prerelease: ${{ contains(steps.version.outputs.version, '-') }} | |
| generate_release_notes: false # We generate our own | |
| make_latest: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Release summary | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| echo "## Release Created Successfully!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** $VERSION" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release URL:** https://github.com/${{ github.repository }}/releases/tag/$VERSION" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Included Assets" >> $GITHUB_STEP_SUMMARY | |
| echo "- Source code (zip)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Source code (tar.gz)" >> $GITHUB_STEP_SUMMARY | |
| # =========================================================================== | |
| # Nightly Release Job | |
| # =========================================================================== | |
| # Runs on every push to main branch (not on tags) | |
| # Creates/updates a rolling "nightly" release with the latest development code | |
| nightly: | |
| name: Create Nightly Release | |
| runs-on: ubuntu-latest | |
| # Only run on pushes to main branch, NOT on tag pushes | |
| if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/') | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for changelog generation | |
| - name: Get build info | |
| id: build_info | |
| run: | | |
| # Get short commit SHA and date for versioning | |
| SHORT_SHA=$(git rev-parse --short HEAD) | |
| BUILD_DATE=$(date +'%Y-%m-%d') | |
| BUILD_TIME=$(date +'%H:%M:%S UTC') | |
| COMMIT_MSG=$(git log -1 --pretty=format:"%s") | |
| echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT | |
| echo "build_date=$BUILD_DATE" >> $GITHUB_OUTPUT | |
| echo "build_time=$BUILD_TIME" >> $GITHUB_OUTPUT | |
| echo "commit_msg=$COMMIT_MSG" >> $GITHUB_OUTPUT | |
| echo "Build info: $SHORT_SHA @ $BUILD_DATE $BUILD_TIME" | |
| - name: Generate recent changes | |
| id: changes | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Build nightly changelog from latest stable tag to HEAD | |
| echo "## What's Changed" > NIGHTLY_CHANGES.md | |
| echo "" >> NIGHTLY_CHANGES.md | |
| LATEST_STABLE_TAG=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1) | |
| if [ -n "$LATEST_STABLE_TAG" ]; then | |
| echo "_Changes since ${LATEST_STABLE_TAG}_" >> NIGHTLY_CHANGES.md | |
| echo "" >> NIGHTLY_CHANGES.md | |
| echo "Using commit range: ${LATEST_STABLE_TAG}..HEAD" | |
| else | |
| echo "_No stable release tag found. Showing last 20 commits (first release scenario)._" >> NIGHTLY_CHANGES.md | |
| echo "" >> NIGHTLY_CHANGES.md | |
| echo "No stable tag found; falling back to last 20 commits" | |
| fi | |
| TEMP_FILE=$(mktemp) | |
| while IFS= read -r commit_sha || [ -n "$commit_sha" ]; do | |
| if [ -z "$commit_sha" ]; then | |
| continue | |
| fi | |
| commit_msg=$(git log -1 --pretty=format:"%s" "$commit_sha") | |
| short_sha=$(git rev-parse --short "$commit_sha") | |
| git_author=$(git log -1 --pretty=format:"%an" "$commit_sha") | |
| api_response=$(gh api "repos/${{ github.repository }}/commits/$commit_sha" 2>/dev/null || echo '{}') | |
| github_username=$(echo "$api_response" | jq -r '.author.login // empty') | |
| if [ -n "$github_username" ]; then | |
| echo "- ${commit_msg} by @${github_username} (${short_sha})" >> "$TEMP_FILE" | |
| else | |
| echo "- ${commit_msg} by ${git_author} (${short_sha})" >> "$TEMP_FILE" | |
| fi | |
| done < <( | |
| if [ -n "$LATEST_STABLE_TAG" ]; then | |
| git log --pretty=format:"%H" "${LATEST_STABLE_TAG}..HEAD" 2>/dev/null || true | |
| else | |
| git log --pretty=format:"%H" -20 2>/dev/null || true | |
| fi | |
| ) | |
| if [ -s "$TEMP_FILE" ]; then | |
| cat "$TEMP_FILE" >> NIGHTLY_CHANGES.md | |
| else | |
| if [ -n "$LATEST_STABLE_TAG" ]; then | |
| echo "- No commits found since ${LATEST_STABLE_TAG}" >> NIGHTLY_CHANGES.md | |
| else | |
| echo "- Various improvements and updates" >> NIGHTLY_CHANGES.md | |
| fi | |
| fi | |
| rm -f "$TEMP_FILE" | |
| echo "" >> NIGHTLY_CHANGES.md | |
| echo "Recent changes generated" | |
| - name: Build nightly release body | |
| run: | | |
| cat > NIGHTLY_BODY.md << 'EOF' | |
| ## ⚠️ Nightly Build (Development Version) | |
| **This is an automated nightly build from the `main` branch.** | |
| > **Warning**: This release may contain untested features, breaking changes, or bugs. | |
| > For stable releases, please use a [versioned release](https://github.com/${{ github.repository }}/releases?q=v&expanded=true). | |
| ### Build Information | |
| - **Commit**: `${{ steps.build_info.outputs.short_sha }}` | |
| - **Date**: ${{ steps.build_info.outputs.build_date }} ${{ steps.build_info.outputs.build_time }} | |
| - **Latest Change**: ${{ steps.build_info.outputs.commit_msg }} | |
| EOF | |
| cat NIGHTLY_CHANGES.md >> NIGHTLY_BODY.md | |
| cat >> NIGHTLY_BODY.md << 'EOF' | |
| --- | |
| ## Quick Start | |
| ```bash | |
| # Clone the repository | |
| git clone https://github.com/${{ github.repository }}.git | |
| cd AIstudioProxyAPI | |
| # Install dependencies | |
| poetry install | |
| # Run the server | |
| poetry run python server.py | |
| ``` | |
| --- | |
| *This nightly release is automatically updated on every push to the main branch.* | |
| **Thank you to all contributors!** | |
| EOF | |
| echo "Nightly release body generated" | |
| - name: Delete existing nightly release | |
| run: | | |
| # Delete existing nightly release if it exists (to avoid accumulation) | |
| echo "Checking for existing nightly release..." | |
| if gh release view nightly &>/dev/null; then | |
| echo "Deleting existing nightly release..." | |
| gh release delete nightly --yes --cleanup-tag | |
| echo "Existing nightly release deleted" | |
| else | |
| echo "No existing nightly release found" | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create nightly release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "Nightly Build (Latest)" | |
| tag_name: nightly | |
| body_path: NIGHTLY_BODY.md | |
| draft: false | |
| prerelease: true # Mark as prerelease since it's development code | |
| generate_release_notes: false | |
| make_latest: false # Don't mark nightly as "latest" - reserve that for stable releases | |
| target_commitish: ${{ github.sha }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Nightly release summary | |
| run: | | |
| echo "## Nightly Release Updated!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commit:** ${{ steps.build_info.outputs.short_sha }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Build Date:** ${{ steps.build_info.outputs.build_date }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release URL:** https://github.com/${{ github.repository }}/releases/tag/nightly" >> $GITHUB_STEP_SUMMARY | |