version: "3"
tasks:
default:
desc: List available tasks
cmds:
- task --list
check:
desc: Run all checks (same as CI)
cmds:
- task: fmt:check
- task: clippy
- task: test
- task: doc
fmt:
desc: Format code with rustfmt
cmds:
- cargo fmt --all
fmt:check:
desc: Check code formatting
cmds:
- cargo fmt --all -- --check
clippy:
desc: Run clippy linter
cmds:
- cargo clippy --all-targets --all-features
test:
desc: Run unit tests (excludes e2e)
cmds:
- cargo test
doc:
desc: Build documentation
cmds:
- cargo doc --no-deps --all-features
env:
RUSTDOCFLAGS: -Dwarnings
build:
desc: Build in debug mode
cmds:
- cargo build
build:release:
desc: Build in release mode
cmds:
- cargo build --release
clean:
desc: Clean build artifacts
cmds:
- cargo clean
pre-commit:install:
desc: Install pre-commit hooks
cmds:
- pre-commit install
pre-commit:run:
desc: Run pre-commit on all files
cmds:
- pre-commit run --all-files
e2e:
desc: Run E2E tests with both transports (requires Docker)
deps: [build]
cmds:
- task: e2e:gitlab:up
- task: e2e:wait
- task: e2e:runner:setup
- defer: { task: e2e:gitlab:down }
- task: e2e:run
e2e:stdio:
desc: Run E2E tests with stdio transport only (no HTTP server)
deps: [build]
cmds:
- task: e2e:gitlab:up
- task: e2e:wait
- task: e2e:runner:setup
- defer: { task: e2e:gitlab:down }
- task: e2e:run:stdio-only
e2e:http:
desc: Run E2E tests with HTTP transport only
deps: [build]
cmds:
- task: e2e:gitlab:up
- task: e2e:wait
- task: e2e:runner:setup
- defer: { task: e2e:gitlab:down }
- task: e2e:run
vars:
FILTER: http
e2e:run:
desc: Run E2E tests (internal - creates PAT, starts MCP server in Docker, runs tests)
internal: true
cmds:
- |
TOKEN=$(./e2e/scripts/create-pat.sh)
export GITLAB_URL=http://localhost:8080
export GITLAB_TOKEN="$TOKEN"
export RUST_TEST_THREADS="${RUST_TEST_THREADS:-1}"
# Start MCP HTTP server in Docker container
echo "Starting MCP HTTP server container..."
docker compose -f e2e/docker-compose.yml --profile mcp up -d --build
cleanup() {
echo "Stopping MCP server container..."
docker compose -f e2e/docker-compose.yml --profile mcp stop
}
trap cleanup EXIT
# Wait for MCP server health endpoint
echo "Waiting for MCP server health endpoint..."
for i in $(seq 1 30); do
curl -sf http://localhost:20399/health >/dev/null 2>&1 && break
sleep 1
done
curl -sf http://localhost:20399/health >/dev/null 2>&1 || { echo "ERROR: MCP server health check failed after 30s"; docker compose -f e2e/docker-compose.yml --profile mcp logs; exit 1; }
echo "MCP server is ready"
export MCP_HTTP_URL=http://localhost:20399/mcp
cargo test -p tanuki-mcp-e2e {{.FILTER}} {{.CLI_ARGS}}
e2e:run:stdio-only:
desc: Run E2E tests without HTTP server (stdio only)
internal: true
cmds:
- |
TOKEN=$(./e2e/scripts/create-pat.sh)
export GITLAB_URL=http://localhost:8080
export GITLAB_TOKEN="$TOKEN"
export RUST_TEST_THREADS="${RUST_TEST_THREADS:-1}"
echo "Running stdio-only tests (HTTP tests will be filtered out)..."
cargo test -p tanuki-mcp-e2e {{.CLI_ARGS}} -- --skip "case_2_http"
e2e:gitlab:up:
desc: Start GitLab CE container for E2E tests
cmds:
- docker compose -f e2e/docker-compose.yml --profile infra up -d
status:
- docker inspect tanuki-mcp-e2e-gitlab --format '{{.State.Running}}' 2>/dev/null | grep -q true
e2e:gitlab:down:
desc: Stop GitLab CE container
cmds:
- docker compose -f e2e/docker-compose.yml --profile infra --profile mcp down -v
e2e:gitlab:logs:
desc: Show GitLab container logs
cmds:
- docker compose -f e2e/docker-compose.yml logs -f gitlab
e2e:mcp:logs:
desc: Show MCP server container logs
cmds:
- docker compose -f e2e/docker-compose.yml --profile mcp logs -f
e2e:wait:
desc: Wait for GitLab to be ready (may take 3-5 minutes)
cmds:
- |
echo "Waiting for GitLab to be ready (this may take 3-5 minutes)..."
until curl -sf http://localhost:8080/users/sign_in >/dev/null 2>&1; do
echo " Waiting for login page..."
sleep 10
done
echo "GitLab is ready!"
e2e:runner:setup:
desc: Setup GitLab runner (create token, register, start)
cmds:
- |
echo "Setting up GitLab runner..."
# Create runner token via Rails console
echo "Creating runner token..."
TOKEN=$(docker exec tanuki-mcp-e2e-gitlab gitlab-rails runner "
Ci::Runner.where(description: 'e2e-runner').destroy_all
runner = Ci::Runner.create!(
runner_type: :instance_type,
description: 'e2e-runner',
run_untagged: true,
active: true
)
puts runner.token
" 2>/dev/null | tail -1)
if [ -z "$TOKEN" ]; then
echo "ERROR: Failed to create runner token"
exit 1
fi
echo "Created runner token"
# Unregister any existing runners
docker exec tanuki-mcp-e2e-gitlab-runner gitlab-runner unregister --all-runners 2>/dev/null || true
# Register the runner
echo "Registering runner..."
docker exec tanuki-mcp-e2e-gitlab-runner gitlab-runner register \
--non-interactive \
--url http://gitlab:80 \
--token "$TOKEN" \
--executor shell \
--description "e2e-shell-runner"
# Start the runner daemon in background
echo "Starting runner daemon..."
docker exec -d tanuki-mcp-e2e-gitlab-runner gitlab-runner run
# Wait for runner to connect
sleep 2
echo "GitLab runner setup complete!"
e2e:status:
desc: Check GitLab container status
cmds:
- docker compose -f e2e/docker-compose.yml ps
- |
if curl -sf http://localhost:8080/users/sign_in >/dev/null 2>&1; then
echo "GitLab is healthy and ready"
else
echo "GitLab is not ready yet"
fi
dev:
desc: Start full development environment (GitLab + MCP + Inspector)
cmds:
- task: e2e:gitlab:up
- task: e2e:wait
- task: e2e:runner:setup
- task: dev:mcp:up
- |
echo ""
echo "=== Development Environment Ready ==="
echo "GitLab: http://localhost:8080 (root/testpassword123!)"
echo "MCP Server: http://localhost:20399/mcp"
echo "Dashboard: http://localhost:20400"
echo "MCP Inspector: http://localhost:6274"
echo ""
echo "To connect Inspector to MCP server:"
echo " Transport: Streamable HTTP"
echo " URL: http://tanuki-mcp:20289/mcp"
echo ""
echo "Stop with: task dev:down"
dev:mcp:up:
desc: Start MCP server and Inspector
internal: true
cmds:
- |
TOKEN=$(./e2e/scripts/create-pat.sh)
export GITLAB_TOKEN="$TOKEN"
docker compose -f e2e/docker-compose.yml --profile mcp --profile inspector up -d --build
echo "Waiting for MCP server..."
for i in $(seq 1 30); do
curl -sf http://localhost:20399/health >/dev/null 2>&1 && break
sleep 1
done
curl -sf http://localhost:20399/health >/dev/null 2>&1 || echo "WARNING: MCP server not responding"
dev:down:
desc: Stop development environment
cmds:
- docker compose -f e2e/docker-compose.yml --profile infra --profile mcp --profile inspector down -v
release:
desc: "Create a release. Usage: task release VERSION=patch|minor|major|x.y.z"
vars:
SKIP_E2E: '{{.SKIP_E2E | default "false"}}'
preconditions:
- sh: '[ -n "{{.VERSION}}" ]'
msg: "VERSION is required. Use: patch, minor, major, or explicit version (e.g., 0.2.0)"
cmds:
- |
git diff --quiet || (echo "ERROR: Working directory not clean" && exit 1)
- echo "Bumping version..."
- |
case "{{.VERSION}}" in
patch|minor|major) cargo set-version --workspace --bump "{{.VERSION}}" ;;
*) cargo set-version --workspace "{{.VERSION}}" ;;
esac
- cargo generate-lockfile
- |
RELEASE_VERSION=$(cargo pkgid | cut -d "@" -f2)
echo "=== Release v$RELEASE_VERSION ==="
- git add Cargo.toml tanuki-mcp-macros/Cargo.toml e2e/Cargo.toml Cargo.lock
- |
RELEASE_VERSION=$(cargo pkgid | cut -d "@" -f2)
git commit -m "chore: release v$RELEASE_VERSION"
- echo "Running checks..."
- task: check
- |
if [ "{{.SKIP_E2E}}" = "false" ]; then
echo "Running E2E tests..."
task e2e
else
echo "Skipping E2E tests (SKIP_E2E=true)"
fi
- |
RELEASE_VERSION=$(cargo pkgid | cut -d "@" -f2)
git tag -a "v$RELEASE_VERSION" -m "Release v$RELEASE_VERSION"
echo "Created tag v$RELEASE_VERSION"
echo ""
echo "=== Release v$RELEASE_VERSION created successfully ==="
echo "To complete the release, push the tag and commit:"
echo " git push origin main"
echo " git push origin v$RELEASE_VERSION"