name: Smoke Test
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
pull_request:
paths:
- "src/**"
- "tests/**"
- "smoke-baseline.json"
repository_dispatch:
types: [corpus-release]
schedule:
- cron: "0 6 * * 0"
workflow_dispatch:
permissions: {}
concurrency:
group: smoke-test-${{ github.ref }}
cancel-in-progress: true
jobs:
smoke-test:
name: Real-log smoke test
runs-on: ubuntu-latest
if: >-
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success'
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6
- name: Resolve corpus release tag
id: corpus-tag
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG=$(gh release view --repo manasight/manasight-corpus --json tagName --jq '.tagName')
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Corpus release tag: $TAG"
- name: Cache corpus tarball
id: cache-corpus
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae with:
path: /tmp/smoke-corpus.tar.gz
key: smoke-corpus-${{ steps.corpus-tag.outputs.tag }}
- name: Download corpus
if: steps.cache-corpus.outputs.cache-hit != 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release download "${{ steps.corpus-tag.outputs.tag }}" \
--repo manasight/manasight-corpus \
--pattern "*.tar.gz" \
--output /tmp/smoke-corpus.tar.gz
- name: Extract corpus
run: |
mkdir -p /tmp/test-logs
tar -xzf /tmp/smoke-corpus.tar.gz -C /tmp/test-logs
gunzip /tmp/test-logs/corpus/*.log.gz
echo "Corpus files:"
ls -lh /tmp/test-logs/corpus/
- name: Run smoke tests
id: smoke
env:
MANASIGHT_TEST_LOGS: /tmp/test-logs/corpus
CORPUS_TAG: ${{ steps.corpus-tag.outputs.tag }}
run: |
# pipefail is load-bearing: without it, tee's exit 0 masks cargo test failures.
set -o pipefail
set +e
cargo test --all-features smoke_test_real_logs -- --nocapture 2>&1 | tee /tmp/smoke-output.txt
SMOKE_EXIT=$?
set -e
echo "exit_code=$SMOKE_EXIT" >> "$GITHUB_OUTPUT"
# Parse ratchet output for job summary.
# Extract everything after "Ratchet" line for the summary.
if grep -q "Ratchet" /tmp/smoke-output.txt; then
echo "has_ratchet=true" >> "$GITHUB_OUTPUT"
else
echo "has_ratchet=false" >> "$GITHUB_OUTPUT"
fi
exit $SMOKE_EXIT
- name: Write job summary
if: always() && steps.smoke.outcome != 'skipped'
run: |
{
echo "## Smoke Test Results"
echo ""
if [ "${{ steps.smoke.outcome }}" = "success" ]; then
echo "**Status:** PASS"
else
echo "**Status:** FAIL"
fi
echo ""
# Build a comparison table from the smoke output.
echo "### Per-File Summary"
echo ""
echo "| File | Entries | Claimed | Unclaimed | Ratchet |"
echo "|------|---------|---------|-----------|---------|"
# Parse each file's stats from the smoke output using POSIX awk
# to avoid fd-sharing issues with nested read loops.
# Note: uses only POSIX awk features (no gawk-specific match()).
awk '
/^File: .+ \([0-9]+ entries\)/ {
# Strip "File: " prefix and " (NNN entries)" suffix.
s = $0
sub(/^File: /, "", s)
sub(/ \([0-9]+ entries\)$/, "", s)
fname = s
# Extract entry count from between parens.
s = $0
sub(/.*\(/, "", s)
sub(/ entries\).*/, "", s)
entries = s + 0
unclaimed = 0
in_file = 1
next
}
in_file && /unclaimed:/ {
# Extract the unclaimed number.
s = $0
sub(/.*unclaimed: */, "", s)
sub(/ .*/, "", s)
unclaimed = s + 0
claimed = entries - unclaimed
pct = (entries > 0) ? int(claimed * 100 / entries) : 0
printf "| `%s` | %d | %d (%d%%) | %d | -- |\n", fname, entries, claimed, pct, unclaimed
in_file = 0
}
/^===/ { in_file = 0 }
' /tmp/smoke-output.txt
echo ""
# Include ratchet report section.
if [ "${{ steps.smoke.outputs.has_ratchet }}" = "true" ]; then
echo "### Ratchet Comparison"
echo ""
echo '```'
sed -n '/^Ratchet/,/^$/p' /tmp/smoke-output.txt
echo '```'
else
echo "### Ratchet Comparison"
echo ""
echo "_No baseline comparison performed._"
fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload report
if: always() && steps.smoke.outcome != 'skipped'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: smoke-test-report
path: /tmp/smoke-output.txt
retention-days: 30
- name: Check for baseline improvements
if: >-
steps.smoke.outcome == 'success' &&
steps.smoke.outputs.has_ratchet == 'true' &&
github.ref == 'refs/heads/main'
id: baseline-check
run: |
if grep -q '\[+\]' /tmp/smoke-output.txt; then
echo "has_improvements=true" >> "$GITHUB_OUTPUT"
else
echo "has_improvements=false" >> "$GITHUB_OUTPUT"
fi
- name: Update baseline and open PR
if: >-
steps.baseline-check.outcome == 'success' &&
steps.baseline-check.outputs.has_improvements == 'true'
env:
MANASIGHT_TEST_LOGS: /tmp/test-logs/corpus
CORPUS_TAG: ${{ steps.corpus-tag.outputs.tag }}
SMOKE_BLESS: "1"
GH_TOKEN: ${{ secrets.BASELINE_PR_TOKEN }}
run: |
# Re-run in bless mode to write updated baseline.
if ! cargo test --all-features smoke_test_real_logs -- --nocapture 2>&1; then
echo "::warning::Bless mode run exited non-zero — baseline may not have been updated"
fi
# Check if baseline actually changed.
if git diff --quiet smoke-baseline.json; then
echo "Baseline unchanged after bless — nothing to do."
exit 0
fi
# Configure git identity for the commit (checkout@v4 does not set these).
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Override the remote URL so git push uses the PAT (not the
# GITHUB_TOKEN that actions/checkout@v4 configured).
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
BRANCH="auto/update-smoke-baseline-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
git add smoke-baseline.json
git commit -m "chore: auto-update smoke-baseline.json
Smoke test detected improved parser counts on main.
This baseline update ratchets forward to the new counts.
Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
git push -u origin "$BRANCH"
gh pr create \
--base main \
--title "chore: auto-update smoke test baseline" \
--body "$(cat <<'EOF'
## Summary
Smoke test CI detected improved parser counts on main.
This PR updates `smoke-baseline.json` to ratchet forward to the new counts.
Auto-generated by the smoke test workflow.
EOF
)"