Fix truncated tooltip label contrast #924
Workflow file for this run
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: Staging deployment | |
| on: | |
| push: | |
| branches-ignore: [main] | |
| pull_request: | |
| types: [opened, reopened] | |
| delete: | |
| concurrency: | |
| group: staging-${{ github.event.pull_request.head.ref || github.event.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| deploy: | |
| if: github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| env: | |
| BRANCH: ${{ github.ref_name }} | |
| FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| - name: Compute staging name | |
| # "github" → "gh": Fly's abuse filter rejects app names containing | |
| # "github" (a phishing target), which every claude/github-issue-* branch | |
| # would otherwise hit. Keep this sed program identical in all three jobs. | |
| run: | | |
| SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/github/gh/g; s/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-30 | sed 's/-*$//') | |
| APP="timetracker-staging-${SLUG}" | |
| echo "SLUG=${SLUG}" >> "$GITHUB_ENV" | |
| echo "APP=${APP}" >> "$GITHUB_ENV" | |
| echo "HOST=${APP}.fly.dev" >> "$GITHUB_ENV" | |
| - name: Set up flyctl | |
| uses: superfly/flyctl-actions/setup-flyctl@master | |
| - name: Create app if missing | |
| run: | | |
| if ! flyctl status --app "$APP" >/dev/null 2>&1; then | |
| flyctl apps create "$APP" --org personal | |
| fi | |
| - name: Set staging secrets | |
| run: | | |
| # Per-app SECRET_KEY so each staging instance is independent and no | |
| # session cookie is shared across instances or with production. | |
| SECRET_KEY="staging-${SLUG}-$(head -c16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')" | |
| # APP_URL derives both ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS. | |
| flyctl secrets set --app "$APP" --stage \ | |
| "SECRET_KEY=${SECRET_KEY}" \ | |
| "APP_URL=https://${HOST}" | |
| - name: Deploy | |
| # --ha=false so Fly provisions a single machine. Staging stores sessions | |
| # in machine-local SQLite (no shared volume), so a second machine would | |
| # serve requests it has no session for, bouncing logged-in users back to | |
| # the login page. scale count 1 fixes apps already created with two. | |
| run: | | |
| flyctl deploy --app "$APP" --config fly.staging.toml --remote-only --yes --ha=false | |
| flyctl scale count 1 --app "$APP" --yes | |
| - name: Summary | |
| run: echo "Deployed to https://${HOST}" >> "$GITHUB_STEP_SUMMARY" | |
| # Comment the staging URL on the branch's PR. Runs both after a successful | |
| # push-deploy (covers PRs that already exist) and when a PR is opened or | |
| # reopened (covers the common case of pushing the branch before opening the | |
| # PR, where the deploy ran with no PR to comment on). The comment is deduped | |
| # by body, so the two paths never double-post. | |
| comment: | |
| needs: [deploy] | |
| if: | | |
| always() && | |
| (github.event_name == 'pull_request' || | |
| (github.event_name == 'push' && needs.deploy.result == 'success')) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| env: | |
| BRANCH: ${{ github.head_ref || github.ref_name }} | |
| steps: | |
| - name: Compute staging host | |
| run: | | |
| SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/github/gh/g; s/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-30 | sed 's/-*$//') | |
| echo "HOST=timetracker-staging-${SLUG}.fly.dev" >> "$GITHUB_ENV" | |
| - name: Comment staging URL on PR | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const host = process.env.HOST; | |
| const branch = process.env.BRANCH; | |
| const body = `Staging deployment: https://${host}`; | |
| const { owner, repo } = context.repo; | |
| const pulls = await github.rest.pulls.list({ | |
| owner, repo, state: "open", head: `${owner}:${branch}`, | |
| }); | |
| const pr = pulls.data[0]; | |
| if (!pr) { | |
| core.info(`No open PR for branch '${branch}', skipping comment`); | |
| return; | |
| } | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner, repo, issue_number: pr.number, | |
| }); | |
| if (comments.some((comment) => comment.body === body)) { | |
| core.info(`Staging URL already commented on PR #${pr.number}`); | |
| return; | |
| } | |
| await github.rest.issues.createComment({ | |
| owner, repo, issue_number: pr.number, body, | |
| }); | |
| core.info(`Commented staging URL on PR #${pr.number}`); | |
| teardown: | |
| if: github.event_name == 'delete' && github.event.ref_type == 'branch' | |
| runs-on: ubuntu-latest | |
| env: | |
| BRANCH: ${{ github.event.ref }} | |
| FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
| steps: | |
| - name: Set up flyctl | |
| uses: superfly/flyctl-actions/setup-flyctl@master | |
| - name: Destroy staging app | |
| run: | | |
| SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/github/gh/g; s/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-30 | sed 's/-*$//') | |
| APP="timetracker-staging-${SLUG}" | |
| flyctl apps destroy "$APP" --yes 2>/dev/null || true |