deploy-upstream #8123
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy new upstream release to Vercel | |
| on: | |
| workflow_dispatch: | |
| repository_dispatch: | |
| types: [deploy-upstream] | |
| jobs: | |
| # ======================================== | |
| # JOB 1: Fetch Versions | |
| # ======================================== | |
| fetch-versions: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| latest-version: ${{ steps.upstream.outputs.latest-version }} | |
| latest-tag: ${{ steps.upstream.outputs.latest-tag }} | |
| production-version: ${{ steps.production.outputs.production-version }} | |
| production-tag: ${{ steps.production.outputs.production-tag }} | |
| latest-patch-in-line-version: ${{ steps.patch-in-line.outputs.latest-patch-in-line-version }} | |
| latest-patch-in-line-tag: ${{ steps.patch-in-line.outputs.latest-patch-in-line-tag }} | |
| steps: | |
| - name: Log trigger information | |
| run: | | |
| echo "Workflow triggered by: ${{ github.event_name }}" | |
| if [ "${{ github.event_name }}" = "repository_dispatch" ]; then | |
| echo "Event type: ${{ github.event.action }}" | |
| echo "Client payload: ${{ toJson(github.event.client_payload) }}" | |
| fi | |
| - name: Generate GitHub App Token | |
| id: app-token | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ vars.GH_APP_ID }} | |
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| fetch-depth: 0 # Fetch full history | |
| - name: Configure Git with GitHub App | |
| run: | | |
| git config --global user.name "dos-automation-bot[bot]" | |
| git config --global user.email "[email protected]" | |
| - name: Identify the latest upstream version | |
| id: upstream | |
| run: | | |
| # Add upstream remote using HTTPS with token | |
| git remote add upstream https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxprotocol/v4-web.git | |
| # Update origin to use HTTPS with token | |
| git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxopsdao/v4-web.git | |
| # Fetch all tags from upstream | |
| git fetch upstream | |
| # Get the latest release tag | |
| LATEST_TAG=$(git tag -l 'release/v*' | sort -V | tail -n 1) | |
| echo "Latest upstream tag found: ${LATEST_TAG}" | |
| # Check if LATEST_TAG is empty | |
| if [ -z "$LATEST_TAG" ]; then | |
| echo "No tags found matching 'release/v*'." | |
| exit 1 | |
| fi | |
| # Export to outputs | |
| echo "latest-tag=${LATEST_TAG}" >> $GITHUB_OUTPUT | |
| echo "latest-version=${LATEST_TAG#release/v}" >> $GITHUB_OUTPUT | |
| - name: Identify the latest production version | |
| id: production | |
| run: | | |
| # Fetch all tags from the main branch | |
| git fetch origin main --tags | |
| # Get the latest tag on the main branch | |
| PRODUCTION_TAG=$(git tag --merged origin/main | sort -V | tail -n 1) | |
| echo "Latest production tag on main branch: ${PRODUCTION_TAG}" | |
| # Check if PRODUCTION_TAG is empty | |
| if [ -z "$PRODUCTION_TAG" ]; then | |
| echo "No production tags found on main branch." | |
| exit 1 | |
| fi | |
| # Export to outputs | |
| echo "production-tag=${PRODUCTION_TAG}" >> $GITHUB_OUTPUT | |
| echo "production-version=${PRODUCTION_TAG#release/v}" >> $GITHUB_OUTPUT | |
| - name: Identify the latest patch in production version line | |
| id: patch-in-line | |
| run: | | |
| # Get the production version to extract major.minor | |
| PRODUCTION_VERSION="${{ steps.production.outputs.production-version }}" | |
| IFS='.' read -r PROD_MAJOR PROD_MINOR PROD_PATCH <<< "$PRODUCTION_VERSION" | |
| echo "Production version: $PRODUCTION_VERSION (Major: $PROD_MAJOR, Minor: $PROD_MINOR, Patch: $PROD_PATCH)" | |
| echo "Looking for latest patch in upstream version line: $PROD_MAJOR.$PROD_MINOR.x" | |
| # Find the latest tag in the same major.minor version line from upstream | |
| LATEST_PATCH_IN_LINE_TAG=$(git tag -l "release/v$PROD_MAJOR.$PROD_MINOR.*" | sort -V | tail -n 1) | |
| if [ -z "$LATEST_PATCH_IN_LINE_TAG" ]; then | |
| echo "No upstream tags found for version line $PROD_MAJOR.$PROD_MINOR.x" | |
| echo "Using production version as fallback" | |
| echo "latest-patch-in-line-tag=${{ steps.production.outputs.production-tag }}" >> $GITHUB_OUTPUT | |
| echo "latest-patch-in-line-version=$PRODUCTION_VERSION" >> $GITHUB_OUTPUT | |
| else | |
| LATEST_PATCH_IN_LINE_VERSION="${LATEST_PATCH_IN_LINE_TAG#release/v}" | |
| echo "Latest patch in upstream version line: $LATEST_PATCH_IN_LINE_TAG ($LATEST_PATCH_IN_LINE_VERSION)" | |
| # Export to outputs | |
| echo "latest-patch-in-line-tag=${LATEST_PATCH_IN_LINE_TAG}" >> $GITHUB_OUTPUT | |
| echo "latest-patch-in-line-version=${LATEST_PATCH_IN_LINE_VERSION}" >> $GITHUB_OUTPUT | |
| fi | |
| # ======================================== | |
| # JOB 2: Determine If Deployment Is Needed | |
| # ======================================== | |
| determine-if-deployment-needed: | |
| runs-on: ubuntu-latest | |
| needs: fetch-versions | |
| outputs: | |
| new-patch-version: ${{ steps.version-check.outputs.new-patch-version }} | |
| steps: | |
| - name: Determine version type | |
| id: version-check | |
| run: | | |
| echo "Checking if the version is a patch, minor, or major" | |
| # Extract version numbers from outputs | |
| IFS='.' read -r PROD_MAJOR PROD_MINOR PROD_PATCH <<< "${{ needs.fetch-versions.outputs.production-version }}" | |
| IFS='.' read -r UPSTREAM_MAJOR UPSTREAM_MINOR UPSTREAM_PATCH <<< "${{ needs.fetch-versions.outputs.latest-version }}" | |
| IFS='.' read -r PATCH_LINE_MAJOR PATCH_LINE_MINOR PATCH_LINE_PATCH <<< "${{ needs.fetch-versions.outputs.latest-patch-in-line-version }}" | |
| # Log the extracted version numbers | |
| echo "Production Version - Major: $PROD_MAJOR, Minor: $PROD_MINOR, Patch: $PROD_PATCH" | |
| echo "Latest Patch in Line - Major: $PATCH_LINE_MAJOR, Minor: $PATCH_LINE_MINOR, Patch: $PATCH_LINE_PATCH" | |
| echo "Latest Version - Major: $UPSTREAM_MAJOR, Minor: $UPSTREAM_MINOR, Patch: $UPSTREAM_PATCH" | |
| # Determine if a new patch version is detected within the same major.minor line | |
| if [ "$PATCH_LINE_MAJOR" -eq "$PROD_MAJOR" ] && [ "$PATCH_LINE_MINOR" -eq "$PROD_MINOR" ] && [ "$PATCH_LINE_PATCH" -gt "$PROD_PATCH" ]; then | |
| echo "New patch version detected: ${{ needs.fetch-versions.outputs.latest-patch-in-line-tag }}" | |
| echo "new-patch-version=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "No new patch version detected." | |
| echo "new-patch-version=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # ======================================== | |
| # JOB 3: Deploy | |
| # ======================================== | |
| deploy: | |
| runs-on: ubuntu-latest | |
| needs: [fetch-versions, determine-if-deployment-needed] | |
| if: needs.determine-if-deployment-needed.outputs.new-patch-version == 'true' | |
| steps: | |
| - name: Generate GitHub App Token | |
| id: app-token | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ vars.GH_APP_ID }} | |
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| fetch-depth: 0 # Fetch full history | |
| - name: Configure Git with GitHub App and GPG signing | |
| run: | | |
| git config --global user.name "dos-automation" | |
| git config --global user.email "[email protected]" | |
| # Configure GPG for non-interactive use | |
| mkdir -p ~/.gnupg | |
| echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf | |
| # Import GPG key and configure signing | |
| echo "${{ secrets.BOT_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import | |
| git config --global user.signingkey $(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2) | |
| git config --global commit.gpgsign true | |
| - name: Setup git remotes | |
| run: | | |
| # Add upstream remote using HTTPS with token | |
| git remote add upstream https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxprotocol/v4-web.git | |
| # Update origin to use HTTPS with token | |
| git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxopsdao/v4-web.git | |
| # Fetch all tags from upstream to ensure they are available locally | |
| git fetch upstream --tags | |
| - name: Create a new release branch for Vercel deployment | |
| run: | | |
| # Create a new branch from the latest release tag | |
| git checkout -b dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} origin/main | |
| # Rebase commits from the latest release tag onto the new release branch | |
| git pull --rebase upstream ${{ needs.fetch-versions.outputs.latest-patch-in-line-tag }} | |
| # Push the release branch to the remote repository | |
| git push --set-upstream origin dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} | |
| - name: Reset main to the feature branch for production deployment and push all changes | |
| run: | | |
| # Checkout the main branch | |
| git checkout main | |
| # Hard reset the main branch to the feature branch | |
| git reset --hard origin/dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} | |
| # Force push the changes to the main branch | |
| sleep 1 | |
| git push --force origin main | |
| # ======================================== | |
| # JOB 4: Notify Failure | |
| # ======================================== | |
| notify-failure: | |
| runs-on: ubuntu-latest | |
| needs: [fetch-versions, determine-if-deployment-needed, deploy] | |
| if: failure() || cancelled() | |
| steps: | |
| - name: Send failure notice to deploymentPromoted bot | |
| env: | |
| BOT_ENDPOINT: ${{ vars.DEPLOYMENT_PROMOTED_URL }} | |
| PROJECT_NAME: v4-web | |
| LATEST_PATCH: ${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} | |
| PRODUCTION_VERSION: ${{ needs.fetch-versions.outputs.production-version }} | |
| run: | | |
| VERSION_PAYLOAD="$LATEST_PATCH" | |
| if [ -z "$VERSION_PAYLOAD" ]; then | |
| VERSION_PAYLOAD="$PRODUCTION_VERSION" | |
| fi | |
| curl -X POST "$BOT_ENDPOINT" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$(jq -n \ | |
| --arg project "$PROJECT_NAME" \ | |
| --arg status "failed" \ | |
| --arg version "$VERSION_PAYLOAD" \ | |
| --arg workflow_run "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ | |
| '{project: $project, status: $status, version: $version, meta: {workflow_run: $workflow_run}}')" |