Skip to content

feat: complete with-watch command inference #653

feat: complete with-watch command inference

feat: complete with-watch command inference #653

Workflow file for this run

name: CI
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
go-quality:
name: Go Quality
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
go:
- .github/workflows/CI.yml
- go.mod
- go.sum
- scripts/generate-go-proto.sh
- scripts/lib/go-proto-tools.sh
- cmds/**
- servers/**
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
GO_CHANGED: ${{ steps.filter.outputs.go }}
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${GO_CHANGED}" = "true" ]; then
run=true
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (no Go-related changes)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Go Quality: no relevant changes"
- name: Setup Go
if: ${{ steps.gate.outputs.run == 'true' }}
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Generate Go protobuf artifacts
if: ${{ steps.gate.outputs.run == 'true' }}
shell: bash
run: ./scripts/generate-go-proto.sh
- name: Check go fmt
if: ${{ steps.gate.outputs.run == 'true' }}
run: |
set -euo pipefail
formatted_output="$(go fmt ./...)"
if [ -n "$formatted_output" ]; then
echo "::error::go fmt reformatted files. Run 'go fmt ./...' locally and commit the result."
printf '%s\n' "$formatted_output"
exit 1
fi
- name: Run go vet
if: ${{ steps.gate.outputs.run == 'true' }}
run: go vet ./...
go-test:
name: Go Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
go:
- .github/workflows/CI.yml
- go.mod
- go.sum
- scripts/generate-go-proto.sh
- scripts/lib/go-proto-tools.sh
- cmds/**
- servers/**
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
GO_CHANGED: ${{ steps.filter.outputs.go }}
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${GO_CHANGED}" = "true" ]; then
run=true
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (no Go-related changes)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Go Test on ${{ matrix.os }}: no relevant changes"
- name: Setup Go
if: ${{ steps.gate.outputs.run == 'true' }}
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Generate Go protobuf artifacts
if: ${{ steps.gate.outputs.run == 'true' }}
shell: bash
run: ./scripts/generate-go-proto.sh
- name: Run go test
if: ${{ steps.gate.outputs.run == 'true' }}
run: go test ./...
rust-fmt:
name: Rust fmt
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
rust:
- .github/workflows/CI.yml
- Cargo.toml
- Cargo.lock
- '**/Cargo.toml'
- '**/Cargo.lock'
- rust-toolchain
- rust-toolchain.toml
- '**/rust-toolchain'
- '**/rust-toolchain.toml'
- '**/*.rs'
- crates/**
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
RUST_CHANGED: ${{ steps.filter.outputs.rust }}
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${RUST_CHANGED}" = "true" ]; then
run=true
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (no Rust-related changes)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Rust fmt: no relevant changes"
- name: Install Rust toolchain
if: ${{ steps.gate.outputs.run == 'true' }}
uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly-2026-01-01
components: rustfmt
- name: Cache Rust dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
uses: Swatinem/rust-cache@v2
- name: Run rustfmt
if: ${{ steps.gate.outputs.run == 'true' }}
run: cargo fmt --all --check
rust-clippy:
name: Rust clippy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
rust:
- .github/workflows/CI.yml
- Cargo.toml
- Cargo.lock
- '**/Cargo.toml'
- '**/Cargo.lock'
- rust-toolchain
- rust-toolchain.toml
- '**/rust-toolchain'
- '**/rust-toolchain.toml'
- '**/*.rs'
- crates/**
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
RUST_CHANGED: ${{ steps.filter.outputs.rust }}
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${RUST_CHANGED}" = "true" ]; then
run=true
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (no Rust-related changes)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Rust clippy: no relevant changes"
- name: Install Rust toolchain
if: ${{ steps.gate.outputs.run == 'true' }}
uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly-2026-01-01
components: clippy
- name: Cache Rust dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
uses: Swatinem/rust-cache@v2
- name: Run clippy
if: ${{ steps.gate.outputs.run == 'true' }}
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
rust-test:
name: Rust test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
rust:
- .github/workflows/CI.yml
- Cargo.toml
- Cargo.lock
- '**/Cargo.toml'
- '**/Cargo.lock'
- rust-toolchain
- rust-toolchain.toml
- '**/rust-toolchain'
- '**/rust-toolchain.toml'
- '**/*.rs'
- crates/**
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
RUST_CHANGED: ${{ steps.filter.outputs.rust }}
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${RUST_CHANGED}" = "true" ]; then
run=true
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (no Rust-related changes)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Rust test: no relevant changes"
- name: Install Rust toolchain
if: ${{ steps.gate.outputs.run == 'true' }}
uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly-2026-01-01
- name: Cache Rust dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
uses: Swatinem/rust-cache@v2
- name: Run cargo test
if: ${{ steps.gate.outputs.run == 'true' }}
run: cargo test --workspace --all-targets
node-devkit-test:
name: Node devkit test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: devkit
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (devkit unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node devkit test: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run Devkit tests
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter devkit... test
node-devkit-build:
name: Node devkit build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: devkit
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (devkit unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node devkit build: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run Devkit build
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter devkit... build
node-mpapp-test:
name: Node mpapp test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: mpapp
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (mpapp unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node mpapp test: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run mpapp tests
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter mpapp test
node-mpapp-lint:
name: Node mpapp lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: mpapp
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (mpapp unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node mpapp lint: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run mpapp lint
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter mpapp lint
node-public-docs-test:
name: Node public-docs test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: public-docs
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (public-docs unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node public-docs test: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run public-docs tests
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter public-docs test
node-dexdex-test:
name: Node dexdex test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
WORKSPACE: dexdex
run: |
set -euo pipefail
run=false
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${CI_WORKFLOW_CHANGED}" = "true" ]; then
run=true
else
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
run="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
fi
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (dexdex unaffected)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node dexdex test: workspace unaffected"
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
- name: Run dexdex tests
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter dexdex test
node-dexdex-ios-build:
name: Node dexdex iOS build
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Filter changed paths
id: filter
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
ci_workflow:
- .github/workflows/CI.yml
dexdex_ios:
- apps/dexdex/src/**
- apps/dexdex/src-tauri/**
- apps/dexdex/public/**
- apps/dexdex/index.html
- apps/dexdex/package.json
- apps/dexdex/tsconfig.json
- apps/dexdex/vite.config.ts
- apps/dexdex/buf.yaml
- apps/dexdex/buf.gen.yaml
- pnpm-lock.yaml
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10.26.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
- name: Determine whether to run
id: gate
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
CI_WORKFLOW_CHANGED: ${{ steps.filter.outputs.ci_workflow }}
DEXDEX_IOS_CHANGED: ${{ steps.filter.outputs.dexdex_ios }}
WORKSPACE: dexdex
run: |
set -euo pipefail
run=false
workspace_affected=false
ci_workflow_changed="${CI_WORKFLOW_CHANGED:-false}"
dexdex_ios_changed="${DEXDEX_IOS_CHANGED:-false}"
if [ "${EVENT_NAME}" = "workflow_dispatch" ] || [ "${ci_workflow_changed}" = "true" ]; then
run=true
elif [ "${dexdex_ios_changed}" = "true" ]; then
affected_json="$(pnpm dlx turbo@2.8.20 query affected --packages "${WORKSPACE}")"
printf '%s\n' "${affected_json}"
workspace_affected="$(printf '%s' "${affected_json}" | jq -r '.data.affectedPackages.items | any(.name == env.WORKSPACE)')"
if [ "${workspace_affected}" = "true" ]; then
run=true
fi
fi
printf 'gate_decision event=%s ci_workflow_changed=%s dexdex_ios_changed=%s workspace_affected=%s final_run=%s\n' \
"${EVENT_NAME}" \
"${ci_workflow_changed}" \
"${dexdex_ios_changed}" \
"${workspace_affected}" \
"${run}"
echo "run=${run}" >> "${GITHUB_OUTPUT}"
- name: Skip (iOS gate unmatched)
if: ${{ steps.gate.outputs.run != 'true' }}
run: |
echo "Skipping Node dexdex iOS build: iOS-related paths unaffected or workspace unaffected"
- name: Setup Rust toolchain
if: ${{ steps.gate.outputs.run == 'true' }}
uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Cache Rust dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
uses: Swatinem/rust-cache@v2
- name: Install dependencies
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm install --frozen-lockfile
# Workaround: this job validates iOS packaging flow, not TypeScript type safety.
# Remove this once DexDex `pnpm build` (tsc + vite) is enforced by a dedicated CI gate.
- name: Build frontend bundle for iOS smoke test
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter dexdex exec vite build
- name: Initialize iOS target
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter dexdex exec tauri ios init --ci
- name: Run dexdex iOS smoke build
if: ${{ steps.gate.outputs.run == 'true' }}
run: pnpm --filter dexdex exec tauri ios build --ci --debug --target aarch64-sim --config '{"build":{"beforeBuildCommand":"true"}}'
ci-result:
name: CI Result
runs-on: ubuntu-latest
if: always()
needs:
- go-quality
- go-test
- rust-fmt
- rust-clippy
- rust-test
- node-devkit-test
- node-devkit-build
- node-mpapp-test
- node-mpapp-lint
- node-public-docs-test
- node-dexdex-test
- node-dexdex-ios-build
steps:
- run: exit 1
if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}