feat(runs): finalize Run 002 — WIN, +\.16 paper P&L #9
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: Announce Release | |
| # Triggered when a release tag is pushed (e.g. v0.1.0, v1.2.3-alpha). | |
| # Generates a builder-log style announcement in English and posts it to: | |
| # - Discord (via webhook) | |
| # - X / Twitter (via OAuth 1.0a User Context) | |
| # | |
| # Required GitHub repository secrets: | |
| # DISCORD_WEBHOOK_URL - Discord channel webhook URL | |
| # X_API_KEY - X / Twitter app consumer key | |
| # X_API_SECRET - X / Twitter app consumer secret | |
| # X_ACCESS_TOKEN - X / Twitter user access token | |
| # X_ACCESS_TOKEN_SECRET - X / Twitter user access token secret | |
| # | |
| # Optional repository variables (vars): | |
| # PROJECT_NAME - Display name (default: "Aratea") | |
| # PROJECT_TAGLINE - Short tagline (default: "Decentralized prediction markets for weather risk") | |
| # ANNOUNCE_DRY_RUN - "true" to skip actual posting (still prints messages to logs) | |
| # ANNOUNCE_DISABLE_X - "true" to skip X posting (Discord still runs) | |
| # ANNOUNCE_DISABLE_DISCORD - "true" to skip Discord posting (X still runs) | |
| on: | |
| push: | |
| tags: | |
| # Semver releases: v0.1.0, v1.2.3, v0.1.0-rc1, v1.0.0-alpha, ... | |
| - 'v[0-9]+.[0-9]+.[0-9]+' | |
| - 'v[0-9]+.[0-9]+.[0-9]+-*' | |
| # Milestone tags: M0, M3, M12, ... | |
| - 'M[0-9]+' | |
| # Kalshi POC run tags: run-001, run-002, run-2026-05, ... | |
| - 'run-*' | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to announce (e.g. v0.1.0). Leave empty to use the latest tag.' | |
| required: false | |
| type: string | |
| dry_run: | |
| description: 'Dry run only (do not actually post)' | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| announce: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # need full history for `git log` between tags | |
| fetch-tags: true # explicitly fetch tag objects so `git for-each-ref refs/tags/*` returns annotated tag bodies | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Resolve tag | |
| id: resolve | |
| # SECURITY: never interpolate `${{ github.event.inputs.* }}` or | |
| # `${{ github.ref_name }}` directly into a shell `run:` block. | |
| # Pass them through `env:` and reference them as `"$VAR"` so a | |
| # malicious tag string (workflow_dispatch input, crafted ref) | |
| # cannot break out into the shell. The tag is also whitelisted | |
| # against `[A-Za-z0-9._/-]+` before being emitted as output. | |
| # Refs: https://securitylab.github.com/research/github-actions-untrusted-input/ | |
| env: | |
| INPUT_TAG: ${{ github.event.inputs.tag }} | |
| REF_TYPE: ${{ github.ref_type }} | |
| REF_NAME: ${{ github.ref_name }} | |
| run: | | |
| if [ -n "$INPUT_TAG" ]; then | |
| TAG="$INPUT_TAG" | |
| elif [ "$REF_TYPE" = "tag" ]; then | |
| TAG="$REF_NAME" | |
| else | |
| TAG=$(git describe --tags --abbrev=0) | |
| fi | |
| if ! printf '%s' "$TAG" | grep -qE '^[A-Za-z0-9._/-]+$'; then | |
| echo "::error::Invalid tag format: $TAG" | |
| exit 1 | |
| fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "Resolved tag: $TAG" | |
| - name: Build announcement messages | |
| id: build | |
| env: | |
| GIT_TAG: ${{ steps.resolve.outputs.tag }} | |
| REPO_URL: ${{ github.server_url }}/${{ github.repository }} | |
| PROJECT_NAME: ${{ vars.PROJECT_NAME || 'Aratea' }} | |
| PROJECT_TAGLINE: ${{ vars.PROJECT_TAGLINE || 'Decentralized prediction markets for weather risk' }} | |
| run: node .github/scripts/build-announcement.mjs | |
| - name: Post to Discord | |
| if: ${{ vars.ANNOUNCE_DISABLE_DISCORD != 'true' && !inputs.dry_run && vars.ANNOUNCE_DRY_RUN != 'true' }} | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | |
| DISCORD_MESSAGE_PATH: announcement.discord.md | |
| run: node .github/scripts/post-discord.mjs | |
| - name: Post to X | |
| if: ${{ vars.ANNOUNCE_DISABLE_X != 'true' && !inputs.dry_run && vars.ANNOUNCE_DRY_RUN != 'true' }} | |
| env: | |
| X_API_KEY: ${{ secrets.X_API_KEY }} | |
| X_API_SECRET: ${{ secrets.X_API_SECRET }} | |
| X_ACCESS_TOKEN: ${{ secrets.X_ACCESS_TOKEN }} | |
| X_ACCESS_TOKEN_SECRET: ${{ secrets.X_ACCESS_TOKEN_SECRET }} | |
| X_MESSAGE_PATH: announcement.x.txt | |
| run: node .github/scripts/post-x.mjs | |
| - name: Upload announcement artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: announcement-${{ steps.resolve.outputs.tag }} | |
| path: | | |
| announcement.discord.md | |
| announcement.x.txt | |
| retention-days: 30 |