Skip to content

Commit 700fc85

Browse files
Merge pull request #4788 from snowflakedb/dev
chore: Merge dev to main before v2.17.0
2 parents 74576ba + 9f0400e commit 700fc85

634 files changed

Lines changed: 24333 additions & 5087 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codex

Whitespace-only changes.

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @snowflakedb/terraform-provider
1+
* @snowflakedb/terraform-provider @snowflakedb/client-side-interfaces

.github/workflows/tests-account-level.yml

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ jobs:
2828
env:
2929
## adding additional suffix to don't have conflict in non-account level tests and their pre-created objects
3030
TEST_SF_TF_TEST_OBJECT_SUFFIX: ${{ format('{0}{1}', ((github.event_name == 'repository_dispatch' && github.event.client_payload.pull_request.head.sha) || (github.event_name == 'pull_request' && github.event.pull_request.head.sha)), 'AL') }}
31+
TEST_SF_TF_TEST_WORKFLOW_ID: "${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.pull_request.head.sha) || (github.event_name == 'pull_request' && github.event.pull_request.head.sha) }}_${{ github.run_attempt }}"
32+
ADDITIONAL_TEST_FLAGS: "-json"
3133
name: Run all account-level tests
3234
runs-on: ubuntu-latest
3335
if: (github.event_name == 'repository_dispatch') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
@@ -138,9 +140,11 @@ jobs:
138140
terraform_wrapper: false
139141

140142
- name: Run integration and acceptance account-level tests
141-
run: make test-account-level-features
143+
# pipefail needs to be set to ensure that the exit code of make test command is captured even when piped (otherwise it would take the exit code of make save-test-results)
144+
run: set -o pipefail && make test-account-level-features | make save-test-results
142145
if: ${{ !cancelled() && steps.setup_terraform.conclusion == 'success' }}
143146
env:
147+
TEST_SF_TF_TEST_TYPE: "account_level"
144148
SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT: ${{ secrets.SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT }}
145149
TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL }}
146150
TEST_SF_TF_AWS_EXTERNAL_KEY_ID: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_KEY_ID }}
@@ -166,17 +170,15 @@ jobs:
166170
Account-level tests ${{ job.status }} for [${{ github.event.client_payload.slash_command.args.named.sha || github.event.pull_request.head.sha }}](https://github.com/snowflakedb/terraform-provider-snowflake/actions/runs/${{ github.run_id }})
167171
168172
# For fork PRs, tests run via repository_dispatch (triggered by /ok-to-test),
169-
# but the resulting check runs are tied to the default branch, not the fork PR.
170-
# This step updates the (skipped) check run on the fork PR's head SHA so the
171-
# PR status reflects the actual test outcome. It resolves the job's display name
172-
# via job.check_run_id (since github.job returns the job_id, not the display name)
173-
# and uses it to find the matching check run on the fork PR's commit.
173+
# but the job check runs are tied to the default branch, not the fork PR SHA.
174+
# This step mirrors the job result onto the fork PR head SHA using a dedicated
175+
# synthetic check run that we own, reusing it across reruns to avoid duplicates.
174176
- name: Set fork job status
175177
uses: actions/github-script@v6
176178
if: ${{ always() }}
177179
id: update_check_run
178180
env:
179-
number: ${{ github.event.client_payload.pull_request.number }}
181+
pr_number: ${{ github.event.client_payload.pull_request.number }}
180182
check_run_id: ${{ job.check_run_id }}
181183
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
182184
conclusion: ${{ job.status }}
@@ -196,20 +198,52 @@ jobs:
196198
const jobName = currentCheck.name;
197199
console.log(`Current job check run name: ${jobName}`);
198200
const ref = process.env.sha;
199-
const { data: checks } = await github.rest.checks.listForRef({
201+
const conclusion = process.env.conclusion;
202+
const externalId = `fork-pr-${process.env.pr_number}-${jobName}`;
203+
const output = {
204+
title: `Tests ${conclusion}`,
205+
summary: `Account-level tests ${conclusion}. See the [workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`
206+
};
207+
208+
const { data: existingRuns } = await github.rest.checks.listForRef({
200209
...context.repo,
201-
ref
210+
ref,
211+
check_name: jobName,
202212
});
203-
const check = checks.check_runs.filter(c => c.name === jobName);
204-
console.log(check);
205-
if (check.length === 0) {
206-
console.log(`No matching check run found for "${jobName}" on ${ref}`);
207-
return;
213+
214+
const existingRun = existingRuns.check_runs
215+
.filter((run) =>
216+
run.head_sha === ref &&
217+
run.name === jobName &&
218+
run.external_id === externalId
219+
)
220+
.sort((left, right) => {
221+
const leftDate = Math.max(new Date(left.started_at || 0).getTime(), new Date(left.completed_at || 0).getTime());
222+
const rightDate = Math.max(new Date(right.started_at || 0).getTime(), new Date(right.completed_at || 0).getTime());
223+
return rightDate - leftDate;
224+
})[0];
225+
226+
let result;
227+
if (existingRun) {
228+
({ data: result } = await github.rest.checks.update({
229+
...context.repo,
230+
check_run_id: existingRun.id,
231+
status: 'completed',
232+
conclusion,
233+
external_id: externalId,
234+
output,
235+
}));
236+
console.log(`Updated check run ${existingRun.id}: ${conclusion} for "${jobName}" on ${ref}`);
237+
} else {
238+
({ data: result } = await github.rest.checks.create({
239+
...context.repo,
240+
name: jobName,
241+
head_sha: ref,
242+
status: 'completed',
243+
conclusion,
244+
external_id: externalId,
245+
output,
246+
}));
247+
console.log(`Created check run: ${conclusion} for "${jobName}" on ${ref}`);
208248
}
209-
const { data: result } = await github.rest.checks.update({
210-
...context.repo,
211-
check_run_id: check[0].id,
212-
status: 'completed',
213-
conclusion: process.env.conclusion
214-
});
215249
return result;

.github/workflows/tests.yml

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ jobs:
2121
environment: test
2222
env:
2323
TEST_SF_TF_TEST_OBJECT_SUFFIX: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.pull_request.head.sha) || (github.event_name == 'pull_request' && github.event.pull_request.head.sha) }}
24+
TEST_SF_TF_TEST_WORKFLOW_ID: "${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.pull_request.head.sha) || (github.event_name == 'pull_request' && github.event.pull_request.head.sha) }}_${{ github.run_attempt }}"
25+
ADDITIONAL_TEST_FLAGS: "-json"
2426
name: Run All
2527
runs-on: ubuntu-latest
2628
if: (github.event_name == 'repository_dispatch') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
@@ -120,13 +122,18 @@ jobs:
120122
chmod 0600 ./config ./config_legacy ./config_v097_compatible_with_service_user
121123
122124
- name: Run unit tests
123-
run: make test-unit
125+
# pipefail needs to be set to ensure that the exit code of make test command is captured even when piped (otherwise it would take the exit code of make save-test-results)
126+
run: set -o pipefail && make test-unit | make save-test-results
124127
if: ${{ !cancelled() && steps.create_config.conclusion == 'success' }}
128+
env:
129+
TEST_SF_TF_TEST_TYPE: "unit"
125130

126131
- name: Run integration tests
127-
run: make test-integration
132+
# pipefail needs to be set to ensure that the exit code of make test command is captured even when piped (otherwise it would take the exit code of make save-test-results)
133+
run: set -o pipefail && make test-integration | make save-test-results
128134
if: ${{ !cancelled() && steps.create_config.conclusion == 'success' }}
129135
env:
136+
TEST_SF_TF_TEST_TYPE: "integration"
130137
SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT: ${{ secrets.SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT }}
131138
TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL }}
132139
TEST_SF_TF_AWS_EXTERNAL_KEY_ID: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_KEY_ID }}
@@ -146,13 +153,18 @@ jobs:
146153
terraform_wrapper: false
147154

148155
- name: Run functional tests of the underlying terraform libraries
149-
run: make test-functional
156+
# pipefail needs to be set to ensure that the exit code of make test command is captured even when piped (otherwise it would take the exit code of make save-test-results)
157+
run: set -o pipefail && make test-functional | make save-test-results
150158
if: ${{ !cancelled() && steps.setup_terraform.conclusion == 'success' }}
159+
env:
160+
TEST_SF_TF_TEST_TYPE: "functional"
151161

152162
- name: Run acceptance tests
153-
run: make test-acceptance
163+
# pipefail needs to be set to ensure that the exit code of make test command is captured even when piped (otherwise it would take the exit code of make save-test-results)
164+
run: set -o pipefail && make test-acceptance | make save-test-results
154165
if: ${{ !cancelled() && steps.setup_terraform.conclusion == 'success' }}
155166
env:
167+
TEST_SF_TF_TEST_TYPE: "acceptance"
156168
SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT: ${{ secrets.SNOWFLAKE_BUSINESS_CRITICAL_ACCOUNT }}
157169
TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_BUCKET_URL }}
158170
TEST_SF_TF_AWS_EXTERNAL_KEY_ID: ${{ secrets.TEST_SF_TF_AWS_EXTERNAL_KEY_ID }}
@@ -179,19 +191,16 @@ jobs:
179191
Integration tests ${{ job.status }} for [${{ github.event.client_payload.slash_command.args.named.sha || github.event.pull_request.head.sha }}](https://github.com/snowflakedb/terraform-provider-snowflake/actions/runs/${{ github.run_id }})
180192
181193
# For fork PRs, tests run via repository_dispatch (triggered by /ok-to-test),
182-
# but the resulting check runs are tied to the default branch, not the fork PR.
183-
# This step updates the (skipped) check run on the fork PR's head SHA so the
184-
# PR status reflects the actual test outcome. It resolves the job's display name
185-
# via job.check_run_id (since github.job returns the job_id, not the display name)
186-
# and uses it to find the matching check run on the fork PR's commit.
194+
# but the job check runs are tied to the default branch, not the fork PR SHA.
195+
# This step mirrors the job result onto the fork PR head SHA using a dedicated
196+
# synthetic check run that we own, reusing it across reruns to avoid duplicates.
187197
- name: Set fork job status
188198
uses: actions/github-script@v6
189199
if: ${{ always() }}
190200
id: update_check_run
191201
env:
192-
number: ${{ github.event.client_payload.pull_request.number }}
202+
pr_number: ${{ github.event.client_payload.pull_request.number }}
193203
check_run_id: ${{ job.check_run_id }}
194-
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
195204
conclusion: ${{ job.status }}
196205
sha: ${{ github.event.client_payload.slash_command.args.named.sha }}
197206
event_name: ${{ github.event_name }}
@@ -209,20 +218,52 @@ jobs:
209218
const jobName = currentCheck.name;
210219
console.log(`Current job check run name: ${jobName}`);
211220
const ref = process.env.sha;
212-
const { data: checks } = await github.rest.checks.listForRef({
221+
const conclusion = process.env.conclusion;
222+
const externalId = `fork-pr-${process.env.pr_number}-${jobName}`;
223+
const output = {
224+
title: `Tests ${conclusion}`,
225+
summary: `Integration tests ${conclusion}. See the [workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`
226+
};
227+
228+
const { data: existingRuns } = await github.rest.checks.listForRef({
213229
...context.repo,
214-
ref
230+
ref,
231+
check_name: jobName,
215232
});
216-
const check = checks.check_runs.filter(c => c.name === jobName);
217-
console.log(check);
218-
if (check.length === 0) {
219-
console.log(`No matching check run found for "${jobName}" on ${ref}`);
220-
return;
233+
234+
const existingRun = existingRuns.check_runs
235+
.filter((run) =>
236+
run.head_sha === ref &&
237+
run.name === jobName &&
238+
run.external_id === externalId
239+
)
240+
.sort((left, right) => {
241+
const leftDate = Math.max(new Date(left.started_at || 0).getTime(), new Date(left.completed_at || 0).getTime());
242+
const rightDate = Math.max(new Date(right.started_at || 0).getTime(), new Date(right.completed_at || 0).getTime());
243+
return rightDate - leftDate;
244+
})[0];
245+
246+
let result;
247+
if (existingRun) {
248+
({ data: result } = await github.rest.checks.update({
249+
...context.repo,
250+
check_run_id: existingRun.id,
251+
status: 'completed',
252+
conclusion,
253+
external_id: externalId,
254+
output,
255+
}));
256+
console.log(`Updated check run ${existingRun.id}: ${conclusion} for "${jobName}" on ${ref}`);
257+
} else {
258+
({ data: result } = await github.rest.checks.create({
259+
...context.repo,
260+
name: jobName,
261+
head_sha: ref,
262+
status: 'completed',
263+
conclusion,
264+
external_id: externalId,
265+
output,
266+
}));
267+
console.log(`Created check run: ${conclusion} for "${jobName}" on ${ref}`);
221268
}
222-
const { data: result } = await github.rest.checks.update({
223-
...context.repo,
224-
check_run_id: check[0].id,
225-
status: 'completed',
226-
conclusion: process.env.conclusion
227-
});
228269
return result;

CONTRIBUTING.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Both integration and acceptance tests require the connection to Snowflake (some
4848

4949
The preferred way of running particular tests locally is to create a config file `~/.snowflake/config`, with the following content.
5050

51-
```sh
51+
```toml
5252
[default]
5353
account_name = "<your account name>"
5454
organization_name = "<organization in which your account is located>"
@@ -60,7 +60,7 @@ host="<host of your account, e.g. organisation-account_name.snowflakecomputing.c
6060

6161
To be able to run all the tests you additionally need the second profile `[secondary_test_account]`:
6262

63-
```sh
63+
```toml
6464
[secondary_test_account]
6565
account_name = "<your account name>"
6666
organization_name = "<organization in which your account is located>"
@@ -70,6 +70,18 @@ role = "<your role on the secondary account>"
7070
host="<host of your account, e.g. organisation-account_name2.snowflakecomputing.com>"
7171
```
7272

73+
Some tests also require an Azure account profile `[azure_test_account]`. This is only used in non-prod environments for tests that require multiple Snowflake instances on different cloud providers (e.g. cross-cloud connection failover tests):
74+
75+
```toml
76+
[azure_test_account]
77+
account_name = "<your Azure account name>"
78+
organization_name = "<organization in which your Azure account is located>"
79+
user = "<your user on the Azure account>"
80+
password = "<your password on the Azure account>"
81+
role = "<your role on the Azure account>"
82+
host="<host of your Azure account, e.g. organisation-azure_account_name.snowflakecomputing.com>"
83+
```
84+
7385
**TIP**: check [how-can-i-get-my-organization-name](https://registry.terraform.io/providers/snowflakedb/snowflake/latest/docs/guides/authentication_methods#how-can-i-get-my-organization-name) and [how-can-i-get-my-account-name](https://registry.terraform.io/providers/snowflakedb/snowflake/latest/docs/guides/authentication_methods#how-can-i-get-my-account-name) sections in our guides if you have troubles setting the proper `organization_name` and `account_name`.
7486

7587
We are aware that not everyone has access to two different accounts, so the majority of tests can be run using just one account. The tests setup however, requires both profiles (`default` and `secondary_test_account`) to be present. You can use the same details for `secondary_test_account` as in the `default` one, if you don't plan to run tests requiring multiple accounts. The warning will be logged when setting up tests with just a single account.
@@ -133,7 +145,7 @@ To add the experiment:
133145
- Add it to [`allExperiments`](pkg/provider/experimentalfeatures/experimental_features.go).
134146
- Guard the logic with conditional statement like (example in the [user resource](pkg/resources/user.go)):
135147
```go
136-
if experimentalfeatures.IsExperimentEnabled(experimentalfeatures.UserEnableDefaultWorkloadIdentity, providerCtx.EnabledExperiments) {
148+
if experimentalfeatures.IsExperimentEnabled(experimentalfeatures.UserEnableDefaultWorkloadIdentity, providerCtx.EnabledExperiments) {
137149
// new logic here
138150
} else {
139151
// old logic here

0 commit comments

Comments
 (0)