A lexicon-driven AppView for ATProto.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113name: CI
on: push: branches: [main, dev] pull_request: branches: [main, dev] workflow_dispatch: inputs: server: description: "Build server (unit tests, e2e, frontend, lint, release)" type: boolean default: true oauth-client: description: "Build oauth-client" type: boolean default: false oauth-client-browser: description: "Build oauth-client-browser" type: boolean default: false oauth-client-node: description: "Build oauth-client-node" type: boolean default: false lex-agent: description: "Build lex-agent" type: boolean default: false nsid: description: "Build nsid" type: boolean default: false delete:
env: SQLX_OFFLINE: true
permissions: id-token: write # Required for OIDC
jobs: # --------------------------------------------------------------------------- # Path detection — determines which job groups should run. # Required because workflow-level `paths` filters can't vary per job. # --------------------------------------------------------------------------- changes: if: github.event_name == 'pull_request' || github.event_name == 'push' runs-on: depot-ubuntu-24.04 outputs: server: ${{ steps.filter.outputs.server }} oauth-client: ${{ steps.filter.outputs.oauth-client }} oauth-client-browser: ${{ steps.filter.outputs.oauth-client-browser }} oauth-client-node: ${{ steps.filter.outputs.oauth-client-node }} lex-agent: ${{ steps.filter.outputs.lex-agent }} nsid: ${{ steps.filter.outputs.nsid }} steps: - name: Checkout repository uses: actions/checkout@v6
- name: Detect changed paths id: filter uses: dorny/paths-filter@v4 with: filters: | server: - 'src/**' - 'web/**' - 'migrations/**' - 'tests/**' - 'Cargo.*' - 'crates/**' - 'Dockerfile' - 'docker-compose*' - 'entrypoint.sh' - '.releaserc.json' oauth-client: - 'packages/oauth-client/**' oauth-client-browser: - 'packages/oauth-client/**' - 'packages/oauth-client-browser/**' oauth-client-node: - 'packages/oauth-client/**' - 'packages/oauth-client-node/**' lex-agent: - 'packages/oauth-client/**' - 'packages/lex-agent/**' nsid: - 'crates/happyview-nsid/**' - 'packages/nsid/**'
# --------------------------------------------------------------------------- # Server — unit tests, e2e tests, frontend build, lint # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # Build server binary — shared by playwright and pr-build (amd64) # --------------------------------------------------------------------------- build-server: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Build release binary uses: docker/build-push-action@v5 with: context: . target: binary platforms: linux/amd64 cache-from: type=gha,scope=builder-linux/amd64 cache-to: type=gha,scope=builder-linux/amd64,mode=max,ignore-error=true outputs: type=local,dest=.
- name: Upload server binary uses: actions/upload-artifact@v4 with: name: happyview-server path: target/release/happyview
unit-tests: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 timeout-minutes: 15 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Cache cargo uses: Swatinem/rust-cache@v2 with: shared-key: test
- name: Run unit tests run: cargo test --lib
- name: Run crate tests run: cargo test --workspace --exclude happyview
e2e-tests: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 timeout-minutes: 15 services: postgres: image: postgres:16-alpine env: POSTGRES_USER: happyview POSTGRES_PASSWORD: happyview POSTGRES_DB: happyview_test ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Cache cargo uses: Swatinem/rust-cache@v2 with: shared-key: test
# Reclaim ~20 GB of preinstalled tooling the Rust build never uses. The # e2e build (all test binaries in debug) plus the restored target cache # otherwise exhausts the runner disk ("No space left on device"). - name: Free disk space run: | sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \ /usr/local/.ghcup /opt/hostedtoolcache/CodeQL df -h /
- name: Add WASM target run: rustup target add wasm32-unknown-unknown
- name: Build test plugin run: cargo build --manifest-path tests/fixtures/test_plugin/Cargo.toml --target wasm32-unknown-unknown --release
# Fast-failing, named gate: verify migrations apply on an *old* (v2.0.0) # database — schema + data, both SQLite and Postgres — not just a fresh one. # (Also included in the full run below; runs here first for a clear signal, # sharing the compiled test binary so the extra cost is ~a second.) - name: Migration upgrade test (old DB → latest) env: TEST_DATABASE_URL: postgres://happyview:happyview@localhost:5432/happyview_test CARGO_PROFILE_DEV_DEBUG: "0" run: cargo test --test migration_upgrade
- name: Run e2e tests env: TEST_DATABASE_URL: postgres://happyview:happyview@localhost:5432/happyview_test # Drop debuginfo from the test build — it dominates target/ size and is # unnecessary in CI. Keeps the enlarged dependency build within disk. CARGO_PROFILE_DEV_DEBUG: "0" run: cargo test --tests
frontend: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Build frontend working-directory: web run: npm ci && npm run build
lint: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Cache cargo uses: Swatinem/rust-cache@v2 with: shared-key: lint
- name: Check formatting run: cargo fmt -- --check
- name: Clippy run: cargo clippy --workspace --all-targets -- -D warnings
audit: needs: changes if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Install cargo-audit uses: taiki-e/install-action@v2 with: tool: cargo-audit
# Fails on any advisory not triaged in .cargo/audit.toml, so newly # disclosed vulnerabilities in our dependencies are caught. - name: Audit dependencies run: cargo audit
playwright: needs: [changes, frontend, build-server] if: >- always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) && needs.frontend.result == 'success' && needs.build-server.result == 'success' runs-on: depot-ubuntu-24.04 permissions: contents: read packages: read steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install frontend dependencies working-directory: web run: npm ci
- name: Install Playwright browsers working-directory: web run: npx playwright install chromium --with-deps
- name: Download server binary uses: actions/download-artifact@v4 with: name: happyview-server path: .builder-override/app/target/release
- name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Start E2E services run: docker compose -f docker-compose.e2e.yml -f docker-compose.e2e.ci.yml up -d --build --wait timeout-minutes: 10
- name: Log resolved Tranquil PDS image run: | docker image inspect ghcr.io/gamesgamesgamesgamesgames/tranquil-dev:latest \ --format 'tranquil-pds resolved to {{.RepoTags}} digest {{.RepoDigests}}'
- name: Run Playwright tests working-directory: web run: npx playwright test
- name: Dump container logs if: failure() run: docker compose -f docker-compose.e2e.yml -f docker-compose.e2e.ci.yml logs
- name: Upload Playwright report if: failure() uses: actions/upload-artifact@v4 with: name: playwright-report path: web/playwright-report/ retention-days: 14
- name: Stop E2E services if: always() run: docker compose -f docker-compose.e2e.yml -f docker-compose.e2e.ci.yml down -v
# --------------------------------------------------------------------------- # PR builds — compile + Docker on every PR push so reviewers can test # --------------------------------------------------------------------------- pr-build: needs: [changes, build-server] if: >- github.event_name == 'pull_request' && github.head_ref != 'dev' && needs.changes.outputs.server == 'true' runs-on: ${{ matrix.runs-on }} permissions: contents: read packages: write strategy: fail-fast: false matrix: include: - platform: linux/amd64 runs-on: depot-ubuntu-24.04 arch: amd64 - platform: linux/arm64 runs-on: depot-ubuntu-24.04-arm arch: arm64 env: GHCR_IMAGE: ghcr.io/${{ github.repository }} steps: - name: Checkout repository uses: actions/checkout@v6
- name: Download server binary (amd64) if: matrix.arch == 'amd64' uses: actions/download-artifact@v4 with: name: happyview-server path: target/release
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Build release binary (arm64) if: matrix.arch != 'amd64' uses: docker/build-push-action@v5 with: context: . target: binary platforms: ${{ matrix.platform }} cache-from: type=gha,scope=builder-${{ matrix.platform }} cache-to: type=gha,scope=builder-${{ matrix.platform }},mode=max,ignore-error=true outputs: type=local,dest=.
- name: Upload artifact uses: actions/upload-artifact@v4 with: name: happyview-linux-${{ matrix.arch }} path: target/release/happyview
- name: Prepare binary override run: | mkdir -p .builder-override/app/target/release cp target/release/happyview .builder-override/app/target/release/happyview
- name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.GHCR_IMAGE }} tags: | type=raw,value=pr-${{ github.event.pull_request.number }}
- name: Build and push by digest id: build uses: docker/build-push-action@v5 with: context: . platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} build-contexts: | builder=.builder-override cache-from: type=gha,scope=pr-${{ matrix.platform }} cache-to: type=gha,scope=pr-${{ matrix.platform }},mode=max,ignore-error=true outputs: type=image,"name=${{ env.GHCR_IMAGE }}",push-by-digest=true,name-canonical=true,push=true
- name: Create manifest run: | TAGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') docker buildx imagetools create --append $TAGS \ ${{ env.GHCR_IMAGE }}@${{ steps.build.outputs.digest }} 2>/dev/null || \ docker buildx imagetools create $TAGS \ ${{ env.GHCR_IMAGE }}@${{ steps.build.outputs.digest }}
pr-build-comment: needs: pr-build runs-on: depot-ubuntu-24.04 permissions: pull-requests: write steps: - name: Comment on PR uses: actions/github-script@v7 with: script: | const sha = context.payload.pull_request.head.sha.substring(0, 7); const prNumber = context.payload.pull_request.number; const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; const image = `ghcr.io/${context.repo.owner}/${context.repo.repo}`; const body = [ '### PR Build', '', `Builds for \`${sha}\`:`, '', '**Docker**', '```sh', `docker pull ${image}:pr-${prNumber}`, '```', '', '**Binaries**', '```sh', `gh run download ${context.runId} -n happyview-linux-amd64`, `gh run download ${context.runId} -n happyview-linux-arm64`, '```', '', `Or download binaries from the [workflow run](${runUrl}).`, ].join('\n');
const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, }); const existing = comments.find(c => c.body.startsWith('### PR Build'));
if (existing) { await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body, }); } else { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body, }); }
# --------------------------------------------------------------------------- # Server release # --------------------------------------------------------------------------- release: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) && needs.unit-tests.result == 'success' && needs.e2e-tests.result == 'success' && needs.frontend.result == 'success' && needs.playwright.result == 'success' && needs.lint.result == 'success' needs: [changes, unit-tests, e2e-tests, frontend, playwright, lint] runs-on: depot-ubuntu-24.04 outputs: version: ${{ steps.semantic.outputs.version }} permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 22
- name: Release id: semantic env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} run: npx -p semantic-release -p semantic-release-gha-output semantic-release
# --------------------------------------------------------------------------- # Build + Docker — compile per-platform, upload to GitHub release, push image # --------------------------------------------------------------------------- build: needs: release if: needs.release.outputs.version != '' runs-on: ${{ matrix.runs-on }} permissions: contents: write packages: write id-token: write strategy: fail-fast: false matrix: include: - platform: linux/amd64 runs-on: depot-ubuntu-24.04 arch: amd64 - platform: linux/arm64 runs-on: depot-ubuntu-24.04-arm arch: arm64 env: GHCR_IMAGE: ghcr.io/${{ github.repository }} ATCR_IMAGE: atcr.io/${{ secrets.ATCR_NAMESPACE }}/happyview steps: - name: Checkout repository uses: actions/checkout@v6
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Build release binary uses: docker/build-push-action@v5 with: context: . target: binary platforms: ${{ matrix.platform }} build-args: | HAPPYVIEW_VERSION=v${{ needs.release.outputs.version }} cache-from: type=gha,scope=builder-${{ matrix.platform }} cache-to: type=gha,scope=builder-${{ matrix.platform }},mode=max,ignore-error=true outputs: type=local,dest=.
- name: Upload binary to release env: GH_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} run: | cp target/release/happyview happyview-linux-${{ matrix.arch }} gh release upload "v${{ needs.release.outputs.version }}" \ happyview-linux-${{ matrix.arch }} \ --clobber
- name: Prepare binary override run: | mkdir -p .builder-override/app/target/release cp target/release/happyview .builder-override/app/target/release/happyview
- name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
# TODO: Re-enable once ATCR rate limit issue is resolved # - name: Log in to ATCR # uses: docker/login-action@v3 # with: # registry: atcr.io # username: ${{ secrets.ATCR_USERNAME }} # password: ${{ secrets.ATCR_PASSWORD }}
- name: Parse version id: version run: | VERSION="${{ needs.release.outputs.version }}" MAJOR="${VERSION%%.*}" MINOR="${VERSION#*.}" MINOR="${MINOR%%.*}" # A `-` suffix means semantic-release cut this from `dev` (e.g. 2.13.0-dev.1). # Prereleases must never move the stable moving tags. case "$VERSION" in *-*) PRERELEASE=true ;; *) PRERELEASE=false ;; esac echo "full=${VERSION}" >> "$GITHUB_OUTPUT" echo "major=${MAJOR}" >> "$GITHUB_OUTPUT" echo "major_minor=${MAJOR}.${MINOR}" >> "$GITHUB_OUTPUT" echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT"
- name: Extract GHCR metadata id: meta-ghcr uses: docker/metadata-action@v5 with: images: ${{ env.GHCR_IMAGE }} tags: | type=raw,value=${{ steps.version.outputs.full }} type=raw,value=${{ steps.version.outputs.major_minor }},enable=${{ steps.version.outputs.prerelease == 'false' }} type=raw,value=${{ steps.version.outputs.major }},enable=${{ steps.version.outputs.prerelease == 'false' }} type=sha
# TODO: Re-enable once ATCR rate limit issue is resolved # - name: Extract ATCR metadata # id: meta-atcr # uses: docker/metadata-action@v5 # with: # images: ${{ env.ATCR_IMAGE }} # tags: | # type=semver,pattern={{version}} # type=semver,pattern={{major}}.{{minor}} # type=semver,pattern={{major}} # type=sha
- name: Build and push to GHCR by digest id: build uses: docker/build-push-action@v5 with: context: . platforms: ${{ matrix.platform }} labels: ${{ steps.meta-ghcr.outputs.labels }} build-contexts: | builder=.builder-override cache-from: type=gha,scope=build-${{ matrix.platform }} cache-to: type=gha,scope=build-${{ matrix.platform }},mode=max,ignore-error=true outputs: type=image,"name=${{ env.GHCR_IMAGE }}",push-by-digest=true,name-canonical=true,push=true
# TODO: Re-enable once ATCR rate limit issue is resolved # - name: Push to ATCR by digest # id: build-atcr # continue-on-error: true # uses: docker/build-push-action@v5 # with: # context: . # platforms: ${{ matrix.platform }} # labels: ${{ steps.meta-atcr.outputs.labels }} # build-contexts: | # builder=.builder-override # cache-from: type=gha,scope=build-${{ matrix.platform }} # outputs: type=image,"name=${{ env.ATCR_IMAGE }}",push-by-digest=true,name-canonical=true,push=true
- name: Create GHCR manifest run: | GHCR_TAGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta-ghcr.outputs.json }}') docker buildx imagetools create --append $GHCR_TAGS \ ${{ env.GHCR_IMAGE }}@${{ steps.build.outputs.digest }} 2>/dev/null || \ docker buildx imagetools create $GHCR_TAGS \ ${{ env.GHCR_IMAGE }}@${{ steps.build.outputs.digest }}
# TODO: Re-enable once ATCR rate limit issue is resolved # - name: Create ATCR manifest # if: steps.build-atcr.outcome == 'success' # continue-on-error: true # run: | # ATCR_TAGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta-atcr.outputs.json }}') # if [ -n "$ATCR_TAGS" ]; then # docker buildx imagetools create --append $ATCR_TAGS \ # ${{ env.ATCR_IMAGE }}@${{ steps.build-atcr.outputs.digest }} 2>/dev/null || \ # docker buildx imagetools create $ATCR_TAGS \ # ${{ env.ATCR_IMAGE }}@${{ steps.build-atcr.outputs.digest }} # fi
# --------------------------------------------------------------------------- # `latest` — retag the finished multi-arch manifest. # # Deliberately not part of `build`'s tag set: those tags are applied per-arch # with `imagetools create --append`, which would append this release's digests # onto whatever index `latest` already points at. `latest` needs no build at # all — once `build` completes, the versioned manifest exists and this is a # single atomic retag of it. # # Skipped for prereleases, since `release` also runs on `dev`. # --------------------------------------------------------------------------- tag-latest: needs: [release, build] if: needs.release.outputs.version != '' && !contains(needs.release.outputs.version, '-') runs-on: depot-ubuntu-24.04 permissions: packages: write env: GHCR_IMAGE: ghcr.io/${{ github.repository }} steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Point latest at the released version run: | docker buildx imagetools create \ -t "${GHCR_IMAGE}:latest" \ "${GHCR_IMAGE}:${{ needs.release.outputs.version }}"
# --------------------------------------------------------------------------- # SDK — per-package tests + releases # --------------------------------------------------------------------------- test-oauth-client: needs: changes if: always() && (needs.changes.outputs.oauth-client == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install dependencies run: bun install
- name: Build run: bun run --filter '@happyview/oauth-client' build
- name: Typecheck run: bun run --filter '@happyview/oauth-client' typecheck
- name: Test run: bun run --filter '@happyview/oauth-client' test
test-oauth-client-browser: needs: changes if: always() && (needs.changes.outputs.oauth-client-browser == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client-browser)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install dependencies run: bun install
- name: Build oauth-client run: bun run --filter '@happyview/oauth-client' build
- name: Build oauth-client-browser run: bun run --filter '@happyview/oauth-client-browser' build
- name: Typecheck run: bun run --filter '@happyview/oauth-client-browser' typecheck
- name: Test run: bun run --filter '@happyview/oauth-client-browser' test
test-oauth-client-node: needs: changes if: always() && (needs.changes.outputs.oauth-client-node == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client-node)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install dependencies run: bun install
- name: Build oauth-client run: bun run --filter '@happyview/oauth-client' build
- name: Build oauth-client-node run: bun run --filter '@happyview/oauth-client-node' build
- name: Typecheck run: bun run --filter '@happyview/oauth-client-node' typecheck
- name: Test run: bun run --filter '@happyview/oauth-client-node' test
test-lex-agent: needs: changes if: always() && (needs.changes.outputs.lex-agent == 'true' || (github.event_name == 'workflow_dispatch' && inputs.lex-agent)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install dependencies run: bun install
- name: Build oauth-client run: bun run --filter '@happyview/oauth-client' build
- name: Build lex-agent run: bun run --filter '@happyview/lex-agent' build
- name: Typecheck run: bun run --filter '@happyview/lex-agent' typecheck
- name: Test run: bun run --filter '@happyview/lex-agent' test
test-nsid: needs: changes if: always() && (needs.changes.outputs.nsid == 'true' || (github.event_name == 'workflow_dispatch' && inputs.nsid)) runs-on: depot-ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install dependencies run: bun install
- name: Build run: bun run --filter '@happyview/nsid' build
- name: Typecheck run: bun run --filter '@happyview/nsid' typecheck
- name: Test run: bun run --filter '@happyview/nsid' test
release-oauth-client: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.oauth-client == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client)) && needs.test-oauth-client.result == 'success' needs: [changes, test-oauth-client] runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install dependencies run: bun install
- name: Build oauth-client run: bun run --filter '@happyview/oauth-client' build
- name: Ensure npm supports trusted publishing run: npm install -g npm@latest
- name: Release oauth-client env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} working-directory: packages/oauth-client run: npx semantic-release
release-oauth-client-browser: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.oauth-client-browser == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client-browser)) && needs.test-oauth-client-browser.result == 'success' && (needs.release-oauth-client.result == 'success' || needs.changes.outputs.oauth-client != 'true') needs: [changes, test-oauth-client-browser, release-oauth-client] runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install dependencies run: bun install
- name: Build SDK packages run: bun run --filter '@happyview/*' build
- name: Resolve workspace dependencies to published versions run: | if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then DIST_TAG="latest" else DIST_TAG="dev" fi CORE_VERSION=$(npm view @happyview/oauth-client@${DIST_TAG} version) node -e " const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('packages/oauth-client-browser/package.json', 'utf8')); if (pkg.dependencies['@happyview/oauth-client']?.startsWith('workspace:')) { pkg.dependencies['@happyview/oauth-client'] = '^${CORE_VERSION}'; fs.writeFileSync('packages/oauth-client-browser/package.json', JSON.stringify(pkg, null, 2) + '\n'); } "
- name: Ensure npm supports trusted publishing run: npm install -g npm@latest
- name: Release oauth-client-browser env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} working-directory: packages/oauth-client-browser run: npx semantic-release
release-oauth-client-node: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.oauth-client-node == 'true' || (github.event_name == 'workflow_dispatch' && inputs.oauth-client-node)) && needs.test-oauth-client-node.result == 'success' && (needs.release-oauth-client.result == 'success' || needs.changes.outputs.oauth-client != 'true') needs: [changes, test-oauth-client-node, release-oauth-client] runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install dependencies run: bun install
- name: Build SDK packages run: bun run --filter '@happyview/*' build
- name: Resolve workspace dependencies to published versions run: | if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then DIST_TAG="latest" else DIST_TAG="dev" fi CORE_VERSION=$(npm view @happyview/oauth-client@${DIST_TAG} version) node -e " const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('packages/oauth-client-node/package.json', 'utf8')); if (pkg.dependencies['@happyview/oauth-client']?.startsWith('workspace:')) { pkg.dependencies['@happyview/oauth-client'] = '^${CORE_VERSION}'; fs.writeFileSync('packages/oauth-client-node/package.json', JSON.stringify(pkg, null, 2) + '\n'); } "
- name: Ensure npm supports trusted publishing run: npm install -g npm@latest
- name: Release oauth-client-node env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} working-directory: packages/oauth-client-node run: npx semantic-release
release-lex-agent: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.lex-agent == 'true' || (github.event_name == 'workflow_dispatch' && inputs.lex-agent)) && needs.test-lex-agent.result == 'success' && (needs.release-oauth-client.result == 'success' || needs.changes.outputs.oauth-client != 'true') needs: [changes, test-lex-agent, release-oauth-client] runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install dependencies run: bun install
- name: Build SDK packages run: bun run --filter '@happyview/*' build
- name: Resolve workspace dependencies to published versions run: | if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then DIST_TAG="latest" else DIST_TAG="dev" fi CORE_VERSION=$(npm view @happyview/oauth-client@${DIST_TAG} version) node -e " const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('packages/lex-agent/package.json', 'utf8')); if (pkg.dependencies['@happyview/oauth-client']?.startsWith('workspace:')) { pkg.dependencies['@happyview/oauth-client'] = '^${CORE_VERSION}'; fs.writeFileSync('packages/lex-agent/package.json', JSON.stringify(pkg, null, 2) + '\n'); } "
- name: Ensure npm supports trusted publishing run: npm install -g npm@latest
- name: Release lex-agent env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} working-directory: packages/lex-agent run: npx semantic-release
release-nsid: if: >- always() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && (needs.changes.outputs.nsid == 'true' || (github.event_name == 'workflow_dispatch' && inputs.nsid)) && needs.test-nsid.result == 'success' needs: [changes, test-nsid] runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 24
- name: Install dependencies run: bun install
- name: Build nsid run: bun run --filter '@happyview/nsid' build
- name: Ensure npm supports trusted publishing run: npm install -g npm@latest
- name: Release nsid env: GITHUB_TOKEN: ${{ secrets.DISPATCH_GH_TOKEN }} working-directory: packages/nsid run: npx semantic-release
# --------------------------------------------------------------------------- # Mirror to Tangled # --------------------------------------------------------------------------- mirror: runs-on: depot-ubuntu-24.04 steps: - uses: actions/checkout@v6 with: fetch-depth: 0
- uses: yesolutions/mirror-action@master with: REMOTE: "git@tangled.org:gamesgamesgamesgames.games/happyview" GIT_SSH_PRIVATE_KEY: ${{ secrets.TANGLED_SSH_PRIVATE_KEY }} GIT_SSH_NO_VERIFY_HOST: "true"