Skip to content

ci(tests): Avoid the use of pull_request_target where possible #9899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2024
Merged
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
137 changes: 35 additions & 102 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
# This file is used to run the runtime tests for the Arduino core for ESP32.
# The tests are run on the hardware, Wokwi and QEMU emulators.
# The QEMU tests are disabled for now as they are redundant with most of the Wokwi tests.
# As the Wokwi tests require access to secrets, they are run in a separate workflow.
# We need to ensure that the artifacts from previous tests in the chain are propagated for publishing the results.
# This is the current trigger sequence for the tests:
# tests.yml -> tests_wokwi.yml -> tests_results.yml
# ⌙> tests_build.yml
# ⌙> tests_hw.yml
# ⌙> tests_qemu.yml

name: Runtime Tests

on:
workflow_dispatch:
pull_request_target:
pull_request:
types: [opened, reopened, closed, synchronize, labeled, unlabeled]
paths:
- '.github/workflows/tests*'
- '.github/scripts/*.sh'
- '!.github/scripts/check-cmakelists.sh'
- '!.github/scripts/find_*'
- '!.github/scripts/on-*.sh'
- '!.github/scripts/set_push_chunks.sh'
- '!.github/scripts/update-version.sh'
- '!.github/scripts/upload_py_tools.sh'
- 'tests/**'
- 'cores/**'
- 'libraries/**'
@@ -19,14 +38,19 @@ concurrency:
group: tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

# To avoid giving elevated permissions to the entire workflow, specify default permissions at the top level
# and then override them for specific jobs.
permissions: { contents: read }

jobs:
push-event-file:
name: Push event file
runs-on: ubuntu-latest
steps:
- name: Upload
uses: actions/upload-artifact@v4
with:
name: event_file
path: ${{ github.event_path }}

gen-matrix:
name: Generate matrix
if: github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
build-types: ${{ steps.set-matrix.outputs.build-types }}
@@ -59,9 +83,8 @@ jobs:

call-build-tests:
name: Build
uses: espressif/arduino-esp32/.github/workflows/build_tests.yml@master
uses: ./.github/workflows/tests_build.yml
needs: gen-matrix
if: github.event.action != 'closed'
strategy:
matrix:
type: ${{ fromJson(needs.gen-matrix.outputs.build-types) }}
@@ -72,11 +95,11 @@ jobs:

call-hardware-tests:
name: Hardware
uses: espressif/arduino-esp32/.github/workflows/hw.yml@master
uses: ./.github/workflows/tests_hw.yml
needs: [gen-matrix, call-build-tests]
if: |
github.repository == 'espressif/arduino-esp32' &&
(github.event_name != 'pull_request_target' ||
(github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'hil_test'))
strategy:
fail-fast: false
@@ -87,26 +110,10 @@ jobs:
type: ${{ matrix.type }}
chip: ${{ matrix.chip }}

call-wokwi-tests:
name: Wokwi
uses: espressif/arduino-esp32/.github/workflows/wokwi.yml@master
needs: [gen-matrix, call-build-tests]
if: github.event.action != 'closed'
strategy:
fail-fast: false
matrix:
type: ${{ fromJson(needs.gen-matrix.outputs.wokwi-types) }}
chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2']
secrets:
WOKWI_CLI_TOKEN: ${{ secrets.WOKWI_CLI_TOKEN }}
with:
type: ${{ matrix.type }}
chip: ${{ matrix.chip }}

# This job is disabled for now
call-qemu-tests:
name: QEMU
uses: espressif/arduino-esp32/.github/workflows/qemu.yml@master
uses: ./.github/workflows/tests_qemu.yml
needs: [gen-matrix, call-build-tests]
if: false
strategy:
@@ -118,78 +125,4 @@ jobs:
type: ${{ matrix.type }}
chip: ${{ matrix.chip }}

unit-test-results:
name: Unit Test Results
needs: [call-hardware-tests, call-wokwi-tests, call-qemu-tests]
if: always() && github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
steps:
- name: Download and Extract HW Artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
merge-multiple: true
pattern: tests-results-hw-*
path: ./results/hw

- name: Download and Extract Wokwi Artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
merge-multiple: true
pattern: tests-results-wokwi-*
path: ./results/wokwi

- name: Download and Extract QEMU Artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
merge-multiple: true
pattern: tests-results-qemu-*
path: ./results/qemu

- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
commit: ${{ github.event.pull_request.head.sha || github.sha }}
files: ./results/**/*.xml
clean:
name: Clean objects
needs: unit-test-results
if: always()
permissions:
actions: write
runs-on: ubuntu-latest
steps:
- name: Clean up caches
uses: actions/github-script@v7
with:
script: |
const ref = '${{ github.event.pull_request.number || github.ref }}';
const key_prefix = 'tests-' + ref + '-';

if ('${{ github.event_name }}' == 'pull_request_target' && '${{ github.event.action }}' != 'closed') {
console.log('Skipping cache cleanup for open PR');
return;
}

await github.paginate(github.rest.actions.getActionsCacheList, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
key: key_prefix
}).then(caches => {
if (caches) {
for (const cache of caches) {
console.log(`Deleting cache: ${cache.key}`);
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id
});
}
}
});
# Wokwi tests are run after this workflow as it needs access to secrets
Original file line number Diff line number Diff line change
@@ -20,8 +20,8 @@ jobs:
id: ${{ github.event.pull_request.number || github.ref }}-${{ github.event.pull_request.head.sha || github.sha }}-${{ inputs.chip }}-${{ inputs.type }}
steps:
- name: Check if already built
if: ${{ github.event.pull_request.number != null }}
id: cache-build-binaries
if: github.event.pull_request.number != null
uses: actions/cache/restore@v4
with:
key: tests-${{ env.id }}-bin
@@ -46,21 +46,6 @@ jobs:
- name: Checkout user repository
if: ${{ steps.check-build.outputs.enabled == 'true' }}
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
sparse-checkout-cone-mode: false
sparse-checkout: |
/*
!.github

# To avoid giving unknown scripts elevated permissions, download them from the master branch
- name: Get CI scripts from master
if: ${{ steps.check-build.outputs.enabled == 'true' }}
run: |
mkdir -p .github
cd .github
curl https://codeload.github.com/${{ github.repository }}/tar.gz/master | tar -xz --strip=2 arduino-esp32-master/.github

- name: Get libs cache
uses: actions/cache@v4
@@ -83,7 +68,7 @@ jobs:

- name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as cache
uses: actions/cache/save@v4
if: ${{ steps.check-build.outputs.enabled == 'true' }}
if: steps.check-build.outputs.enabled == 'true' && github.event.pull_request.number != null
with:
key: tests-${{ env.id }}-bin
path: |
21 changes: 3 additions & 18 deletions .github/workflows/hw.yml → .github/workflows/tests_hw.yml
Original file line number Diff line number Diff line change
@@ -22,9 +22,9 @@ jobs:
image: python:3.10.1-bullseye
options: --privileged
steps:
- name: Check if already built
if: ${{ github.event.pull_request.number != null }}
- name: Check if already passed
id: cache-results
if: github.event.pull_request.number != null
uses: actions/cache/restore@v4
with:
key: tests-${{ env.id }}-results-hw
@@ -48,21 +48,6 @@ jobs:
- name: Checkout user repository
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
sparse-checkout-cone-mode: false
sparse-checkout: |
/*
!.github

# To avoid giving unknown scripts elevated permissions, download them from the master branch
- name: Get CI scripts from master
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
run: |
mkdir -p .github
cd .github
curl https://codeload.github.com/${{ github.repository }}/tar.gz/master | tar -xz --strip=2 arduino-esp32-master/.github

# setup-python currently only works on ubuntu images
# - uses: actions/setup-python@v5
@@ -95,7 +80,7 @@ jobs:

- name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as cache
uses: actions/cache/save@v4
if: ${{ always() && steps.check-tests.outputs.enabled == 'true' }}
if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null
with:
key: tests-${{ env.id }}-results-hw
path: |
Original file line number Diff line number Diff line change
@@ -18,9 +18,9 @@ jobs:
QEMU_INSTALL_PATH: "$HOME"
runs-on: ubuntu-latest
steps:
- name: Check if already run
if: ${{ github.event.pull_request.number != null }}
- name: Check if already passed
id: get-cache-results
if: github.event.pull_request.number != null
uses: actions/cache/restore@v4
with:
key: tests-${{ env.id }}-results-qemu
@@ -97,7 +97,7 @@ jobs:
with:
path: |
~/qemu
key: qemu-${{ steps.get-qemu-version.outputs.release }}-${{ hashFiles('.github/workflows/qemu.yml') }}
key: qemu-${{ steps.get-qemu-version.outputs.release }}-${{ hashFiles('.github/workflows/tests_qemu.yml') }}

- name: Download QEMU
if: ${{ steps.cache-qemu.outputs.cache-hit != 'true' && steps.check-tests.outputs.enabled == 'true' }}
@@ -125,7 +125,7 @@ jobs:

- name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as cache
uses: actions/cache/save@v4
if: ${{ always() && steps.check-tests.outputs.enabled == 'true' }}
if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null
with:
key: tests-${{ env.id }}-results-qemu
path: |
107 changes: 107 additions & 0 deletions .github/workflows/tests_results.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Publish and clean test results

on:
workflow_run:
workflows: ["Wokwi tests"]
types:
- completed

# No permissions by default
permissions: { contents: read }

jobs:
unit-test-results:
name: Unit Test Results
if: |
github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure' ||
github.event.workflow_run.conclusion == 'timed_out'
runs-on: ubuntu-latest
permissions:
actions: write
statuses: write
checks: write
pull-requests: write
steps:
- name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@v6
with:
run_id: ${{ github.event.workflow_run.id }}
path: ./artifacts

- name: Get original info
run: |
original_event=$(cat ./artifacts/parent-artifacts/event.txt)
original_action=$(cat ./artifacts/parent-artifacts/action.txt)
original_sha=$(cat ./artifacts/parent-artifacts/sha.txt)
original_ref=$(cat ./artifacts/parent-artifacts/ref.txt)
echo "original_event=$original_event" >> $GITHUB_ENV
echo "original_action=$original_action" >> $GITHUB_ENV
echo "original_sha=$original_sha" >> $GITHUB_ENV
echo "original_ref=$original_ref" >> $GITHUB_ENV
echo "original_event = $original_event"
echo "original_action = $original_action"
echo "original_sha = $original_sha"
echo "original_ref = $original_ref"
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
commit: ${{ env.original_sha }}
event_file: ./artifacts/parent-artifacts/event_file/event.json
event_name: ${{ env.original_event }}
files: ./artifacts/**/*.xml
action_fail: true

- name: Clean up caches
uses: actions/github-script@v7
with:
script: |
const ref = '${{ env.original_ref }}';
const key_prefix = 'tests-' + ref + '-';
if ('${{ env.original_event }}' == 'pull_request' && '${{ env.original_action }}' != 'closed') {
console.log('Skipping cache cleanup for open PR');
return;
}
await github.paginate(github.rest.actions.getActionsCacheList, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
key: key_prefix
}).then(caches => {
if (caches) {
for (const cache of caches) {
console.log(`Deleting cache: ${cache.key}`);
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id
});
}
}
});
- name: Report conclusion
uses: actions/github-script@v7
if: always()
with:
script: |
const owner = '${{ github.repository_owner }}';
const repo = '${{ github.repository }}'.split('/')[1];
const sha = '${{ env.original_sha }}';
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`sha: ${sha}`);
const { context: name, state } = (await github.rest.repos.createCommitStatus({
context: 'Runtime Tests / Report results (${{ env.original_event }} -> workflow_run -> workflow_run)',
owner: owner,
repo: repo,
sha: sha,
state: '${{ job.status }}',
description: '${{ job.status }}' ? 'Runtime tests successful' : 'Runtime tests failed',
target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})).data;
core.info(`${name} is ${state}`);
289 changes: 289 additions & 0 deletions .github/workflows/tests_wokwi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
name: Wokwi tests

on:
workflow_run:
workflows: ["Runtime Tests"]
types:
- completed

# No permissions by default
permissions: { contents: read }

env:
WOKWI_TIMEOUT: 600000 # Milliseconds

jobs:
get-artifacts:
name: Get required artifacts
runs-on: ubuntu-latest
permissions:
actions: read
statuses: write
outputs:
pr_num: ${{ steps.set-ref.outputs.pr_num }}
ref: ${{ steps.set-ref.outputs.ref }}
steps:
- name: Report pending
uses: actions/github-script@v7
with:
script: |
const owner = '${{ github.repository_owner }}';
const repo = '${{ github.repository }}'.split('/')[1];
const sha = '${{ github.event.workflow_run.head_sha }}';
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`sha: ${sha}`);
const { context: name, state } = (await github.rest.repos.createCommitStatus({
context: 'Runtime Tests / Wokwi (Get artifacts) (${{ github.event.workflow_run.event }} -> workflow_run)',
owner: owner,
repo: repo,
sha: sha,
state: 'pending',
target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})).data;
core.info(`${name} is ${state}`);
- name: Download and extract event file
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: event_file
path: artifacts/event_file

- name: Try to read PR number
id: set-ref
run: |
pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)
if [ -z "$pr_num" ] || [ "$pr_num" == "null" ]; then
pr_num=""
fi
ref=$pr_num
if [ -z "$ref" ] || [ "$ref" == "null" ]; then
ref=${{ github.ref }}
fi
action=$(jq -r '.action' artifacts/event_file/event.json)
if [ "$action" == "null" ]; then
action=""
fi
echo "pr_num = $pr_num"
printf "$ref" >> artifacts/ref.txt
printf "Ref = "
cat artifacts/ref.txt
printf "${{ github.event.workflow_run.event }}" >> artifacts/event.txt
printf "\nEvent name = "
cat artifacts/event.txt
printf "${{ github.event.workflow_run.head_sha || github.sha }}" >> artifacts/sha.txt
printf "\nHead SHA = "
cat artifacts/sha.txt
printf "$action" >> artifacts/action.txt
printf "\nAction = "
cat artifacts/action.txt
if [ -z "$ref" ] || [ "$ref" == "null" ]; then
echo "Failed to get PR number or ref"
exit 1
fi
echo "pr_num=$pr_num" >> $GITHUB_OUTPUT
echo "ref=$ref" >> $GITHUB_OUTPUT
- name: Download and extract parent hardware results
uses: actions/download-artifact@v4
continue-on-error: true
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
pattern: tests-results-hw-*
merge-multiple: true
path: artifacts/results/hw

- name: Download and extract parent QEMU results
uses: actions/download-artifact@v4
continue-on-error: true
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
pattern: tests-results-qemu-*
merge-multiple: true
path: artifacts/results/qemu

- name: Upload parent artifacts
uses: actions/upload-artifact@v4
with:
name: parent-artifacts
path: artifacts
if-no-files-found: error

- name: Report conclusion
uses: actions/github-script@v7
if: always()
with:
script: |
const owner = '${{ github.repository_owner }}';
const repo = '${{ github.repository }}'.split('/')[1];
const sha = '${{ github.event.workflow_run.head_sha }}';
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`sha: ${sha}`);
const { context: name, state } = (await github.rest.repos.createCommitStatus({
context: 'Runtime Tests / Wokwi (Get artifacts) (${{ github.event.workflow_run.event }} -> workflow_run)',
owner: owner,
repo: repo,
sha: sha,
state: '${{ job.status }}',
target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})).data;
core.info(`${name} is ${state}`);
wokwi-test:
name: Wokwi ${{ matrix.chip }} ${{ matrix.type }} tests
if: |
github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure' ||
github.event.workflow_run.conclusion == 'timed_out'
runs-on: ubuntu-latest
needs: get-artifacts
env:
id: ${{ needs.get-artifacts.outputs.ref }}-${{ github.event.workflow_run.head_sha || github.sha }}-${{ matrix.chip }}-${{ matrix.type }}
permissions:
actions: read
statuses: write
strategy:
fail-fast: false
matrix:
type: ['validation']
chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2']
steps:
- name: Report pending
uses: actions/github-script@v7
with:
script: |
const owner = '${{ github.repository_owner }}';
const repo = '${{ github.repository }}'.split('/')[1];
const sha = '${{ github.event.workflow_run.head_sha }}';
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`sha: ${sha}`);
const { context: name, state } = (await github.rest.repos.createCommitStatus({
context: 'Runtime Tests / Wokwi (${{ matrix.type }}, ${{ matrix.chip }}) / Wokwi ${{ matrix.chip }} ${{ matrix.type }} tests (${{ github.event.workflow_run.event }} -> workflow_run)',
owner: owner,
repo: repo,
sha: sha,
state: 'pending',
target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})).data;
core.info(`${name} is ${state}`);
- name: Check if already passed
id: get-cache-results
if: needs.get-artifacts.outputs.pr_num
uses: actions/cache/restore@v4
with:
key: tests-${{ env.id }}-results-wokwi
path: |
tests/**/*.xml
tests/**/result_*.json
- name: Evaluate if tests should be run
id: check-tests
run: |
cache_exists=${{ steps.get-cache-results.outputs.cache-hit == 'true' }}
enabled=true
if [[ $cache_exists == 'true' ]]; then
echo "Already ran, skipping"
enabled=false
fi
echo "enabled=$enabled" >> $GITHUB_OUTPUT
# Note that changes to the workflows and tests will only be picked up after the PR is merged
- name: Checkout repository
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/checkout@v4

- uses: actions/setup-python@v5
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
with:
cache-dependency-path: tests/requirements.txt
cache: 'pip'
python-version: '3.x'

- name: Install dependencies
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
run: |
pip install -U pip
pip install -r tests/requirements.txt --extra-index-url https://dl.espressif.com/pypi
- name: Install Wokwi CLI
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
run: curl -L https://wokwi.com/ci/install.sh | sh

- name: Wokwi CI Server
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: wokwi/wokwi-ci-server-action@v1

- name: Get binaries
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: tests-bin-${{ matrix.chip }}-${{ matrix.type }}
path: |
~/.arduino/tests
- name: Run Tests
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
env:
WOKWI_CLI_TOKEN: ${{ secrets.WOKWI_CLI_TOKEN }}
run: |
bash .github/scripts/tests_run.sh -c -type ${{ matrix.type }} -t ${{ matrix.chip }} -i 0 -m 1 -W ${{ env.WOKWI_TIMEOUT }}
- name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as cache
uses: actions/cache/save@v4
if: steps.check-tests.outputs.enabled == 'true' && needs.get-artifacts.outputs.pr_num
with:
key: tests-${{ env.id }}-results-wokwi
path: |
tests/**/*.xml
tests/**/result_*.json
- name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: tests-results-wokwi-${{ matrix.chip }}-${{ matrix.type }}
overwrite: true
path: |
tests/**/*.xml
tests/**/result_*.json
- name: Report conclusion
uses: actions/github-script@v7
if: always()
with:
script: |
const owner = '${{ github.repository_owner }}';
const repo = '${{ github.repository }}'.split('/')[1];
const sha = '${{ github.event.workflow_run.head_sha }}';
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`sha: ${sha}`);
const { context: name, state } = (await github.rest.repos.createCommitStatus({
context: 'Runtime Tests / Wokwi (${{ matrix.type }}, ${{ matrix.chip }}) / Wokwi ${{ matrix.chip }} ${{ matrix.type }} tests (${{ github.event.workflow_run.event }} -> workflow_run)',
owner: owner,
repo: repo,
sha: sha,
state: '${{ job.status }}',
target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})).data;
core.info(`${name} is ${state}`);
124 changes: 0 additions & 124 deletions .github/workflows/wokwi.yml

This file was deleted.

Loading