deploy #2
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 | |
| # Two jobs: `frontend` deploys the React app to Cloudflare Pages, `engine` | |
| # deploys the meridian-server Docker image to Fly.io. Both require repo | |
| # secrets to be configured first; see docs/setup-guide.md. | |
| # | |
| # Trigger model: `workflow_dispatch` only for v1, so merging the deploy | |
| # artifacts PR does not fail loudly before the secrets are in place. Once | |
| # the first manual deploy succeeds, flip the trigger to `push: branches: | |
| # [main]` (a one-line follow-up) so subsequent merges deploy automatically. | |
| # | |
| # Every value flowing in from a GitHub-controlled context (commit SHA, | |
| # branch name, the workflow_dispatch input enum) is bound through `env:` | |
| # or an action input rather than interpolated directly into a `run:` | |
| # block, so the workflow is not exposed to script-injection through any | |
| # field an attacker could populate. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| target: | |
| description: "Which surface to deploy" | |
| required: true | |
| type: choice | |
| default: "both" | |
| options: ["both", "frontend", "engine"] | |
| # Cancel a stale deploy if a newer one starts on the same ref so two | |
| # concurrent manual triggers do not race against each other on Cloudflare | |
| # or Fly. | |
| concurrency: | |
| group: deploy-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| frontend: | |
| if: ${{ inputs.target == 'both' || inputs.target == 'frontend' }} | |
| name: frontend (Cloudflare Pages) | |
| runs-on: ubuntu-24.04 | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| permissions: | |
| contents: read | |
| deployments: write | |
| env: | |
| VITE_MERIDIAN_WS: wss://meridian-engine.fly.dev/ws | |
| VITE_MERIDIAN_VERSION: ${{ github.sha }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| - name: Enable pnpm via corepack | |
| run: corepack enable | |
| - name: Resolve pnpm store path | |
| id: pnpm-store | |
| run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT" | |
| - name: Cache pnpm store | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.pnpm-store.outputs.path }} | |
| key: pnpm-${{ runner.os }}-${{ hashFiles('frontend/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| pnpm-${{ runner.os }}- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build production bundle | |
| run: pnpm run build | |
| - name: Publish to Cloudflare Pages | |
| uses: cloudflare/pages-action@v1 | |
| with: | |
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| projectName: meridian-orderbook | |
| directory: frontend/dist | |
| branch: ${{ github.ref_name }} | |
| gitHubToken: ${{ secrets.GITHUB_TOKEN }} | |
| engine: | |
| if: ${{ inputs.target == 'both' || inputs.target == 'engine' }} | |
| name: engine (Fly.io) | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup flyctl | |
| uses: superfly/flyctl-actions/setup-flyctl@master | |
| # `flyctl deploy --remote-only` ships the build context to Fly's | |
| # remote builder so the runner does not need its own Docker daemon. | |
| - name: Deploy meridian-engine | |
| run: flyctl deploy --remote-only --app meridian-engine | |
| env: | |
| FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} |