Skip to content
Merged
Changes from 3 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
65b18be
Initial plan
Copilot Jan 16, 2026
492cd3b
Add code-coverage GitHub Actions workflow
Copilot Jan 16, 2026
f7fb76f
Fix YAML syntax in code-coverage workflow
Copilot Jan 16, 2026
214235d
Apply suggestion from @Copilot
cacosta33 Jan 16, 2026
c52a606
Apply suggestion from @Copilot
cacosta33 Jan 16, 2026
dd6cb21
Apply suggestions from code review
cacosta33 Jan 16, 2026
773e749
Fix 0.0% coverage issue with better error handling and debugging
Copilot Jan 16, 2026
98c096d
Fix gradle.properties parsing error causing build failure
Copilot Jan 16, 2026
7af1ddd
Pivot to Azure Pipeline for code coverage instead of GitHub Actions
Copilot Jan 20, 2026
20be74e
fix
fadidurah Jan 20, 2026
9cc64db
common
fadidurah Jan 28, 2026
08cf666
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
fadidurah Jan 28, 2026
2c82323
revert
fadidurah Jan 28, 2026
bae3a06
try code cov pipeline
fadidurah Jan 29, 2026
dc0a7e9
jacoco
fadidurah Jan 29, 2026
faee566
jacoco
fadidurah Jan 29, 2026
05e2731
jacoco
fadidurah Jan 29, 2026
d72bc1a
actually use jacoco
fadidurah Jan 29, 2026
a4f783b
actually use jacoco
fadidurah Jan 29, 2026
45e908f
actually use jacoco
fadidurah Jan 29, 2026
a33e982
limit to one test task
fadidurah Jan 29, 2026
769bc50
limit to one test task
fadidurah Jan 29, 2026
0a2a704
limit to one test task
fadidurah Jan 29, 2026
133b5f8
limit to one test task
fadidurah Jan 30, 2026
826bf61
limit to one test task
fadidurah Jan 30, 2026
e7c3acf
limit to one test task
fadidurah Jan 30, 2026
39adcee
limit to one test task
fadidurah Jan 30, 2026
fef82c2
limit to one test task
fadidurah Jan 31, 2026
48b349b
Fix Yaml
fadidurah Jan 31, 2026
89511d8
Fix Yaml
fadidurah Jan 31, 2026
22f2bea
comment out jobs for now
fadidurah Jan 31, 2026
19daab4
comment out jobs for now
fadidurah Jan 31, 2026
1aa01fd
comment out jobs for now
fadidurah Jan 31, 2026
c878ded
comment out jobs for now
fadidurah Jan 31, 2026
664ee44
fix gradle
fadidurah Jan 31, 2026
38eeca6
fix gradle
fadidurah Jan 31, 2026
7e3ca58
try without filtering
fadidurah Jan 31, 2026
42d9441
add java location
fadidurah Feb 2, 2026
b4be4e2
test
fadidurah Feb 2, 2026
5c986f3
test
fadidurah Feb 2, 2026
fc1f660
test
fadidurah Feb 3, 2026
6ea74e7
Merge branch 'dev' into copilot/add-code-coverage-check
fadidurah Feb 3, 2026
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
324 changes: 324 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
# Code Coverage Check Workflow
#
# This workflow runs code coverage checks for PRs targeting the 'dev' branch.
# It compares code coverage between the PR branch and the latest dev branch.
#
# Features:
# - Runs only for PRs targeting 'dev' branch
# - Can be skipped with 'code-coverage-skip' label
# - Compares total code coverage percentage (PR vs dev)
# - Fails if coverage decreases
# - Shows clear output with before/after coverage and delta

name: code-coverage

on:
pull_request:
branches:
- dev
types: [opened, reopened, synchronize, labeled, unlabeled]

permissions:
contents: read
pull-requests: write
checks: write

# Prevent multiple simultaneous runs for the same PR
concurrency:
group: code-coverage-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
code-coverage:
name: Code Coverage Check
runs-on: ubuntu-latest

# Skip if PR has 'code-coverage-skip' label
if: "!contains(github.event.pull_request.labels.*.name, 'code-coverage-skip')"

steps:
- name: Check for skip label
id: check_skip
run: |
echo "Running code coverage check (no skip label found)"

- name: Checkout PR branch
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Enable public Maven repositories
run: |
echo "Enabling mavenCentral and public repositories for GitHub Actions..."
# Uncomment mavenCentral in build.gradle
sed -i 's|// mavenCentral()|mavenCentral()|g' build.gradle
Comment thread
cacosta33 marked this conversation as resolved.
Outdated

# Create gradle.properties with dummy credentials to avoid errors
if [ ! -f gradle.properties ]; then
echo "Creating gradle.properties..."
touch gradle.properties
fi

# Add dummy credentials for VSTS Maven (will fallback to mavenCentral)
echo "vstsUsername=dummy" >> gradle.properties
echo "vstsMavenAccessToken=dummy" >> gradle.properties

- name: Run tests with code coverage on PR branch
id: pr_coverage
run: |
echo "Running code coverage on PR branch..."

# Run the coverage task as defined in the Azure pipeline
./gradlew :msal:localDebugMsalUnitTestCoverageReport -PcodeCoverageEnabled=true --no-daemon || true
Comment thread
cacosta33 marked this conversation as resolved.
Outdated

# Check if coverage report was generated
COVERAGE_FILE="msal/build/reports/jacoco/localDebugMsalUnitTestCoverageReport/localDebugMsalUnitTestCoverageReport.xml"
if [ ! -f "$COVERAGE_FILE" ]; then
echo "⚠️ Coverage report not found at $COVERAGE_FILE"
echo "Attempting to find coverage files..."

# Try to find the coverage XML file
find msal/build -name "*.xml" -path "*/jacoco/*" || true

echo "pr_coverage=0.0" >> $GITHUB_OUTPUT
echo "pr_coverage_found=false" >> $GITHUB_OUTPUT
else
# Extract coverage percentage from XML report
# Jacoco XML format: <counter type="INSTRUCTION" missed="X" covered="Y"/>
# Coverage % = (covered / (covered + missed)) * 100

COVERED=$(grep -o 'type="INSTRUCTION" missed="[0-9]*" covered="[0-9]*"' "$COVERAGE_FILE" | head -1 | grep -o 'covered="[0-9]*"' | grep -o '[0-9]*')
MISSED=$(grep -o 'type="INSTRUCTION" missed="[0-9]*" covered="[0-9]*"' "$COVERAGE_FILE" | head -1 | grep -o 'missed="[0-9]*"' | grep -o '[0-9]*')

Comment thread
cacosta33 marked this conversation as resolved.
Outdated
if [ -n "$COVERED" ] && [ -n "$MISSED" ]; then
TOTAL=$((COVERED + MISSED))
if [ $TOTAL -gt 0 ]; then
PR_COVERAGE=$(awk "BEGIN {printf \"%.2f\", ($COVERED / $TOTAL) * 100}")
echo "✅ PR Coverage: ${PR_COVERAGE}% (Covered: $COVERED, Missed: $MISSED, Total: $TOTAL)"
echo "pr_coverage=$PR_COVERAGE" >> $GITHUB_OUTPUT
echo "pr_coverage_found=true" >> $GITHUB_OUTPUT
else
echo "pr_coverage=0.0" >> $GITHUB_OUTPUT
echo "pr_coverage_found=false" >> $GITHUB_OUTPUT
fi
else
echo "⚠️ Could not extract coverage data from XML"
echo "pr_coverage=0.0" >> $GITHUB_OUTPUT
echo "pr_coverage_found=false" >> $GITHUB_OUTPUT
fi
fi
continue-on-error: true

- name: Checkout dev branch
run: |
echo "Switching to dev branch for baseline coverage..."
git fetch origin dev:dev
git checkout dev

- name: Run tests with code coverage on dev branch
id: dev_coverage
run: |
echo "Running code coverage on dev branch..."

# Clean previous build artifacts
./gradlew clean --no-daemon

# Run the coverage task as defined in the Azure pipeline
./gradlew :msal:localDebugMsalUnitTestCoverageReport -PcodeCoverageEnabled=true --no-daemon || true
Comment thread
cacosta33 marked this conversation as resolved.
Outdated

# Check if coverage report was generated
COVERAGE_FILE="msal/build/reports/jacoco/localDebugMsalUnitTestCoverageReport/localDebugMsalUnitTestCoverageReport.xml"
if [ ! -f "$COVERAGE_FILE" ]; then
echo "⚠️ Coverage report not found at $COVERAGE_FILE"
echo "dev_coverage=0.0" >> $GITHUB_OUTPUT
echo "dev_coverage_found=false" >> $GITHUB_OUTPUT
else
# Extract coverage percentage from XML report
COVERED=$(grep -o 'type="INSTRUCTION" missed="[0-9]*" covered="[0-9]*"' "$COVERAGE_FILE" | head -1 | grep -o 'covered="[0-9]*"' | grep -o '[0-9]*')
MISSED=$(grep -o 'type="INSTRUCTION" missed="[0-9]*" covered="[0-9]*"' "$COVERAGE_FILE" | head -1 | grep -o 'missed="[0-9]*"' | grep -o '[0-9]*')
Comment thread
cacosta33 marked this conversation as resolved.
Outdated

if [ -n "$COVERED" ] && [ -n "$MISSED" ]; then
TOTAL=$((COVERED + MISSED))
if [ $TOTAL -gt 0 ]; then
DEV_COVERAGE=$(awk "BEGIN {printf \"%.2f\", ($COVERED / $TOTAL) * 100}")
echo "✅ Dev Coverage: ${DEV_COVERAGE}% (Covered: $COVERED, Missed: $MISSED, Total: $TOTAL)"
echo "dev_coverage=$DEV_COVERAGE" >> $GITHUB_OUTPUT
echo "dev_coverage_found=true" >> $GITHUB_OUTPUT
else
echo "dev_coverage=0.0" >> $GITHUB_OUTPUT
echo "dev_coverage_found=false" >> $GITHUB_OUTPUT
fi
else
echo "⚠️ Could not extract coverage data from XML"
echo "dev_coverage=0.0" >> $GITHUB_OUTPUT
echo "dev_coverage_found=false" >> $GITHUB_OUTPUT
fi
fi
continue-on-error: true

- name: Compare coverage and determine result
id: compare
run: |
PR_COVERAGE="${{ steps.pr_coverage.outputs.pr_coverage }}"
DEV_COVERAGE="${{ steps.dev_coverage.outputs.dev_coverage }}"
PR_FOUND="${{ steps.pr_coverage.outputs.pr_coverage_found }}"
DEV_FOUND="${{ steps.dev_coverage.outputs.dev_coverage_found }}"

echo "PR Coverage Found: $PR_FOUND"
echo "Dev Coverage Found: $DEV_FOUND"

# Default to 0.0 if not set
PR_COVERAGE="${PR_COVERAGE:-0.0}"
DEV_COVERAGE="${DEV_COVERAGE:-0.0}"

echo "📊 Coverage Comparison:"
echo " Dev branch: ${DEV_COVERAGE}%"
echo " PR branch: ${PR_COVERAGE}%"

# Calculate delta using awk for floating point arithmetic
DELTA=$(awk "BEGIN {printf \"%.2f\", $PR_COVERAGE - $DEV_COVERAGE}")
echo " Delta: ${DELTA}%"

# Determine if coverage increased, decreased, or stayed the same
if (( $(echo "$DELTA < 0" | bc -l) )); then
RESULT="decreased"
STATUS="❌ FAILED"
EXIT_CODE=1
elif (( $(echo "$DELTA > 0" | bc -l) )); then
Comment thread
cacosta33 marked this conversation as resolved.
Outdated
RESULT="increased"
STATUS="✅ PASSED"
EXIT_CODE=0
else
RESULT="unchanged"
STATUS="✅ PASSED"
EXIT_CODE=0
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$STATUS - Code Coverage Check"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📈 Coverage Summary:"
echo " Before (dev): ${DEV_COVERAGE}%"
echo " After (PR): ${PR_COVERAGE}%"
echo " Delta: ${DELTA}%"
echo " Result: Coverage $RESULT"
echo ""

if [ "$RESULT" = "decreased" ]; then
echo "⚠️ Code coverage has decreased by ${DELTA#-}%"
echo " Please add tests to maintain or improve coverage."
elif [ "$RESULT" = "increased" ]; then
echo "🎉 Great job! Code coverage improved by ${DELTA}%"
else
echo "✓ Code coverage maintained at ${PR_COVERAGE}%"
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Set outputs for comment
echo "pr_coverage=$PR_COVERAGE" >> $GITHUB_OUTPUT
echo "dev_coverage=$DEV_COVERAGE" >> $GITHUB_OUTPUT
echo "delta=$DELTA" >> $GITHUB_OUTPUT
echo "result=$RESULT" >> $GITHUB_OUTPUT
echo "status=$STATUS" >> $GITHUB_OUTPUT
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT

# Exit with appropriate code
exit $EXIT_CODE

- name: Post coverage comment
if: always()
Comment thread
cacosta33 marked this conversation as resolved.
Outdated
uses: actions/github-script@v7
env:
PR_COVERAGE: ${{ steps.compare.outputs.pr_coverage }}
DEV_COVERAGE: ${{ steps.compare.outputs.dev_coverage }}
DELTA: ${{ steps.compare.outputs.delta }}
RESULT: ${{ steps.compare.outputs.result }}
STATUS: ${{ steps.compare.outputs.status }}
with:
script: |
const prCoverage = process.env.PR_COVERAGE || '0.0';
const devCoverage = process.env.DEV_COVERAGE || '0.0';
const delta = process.env.DELTA || '0.0';
const result = process.env.RESULT || 'unknown';
const status = process.env.STATUS || '❓ UNKNOWN';

let emoji = '📊';
let message = '';

if (result === 'decreased') {
emoji = '⚠️';
message = 'Code coverage has **decreased** by ' + delta.replace('-', '') + '%. Please add tests to maintain or improve coverage.';
Comment thread
cacosta33 marked this conversation as resolved.
Outdated
} else if (result === 'increased') {
emoji = '🎉';
message = 'Great job! Code coverage **improved** by ' + delta + '%.';
} else if (result === 'unchanged') {
emoji = '✅';
message = 'Code coverage **maintained** at ' + prCoverage + '%.';
}

let comment = '## ' + emoji + ' Code Coverage Report\n\n';
comment += status + '\n\n';
comment += '| Branch | Coverage | Delta |\n';
comment += '|--------|----------|-------|\n';
comment += '| dev (baseline) | ' + devCoverage + '% | - |\n';
comment += '| PR branch | ' + prCoverage + '% | ' + delta + '% |\n\n';
comment += message + '\n\n';
comment += '---\n';
comment += '*This check can be skipped by adding the `code-coverage-skip` label to the PR.*';

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});

# Handle skipped case with explicit success
code-coverage-skipped:
name: Code Coverage Check (Skipped)
runs-on: ubuntu-latest

# Run only if PR has 'code-coverage-skip' label
if: "contains(github.event.pull_request.labels.*.name, 'code-coverage-skip')"

steps:
- name: Skip coverage check
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ PASSED - Code Coverage Check (Skipped)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Code coverage check skipped due to 'code-coverage-skip' label."
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

- name: Post skip comment
uses: actions/github-script@v7
with:
script: |
let comment = '## ⏭️ Code Coverage Check Skipped\n\n';
comment += '✅ **PASSED** (Skipped)\n\n';
comment += 'This PR has the `code-coverage-skip` label, so the code coverage check was skipped.\n\n';
comment += '---\n';
comment += '*To re-enable coverage checks, remove the `code-coverage-skip` label.*';

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
Comment thread
cacosta33 marked this conversation as resolved.
Outdated