Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion .github/workflows/smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,72 @@ jobs:

- name: Checkout
uses: actions/checkout@v4
with:
# Full history so PR-scoped verify can diff against the base commit.
fetch-depth: 0

- name: Scope verify to changed examples (pull requests only)
env:
EVENT_NAME: ${{ github.event_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
# Non-PR events (push to main, cron, upstream release, manual dispatch)
# always run the full suite: a dependency bump or scheduled run must
# exercise every example, not just a diff.
if [ "$EVENT_NAME" != "pull_request" ]; then
echo "VERIFY_PATHS=." >> "$GITHUB_ENV"
echo "Full verify (event=$EVENT_NAME)"
exit 0
fi

git fetch --no-tags --depth=1 origin "$PR_BASE_SHA" 2>/dev/null || true
CHANGED=$(git diff --name-only "$PR_BASE_SHA" HEAD)
echo "Changed files:"
printf '%s\n' "$CHANGED"

# Example roots are directories that own an expected/ folder.
EXROOTS=$(find . -type d -name expected -not -path '*/node_modules/*' \
| sed 's#/expected$##;s#^\./##' | sort -u)

SELECTED=""
FALLBACK=0
while IFS= read -r f; do
[ -z "$f" ] && continue
MATCH=""
for root in $EXROOTS; do
case "$f" in
"$root"/*) MATCH="$root"; break ;;
esac
done
if [ -n "$MATCH" ]; then
# Reject any path with characters outside a safe allowlist before it
# reaches $GITHUB_ENV / make / find. This closes the injection and
# word-splitting surface from PR-controlled directory names; the
# allowlist excludes spaces and shell metacharacters, so the
# space-separated `find $(VERIFY_PATHS)` in the Makefile stays safe.
case "$MATCH" in
*[!A-Za-z0-9._/-]*)
echo "Unsafe example path forces full verify: $MATCH"
FALLBACK=1 ;;
*)
case " $SELECTED " in *" $MATCH "*) : ;; *) SELECTED="$SELECTED $MATCH" ;; esac ;;
esac
else
# A file outside every example dir (Makefile, scripts/, workflow,
# shared requirements, docs) can affect any example -> full run.
echo "Shared/global change forces full verify: $f"
FALLBACK=1
fi
done <<< "$CHANGED"

if [ "$FALLBACK" -eq 1 ] || [ -z "${SELECTED// /}" ]; then
echo "VERIFY_PATHS=." >> "$GITHUB_ENV"
echo "Full verify (fallback=$FALLBACK, selected='${SELECTED# }')"
else
echo "VERIFY_PATHS=${SELECTED# }" >> "$GITHUB_ENV"
echo "Scoped verify: ${SELECTED# }"
printf '### Scoped smoke: `%s`\n' "${SELECTED# }" >> "$GITHUB_STEP_SUMMARY"
fi

- name: Setup Python
uses: actions/setup-python@v5
Expand Down Expand Up @@ -129,7 +195,7 @@ jobs:
PY

- name: Run make verify
run: make verify
run: make verify VERIFY_PATHS="${VERIFY_PATHS:-.}"

- name: Smoke test cubrid-mcp-server
run: python -c "import cubrid_mcp_server; print('cubrid-mcp-server import OK')"
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ DOCKER_COMPOSE := docker compose
NORMALIZE := bash scripts/normalize_output.sh
PYTHON := python3

# Search roots for `make verify`. Defaults to the whole tree; CI narrows this to
# only the changed example directories on pull requests (see smoke-test.yml).
VERIFY_PATHS ?= .

help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
Expand All @@ -27,10 +31,10 @@ clean: ## Stop and remove all data
$(DOCKER_COMPOSE) down -v
@echo "✓ Cleaned up all containers and volumes"

verify: ## Verify example outputs against expected results
@echo "Verifying example outputs..."
verify: ## Verify example outputs against expected results (VERIFY_PATHS scopes the search roots)
@echo "Verifying example outputs in: $(VERIFY_PATHS)"
@PASS=0; FAIL=0; SKIP=0; \
for expected in $$(find . -path '*/expected/*.expected' | sort); do \
for expected in $$(find $(VERIFY_PATHS) -path '*/expected/*.expected' | sort); do \
dir=$$(dirname "$$(dirname "$$expected")"); \
base=$$(basename "$$expected" .expected); \
script="$$dir/$$base.py"; \
Expand Down
Loading