Restore lexer depth on the unclosed-bracket error path #1954
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| env: | |
| __MSRV: &msrv "1.88.0" | |
| CHECK_SHARDS: 7 # for *each* MSRV and stable, so double for total check jobs | |
| MIRI_SHARDS: 5 | |
| TYPE_CHECK_TARGETS: > | |
| { | |
| "no_std": [ | |
| "thumbv7em-none-eabihf" | |
| ], | |
| "std_no_offset": [ | |
| "x86_64-unknown-netbsd", | |
| "x86_64-unknown-illumos", | |
| "wasm32-wasip1" | |
| ], | |
| "std_with_offset": [ | |
| "x86_64-unknown-linux-gnu", | |
| "x86_64-apple-darwin", | |
| "x86_64-pc-windows-gnu" | |
| ], | |
| "wasm": [ | |
| "wasm32-unknown-unknown" | |
| ] | |
| } | |
| defaults: | |
| run: | |
| shell: bash | |
| on: | |
| push: | |
| branches: ["**"] | |
| tags-ignore: ["**"] | |
| paths-ignore: | |
| - "**.md" | |
| - LICENSE-Apache | |
| - LICENSE-MIT | |
| pull_request: | |
| paths-ignore: | |
| - "**.md" | |
| - "**/LICENSE-Apache" | |
| - "**/LICENSE-MIT" | |
| - .github/FUNDING.yml | |
| - .editorconfig | |
| - .gitignore | |
| - logo.svg | |
| jobs: | |
| compute-shards: | |
| name: Compute shards | |
| runs-on: &default-os ubuntu-latest | |
| if: &pr-or-push (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) || github.event_name == 'push' | |
| outputs: | |
| check-matrix: ${{ steps.build-check-matrix.outputs.matrix }} | |
| miri-matrix: ${{ steps.build-miri-matrix.outputs.matrix }} | |
| steps: | |
| - name: Build check matrix | |
| id: build-check-matrix | |
| run: | | |
| MATRIX=$(jq -c -n \ | |
| --argjson shards "${{ env.CHECK_SHARDS }}" \ | |
| --arg msrv "${{ env.__MSRV }}" \ | |
| '[ | |
| range(1; $shards + 1) as $shard | | |
| {shard: $shard, version: $msrv, name: "MSRV"}, | |
| {shard: $shard, version: "stable", name: "stable"} | |
| ]') | |
| echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" | |
| - name: Build miri matrix | |
| id: build-miri-matrix | |
| run: | | |
| MATRIX=$(jq -c -n \ | |
| --argjson shards "${{ env.MIRI_SHARDS }}" \ | |
| '[ | |
| range(1; $shards + 1) as $shard | | |
| {shard: $shard} | |
| ]') | |
| echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" | |
| check-targets: | |
| name: Type checking (${{ matrix.name }}, shard ${{ matrix.shard }}) | |
| runs-on: *default-os | |
| needs: compute-shards | |
| if: *pr-or-push | |
| strategy: | |
| matrix: | |
| include: ${{ fromJSON(needs.compute-shards.outputs.check-matrix) }} | |
| steps: | |
| - &checkout | |
| name: Checkout sources | |
| uses: actions/checkout@v7 | |
| - &cache | |
| name: Cache cargo output | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Install toolchain | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ matrix.version }} | |
| - name: Install cargo-hack | |
| uses: taiki-e/install-action@cargo-hack | |
| - name: Remove dev-dependencies | |
| run: | | |
| cargo hack check --remove-dev-deps -p time --features macros --target x86_64-unknown-linux-gnu | |
| - name: Generate shard commands | |
| id: generate | |
| env: | |
| SHARD: ${{ matrix.shard }} | |
| run: | | |
| set -euo pipefail | |
| CHECK_SHARDS='${{ env.CHECK_SHARDS }}' | |
| ALL_COMMANDS=$(mktemp) | |
| for kind in no_std std_no_offset std_with_offset wasm; do | |
| case "$kind" in | |
| no_std) | |
| query='.no_std + .std_no_offset + .std_with_offset' | |
| exclude='std,wasm-bindgen,formatting,serde-human-readable,serde-well-known,local-offset,quickcheck' | |
| enable='macros' | |
| groups=( | |
| --group-features 'serde,rand' | |
| ) | |
| ;; | |
| std_no_offset) | |
| query='.std_no_offset + .std_with_offset' | |
| exclude='wasm-bindgen,local-offset' | |
| enable='macros,std' | |
| groups=( | |
| --group-features 'serde,rand' | |
| --group-features 'formatting,parsing' | |
| --group-features 'serde-human-readable,serde-well-known' | |
| ) | |
| ;; | |
| std_with_offset) | |
| query='.std_with_offset' | |
| exclude='' | |
| enable='macros,wasm-bindgen,std,local-offset' | |
| groups=( | |
| --group-features 'serde,rand' | |
| --group-features 'formatting,parsing' | |
| --group-features 'serde-human-readable,serde-well-known' | |
| ) | |
| ;; | |
| wasm) | |
| query='.wasm' | |
| exclude='rand,rand08,rand09,rand010,quickcheck,local-offset' | |
| enable='macros' | |
| groups=( | |
| --group-features 'formatting,parsing' | |
| --group-features 'serde-human-readable,serde-well-known' | |
| ) | |
| ;; | |
| esac | |
| TARGET_ARGS=$(echo "$TYPE_CHECK_TARGETS" \ | |
| | jq -r "$query | map(\"--target \" + .) | join(\" \")") | |
| [ -z "$TARGET_ARGS" ] && continue | |
| echo "$TARGET_ARGS" \ | |
| | xargs -d" " \ | |
| cargo hack --print-command-list check \ | |
| -p time \ | |
| --feature-powerset \ | |
| --optional-deps \ | |
| --exclude-features "default,$exclude" \ | |
| --features "$enable" \ | |
| "${groups[@]}" \ | |
| --exclude-all-features \ | |
| 2>/dev/null \ | |
| | grep -v '^info:' \ | |
| | awk '{ | |
| if ($0 ~ /^ /) { | |
| cmd = cmd $0 | |
| } else { | |
| if (cmd != "") split_and_print(cmd) | |
| cmd = $0 | |
| } | |
| } | |
| END { | |
| if (cmd != "") split_and_print(cmd) | |
| } | |
| function split_and_print(c) { | |
| n = split(c, parts, " ") | |
| prefix = "" | |
| delete targets | |
| idx = 0 | |
| for (i = 1; i <= n; i++) { | |
| if (parts[i] == "--target") { | |
| targets[++idx] = parts[++i] | |
| } else { | |
| if (prefix == "") { | |
| prefix = parts[i] | |
| } else { | |
| prefix = prefix " " parts[i] | |
| } | |
| } | |
| } | |
| for (i = 1; i <= idx; i++) { | |
| print prefix " --target " targets[i] | |
| } | |
| }' \ | |
| >> "$ALL_COMMANDS" | |
| done | |
| TOTAL_COMMANDS=$(wc -l < "$ALL_COMMANDS") | |
| echo "$TOTAL_COMMANDS total commands" | |
| FILTERED_COMMANDS=$(mktemp) | |
| awk -v shards="$CHECK_SHARDS" -v shard="$SHARD" \ | |
| '(NR-1) % shards == (shard - 1)' \ | |
| "$ALL_COMMANDS" > "$FILTERED_COMMANDS" | |
| SHARD_COMMANDS=$(wc -l < "$FILTERED_COMMANDS") | |
| echo "$SHARD_COMMANDS commands in shard $SHARD" | |
| echo "count=$SHARD_COMMANDS" >> "$GITHUB_OUTPUT" | |
| echo "path=$FILTERED_COMMANDS" >> "$GITHUB_OUTPUT" | |
| if [ "$SHARD_COMMANDS" -eq 0 ]; then echo "No commands for this shard"; exit 0; fi | |
| NEEDED_TARGETS=$(grep -oP '(?<=--target )\S+' "$FILTERED_COMMANDS" \ | |
| | sort -u | paste -sd ' ' || true) | |
| if [ -n "$NEEDED_TARGETS" ]; then | |
| rustup target add $NEEDED_TARGETS | |
| fi | |
| - name: Run shard commands | |
| env: | |
| SHARD: ${{ matrix.shard }} | |
| SHARD_COMMANDS: ${{ steps.generate.outputs.count }} | |
| run: | | |
| set -euo pipefail | |
| count=0 | |
| while IFS= read -r cmd; do | |
| [ -z "$cmd" ] && continue | |
| count=$((count + 1)) | |
| echo "::group::[$count/$SHARD_COMMANDS] $cmd" | |
| eval "$cmd" | |
| echo "::endgroup::" | |
| done < "${{ steps.generate.outputs.path }}" | |
| test: | |
| name: Test (${{ matrix.os.name }}, ${{ matrix.rust.name }}) | |
| runs-on: ${{ matrix.os.value }} | |
| if: *pr-or-push | |
| strategy: | |
| matrix: | |
| rust: | |
| - { version: *msrv, name: MSRV } | |
| - { version: stable, name: stable } | |
| os: | |
| - { name: Ubuntu, value: ubuntu-latest } | |
| - { name: Windows, value: windows-latest } | |
| - { name: MacOS, value: macOS-latest } | |
| steps: | |
| - *checkout | |
| - *cache | |
| - name: Install toolchain | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ matrix.rust.version }} | |
| - name: Test | |
| run: cargo test -p time --all-features | |
| miri-prepare: | |
| name: Prepare miri | |
| runs-on: *default-os | |
| if: *pr-or-push | |
| steps: | |
| - *checkout | |
| - name: Install toolchain | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| components: miri, rust-src | |
| - name: Cache cargo output | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| shared-key: miri-cache | |
| - name: Setup Miri sysroot | |
| run: cargo miri setup | |
| - name: Copy sysroot to workspace | |
| run: | | |
| mkdir -p miri-sysroot | |
| cp -a "$HOME/.cache/miri/lib" miri-sysroot/ | |
| - name: Enumerate miri tests | |
| run: cargo miri test --no-run -p time --all-features | |
| env: | |
| MIRI_SYSROOT: ${{ github.workspace }}/miri-sysroot | |
| MIRIFLAGS: &miriflags -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check | |
| QUICKCHECK_MAX_TESTS: 100 | |
| - name: List tests and create shard files | |
| env: | |
| MIRI_SYSROOT: ${{ github.workspace }}/miri-sysroot | |
| run: | | |
| set -euo pipefail | |
| MIRI_SHARDS='${{ env.MIRI_SHARDS }}' | |
| # Capture binary paths from the --no-run output. | |
| # Lib+doc tests share the time-<hash> binary; integration tests use tests-<hash>. | |
| LIB_BINARY=$(cargo +nightly miri test --no-run -p time --all-features --lib 2>&1 \ | |
| | grep -oP 'target/miri/[^ )]+') | |
| TESTS_BINARY=$(cargo +nightly miri test --no-run -p time --all-features --test tests 2>&1 \ | |
| | grep -oP 'target/miri/[^ )]+') | |
| echo "lib binary: $LIB_BINARY" | |
| echo "tests binary: $TESTS_BINARY" | |
| mkdir -p miri-tests | |
| # Lib tests | |
| cargo test -p time --all-features --lib -- --list 2>/dev/null \ | |
| | grep -oP '^[\w:]+(?=: test$)' \ | |
| | awk -v n="$MIRI_SHARDS" '{ f="miri-tests/shard-" ((NR-1) % n + 1); print "lib " $0 >> f }' | |
| # Integration tests | |
| cargo test -p time --all-features --test tests -- --list 2>/dev/null \ | |
| | grep -oP '^[\w:]+(?=: test$)' \ | |
| | awk -v n="$MIRI_SHARDS" '{ f="miri-tests/shard-" ((NR-1) % n + 1); print "tests " $0 >> f }' | |
| # Doc tests | |
| cargo test -p time --all-features --doc -- --list 2>/dev/null \ | |
| | sed -n 's/: test$//p' \ | |
| | awk -v n="$MIRI_SHARDS" '{ f="miri-tests/shard-" ((NR-1) % n + 1); print "doc " $0 >> f }' | |
| for s in $(seq 1 "$MIRI_SHARDS"); do | |
| count=$(wc -l < "miri-tests/shard-$s") | |
| echo "shard $s: $count tests" | |
| done | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: miri-artifact | |
| path: | | |
| miri-sysroot/ | |
| miri-tests/ | |
| miri: | |
| name: Test (miri, shard ${{ matrix.shard }}) | |
| runs-on: *default-os | |
| needs: [compute-shards, miri-prepare] | |
| if: *pr-or-push | |
| strategy: | |
| matrix: | |
| include: ${{ fromJSON(needs.compute-shards.outputs.miri-matrix) }} | |
| steps: | |
| - *checkout | |
| - name: Install toolchain | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| components: miri, rust-src | |
| - name: Cache cargo output | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| shared-key: miri-cache | |
| - name: Download artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: miri-artifact | |
| - name: Fix build script permissions | |
| run: | | |
| find target/miri -name 'build-script-build' -exec chmod +x {} \; | |
| - name: Run shard tests | |
| env: | |
| SHARD: ${{ matrix.shard }} | |
| MIRIFLAGS: *miriflags | |
| QUICKCHECK_MAX_TESTS: 100 | |
| run: | | |
| set -euo pipefail | |
| export MIRI_SYSROOT="$PWD/miri-sysroot" | |
| shard_file="miri-tests/shard-$SHARD" | |
| if [ ! -f "$shard_file" ] || [ ! -s "$shard_file" ]; then | |
| echo "No tests for this shard" | |
| exit 0 | |
| fi | |
| # Group tests by source type (newline-separated for space-safe doc test names) | |
| lib_tests="" | |
| tests_tests="" | |
| doc_tests="" | |
| while IFS=' ' read -r source_type test_name; do | |
| case "$source_type" in | |
| lib) lib_tests="${lib_tests}${test_name}"$'\n' ;; | |
| tests) tests_tests="${tests_tests}${test_name}"$'\n' ;; | |
| doc) doc_tests="${doc_tests}${test_name}"$'\n' ;; | |
| esac | |
| done < "$shard_file" | |
| run_group() { | |
| local label="$1" tests="$2" extra_args="$3" | |
| [ -z "$tests" ] && return 0 | |
| local n | |
| n=$(printf '%s' "$tests" | wc -l) | |
| echo "::group::$label ($n tests in shard)" | |
| test_args=() | |
| while IFS= read -r test_name; do | |
| [ -z "$test_name" ] && continue | |
| test_args+=("$test_name") | |
| done < <(printf '%s' "$tests") | |
| cargo miri test -p time --all-features $extra_args -- --exact "${test_args[@]}" | |
| local exit_code=$? | |
| echo "::endgroup::" | |
| return "$exit_code" | |
| } | |
| fails=0 | |
| run_group "Lib tests" "$lib_tests" "--lib" || fails=$((fails + 1)) | |
| run_group "Integration tests" "$tests_tests" "--test tests" || fails=$((fails + 1)) | |
| run_group "Doc tests" "$doc_tests" "--doc" || fails=$((fails + 1)) | |
| if [ "$fails" -ne 0 ]; then | |
| exit 1 | |
| fi | |
| miri-cleanup: | |
| name: Clean up miri artifact | |
| runs-on: *default-os | |
| needs: miri | |
| if: ${{ always() && ((github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) || github.event_name == 'push') }} | |
| steps: | |
| - uses: geekyeggo/delete-artifact@v6 | |
| with: | |
| name: miri-artifact | |
| misc: | |
| name: Miscellaneous | |
| runs-on: *default-os | |
| permissions: | |
| issues: write | |
| if: *pr-or-push | |
| steps: | |
| - *checkout | |
| - *cache | |
| - name: Install nightly toolchain | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| components: rustfmt | |
| - name: Install stable toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| targets: x86_64-unknown-linux-gnu, x86_64-pc-windows-gnu | |
| - name: Check formatting | |
| run: cargo +nightly fmt --all -- {time,time-macros,time-core}/**/*.rs --check | |
| env: | |
| RUSTFLAGS: --cfg bench | |
| - name: Run clippy | |
| run: | | |
| cargo clippy --all-features --all-targets | |
| env: | |
| RUSTFLAGS: --cfg bench | |
| - name: Type-check benchmarks | |
| run: cargo +stable check -p time --benches --all-features | |
| env: | |
| RUSTFLAGS: --cfg bench | |
| - name: Install cross-compilation dependencies | |
| run: sudo apt install gcc-mingw-w64 | |
| # We're testing the linking, so running `cargo check` is insufficient. | |
| - name: Cross-build tests | |
| run: cargo +stable build -p time --tests --all-features --target x86_64-pc-windows-gnu | |
| # Test with default feature set to prevent #735 from happening again. | |
| - name: Doc test (default features) | |
| run: cargo +stable test -p time --doc | |
| - name: Generate documentation | |
| run: cargo +nightly doc --workspace --all-features --no-deps | |
| env: | |
| RUSTDOCFLAGS: --cfg docsrs | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Generate coverage report | |
| run: | | |
| cargo llvm-cov clean --workspace | |
| cargo llvm-cov test -p time --no-report --all-features | |
| cargo llvm-cov report --lcov > lcov.txt | |
| env: | |
| RUSTFLAGS: --cfg __ui_tests | |
| - name: Upload coverage report | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./lcov.txt | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| publish-documentation: | |
| name: Publish docs | |
| needs: | |
| - misc | |
| - check-targets | |
| - miri | |
| - test | |
| if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.master_branch) | |
| uses: time-rs/time-rs.github.io/.github/workflows/trigger-deploy.yaml@main | |
| secrets: inherit | |
| permissions: | |
| actions: write |