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
name: Integration Tests | |
on: | |
workflow_dispatch: | |
inputs: | |
use_minimal_test_account: | |
description: 'Indicate whether to use a minimal test account with limited resources for testing. Defaults to "false"' | |
required: false | |
default: 'false' | |
test_suite: | |
description: "Specify test suite to run from the 'tests/integration' directory. Examples: 'cli', 'domains', 'events', etc. If not provided, all suites are executed" | |
required: false | |
run_long_tests: | |
description: "Select 'True' to include long-running tests (e.g., database provisioning, server rebuilds). Defaults to 'False'" | |
required: false | |
type: choice | |
options: | |
- "True" | |
- "False" | |
default: "False" | |
sha: | |
description: 'Specify commit hash to test. This value is mandatory to ensure the tests run against a specific commit' | |
required: true | |
default: '' | |
pull_request_number: | |
description: 'Specify pull request number associated with the commit. Optional, but recommended when providing a commit hash (sha)' | |
required: false | |
openapi_spec_url: | |
description: 'Specify URL of the OpenAPI specification file to use for testing. Useful for validating tests against a specific API version or custom specification' | |
required: false | |
default: '' | |
python-version: | |
description: 'Specify the Python version to use for running tests. Leave empty to use the default Python version configured in the environment' | |
required: false | |
run-eol-python-version: | |
description: 'Indicates whether to run tests using an End-of-Life (EOL) Python version. Defaults to "false". Choose "true" to include tests for deprecated Python versions' | |
required: false | |
default: 'false' | |
type: choice | |
options: | |
- 'true' | |
- 'false' | |
push: | |
branches: | |
- main | |
- dev | |
env: | |
DEFAULT_PYTHON_VERSION: "3.10" | |
EOL_PYTHON_VERSION: "3.8" | |
EXIT_STATUS: 0 | |
jobs: | |
integration_tests: | |
name: Run integration tests on Ubuntu | |
runs-on: ubuntu-latest | |
if: github.event_name == 'workflow_dispatch' && inputs.sha != '' || github.event_name == 'push' || github.event_name == 'pull_request' | |
steps: | |
- name: Checkout Repository with SHA | |
if: ${{ inputs.sha != '' }} | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
submodules: 'recursive' | |
ref: ${{ inputs.sha }} | |
- name: Checkout Repository without SHA | |
if: ${{ inputs.sha == '' }} | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
submodules: 'recursive' | |
- name: Get the hash value of the latest commit from the PR branch | |
uses: octokit/[email protected] | |
id: commit-hash | |
if: ${{ inputs.pull_request_number != '' }} | |
with: | |
query: | | |
query PRHeadCommitHash($owner: String!, $repo: String!, $pr_num: Int!) { | |
repository(owner:$owner, name:$repo) { | |
pullRequest(number: $pr_num) { | |
headRef { | |
target { | |
... on Commit { | |
oid | |
} | |
} | |
} | |
} | |
} | |
} | |
owner: ${{ github.event.repository.owner.login }} | |
repo: ${{ github.event.repository.name }} | |
pr_num: ${{ fromJSON(inputs.pull_request_number) }} | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Update system packages | |
run: sudo apt-get update -y | |
- name: Setup Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ inputs.run-eol-python-version == 'true' && env.EOL_PYTHON_VERSION || inputs.python-version || env.DEFAULT_PYTHON_VERSION }} | |
- name: Install Python dependencies and update cert | |
run: | | |
pip install wheel boto3 && \ | |
pip install certifi -U && \ | |
pip install .[obj,dev] | |
- name: Install Package | |
run: make install SPEC="${{ inputs.OPENAPI_SPEC_URL }}" | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set LINODE_CLI_TOKEN | |
run: | | |
echo "LINODE_CLI_TOKEN=${{ secrets[inputs.use_minimal_test_account == 'true' && 'MINIMAL_LINODE_TOKEN' || 'LINODE_TOKEN'] }}" >> $GITHUB_ENV | |
- name: Run the integration test suite | |
run: | | |
timestamp=$(date +'%Y%m%d%H%M') | |
report_filename="${timestamp}_cli_test_report.xml" | |
make test-int TEST_ARGS="-v --junitxml=${report_filename}" TEST_SUITE="obj" RUN_LONG_TESTS="${{ inputs.run_long_tests }}" | |
env: | |
LINODE_CLI_TOKEN: ${{ env.LINODE_CLI_TOKEN }} | |
- name: Upload Test Report as Artifact | |
if: always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-report-file | |
if-no-files-found: ignore | |
path: '*.xml' | |
retention-days: 1 | |
- name: Update PR Check Run | |
uses: actions/github-script@v7 | |
id: update-check-run | |
if: ${{ inputs.pull_request_number != '' && fromJson(steps.commit-hash.outputs.data).repository.pullRequest.headRef.target.oid == inputs.sha }} | |
env: | |
number: ${{ inputs.pull_request_number }} | |
job: ${{ github.job }} | |
conclusion: ${{ job.status }} | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
script: | | |
const { data: pull } = await github.rest.pulls.get({ | |
...context.repo, | |
pull_number: process.env.number | |
}); | |
const ref = pull.head.sha; | |
const { data: checks } = await github.rest.checks.listForRef({ | |
...context.repo, | |
ref | |
}); | |
const check = checks.check_runs.filter(c => c.name === process.env.job); | |
const { data: result } = await github.rest.checks.update({ | |
...context.repo, | |
check_run_id: check[0].id, | |
status: 'completed', | |
conclusion: process.env.conclusion | |
}); | |
return result; | |
apply-calico-rules: | |
runs-on: ubuntu-latest | |
needs: [integration_tests] | |
if: ${{ success() || failure() }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
submodules: 'recursive' | |
- name: Set LINODE_CLI_TOKEN | |
run: | | |
echo "LINODE_CLI_TOKEN=${{ secrets[inputs.use_minimal_test_account == 'true' && 'MINIMAL_LINODE_TOKEN' || 'LINODE_TOKEN'] }}" >> $GITHUB_ENV | |
- name: Download kubectl and calicoctl for LKE clusters | |
run: | | |
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" | |
curl -LO "https://github.com/projectcalico/calico/releases/download/v3.25.0/calicoctl-linux-amd64" | |
chmod +x calicoctl-linux-amd64 kubectl | |
mv calicoctl-linux-amd64 /usr/local/bin/calicoctl | |
mv kubectl /usr/local/bin/kubectl | |
- name: Apply Calico Rules to LKE | |
run: | | |
cd e2e_scripts/cloud_security_scripts/lke_calico_rules/ && ./lke_calico_rules_e2e.sh | |
env: | |
LINODE_TOKEN: ${{ env.LINODE_CLI_TOKEN }} | |
add-fw-to-remaining-instances: | |
runs-on: ubuntu-latest | |
needs: [integration_tests] | |
if: ${{ success() || failure() }} | |
steps: | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.x' | |
- name: Install Linode CLI | |
run: | | |
pip install linode-cli | |
- name: Set LINODE_CLI_TOKEN | |
run: | | |
echo "LINODE_CLI_TOKEN=${{ secrets[inputs.use_minimal_test_account == 'true' && 'MINIMAL_LINODE_TOKEN' || 'LINODE_TOKEN'] }}" >> $GITHUB_ENV | |
- name: Create Firewall and Attach to Instances | |
run: | | |
FIREWALL_ID=$(linode-cli firewalls create --label "e2e-fw-$(date +%s)" --rules.inbound_policy "DROP" --rules.outbound_policy "ACCEPT" --text --format=id --no-headers) | |
echo "Created Firewall with ID: $FIREWALL_ID" | |
for instance_id in $(linode-cli linodes list --format "id" --text --no-header); do | |
echo "Attaching firewall to instance: $instance_id" | |
if linode-cli firewalls device-create "$FIREWALL_ID" --id "$instance_id" --type linode; then | |
echo "Firewall attached to instance $instance_id successfully." | |
else | |
echo "An error occurred while attaching firewall to instance $instance_id. Skipping..." | |
fi | |
done | |
env: | |
LINODE_CLI_TOKEN: ${{ env.LINODE_CLI_TOKEN }} | |
process-upload-report: | |
runs-on: ubuntu-latest | |
needs: [integration_tests] | |
if: always() && github.repository == 'linode/linode-cli' # Run even if integration tests fail and only on main repository | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
submodules: 'recursive' | |
- name: Download test report | |
uses: actions/download-artifact@v4 | |
with: | |
name: test-report-file | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.x' | |
- name: Install Python dependencies | |
run: pip3 install requests wheel boto3==1.35.99 | |
- name: Set release version env | |
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV | |
- name: Add variables and upload test results | |
if: always() | |
run: | | |
filename=$(ls | grep -E '^[0-9]{12}_cli_test_report\.xml$') | |
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/add_gha_info_to_xml.py \ | |
--branch_name "${GITHUB_REF#refs/*/}" \ | |
--gha_run_id "$GITHUB_RUN_ID" \ | |
--gha_run_number "$GITHUB_RUN_NUMBER" \ | |
--xmlfile "${filename}" | |
sync | |
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/xml_to_obj.py "${filename}" | |
env: | |
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }} | |
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }} | |
notify-slack: | |
runs-on: ubuntu-latest | |
needs: [integration_tests] | |
if: ${{ (success() || failure()) && github.repository == 'linode/linode-cli' }} # Run even if integration tests fail and only on main repository | |
steps: | |
- name: Notify Slack | |
uses: slackapi/[email protected] | |
with: | |
method: chat.postMessage | |
token: ${{ secrets.SLACK_BOT_TOKEN }} | |
payload: | | |
channel: ${{ secrets.SLACK_CHANNEL_ID }} | |
blocks: | |
- type: section | |
text: | |
type: mrkdwn | |
text: ":rocket: *${{ github.workflow }} Completed in: ${{ github.repository }}* :white_check_mark:" | |
- type: divider | |
- type: section | |
fields: | |
- type: mrkdwn | |
text: "*Build Result:*\n${{ needs.integration_tests.result == 'success' && ':large_green_circle: Build Passed' || ':red_circle: Build Failed' }}" | |
- type: mrkdwn | |
text: "*Branch:*\n`${{ github.ref_name }}`" | |
- type: section | |
fields: | |
- type: mrkdwn | |
text: "*Commit Hash:*\n<${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}>" | |
- type: mrkdwn | |
text: "*Run URL:*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run Details>" | |
- type: divider | |
- type: context | |
elements: | |
- type: mrkdwn | |
text: "Triggered by: :bust_in_silhouette: `${{ github.actor }}`" |