-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(acctest): incremental run support
- Loading branch information
1 parent
80df024
commit 5f79ee2
Showing
1 changed file
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
name: Incremental Acceptance Tests | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
- v* | ||
types: | ||
- opened | ||
- synchronize | ||
- reopened | ||
- labeled | ||
- unlabeled | ||
push: | ||
branches: | ||
- main | ||
- v* | ||
workflow_dispatch: {} | ||
|
||
permissions: read-all | ||
|
||
concurrency: | ||
group: ci-${{ github.head_ref || github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
selproj: | ||
name: Run selproj | ||
runs-on: ubuntu-latest | ||
if: > | ||
(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || | ||
github.event_name == 'push' | ||
outputs: | ||
suffix: ${{ steps.selproj.outputs.suffix }} | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- id: selproj | ||
run: echo "suffix=$(make -s ci-selproj | tr -d '\n')" >> $GITHUB_OUTPUT | ||
env: | ||
AIVEN_TOKEN: ${{ secrets.AIVEN_TOKEN }} | ||
AIVEN_PROJECT_NAME_PREFIX: ${{ secrets.AIVEN_PROJECT_NAME_PREFIX }} | ||
|
||
parse_sdkv2_files: | ||
name: Parse SDKv2 resource and datasource files | ||
runs-on: ubuntu-latest | ||
if: > | ||
(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || | ||
github.event_name == 'push' | ||
env: | ||
SDKV2_IMPL_PATH: internal/sdkprovider | ||
|
||
outputs: | ||
files: ${{ steps.parse_files.outputs.files }} | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Find provider.go file | ||
id: find_provider_go_file | ||
run: | | ||
echo "path=$(find "$SDKV2_IMPL_PATH" -type f -name 'provider.go')" >> $GITHUB_OUTPUT | ||
- name: Extract imports | ||
id: extract_imports | ||
run: | | ||
provider_go_file=${{ steps.find_provider_go_file.outputs.path }} | ||
imports=$(awk '/^import \(/{flag=1;next}/^\)/{flag=0}flag' "$provider_go_file") | ||
imports=$(echo "$imports" | jq -R -s -c 'split("\n") | map(select(length > 0) | gsub("[[:space:]\"]";""))') | ||
echo "imports=$imports" >> $GITHUB_OUTPUT | ||
- name: Build import map | ||
id: build_import_map | ||
run: | | ||
import_lines=$(echo '${{ steps.extract_imports.outputs.imports }}' | jq -r '.[]') | ||
import_map="{}" | ||
while IFS= read -r line; do | ||
if [[ $line =~ ^(.*)"$SDKV2_IMPL_PATH"/(.*)$ ]]; then | ||
package_path="${BASH_REMATCH[2]}" | ||
package_name=$(basename "$package_path") | ||
echo "Found package $package_name in $SDKV2_IMPL_PATH/$package_path" | ||
import_map=$( | ||
echo "$import_map" | jq -c --arg key "$package_name" --arg value "$package_path" \ | ||
'. + {($key): $value}' | ||
) | ||
fi | ||
done <<< "$import_lines" | ||
echo "import_map=$import_map" >> $GITHUB_OUTPUT | ||
- name: Parse files | ||
id: parse_files | ||
run: | | ||
provider_go_file=${{ steps.find_provider_go_file.outputs.path }} | ||
import_map='${{ steps.build_import_map.outputs.import_map }}' | ||
files="[]" | ||
while read -r name type func_with_parentheses; do | ||
if [[ -z "$name" || -z "$func_with_parentheses" ]]; then | ||
continue | ||
fi | ||
func="${func_with_parentheses%)*}" | ||
func="${func##*.}" | ||
package_name="${func_with_parentheses%%.*}" | ||
path=$(echo $import_map | jq -r --arg package_name "$package_name" '.[$package_name] // empty') | ||
if [[ -n "$path" ]]; then | ||
path="$SDKV2_IMPL_PATH/$path" | ||
file=$(find "$path" -type f -name '*.go' -exec grep -l "$func" {} +) | ||
if [[ -n "$file" ]]; then | ||
echo "Found $type $name in $file" | ||
files=$( | ||
echo "$files" | jq -c --arg name "$name" --arg type "$type" --arg file "$file" \ | ||
'. + [{($name): {("type"): $type, ("file"): $file}}]' | ||
) | ||
fi | ||
fi | ||
done < <(awk -v file="$provider_go_file" ' | ||
/ResourcesMap: map\[string\]\*schema\.Resource{/ { type="resource"; capture = 1; next } | ||
/DataSourcesMap: map\[string\]\*schema\.Resource{/ { type="datasource"; capture = 1; next } | ||
capture && /\}/ { capture = 0 } | ||
capture && NF { | ||
gsub(/[\t "]+/, "") | ||
split($0, a, ":") | ||
print a[1], type, a[2] | ||
} | ||
' "$provider_go_file") | ||
echo "files=$files" >> $GITHUB_OUTPUT | ||
parse_plugin_framework_files: | ||
name: Parse Plugin Framework resource and datasource files | ||
runs-on: ubuntu-latest | ||
if: > | ||
(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || | ||
github.event_name == 'push' | ||
env: | ||
PLUGIN_FRAMEWORK_IMPL_PATH: internal/plugin | ||
|
||
outputs: | ||
files: ${{ steps.parse_files.outputs.files }} | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Parse files | ||
id: parse_files | ||
run: | | ||
files="[]" | ||
while IFS= read -r file; do | ||
while IFS=, read -r name type file; do | ||
echo "Found $type $name in $file" | ||
files=$( | ||
echo "$files" | jq -c --arg name "$name" --arg type "$type" --arg file "$file" \ | ||
'. + [{($name): {("type"): $type, ("file"): $file}}]' | ||
) | ||
done < <(awk -v file="$file" ' | ||
/resp\.TypeName\s*=\s*req\.ProviderTypeName\s*\+\s*"/ { | ||
match($0, /"(_[^"]+)"/, arr) | ||
if (length(arr[1]) > 0) { | ||
type = "datasource" | ||
while((getline line < file) > 0) { | ||
if (line ~ /_ resource\.Resource/) { | ||
type = "resource" | ||
break | ||
} | ||
} | ||
close(file) | ||
print "aiven" arr[1] "," type "," file | ||
} | ||
} | ||
' "$file") | ||
done < <(find "$PLUGIN_FRAMEWORK_IMPL_PATH" -type f -name '*.go') | ||
echo "files=$files" >> $GITHUB_OUTPUT | ||
combine_parsed_files: | ||
name: Combine parsed files | ||
runs-on: ubuntu-latest | ||
|
||
needs: | ||
- parse_sdkv2_files | ||
- parse_plugin_framework_files | ||
|
||
outputs: | ||
files: ${{ steps.combine_parsed_files.outputs.files }} | ||
|
||
steps: | ||
- name: Combine parsed files | ||
id: combine_parsed_files | ||
run: | | ||
files='[]' | ||
mapfile -t sdkv2_files < <(echo '${{ needs.parse_sdkv2_files.outputs.files }}' | jq -c '.[]') | ||
mapfile -t plugin_framework_files < <(echo '${{ needs.parse_plugin_framework_files.outputs.files }}' | jq -c '.[]') | ||
|
||
add_file_to_files() { | ||
local file_json=$1 | ||
files=$( | ||
jq -c --argjson files "$files" --argjson file_json "$file_json" \ | ||
'$files + [($file_json | to_entries | .[0] | {key: .key, value: .value}) | {(.key): .value}]' <<< "{}" | ||
) | ||
} | ||
|
||
for file_json in "${sdkv2_files[@]}" "${plugin_framework_files[@]}"; do | ||
add_file_to_files "$file_json" | ||
done | ||
|
||
echo "files=$files" >> $GITHUB_OUTPUT | ||
|
||
find_tests: | ||
name: Find tests | ||
runs-on: ubuntu-latest | ||
|
||
needs: | ||
- combine_parsed_files | ||
|
||
outputs: | ||
tests: ${{ steps.find_tests.outputs.tests }} | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: go.mod | ||
|
||
- name: Find tests | ||
id: find_tests | ||
run: | | ||
tests=() | ||
mapfile -t parsed_files < <(echo '${{ needs.combine_parsed_files.outputs.files }}' | jq -c '.[]') | ||
for parsed_file in "${parsed_files[@]}"; do | ||
name=$(echo "$parsed_file" | jq -r 'keys[0]') | ||
type=$(echo "$parsed_file" | jq -r --arg name "$name" '.[$name].type') | ||
file=$(echo "$parsed_file" | jq -r --arg name "$name" '.[$name].file') | ||
dir=$(dirname "$file") | ||
file_changed=false | ||
dep_changed=false | ||
if git diff "origin/${{ github.base_ref || 'main' }}" --name-only | grep -q "^$file$"; then | ||
echo "Definition of $name $type in $file changed" | ||
file_changed=true | ||
else | ||
deps=$( | ||
go list -json "./$dir" | jq -r '.Deps[]' | grep -oP '^github.com/aiven/terraform-provider-aiven/\K.*' | ||
) | ||
for dep in $deps; do | ||
if git diff "origin/${{ github.base_ref || 'main' }}" --name-only | grep -q "$dep"; then | ||
echo "Dependency $dep of $name $type changed" | ||
dep_changed=true | ||
break | ||
fi | ||
done | ||
fi | ||
if [ "$file_changed" = true ] || [ "$dep_changed" = true ]; then | ||
pattern="" | ||
[[ "$type" == "resource" ]] && pattern="resource \"$name\"" | ||
[[ "$type" == "datasource" ]] && pattern="data \"$name\"" | ||
while IFS= read -r test; do | ||
if grep -q "$pattern" "$test"; then | ||
echo "Found test for $name $type in $test" | ||
tests+=("$test") | ||
fi | ||
done < <(find internal -type f -name '*_test.go' -exec grep -l "$pattern" {} +) | ||
fi | ||
done | ||
readarray -t unique_tests < <(printf '%s\n' "${tests[@]}" | awk '!seen[$0]++') | ||
tests_json=$(printf '%s\n' "${unique_tests[@]}" | jq -R . | jq -s -c .) | ||
echo "tests=$tests_json" >> $GITHUB_OUTPUT | ||
run_tests: | ||
name: Run tests | ||
runs-on: ubuntu-latest | ||
|
||
needs: | ||
- selproj | ||
- find_tests | ||
|
||
env: | ||
COUNT: 1 | ||
PARALLEL: 10 | ||
TIMEOUT: 180m | ||
|
||
strategy: | ||
max-parallel: 5 | ||
matrix: | ||
test: ${{ fromJson(needs.find_tests.outputs.tests) }} | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: go.mod | ||
|
||
- name: Run tests | ||
run: go test ${{ matrix.test }} -v -count $COUNT -parallel $PARALLEL -timeout $TIMEOUT | ||
env: | ||
TF_ACC: 1 | ||
CGO_ENABLED: 0 | ||
AIVEN_TOKEN: ${{ secrets.AIVEN_TOKEN }} | ||
AIVEN_PROJECT_NAME: ${{ secrets.AIVEN_PROJECT_NAME_PREFIX }}${{ needs.selproj.outputs.suffix }} | ||
AIVEN_ORGANIZATION_NAME: ${{ secrets.AIVEN_ORGANIZATION_NAME }} | ||
AIVEN_ACCOUNT_NAME: ${{ secrets.AIVEN_ORGANIZATION_NAME }} |