Skip to content

Build and Test (Unit + E2E) #6259

Build and Test (Unit + E2E)

Build and Test (Unit + E2E) #6259

name: Build and Test (Unit + E2E)
# Trigger the workflow on PRs to the main branch.
# It performs the following checks:
# 1. Calculate the size difference between the webview bundles of the main branch and the PR branch.
# 2. Calculate the size difference between the VSIX files of the main branch and the PR branch.
# 3. Does a check if the PR has properly localized strings.
on:
schedule:
- cron: "0 0 * * *"
push:
branches:
- main
pull_request:
branches:
- main
- "release/**"
workflow_dispatch:
jobs:
build-and-test:
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
actions: read
issues: write
pull-requests: write
steps:
- name: Checkout PR branch
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Check if baseline comparison needed
if: github.event_name == 'pull_request'
run: |
if [[ "${{ github.event.pull_request.base.ref }}" == "main" ]] || [[ "${{ github.event.pull_request.base.ref }}" == release/* ]]; then
echo "should_compare_baseline=true" >> $GITHUB_ENV
else
echo "should_compare_baseline=false" >> $GITHUB_ENV
fi
- name: Download baseline sizes
if: env.should_compare_baseline == 'true'
continue-on-error: true
uses: dawidd6/action-download-artifact@v6
with:
workflow: publish-baseline.yml
branch: ${{ github.event.pull_request.base.ref }}
name: baseline-sizes
path: ./baseline
if_no_artifact_found: warn
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
- name: Setup .NET Core # Required to execute ReportGenerator
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.x
dotnet-quality: "ga"
- name: Install root dependencies
run: |
npm ci
- name: MSSQL - Install dependencies and build
uses: ./.github/actions/build-mssql
- name: SqlProj - Install dependencies and build
uses: ./.github/actions/build-sqlproj
- name: DataWorkspace - Install dependencies and build
uses: ./.github/actions/build-data-workspace
- name: Run lint
run: |
npm run lint
# Calculate sizes and package before testing;
# Testing generates sourcemaps and instrumented code
# that increase size
- name: Package extensions
run: |
npm run package
- name: MSSQL - Upload VSIX files
uses: actions/upload-artifact@v6
with:
name: mssql-vsix
path: ./extensions/mssql/*.vsix
- name: SqlProj - Upload VSIX files
uses: actions/upload-artifact@v6
with:
name: sql-database-projects-vsix
path: ./extensions/sql-database-projects/*.vsix
- name: DataWorkspace - Upload VSIX files
uses: actions/upload-artifact@v4
with:
name: data-workspace-vsix
path: ./extensions/data-workspace/*.vsix
- name: Keymap - Upload VSIX files
uses: actions/upload-artifact@v6
with:
name: keymap-vsix
path: ./extensions/database-management-keymap/*.vsix
- name: Setting up change icons
if: env.should_compare_baseline == 'true'
run: |
echo "better_change_icon=🟢" >> $GITHUB_ENV
echo "worse_change_icon=🔴" >> $GITHUB_ENV
echo "no_change_icon=⚪" >> $GITHUB_ENV
- name: Calculate vsix file sizes
if: env.should_compare_baseline == 'true'
run: |
# Get baseline size from downloaded artifact or default to 0
if [ -f ./baseline/baseline-sizes.json ]; then
target_size=$(jq -r '.mssql.vsix_kb' ./baseline/baseline-sizes.json)
else
echo "⚠️ No baseline found, using 0 for comparison"
target_size=0
fi
pr_vsix=$(find ./extensions/mssql -name "*.vsix")
pr_size=$(stat -c%s "$pr_vsix")
pr_size=$((pr_size / 1024))
size_diff=$((pr_size - target_size))
if [ "$target_size" -gt 0 ]; then
percentage_change=$((100 * size_diff / target_size))
else
percentage_change=0
fi
echo "Baseline VSIX size: $target_size KB"
echo "PR branch VSIX size: $pr_size KB"
echo "Size difference: $size_diff KB"
echo "Percentage change: $percentage_change%"
echo "mssql_target_vsix_size=$target_size" >> $GITHUB_ENV
echo "mssql_pr_vsix_size=$pr_size" >> $GITHUB_ENV
echo "mssql_vsix_size_diff=$size_diff" >> $GITHUB_ENV
echo "mssql_vsix_percentage_change=$percentage_change" >> $GITHUB_ENV
if [ "$percentage_change" -gt 0 ]; then
echo "mssql_vsix_change_icon=$worse_change_icon" >> $GITHUB_ENV
elif [ "$percentage_change" -lt 0 ]; then
echo "mssql_vsix_change_icon=$better_change_icon" >> $GITHUB_ENV
else
echo "mssql_vsix_change_icon=$no_change_icon" >> $GITHUB_ENV
fi
- name: Calculate sql-database-projects vsix file sizes
if: env.should_compare_baseline == 'true'
run: |
# Get baseline size from downloaded artifact or default to 0
if [ -f ./baseline/baseline-sizes.json ]; then
target_size=$(jq -r '.sql_database_projects.vsix_kb' ./baseline/baseline-sizes.json)
else
echo "⚠️ No baseline found, using 0 for comparison"
target_size=0
fi
pr_vsix=$(find ./extensions/sql-database-projects -name "*.vsix")
pr_size=$(stat -c%s "$pr_vsix")
pr_size=$((pr_size / 1024))
size_diff=$((pr_size - target_size))
if [ "$target_size" -gt 0 ]; then
percentage_change=$((100 * size_diff / target_size))
else
percentage_change=0
fi
echo "Baseline sql-database-projects VSIX size: $target_size KB"
echo "PR branch sql-database-projects VSIX size: $pr_size KB"
echo "Size difference: $size_diff KB"
echo "Percentage change: $percentage_change%"
echo "sqlproj_target_vsix_size=$target_size" >> $GITHUB_ENV
echo "sqlproj_pr_vsix_size=$pr_size" >> $GITHUB_ENV
echo "sqlproj_vsix_size_diff=$size_diff" >> $GITHUB_ENV
echo "sqlproj_vsix_percentage_change=$percentage_change" >> $GITHUB_ENV
if [ "$percentage_change" -gt 0 ]; then
echo "sqlproj_vsix_change_icon=$worse_change_icon" >> $GITHUB_ENV
elif [ "$percentage_change" -lt 0 ]; then
echo "sqlproj_vsix_change_icon=$better_change_icon" >> $GITHUB_ENV
else
echo "sqlproj_vsix_change_icon=$no_change_icon" >> $GITHUB_ENV
fi
- name: Calculate data-workspace vsix file sizes
if: env.should_compare_baseline == 'true'
run: |
# Get baseline size from downloaded artifact or default to 0
if [ -f ./baseline/baseline-sizes.json ]; then
target_size=$(jq -r '.data_workspace.vsix_kb' ./baseline/baseline-sizes.json)
else
echo "⚠️ No baseline found, using 0 for comparison"
target_size=0
fi
pr_vsix=$(find ./extensions/data-workspace -name "*.vsix")
pr_size=$(stat -c%s "$pr_vsix")
pr_size=$((pr_size / 1024))
size_diff=$((pr_size - target_size))
if [ "$target_size" -gt 0 ]; then
percentage_change=$((100 * size_diff / target_size))
else
percentage_change=0
fi
echo "Baseline data-workspace VSIX size: $target_size KB"
echo "PR branch data-workspace VSIX size: $pr_size KB"
echo "Size difference: $size_diff KB"
echo "Percentage change: $percentage_change%"
echo "dataworkspace_target_vsix_size=$target_size" >> $GITHUB_ENV
echo "dataworkspace_pr_vsix_size=$pr_size" >> $GITHUB_ENV
echo "dataworkspace_vsix_size_diff=$size_diff" >> $GITHUB_ENV
echo "dataworkspace_vsix_percentage_change=$percentage_change" >> $GITHUB_ENV
if [ "$percentage_change" -gt 0 ]; then
echo "dataworkspace_vsix_change_icon=$worse_change_icon" >> $GITHUB_ENV
elif [ "$percentage_change" -lt 0 ]; then
echo "dataworkspace_vsix_change_icon=$better_change_icon" >> $GITHUB_ENV
else
echo "dataworkspace_vsix_change_icon=$no_change_icon" >> $GITHUB_ENV
fi
- name: Keymap - Calculate vsix file sizes
if: env.should_compare_baseline == 'true'
run: |
# Get baseline size from downloaded artifact or default to 0
if [ -f ./baseline/baseline-sizes.json ]; then
target_size=$(jq -r '.keymap.vsix_kb' ./baseline/baseline-sizes.json)
else
echo "⚠️ No baseline found, using 0 for comparison"
target_size=0
fi
pr_vsix=$(find ./extensions/database-management-keymap -name "*.vsix")
pr_size=$(stat -c%s "$pr_vsix")
pr_size=$((pr_size / 1024))
size_diff=$((pr_size - target_size))
if [ "$target_size" -gt 0 ]; then
percentage_change=$((100 * size_diff / target_size))
else
percentage_change=0
fi
echo "Baseline keymap VSIX size: $target_size KB"
echo "PR branch keymap VSIX size: $pr_size KB"
echo "Size difference: $size_diff KB"
echo "Percentage change: $percentage_change%"
echo "keymap_target_vsix_size=$target_size" >> $GITHUB_ENV
echo "keymap_pr_vsix_size=$pr_size" >> $GITHUB_ENV
echo "keymap_vsix_size_diff=$size_diff" >> $GITHUB_ENV
echo "keymap_vsix_percentage_change=$percentage_change" >> $GITHUB_ENV
if [ "$percentage_change" -gt 0 ]; then
echo "keymap_vsix_change_icon=$worse_change_icon" >> $GITHUB_ENV
elif [ "$percentage_change" -lt 0 ]; then
echo "keymap_vsix_change_icon=$better_change_icon" >> $GITHUB_ENV
else
echo "keymap_vsix_change_icon=$no_change_icon" >> $GITHUB_ENV
fi
- name: MSSQL - Run unit tests
continue-on-error: true
run: |
set +e # Don't exit on errors
DISPLAY=:10 npm run test -- --target mssql
UNIT_EXIT_CODE=$?
echo "mssql_unit_tests_pr_exit_code=$UNIT_EXIT_CODE" >> $GITHUB_ENV
- name: MSSQL - Unit Test Report
uses: dorny/test-reporter@v2
if: success() || failure()
with:
name: "Unit Test Report"
path: ./test-reports/**/*.xml
reporter: jest-junit
working-directory: ./extensions/mssql
badge-title: "unit-tests"
fail-on-error: false
- name: Build mappings for Webviews
continue-on-error: true
run: |
cd ./extensions/mssql
npm run build:webviews-bundle
- name: Setup environment for smoke tests
run: |
echo "Setting up environment for smoke tests"
PASS_LOWER="$(LC_ALL=C tr -dc 'a-z' < /dev/urandom | head -c 1)"
PASS_UPPER="$(LC_ALL=C tr -dc 'A-Z' < /dev/urandom | head -c 1)"
PASS_DIGIT="$(LC_ALL=C tr -dc '0-9' < /dev/urandom | head -c 1)"
PASS_SPECIAL="$(LC_ALL=C tr -dc '!@#^%' < /dev/urandom | head -c 1)"
PASS_REST="$(LC_ALL=C tr -dc 'A-Za-z0-9!@#^%' < /dev/urandom | head -c 12)"
PASSWORD="${PASS_LOWER}${PASS_UPPER}${PASS_DIGIT}${PASS_SPECIAL}${PASS_REST}"
echo "PASSWORD=$PASSWORD" >> $GITHUB_ENV
docker rm -f mssql-server >/dev/null 2>&1 || true
docker pull mcr.microsoft.com/mssql/server:2025-latest
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Developer" -e "MSSQL_SA_PASSWORD=$PASSWORD" \
-p 1433:1433 --name mssql-server -d mcr.microsoft.com/mssql/server:2025-latest
SERVER_READY=false
for i in {1..30}; do
if docker logs mssql-server 2>&1 | grep -q "SQL Server is now ready for client connections"; then
SERVER_READY=true
break
fi
sleep 2
done
docker logs mssql-server --tail 50
if [ "$SERVER_READY" != "true" ]; then
echo "SQL Server did not become ready in time."
exit 1
fi
working-directory: ./extensions/mssql
- name: Run smoke tests
continue-on-error: true
run: |
set +e # Don't exit on errors
export VS_CODE_VERSION=stable
export SERVER_NAME=localhost
export AUTHENTICATION_TYPE="SQL Login"
export USER_NAME=sa
export PASSWORD=${{ env.PASSWORD }}
export SAVE_PASSWORD=No
export PROFILE_NAME=test-server
export BUILT_VSIX_PATH=$(find ./extensions/mssql -name "*.vsix" -exec realpath {} \; | head -n 1)
DISPLAY=:10 npm run smoketest -- --target mssql
SMOKE_EXIT_CODE=$?
echo "mssql_smoke_tests_pr_exit_code=$SMOKE_EXIT_CODE" >> $GITHUB_ENV
- name: Upload Smoke Test Screenshots and Videos
uses: actions/upload-artifact@v6
with:
name: smoke-test-failure-screenshots
path: ./extensions/mssql/test-results/**/
retention-days: 7
- name: Smoke Test Report
uses: dorny/test-reporter@v2
if: success() || failure()
with:
name: "Smoke Test Report"
path: ./test-reports/**/smoke-results.xml
reporter: jest-junit
working-directory: ./extensions/mssql
badge-title: "smoke-tests"
fail-on-error: false
- name: Merge Smoke and Unit Test Coverage Reports
run: |
if [ -f extensions/mssql/test/resources/mergeReports.js ]; then
node extensions/mssql/test/resources/mergeReports.js extensions/mssql/coverage/coverage-e2e/cobertura-coverage.xml extensions/mssql/coverage/cobertura-coverage.xml
else
echo "mergeReports.js not found, skipping..."
fi
- name: Generate Coverage Report
uses: danielpalme/ReportGenerator-GitHub-Action@5.4.4
with:
reports: "./extensions/mssql/coverage/cobertura-coverage.xml"
targetdir: "coveragereport"
reporttypes: "Html"
toolpath: "reportgeneratortool"
- name: Upload coverage report artifact
uses: actions/upload-artifact@v6
with:
name: CoverageReport
path: coveragereport
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: "./extensions/mssql/coverage"
exclude: "coverage-e2e"
- name: Write PR results to markdown
if: env.should_compare_baseline == 'true'
run: |
echo "### PR Changes" >> results.md
echo "| Category | Target Branch | PR Branch | Difference |" >> results.md
echo "|------------------------------|--------------------|-------------------|----------------------|" >> results.md
echo "| vscode-mssql VSIX | ${{ env.mssql_target_vsix_size }} KB | ${{ env.mssql_pr_vsix_size }} KB | ${{ env.mssql_vsix_change_icon }} ${{ env.mssql_vsix_size_diff }} KB ( ${{ env.mssql_vsix_percentage_change }}% ) |" >> results.md
echo "| sql-database-projects VSIX | ${{ env.sqlproj_target_vsix_size }} KB | ${{ env.sqlproj_pr_vsix_size }} KB | ${{ env.sqlproj_vsix_change_icon }} ${{ env.sqlproj_vsix_size_diff }} KB ( ${{ env.sqlproj_vsix_percentage_change }}% ) |" >> results.md
echo "| data-workspace VSIX | ${{ env.dataworkspace_target_vsix_size }} KB | ${{ env.dataworkspace_pr_vsix_size }} KB | ${{ env.dataworkspace_vsix_change_icon }} ${{ env.dataworkspace_vsix_size_diff }} KB ( ${{ env.dataworkspace_vsix_percentage_change }}% ) |" >> results.md
echo "| keymap VSIX | ${{ env.keymap_target_vsix_size }} KB | ${{ env.keymap_pr_vsix_size }} KB | ${{ env.keymap_vsix_change_icon }} ${{ env.keymap_vsix_size_diff }} KB ( ${{ env.keymap_vsix_percentage_change }}% ) |" >> results.md
- name: Find comment
uses: peter-evans/find-comment@v3
if: env.should_compare_baseline == 'true'
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: |
### PR Changes
- name: Create or update comment
uses: peter-evans/create-or-update-comment@v4
if: env.should_compare_baseline == 'true'
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body-path: ./results.md
comment-id: ${{ steps.fc.outputs.comment-id }}
edit-mode: replace
- name: SqlProj - Run unit tests
continue-on-error: true
run: |
set +e # Don't exit on errors
DISPLAY=:10 npm run test -- --target sql-database-projects
UNIT_EXIT_CODE=$?
echo "sqlproj_unit_tests_pr_exit_code=$UNIT_EXIT_CODE" >> $GITHUB_ENV
- name: DataWorkspace - Run unit tests
continue-on-error: true
run: |
set +e # Don't exit on errors
DISPLAY=:10 npm run test -- --target data-workspace
UNIT_EXIT_CODE=$?
echo "dataworkspace_unit_tests_pr_exit_code=$UNIT_EXIT_CODE" >> $GITHUB_ENV
- name: Generate xliff files
run: |
npm run localization
# Check if there are git changes in english xlf files
- name: Check for changes in localization files
run: |
CHANGES_FOUND=false
if ! git diff --quiet --exit-code ./localization/xliff/vscode-mssql.xlf; then
echo "Changes found in vscode-mssql.xlf"
CHANGES_FOUND=true
fi
if ! git diff --quiet --exit-code ./localization/xliff/sql-database-projects.xlf; then
echo "Changes found in sql-database-projects.xlf"
CHANGES_FOUND=true
fi
if ! git diff --quiet --exit-code ./extensions/mssql/l10n/bundle.l10n.json; then
echo "Changes found in mssql bundle.l10n.json"
CHANGES_FOUND=true
fi
if ! git diff --quiet --exit-code ./extensions/sql-database-projects/l10n/bundle.l10n.json; then
echo "Changes found in sql-database-projects bundle.l10n.json"
CHANGES_FOUND=true
fi
if ! git diff --quiet --exit-code ./localization/xliff/data-workspace.xlf; then
echo "Changes found in data-workspace.xlf"
CHANGES_FOUND=true
fi
if ! git diff --quiet --exit-code ./extensions/data-workspace/l10n/bundle.l10n.json; then
echo "Changes found in data-workspace bundle.l10n.json"
CHANGES_FOUND=true
fi
if [ "$CHANGES_FOUND" = "true" ]; then
echo "loc_update_required=true" >> $GITHUB_ENV
else
echo "Changes not found in any localization files"
echo "loc_update_required=false" >> $GITHUB_ENV
fi
- name: Find comment
uses: peter-evans/find-comment@v3
if: github.event_name == 'pull_request'
id: loc-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: |
# Updates to localized strings required
- name: Create or update comment
if: github.event_name == 'pull_request' && env.loc_update_required == 'true'
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.loc-comment.outputs.comment-id }}
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body: |
# Updates to localized strings required
Please update the localized strings in the PR with following steps:
1. Run `npm run localization` from the root directory of the PR branch.
2. Commit the updated localization files:
* XLIFF files: `localization/xliff/*.xlf`
* Bundle files: `extensions/mssql/l10n/bundle.l10n.json` and `extensions/sql-database-projects/l10n/bundle.l10n.json`
The localization system extracts strings from both extensions to a centralized location.
edit-mode: replace
- name: Delete comment
if: ${{ github.event_name == 'pull_request' && env.loc_update_required == 'false' && steps.loc-comment.outputs.comment-id != '' }}
run: |
curl -X DELETE \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ github.repository }}/issues/comments/${{ steps.loc-comment.outputs.comment-id }}
- name: Fail pipeline if any checks failed
if: always()
run: |
# Initialize failure flag
PIPELINE_FAILED=false
echo "Checking pipeline results..."
# Check MSSQL unit tests
if [ "${{ env.mssql_unit_tests_pr_exit_code }}" != "0" ] && [ "${{ env.mssql_unit_tests_pr_exit_code }}" != "" ]; then
echo " ❌ MSSQL unit tests failed with exit code ${{ env.mssql_unit_tests_pr_exit_code }}"
PIPELINE_FAILED=true
fi
# Check SqlProj unit tests
if [ "${{ env.sqlproj_unit_tests_pr_exit_code }}" != "0" ] && [ "${{ env.sqlproj_unit_tests_pr_exit_code }}" != "" ]; then
echo " ❌ SqlProj unit tests failed with exit code ${{ env.sqlproj_unit_tests_pr_exit_code }}"
PIPELINE_FAILED=true
fi
# Check DataWorkspace unit tests
if [ "${{ env.dataworkspace_unit_tests_pr_exit_code }}" != "0" ] && [ "${{ env.dataworkspace_unit_tests_pr_exit_code }}" != "" ]; then
echo " ⚠️ DataWorkspace unit tests failed with exit code ${{ env.dataworkspace_unit_tests_pr_exit_code }} (warning because tests not yet stablized)"
# PIPELINE_FAILED=true # Don't fail for dataworkspace unit tests yet; they aren't stable
fi
# Check MSSQL smoke tests
if [ "${{ env.mssql_smoke_tests_pr_exit_code }}" != "0" ] && [ "${{ env.mssql_smoke_tests_pr_exit_code }}" != "" ]; then
echo " ❌ MSSQL smoke tests failed with exit code ${{ env.mssql_smoke_tests_pr_exit_code }}"
PIPELINE_FAILED=true
fi
# Check MSSQL VSIX percentage change (if variables exist)
if [ "${{ env.mssql_vsix_percentage_change }}" != "" ] && [ $(echo "${{ env.mssql_vsix_percentage_change }} > 5" | bc -l) -eq 1 ]; then
echo " ❌ MSSQL VSIX size increased by more than 5% (${{ env.mssql_vsix_percentage_change }}%)"
PIPELINE_FAILED=true
fi
# Check SqlProj VSIX percentage change (if variables exist)
if [ "${{ env.sqlproj_vsix_percentage_change }}" != "" ] && [ $(echo "${{ env.sqlproj_vsix_percentage_change }} > 5" | bc -l) -eq 1 ]; then
echo " ❌ SqlProj VSIX size increased by more than 5% (${{ env.sqlproj_vsix_percentage_change }}%)"
PIPELINE_FAILED=true
fi
# Check DataWorkspace VSIX percentage change (if variables exist)
if [ "${{ env.dataworkspace_vsix_percentage_change }}" != "" ] && [ $(echo "${{ env.dataworkspace_vsix_percentage_change }} > 5" | bc -l) -eq 1 ]; then
echo " ❌ DataWorkspace VSIX size increased by more than 5% (${{ env.dataworkspace_vsix_percentage_change }}%)"
PIPELINE_FAILED=true
fi
# Check localization
if [ "${{ env.loc_update_required }}" = "true" ]; then
echo " ❌ Updates to localized strings are required"
PIPELINE_FAILED=true
fi
# Fail if any issues were found
if [ "$PIPELINE_FAILED" = "true" ]; then
echo ""
echo "Pipeline failed due to the above issues."
exit 1
else
echo " ✅ All checks passed!"
fi