name: tinymist::ci
on:
  push:
    branches:
      - main
      - nightly
      - stable/**
    tags:
      - "*"
  pull_request:
    types: [opened, synchronize]
    branches:
      - main
      - nightly
      - stable/**
  workflow_dispatch:

env:
  RUSTFLAGS: '-Dwarnings'
  CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
  CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc

jobs:
  pre_build:
    permissions:
      actions: write
      contents: read
    name: Duplicate Actions Detection
    runs-on: ubuntu-latest
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@v5
        with:
          cancel_others: "true"

  checks-linux:
    name: Check Clippy, Formatting, Completion, Documentation, and Tests (Linux)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Checkout Typst renderer suite
        uses: actions/checkout@v4
        with:
          repository: ParaN3xus/typst
          ref: 6743cf2415fb3c11c292d371d16746cbee44c114
          path: typst-upstream
      - uses: typst-community/setup-typst@v4
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          components: clippy, rustfmt
          cache-shared-key: x86_64-unknown-linux-gnu
          cache-save-if: false
      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: 'yarn'
      - name: Install system deps
        run: |
          sudo apt-get update
          sudo apt-get install -y libfontconfig1-dev libvulkan1 mesa-vulkan-drivers vulkan-tools
      - name: Check Vulkan software renderer
        run: |
          ls -l /usr/share/vulkan/icd.d
          vulkaninfo --summary || true
        env:
          VK_DRIVER_FILES: /usr/share/vulkan/icd.d/lvp_icd.json
          VK_ICD_FILENAMES: /usr/share/vulkan/icd.d/lvp_icd.json
      - name: Install deps
        run: yarn install
      - name: Check and build assets
        run: |
          yarn build:preview
          yarn build:l10n
      - run: cargo clippy --workspace --all-targets --locked
      - run: scripts/feature-testing.sh
      - run: cargo fmt --check --all
      - run: cargo doc --workspace --no-deps
      - run: yarn build:typlite
      - run: node ./scripts/link-docs.mjs --check
      - name: Generate completions
        run: |
          mkdir -p completions/{zsh,bash,fish/vendor_completions.d,elvish/lib,nushell/vendor/autoload,powershell}/
          cargo run --bin tinymist -- completion zsh        > completions/zsh/_tinymist
          cargo run --bin tinymist -- completion bash       > completions/bash/tinymist
          cargo run --bin tinymist -- completion fish       > completions/fish/vendor_completions.d/tinymist.fish
          cargo run --bin tinymist -- completion elvish     > completions/elvish/lib/tinymist.elv
          cargo run --bin tinymist -- completion nushell    > completions/nushell/vendor/autoload/tinymist.nu
          cargo run --bin tinymist -- completion powershell > completions/powershell/tinymist.ps1
          tar -czvf tinymist-completions.tar.gz completions
      - name: upload completions
        uses: actions/upload-artifact@v4
        with:
          name: tinymist-completion-scripts
          path: tinymist-completions.tar.gz
      - name: Build Vello renderer diff bundle
        run: cargo test -p tinymist-viewer --test vello_renderer_suite --locked -- --nocapture
        env:
          TINYMIST_TYPST_TESTS: ${{ github.workspace }}/typst-upstream/tests
          TINYMIST_TYPST_REF: "ParaN3xus/typst@6743cf2415fb3c11c292d371d16746cbee44c114"
          TINYMIST_RENDERER_DIFF: "1"
          WGPU_BACKEND: vulkan
          VK_DRIVER_FILES: /usr/share/vulkan/icd.d/lvp_icd.json
          VK_ICD_FILENAMES: /usr/share/vulkan/icd.d/lvp_icd.json
      - name: Upload Vello renderer diff bundle
        id: upload_renderer_diff
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: renderer-diff-vello
          path: target/tinymist-viewer/vello-renderer/renderer-diff-vello
          if-no-files-found: ignore
          retention-days: 14
      - name: Show renderer diff viewer link
        if: always()
        run: |
          artifact_id="${{ steps.upload_renderer_diff.outputs.artifact-id }}"
          page_url="https://myriad-dreamin.github.io/tinymist/renderer-diff/?owner=${{ github.repository_owner }}&repo=${{ github.event.repository.name }}&run=${{ github.run_id }}"
          if [ -n "${artifact_id}" ]; then
            page_url="${page_url}&artifact=${artifact_id}"
          fi
          echo "Renderer diff viewer: ${page_url}"
          {
            echo "### Renderer diff viewer"
            echo ""
            echo "[Open renderer diff viewer](${page_url})"
          } >> "$GITHUB_STEP_SUMMARY"
      - name: Test tinymist
        run: cargo test --workspace --features tinymist/system --locked -- --skip=e2e
        env:
          WGPU_BACKEND: vulkan
          VK_DRIVER_FILES: /usr/share/vulkan/icd.d/lvp_icd.json
          VK_ICD_FILENAMES: /usr/share/vulkan/icd.d/lvp_icd.json
      - name: Test real filesystem watcher
        run: cargo test -p tinymist-project -p tinymist --features tinymist-project/system,tinymist-project/mock,tinymist/system --locked real_fs_ -- --ignored
      - name: Test Lockfile (Prepare)
        run: ./scripts/test-lock.sh
      - name: Test Lockfile (Check)
        run: cargo test --package tinymist --lib --locked -- route::tests --show-output --ignored

  checks-windows:
    name: Check Minimum Rust version and Tests (Windows)
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: 1.92.0 # check-min-version
          cache-shared-key: x86_64-pc-windows-msvc
          cache-save-if: false
      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 24
      - name: Install deps
        run: yarn install
      - name: Check Rust Version
        run: yarn check-msrv
      - name: Check and build assets
        run: |
          yarn build:preview
          yarn build:l10n
      - run: cargo check --workspace --locked
      - name: Test tinymist
        run: cargo test --workspace --features tinymist/system --locked -- --skip=e2e

  prepare-build:
    runs-on: "ubuntu-latest"
    outputs:
      tag: ${{ steps.tag.outputs.tag }}
    steps:
      - uses: actions/checkout@v4
      - id: tag # get the tag from package.json
        run:
          echo "tag=v$(jq -r '.version' editors/vscode/package.json)" >> $GITHUB_OUTPUT
      - name: Show tag
        run: echo "Tag is ${{ steps.tag.outputs.tag }}"
  
  announce:
    needs: [prepare-build]
    permissions:
      contents: write
    uses: ./.github/workflows/announce.yml
    if: ${{ startsWith(github.ref, 'refs/tags/') }}
    secrets: inherit
    with:
      tag: ${{ needs.prepare-build.outputs.tag }}

  build:
    needs: [prepare-build] # , announce
    permissions:
      contents: write
    uses: ./.github/workflows/release.yml
    secrets: inherit
    with:
      tag: ${{ (startsWith(github.ref, 'refs/tags/') && needs.prepare-build.outputs.tag) || '' }}
      targets: ${{ (!startsWith(github.ref, 'refs/tags/') && 'aarch64-apple-darwin,x86_64-pc-windows-msvc,x86_64-unknown-linux-gnu') || 'all' }}

  checks-neovim:
    name: Neovim Spec Tests
    runs-on: ubuntu-latest
    needs: [prepare-build]
    permissions:
      actions: read
      contents: read
    env:
      RUST_TARGET: x86_64-unknown-linux-gnu
    steps:
      - uses: actions/checkout@v4
      - name: Wait for tinymist binary artifact
        env:
          GH_TOKEN: ${{ github.token }}
          ARTIFACT_NAME: artifacts-build-local-${{ env.RUST_TARGET }}
        run: |
          set -euo pipefail
          for attempt in {1..720}; do
            if gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts" \
              --jq '.artifacts[].name' | grep -Fxq "$ARTIFACT_NAME"; then
              echo "Found artifact: $ARTIFACT_NAME"
              exit 0
            fi
            echo "Waiting for $ARTIFACT_NAME ($attempt/720)"
            sleep 30
          done
          echo "Timed out waiting for artifact: $ARTIFACT_NAME" >&2
          exit 1
      - name: Download tinymist binary artifact
        uses: actions/download-artifact@v4
        with:
          name: artifacts-build-local-${{ env.RUST_TARGET }}
          path: prebuilts
      - name: Unzip tinymist binary artifact
        run: |
          tar -xvf prebuilts/tinymist-${{ env.RUST_TARGET }}.tar.gz -C prebuilts
          mv prebuilts/tinymist-${{ env.RUST_TARGET }}/tinymist prebuilts/tinymist
          chmod +x prebuilts/tinymist
      - name: Run Neovim specs
        run: ./editors/neovim/bootstrap.sh test
        env:
          TINYMIST_BIN: ${{ github.workspace }}/prebuilts/tinymist
