cli-xtask 0.10.2

A collection of utility functions and command line interfaces for cargo-xtask
Documentation
name: CI

on:
  push:
    branches:
      - main
  pull_request:

env:
  CARGO_TERM_COLOR: always

jobs:
  set-matrix:
    runs-on: ubuntu-latest
    outputs:
      rust: ${{ steps.set-values.outputs.rust }}
      os: ${{ steps.set-values.outputs.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - name: Set matrix values
        id: set-values
        run: |
          root_package_id="$(cargo metadata --format-version 1 | jq -cr '.resolve.root')"
          root_package="$(cargo metadata --format-version 1 | jq -c --arg pkgid "${root_package_id}" '.packages[] | select(.id == $pkgid)')"
          echo "${root_package}" | jq -c '{ root_package: .name }'

          msrv="$(echo "${root_package}" | jq '.rust_version')"
          rust="$(echo "[\"stable\", ${msrv}]" | jq -c)"
          echo "rust=${rust}" >> "${GITHUB_OUTPUT}"

          os="$(echo '["ubuntu-latest", "macos-latest", "windows-latest"]' | jq -c)"
          echo "os=${os}" >> "${GITHUB_OUTPUT}"

          jq -n --argjson rust "${rust}" --argjson os "${os}" '{ rust: $rust, os: $os }'
        shell: bash

  set-workspace:
    runs-on: ubuntu-latest
    outputs:
      workspaces: ${{ steps.set-workspace.outputs.workspaces }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - name: Set workspace paths
        id: set-workspace
        run: |
          value="$(cargo xtask exec --all-workspaces -- pwd | sed "s@^$(pwd)@.@" | sed 's/$/ -> target/')"
          echo "${value}"
          value="${value//$'\n'/'%0A'}"
          echo "workspaces=${value}" >> "${GITHUB_OUTPUT}"
        shell: bash

  test:
    name: Test
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        rust: ${{ fromJSON(needs.set-matrix.outputs.rust) }}
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      # DO NOT USE `--all-targets` here, doctests are not built with `--all-targets`
      - run: cargo xtask test --exhaustive
        shell: bash

  integration_test:
    name: Integration test
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        rust: ${{ fromJSON(needs.set-matrix.outputs.rust) }}
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
          components: rustfmt,clippy
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-udeps,cargo-sync-rdme
      - run: rustup toolchain add nightly --profile minimal
        shell: bash
      - run: cargo xtask xtask-test
        shell: bash

  coverage_test:
    name: Coverage (test)
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        rust: [stable]
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
          components: llvm-tools-preview
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-llvm-cov
      - run: rustup toolchain add nightly --profile minimal --component llvm-tools-preview
        shell: bash
      - name: Generate code coverage
        run: |
          cargo llvm-cov --workspace --all-targets --all-features --lcov --output-path lcov-test.info
          cargo +nightly llvm-cov --doctests --workspace --all-features --lcov --output-path lcov-doctest.info
          cargo llvm-cov run -p xtask --lcov --output-path lcov-exec.info -- exec --all-workspaces --exclude-current-workspace -- cargo llvm-cov --workspace --lcov --output-path lcov-test.info
        shell: bash
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: |
            **/lcov-*.info
          fail_ci_if_error: false

  coverage_integration_test:
    name: Coverage (integration test)
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        rust: [nightly]
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
          components: llvm-tools-preview,rustfmt,clippy
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-udeps,cargo-sync-rdme,cargo-llvm-cov
      - name: Generate code coverage
        run: cargo llvm-cov run -p xtask --lcov --output-path lcov-xtask.info -- xtask-test --cargo-llvm-cov
        shell: bash
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: |
            **/lcov-*.info
          fail_ci_if_error: false


  build:
    name: Build
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        rust: ${{ fromJSON(needs.set-matrix.outputs.rust) }}
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      - name: cargo xtask build
        run: cargo xtask build --exhaustive -- --all-targets
        shell: bash

  lint:
    name: Lint
    needs: [set-matrix, set-workspace]
    strategy:
      fail-fast: false
      matrix:
        os: ${{ fromJSON(needs.set-matrix.outputs.os) }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt,clippy
      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ needs.set-workspace.outputs.workspaces }}
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-udeps,cargo-sync-rdme
      - run: rustup toolchain add nightly --profile minimal
        shell: bash
      - run: cargo xtask lint --exhaustive
        shell: bash

  release-dry-run:
    name: Release dry run
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-udeps,cargo-sync-rdme,cargo-release
      - run: rustup toolchain add nightly --profile minimal
        shell: bash
      - run: cargo release patch -vv --allow-branch '*'
        shell: bash

  actionlint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Check workflow files
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          echo "::add-matcher::.github/actionlint-matcher.json"
          ./actionlint -color
        shell: bash