Skip to content

Commit a768670

Browse files
authored
Merge branch 'main' into feature/drc-3295-pr1-per-node-db-emitter
2 parents 29bbc99 + ab86991 commit a768670

2 files changed

Lines changed: 231 additions & 0 deletions

File tree

.github/workflows/integration-tests-cloud.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,52 @@ jobs:
189189
}"
190190
env:
191191
SLACK_WEBHOOK_URL_DEV: ${{ secrets.SLACK_WEBHOOK_URL_DEV }}
192+
193+
# Staging recce-cloud CLI smoke test (standalone package, RECCE_API_TOKEN auth)
194+
# Runs daily after nightly build; prod variant will be added once staging is stable.
195+
smoke-test-recce-cloud-staging:
196+
needs: resolve-environment
197+
if: needs.resolve-environment.outputs.environment == 'staging'
198+
concurrency:
199+
group: smoke-test-recce-cloud-staging
200+
cancel-in-progress: false
201+
runs-on: ubuntu-latest
202+
strategy:
203+
max-parallel: 1
204+
matrix:
205+
include:
206+
- python-version: "3.11"
207+
dbt-version: "1.8"
208+
- python-version: "3.13"
209+
dbt-version: "latest"
210+
steps:
211+
- uses: actions/checkout@v4
212+
with:
213+
persist-credentials: false
214+
215+
- name: Install uv
216+
uses: astral-sh/setup-uv@v4
217+
with:
218+
version: "latest"
219+
220+
- name: Install recce-cloud and dbt
221+
run: |
222+
uv venv --python ${{ matrix.python-version }}
223+
uv pip install ./recce_cloud
224+
if [ "${{ matrix.dbt-version }}" == "latest" ]; then
225+
uv pip install dbt-core dbt-duckdb
226+
else
227+
uv pip install dbt-core~=${{ matrix.dbt-version }}.0 dbt-duckdb~=${{ matrix.dbt-version }}.0
228+
fi
229+
230+
- name: Run smoke test - recce-cloud CLI (staging)
231+
run: |
232+
source .venv/bin/activate
233+
./integration_tests/dbt/smoke_test_recce_cloud.sh
234+
env:
235+
RECCE_API_TOKEN: ${{ secrets.RECCE_API_TOKEN_STAGING }}
236+
RECCE_ORG: ${{ vars.RECCE_SMOKE_TEST_ORG_STAGING }}
237+
RECCE_PROJECT: ${{ vars.RECCE_SMOKE_TEST_PROJECT_STAGING }}
238+
RECCE_CLOUD_API_HOST: ${{ vars.RECCE_CLOUD_API_HOST_STAGING }}
239+
PY: ${{ matrix.python-version }}
240+
DBT: ${{ matrix.dbt-version }}
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Smoke test for the standalone `recce-cloud` CLI against a live Recce Cloud
5+
# environment. This exercises the RECCE_API_TOKEN-based workflow end to end,
6+
# including the session-base (isolated base) upload path.
7+
#
8+
# Required env vars:
9+
# RECCE_API_TOKEN - API token for the test project
10+
# RECCE_ORG - Organization slug or ID for the test project
11+
# RECCE_PROJECT - Project slug or ID for the test project
12+
#
13+
# Optional env vars:
14+
# RECCE_CLOUD_API_HOST - Override the cloud host (e.g. staging)
15+
# PY, DBT - Matrix identifiers (used in the unique session name)
16+
# GITHUB_RUN_ID - GHA run id (used in the unique session name)
17+
# GITHUB_RUN_ATTEMPT - GHA run attempt (used in the unique session name)
18+
19+
: "${RECCE_API_TOKEN:?RECCE_API_TOKEN is required}"
20+
: "${RECCE_ORG:?RECCE_ORG is required}"
21+
: "${RECCE_PROJECT:?RECCE_PROJECT is required}"
22+
23+
# Distinguish prod vs staging in the session name so runs don't collide
24+
ENV_NAME="prod"
25+
if [[ -n "${RECCE_CLOUD_API_HOST:-}" ]]; then
26+
ENV_NAME="staging"
27+
fi
28+
29+
SESSION_NAME="smoke-rc-${ENV_NAME}-py${PY:-unknown}-dbt${DBT:-unknown}-${GITHUB_RUN_ID:-local}-${GITHUB_RUN_ATTEMPT:-1}"
30+
SESSION_ID=""
31+
32+
NEW_WORKSPACE=$(dirname "${GITHUB_WORKSPACE:-$PWD}")
33+
cd "$NEW_WORKSPACE"
34+
pwd
35+
36+
# Disable anonymous telemetry for the smoke run
37+
mkdir -p ~/.recce
38+
echo "user_id: 00000000000000000000000000000000" > ~/.recce/profile.yml
39+
echo "anonymous_tracking: false" >> ~/.recce/profile.yml
40+
41+
cleanup() {
42+
local exit_code=$?
43+
if [[ -n "$SESSION_ID" ]]; then
44+
echo "Teardown: deleting session $SESSION_ID"
45+
recce-cloud delete --session-id "$SESSION_ID" --force || true
46+
fi
47+
exit $exit_code
48+
}
49+
trap cleanup EXIT
50+
51+
# --------------------------------------------------------------------
52+
# 0. Sanity: CLI is installed and runnable
53+
# --------------------------------------------------------------------
54+
recce-cloud version
55+
56+
# --------------------------------------------------------------------
57+
# 1. Prepare jaffle_shop fixture
58+
# --------------------------------------------------------------------
59+
GIT_REPO="https://github.com/DataRecce/jaffle_shop_duckdb.git"
60+
GIT_BRANCH="chore/smoke-test-cloud"
61+
rm -rf jaffle_shop_duckdb
62+
git clone --depth 1 --branch $GIT_BRANCH $GIT_REPO
63+
cd jaffle_shop_duckdb
64+
65+
dbt --version
66+
dbt deps
67+
68+
# --------------------------------------------------------------------
69+
# 2. Build BASE artifacts -> target-base/
70+
# --------------------------------------------------------------------
71+
git restore models/customers.sql || true
72+
dbt seed --target-path target-base
73+
dbt run --target-path target-base
74+
dbt docs generate --target-path target-base
75+
test -s target-base/manifest.json
76+
test -s target-base/catalog.json
77+
78+
# --------------------------------------------------------------------
79+
# 3. Build PR artifacts -> target/
80+
# --------------------------------------------------------------------
81+
echo "where customer_id > 0" >> models/customers.sql
82+
dbt run
83+
dbt docs generate
84+
git restore models/customers.sql
85+
test -s target/manifest.json
86+
test -s target/catalog.json
87+
88+
# --------------------------------------------------------------------
89+
# 4. Bind project to the test org/project
90+
# --------------------------------------------------------------------
91+
recce-cloud init --org "$RECCE_ORG" --project "$RECCE_PROJECT"
92+
recce-cloud init --status
93+
94+
# --------------------------------------------------------------------
95+
# 5. Doctor baseline (informational)
96+
#
97+
# `recce-cloud doctor` exits non-zero if ANY of its four checks fails,
98+
# and Production Metadata / Dev Session can legitimately be unpopulated
99+
# in a fresh test project. We only enforce login + project_binding here.
100+
# --------------------------------------------------------------------
101+
recce-cloud doctor --json > doctor.pre.json || true
102+
echo "--- recce-cloud doctor output ---"
103+
cat doctor.pre.json
104+
echo "---------------------------------"
105+
jq -e '.login.status == "pass"' doctor.pre.json > /dev/null
106+
jq -e '.project_binding.status == "pass"' doctor.pre.json > /dev/null
107+
108+
# --------------------------------------------------------------------
109+
# 6. Upload PR artifacts by session name
110+
# --------------------------------------------------------------------
111+
recce-cloud upload --session-name "$SESSION_NAME" --yes --target-path target
112+
SESSION_ID=$(recce-cloud list --json | jq -r --arg n "$SESSION_NAME" '.[] | select(.name == $n) | .id' | head -n 1)
113+
if [[ -z "$SESSION_ID" ]]; then
114+
echo "ERROR: could not resolve session id for $SESSION_NAME"
115+
exit 1
116+
fi
117+
echo "Created session: $SESSION_ID ($SESSION_NAME)"
118+
119+
# --------------------------------------------------------------------
120+
# 7. Pre-condition: the new session has no isolated base yet
121+
# --------------------------------------------------------------------
122+
recce-cloud list --json | jq -e --arg i "$SESSION_ID" \
123+
'.[] | select(.id == $i) | .has_isolated_base == false' > /dev/null
124+
125+
# --------------------------------------------------------------------
126+
# 8. Upload SESSION BASE artifacts (isolated base)
127+
# --------------------------------------------------------------------
128+
recce-cloud upload --session-base --session-id "$SESSION_ID" --target-path target-base
129+
recce-cloud list --json | jq -e --arg i "$SESSION_ID" \
130+
'.[] | select(.id == $i) | .has_isolated_base == true' > /dev/null
131+
echo "Isolated base uploaded successfully"
132+
133+
# --------------------------------------------------------------------
134+
# 9. Negative check: --session-base + --type prod must be rejected
135+
# --------------------------------------------------------------------
136+
set +e
137+
recce-cloud upload --session-base --type prod --target-path target > /dev/null 2>&1
138+
NEG_EXIT=$?
139+
set -e
140+
if [[ "$NEG_EXIT" -eq 0 ]]; then
141+
echo "ERROR: --session-base + --type prod should have failed, but exited 0"
142+
exit 1
143+
fi
144+
echo "Negative check passed (exit $NEG_EXIT)"
145+
146+
# --------------------------------------------------------------------
147+
# 10. Download the PR session artifacts
148+
# --------------------------------------------------------------------
149+
rm -rf target-downloaded
150+
recce-cloud download --session-id "$SESSION_ID" --target-path target-downloaded --force
151+
test -s target-downloaded/manifest.json
152+
test -s target-downloaded/catalog.json
153+
154+
# --------------------------------------------------------------------
155+
# 11. Download a known production session (read-only sanity)
156+
# --------------------------------------------------------------------
157+
PROD_SESSION_ID=$(recce-cloud list --type prod --json | jq -r '.[0].id // empty')
158+
if [[ -z "$PROD_SESSION_ID" ]]; then
159+
echo "ERROR: no production session found in test project; seed one first"
160+
exit 1
161+
fi
162+
rm -rf target-prod
163+
recce-cloud download --session-id "$PROD_SESSION_ID" --target-path target-prod --force
164+
test -s target-prod/manifest.json
165+
166+
# --------------------------------------------------------------------
167+
# 12. Dry-run paths (no side effects)
168+
# --------------------------------------------------------------------
169+
recce-cloud upload --dry-run --target-path target
170+
recce-cloud download --session-id "$SESSION_ID" --dry-run
171+
recce-cloud delete --session-id "$SESSION_ID" --dry-run
172+
173+
# --------------------------------------------------------------------
174+
# 13. Delete session + verify
175+
# --------------------------------------------------------------------
176+
recce-cloud delete --session-id "$SESSION_ID" --force
177+
recce-cloud list --json | jq -e --arg i "$SESSION_ID" 'all(.[]; .id != $i)' > /dev/null
178+
179+
# Session is gone; skip the EXIT-trap double-delete
180+
SESSION_ID=""
181+
182+
echo "recce-cloud smoke test completed successfully"

0 commit comments

Comments
 (0)