Skip to content
Latchkey

continuous-integration workflow (nushell/nushell)

The continuous-integration workflow from nushell/nushell, explained and optimized by Latchkey.

C

CI health: C - fair

Run this on Latchkey for self-healing, caching, and up to 58% lower cost.

Grade your own workflow free or run it on Latchkey →
Source: nushell/nushell.github/workflows/ci.ymlLicense MITView source

What it does

This is the continuous-integration workflow from the nushell/nushell repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
on:
  pull_request:
  push:
    branches:
      - main
      - 'patch-release-*'

name: continuous-integration

env:
  NU_LOG_LEVEL: DEBUG
  CLIPPY_OPTIONS: "-D warnings"
  NUSHELL_CARGO_PROFILE: ci
  MAIN_OPTIONS: --workspace --exclude nu_plugin_* --all-targets
  PLUGIN_OPTIONS: --package nu_plugin_* --all-targets
  WASM_OPTIONS: >-
    --no-default-features
    --target wasm32-unknown-unknown
    -p nu-cmd-base
    -p nu-cmd-extra
    -p nu-cmd-lang
    -p nu-color-config
    -p nu-command
    -p nu-derive-value
    -p nu-engine
    -p nu-glob
    -p nu-json
    -p nu-parser
    -p nu-path
    -p nu-pretty-hex
    -p nu-protocol
    -p nu-std
    -p nu-system
    -p nu-table
    -p nu-term-grid
    -p nu-utils
    -p nuon

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  cargo:
    name: "`cargo` in ${{ matrix.workspace.name }} (${{ matrix.target.name }})"
    strategy:
      fail-fast: true
      matrix:
        target:
          # Pinning to Ubuntu 22.04 because building on newer Ubuntu versions causes linux-gnu
          # builds to link against a too-new-for-many-Linux-installs glibc version. Consider
          # revisiting this when 22.04 is closer to EOL (June 2027)
          - name: Ubuntu
            host: ubuntu-22.04
            target: x86_64-unknown-linux-gnu
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: Windows
            host: windows-latest
            target: x86_64-pc-windows-msvc
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: MacOS
            host: macos-latest
            target: x86_64-apple-darwin
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: Ubuntu Plugins
            host: ubuntu-22.04
            target: x86_64-unknown-linux-gnu
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: Windows Plugins
            host: windows-latest
            target: x86_64-pc-windows-msvc
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: MacOS Plugins
            host: macos-latest
            target: x86_64-apple-darwin
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: WASM
            host: ubuntu-22.04
            target: wasm32-unknown-unknown
            options: WASM_OPTIONS
            steps: [build, check]

        workspace:
          - name: root
            path: ./
            profile: ci
            skip: []
          - name: nu-parser/fuzz
            path: ./crates/nu-parser/fuzz
            profile: dev
            skip: [build, test, doctest]
          - name: nu-path/fuzz
            path: ./crates/nu-path/fuzz
            profile: dev
            skip: [build, test, doctest]

        exclude:
          - target: { name: WASM }
            workspace: { name: nu-parser/fuzz }
          - target: { name: WASM }
            workspace: { name: nu-path/fuzz }
          - target: { name: Ubuntu Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: Ubuntu Plugins }
            workspace: { name: nu-path/fuzz }
          - target: { name: Windows Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: Windows Plugins }
            workspace: { name: nu-path/fuzz }
          - target: { name: MacOS Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: MacOS Plugins }
            workspace: { name: nu-path/fuzz }
    
    runs-on: ${{ matrix.target.host }}

    steps:
      - name: Checkout Repo
        uses: actions/checkout@v7

      - name: Setup Rust Toolchain
        run: rustup target add ${{ matrix.target.target }}
        working-directory: ${{ matrix.workspace.path }}

      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ matrix.workspace.path }} -> target
          cache-all-crates: true
          cache-workspace-crates: true

      - name: cargo fmt
        if: contains(matrix.target.steps, 'fmt') && !contains(matrix.workspace.skip, 'fmt')
        working-directory: ${{ matrix.workspace.path }}
        run: |
          rustup component add rustfmt
          cargo fmt --all --check

      - name: cargo check
        if: contains(matrix.target.steps, 'check') && !contains(matrix.workspace.skip, 'check')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo check ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}
        
      - name: cargo clippy
        if: contains(matrix.target.steps, 'clippy') && !contains(matrix.workspace.skip, 'clippy')
        working-directory: ${{ matrix.workspace.path }}
        run: |
          rustup component add clippy
          cargo clippy ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }} -- ${{ env['CLIPPY_OPTIONS'] }}

      - name: cargo build
        if: contains(matrix.target.steps, 'build') && !contains(matrix.workspace.skip, 'build')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo build ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}

      - name: cargo test
        if: contains(matrix.target.steps, 'test') && !contains(matrix.workspace.skip, 'test')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo test ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}

      - name: cargo test --doc
        if: contains(matrix.target.steps, 'doctest') && !contains(matrix.workspace.skip, 'doctest')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo test --workspace --doc --profile ${{ matrix.workspace.profile }}

      - name: Assert Clean Repo
        run: git diff --quiet && git diff --cached --quiet

  std-lib-and-python-virtualenv:
    strategy:
      fail-fast: true
      matrix:
        platform: [ubuntu-22.04, macos-latest, windows-latest]
        py:
          - py

    runs-on: ${{ matrix.platform }}

    steps:
      - uses: actions/checkout@v7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.12.0

      - name: Install Nushell
        run: cargo install --path . --locked --force

      - name: Upload Nushell build (Ubuntu and macOS)
        uses: actions/upload-artifact@v7
        if: runner.os != 'Windows'
        with:
          name: "nu-${{ github.event.number || github.ref_name }}-${{ matrix.platform }}"
          path: "~/.cargo/bin/nu"
          retention-days: 14

      - name: Upload Nushell build (Windows)
        uses: actions/upload-artifact@v7
        if: runner.os == 'Windows'
        with:
          name: "nu-${{ github.event.number || github.ref_name }}-${{ matrix.platform }}"
          path: 'C:\Users\runneradmin\.cargo\bin\nu.exe'
          retention-days: 14

      - name: Standard library tests
        run: nu -c 'use crates/nu-std/testing.nu; testing run-tests --path crates/nu-std'

      - name: Ensure that Cargo.toml MSRV and rust-toolchain.toml use the same version
        run: nu .github/workflows/check-msrv.nu

      - name: Setup Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.10"

      - name: Install virtualenv
        run: pip install virtualenv
        shell: bash

      - name: Test Nushell in virtualenv
        run: nu scripts/test_virtualenv.nu
        shell: bash

      - name: Check for clean repo
        shell: bash
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "there are changes";
            git status --porcelain
            exit 1
          else
            echo "no changes in working directory";
          fi

The same workflow, on Latchkey

Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.

on:
  pull_request:
  push:
    branches:
      - main
      - 'patch-release-*'
 
name: continuous-integration
 
env:
  NU_LOG_LEVEL: DEBUG
  CLIPPY_OPTIONS: "-D warnings"
  NUSHELL_CARGO_PROFILE: ci
  MAIN_OPTIONS: --workspace --exclude nu_plugin_* --all-targets
  PLUGIN_OPTIONS: --package nu_plugin_* --all-targets
  WASM_OPTIONS: >-
    --no-default-features
    --target wasm32-unknown-unknown
    -p nu-cmd-base
    -p nu-cmd-extra
    -p nu-cmd-lang
    -p nu-color-config
    -p nu-command
    -p nu-derive-value
    -p nu-engine
    -p nu-glob
    -p nu-json
    -p nu-parser
    -p nu-path
    -p nu-pretty-hex
    -p nu-protocol
    -p nu-std
    -p nu-system
    -p nu-table
    -p nu-term-grid
    -p nu-utils
    -p nuon
 
concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
  cancel-in-progress: true
 
jobs:
  cargo:
    timeout-minutes: 30
    name: "`cargo` in ${{ matrix.workspace.name }} (${{ matrix.target.name }})"
    strategy:
      fail-fast: true
      matrix:
        target:
          # Pinning to Ubuntu 22.04 because building on newer Ubuntu versions causes linux-gnu
          # builds to link against a too-new-for-many-Linux-installs glibc version. Consider
          # revisiting this when 22.04 is closer to EOL (June 2027)
          - name: Ubuntu
            host: ubuntu-22.04
            target: x86_64-unknown-linux-gnu
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: Windows
            host: windows-latest
            target: x86_64-pc-windows-msvc
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: MacOS
            host: macos-latest
            target: x86_64-apple-darwin
            options: MAIN_OPTIONS
            steps: [fmt, clippy, build, test, doctest]
          - name: Ubuntu Plugins
            host: ubuntu-22.04
            target: x86_64-unknown-linux-gnu
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: Windows Plugins
            host: windows-latest
            target: x86_64-pc-windows-msvc
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: MacOS Plugins
            host: macos-latest
            target: x86_64-apple-darwin
            options: PLUGIN_OPTIONS
            steps: [clippy, build, test]
          - name: WASM
            host: ubuntu-22.04
            target: wasm32-unknown-unknown
            options: WASM_OPTIONS
            steps: [build, check]
 
        workspace:
          - name: root
            path: ./
            profile: ci
            skip: []
          - name: nu-parser/fuzz
            path: ./crates/nu-parser/fuzz
            profile: dev
            skip: [build, test, doctest]
          - name: nu-path/fuzz
            path: ./crates/nu-path/fuzz
            profile: dev
            skip: [build, test, doctest]
 
        exclude:
          - target: { name: WASM }
            workspace: { name: nu-parser/fuzz }
          - target: { name: WASM }
            workspace: { name: nu-path/fuzz }
          - target: { name: Ubuntu Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: Ubuntu Plugins }
            workspace: { name: nu-path/fuzz }
          - target: { name: Windows Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: Windows Plugins }
            workspace: { name: nu-path/fuzz }
          - target: { name: MacOS Plugins }
            workspace: { name: nu-parser/fuzz }
          - target: { name: MacOS Plugins }
            workspace: { name: nu-path/fuzz }
    
    runs-on: ${{ matrix.target.host }}
 
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v7
 
      - name: Setup Rust Toolchain
        run: rustup target add ${{ matrix.target.target }}
        working-directory: ${{ matrix.workspace.path }}
 
      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: ${{ matrix.workspace.path }} -> target
          cache-all-crates: true
          cache-workspace-crates: true
 
      - name: cargo fmt
        if: contains(matrix.target.steps, 'fmt') && !contains(matrix.workspace.skip, 'fmt')
        working-directory: ${{ matrix.workspace.path }}
        run: |
          rustup component add rustfmt
          cargo fmt --all --check
 
      - name: cargo check
        if: contains(matrix.target.steps, 'check') && !contains(matrix.workspace.skip, 'check')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo check ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}
        
      - name: cargo clippy
        if: contains(matrix.target.steps, 'clippy') && !contains(matrix.workspace.skip, 'clippy')
        working-directory: ${{ matrix.workspace.path }}
        run: |
          rustup component add clippy
          cargo clippy ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }} -- ${{ env['CLIPPY_OPTIONS'] }}
 
      - name: cargo build
        if: contains(matrix.target.steps, 'build') && !contains(matrix.workspace.skip, 'build')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo build ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}
 
      - name: cargo test
        if: contains(matrix.target.steps, 'test') && !contains(matrix.workspace.skip, 'test')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo test ${{ env[matrix.target.options] }} --profile ${{ matrix.workspace.profile }}
 
      - name: cargo test --doc
        if: contains(matrix.target.steps, 'doctest') && !contains(matrix.workspace.skip, 'doctest')
        working-directory: ${{ matrix.workspace.path }}
        run: cargo test --workspace --doc --profile ${{ matrix.workspace.profile }}
 
      - name: Assert Clean Repo
        run: git diff --quiet && git diff --cached --quiet
 
  std-lib-and-python-virtualenv:
    timeout-minutes: 30
    strategy:
      fail-fast: true
      matrix:
        platform: [ubuntu-22.04, macos-latest, windows-latest]
        py:
          - py
 
    runs-on: ${{ matrix.platform }}
 
    steps:
      - uses: actions/checkout@v7
 
      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
 
      - name: Install Nushell
        run: cargo install --path . --locked --force
 
      - name: Upload Nushell build (Ubuntu and macOS)
        uses: actions/upload-artifact@v7
        if: runner.os != 'Windows'
        with:
          name: "nu-${{ github.event.number || github.ref_name }}-${{ matrix.platform }}"
          path: "~/.cargo/bin/nu"
          retention-days: 14
 
      - name: Upload Nushell build (Windows)
        uses: actions/upload-artifact@v7
        if: runner.os == 'Windows'
        with:
          name: "nu-${{ github.event.number || github.ref_name }}-${{ matrix.platform }}"
          path: 'C:\Users\runneradmin\.cargo\bin\nu.exe'
          retention-days: 14
 
      - name: Standard library tests
        run: nu -c 'use crates/nu-std/testing.nu; testing run-tests --path crates/nu-std'
 
      - name: Ensure that Cargo.toml MSRV and rust-toolchain.toml use the same version
        run: nu .github/workflows/check-msrv.nu
 
      - name: Setup Python
        uses: actions/setup-python@v6
        with:
          cache: 'pip'
          python-version: "3.10"
 
      - name: Install virtualenv
        run: pip install virtualenv
        shell: bash
 
      - name: Test Nushell in virtualenv
        run: nu scripts/test_virtualenv.nu
        shell: bash
 
      - name: Check for clean repo
        shell: bash
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "there are changes";
            git status --porcelain
            exit 1
          else
            echo "no changes in working directory";
          fi
 

What changed

2 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 2 jobs (24 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow