Skip to content

CI on forks - Sonar analysis #171

CI on forks - Sonar analysis

CI on forks - Sonar analysis #171

Workflow file for this run

name: CI on forks - Sonar analysis
on:
workflow_run:
workflows: [CI on forks - build and tests]
types:
- completed
permissions: {}
jobs:
java:
name: Run Sonar Analysis for forks (Java)
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
permissions:
actions: write
checks: write
contents: read
issues: read
pull-requests: write
statuses: write
steps:
- name: Download PR information
uses: actions/github-script@v7
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let prInfoArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("pr-info-")
})[0];
if (!prInfoArtifact) {
core.setFailed("❌ No PR info artifact found");
return;
}
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: prInfoArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/pr-info';
if (!fs.existsSync(temp)){
fs.mkdirSync(temp, { recursive: true });
}
fs.writeFileSync(path.join(temp, 'pr-info.zip'), Buffer.from(download.data));
console.log("PR information downloaded");
- name: Extract PR Information
run: |
mkdir -p ${{ runner.temp }}/pr-info-extracted
unzip -q ${{ runner.temp }}/pr-info/pr-info.zip -d ${{ runner.temp }}/pr-info-extracted
REPO_NAME=$(cat ${{ runner.temp }}/pr-info-extracted/repo-name)
HEAD_REF=$(cat ${{ runner.temp }}/pr-info-extracted/head-ref)
HEAD_SHA=$(cat ${{ runner.temp }}/pr-info-extracted/head-sha)
PR_NUMBER=$(cat ${{ runner.temp }}/pr-info-extracted/pr-number)
BASE_REF=$(cat ${{ runner.temp }}/pr-info-extracted/base-ref)
echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV
echo "HEAD_REF=$HEAD_REF" >> $GITHUB_ENV
echo "HEAD_SHA=$HEAD_SHA" >> $GITHUB_ENV
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
echo "BASE_REF=$BASE_REF" >> $GITHUB_ENV
echo "PR information extracted: $REPO_NAME $HEAD_REF $HEAD_SHA $PR_NUMBER $BASE_REF"
- name: Checkout sources
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: ${{ env.HEAD_REF }}
repository: ${{ env.REPO_NAME }}
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
with:
distribution: 'temurin'
java-version: '21'
- name: Download artifact
uses: actions/github-script@v7
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("data-for-sonar-analysis-")
})[0];
if (!matchArtifact) {
core.setFailed("❌ No matching artifact found");
return;
}
const prNumber = matchArtifact.name.replace("data-for-sonar-analysis-", "");
console.log(`PR number: ${prNumber}`);
core.exportVariable('PR_NUMBER', prNumber);
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/artifacts';
if (!fs.existsSync(temp)){
fs.mkdirSync(temp);
}
fs.writeFileSync(path.join(temp, 'sonar-data.zip'), Buffer.from(download.data));
- name: Extract Sonar Analysis Data
run: |
mkdir -p ${{ runner.temp }}/extracted
unzip -q ${{ runner.temp }}/artifacts/sonar-data.zip -d ${{ runner.temp }}/extracted
cp -r ${{ runner.temp }}/extracted/* .
ls -la metrix-distribution/target/site/jacoco-aggregate/ || echo "Jacoco report directory not found"
- name: Prepare Sonar Analysis
run: |
echo "Checking required directories..."
if [ -f "metrix-distribution/target/site/jacoco-aggregate/jacoco.xml" ]; then
echo "Jacoco report found"
else
echo "Warning: Jacoco report not found at expected location"
fi
echo "Finding sources and binaries..."
SOURCES=$(find . -type d -path "*/main/java" | sort -u | paste -sd "," -)
if [ -z "$SOURCES" ]; then
echo "Warning: No source directories found!"
else
echo "SOURCES : $SOURCES"
echo "SOURCES=$SOURCES" >> $GITHUB_ENV
fi
GENERATED=$(find . -type d -path "*/target/generated-sources" | sort -u | paste -sd "," -)
if [ -z "$GENERATED" ]; then
echo "Warning: No generated source directories found!"
else
echo "GENERATED : $GENERATED"
echo "GENERATED=$GENERATED" >> $GITHUB_ENV
fi
TESTS=$(find . -type d -path "*/test/java" | sort -u | paste -sd "," -)
if [ -z "$TESTS" ]; then
echo "Warning: No test directories found!"
else
echo "TESTS : $TESTS"
echo "TESTS=$TESTS" >> $GITHUB_ENV
fi
BINARIES=$(find . -type d -path "*/target/classes" | sort -u | paste -sd "," -)
if [ -z "$BINARIES" ]; then
echo "Warning: No binaries directories found!"
else
echo "BINARIES : $BINARIES"
echo "BINARIES=$BINARIES" >> $GITHUB_ENV
fi
LIBRARIES="metrix-distribution/target/dependency"
if [ -z "$LIBRARIES" ]; then
echo "Warning: No libraries directory found!"
else
echo "LIBRARIES : $LIBRARIES"
echo "LIBRARIES=$LIBRARIES" >> $GITHUB_ENV
fi
# This sonar action should NOT be replaced by a direct use of the mvn verify command since we don't want external
# code to run in a workflow_run workflow (it may lead to security issues).
- name: Run Sonar Analysis (Java)
uses: SonarSource/sonarqube-scan-action@2500896589ef8f7247069a56136f8dc177c27ccf # v5.2.0
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: >
-Dsonar.projectKey=com.powsybl:powsybl-metrix
-Dsonar.organization=powsybl-ci-github
-Dsonar.sources="${{ env.SOURCES }}"
-Dsonar.generatedSources="${{ env.GENERATED }}"
-Dsonar.tests="${{ env.TESTS }}"
-Dsonar.java.binaries="${{ env.BINARIES }}"
-Dsonar.java.libraries="${{ env.LIBRARIES }}"
-Dsonar.java.test.libraries="${{ env.LIBRARIES }}"
-Dsonar.coverage.jacoco.xmlReportPaths="metrix-distribution/target/site/jacoco-aggregate/jacoco.xml"
-Dsonar.pullrequest.key="${{ env.PR_NUMBER }}"
-Dsonar.pullrequest.branch="${{ env.HEAD_REF }}"
-Dsonar.pullrequest.base="${{ env.BASE_REF }}"
-Dsonar.pullrequest.provider=github
-Dsonar.pullrequest.github.repository=${{ github.repository }}
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.scm.provider=git
-Dsonar.qualitygate.wait=true
-Dsonar.scm.revision=${{ env.HEAD_SHA }}
- name: Delete artifacts used in analysis
if: always()
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of artifacts.data.artifacts) {
if (
artifact.name.startsWith("data-for-sonar-analysis-") ||
artifact.name.startsWith("pr-info-")
) {
console.log(`Deleting artifact: ${artifact.name} (ID: ${artifact.id})`);
await github.rest.actions.deleteArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id
});
}
}
cpp:
name: Run Sonar Analysis for forks (C++)
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
steps:
- name: Download PR information
uses: actions/github-script@v7
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let prInfoArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("cpp-pr-info-")
})[0];
if (!prInfoArtifact) {
core.setFailed("❌ No PR info artifact found");
return;
}
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: prInfoArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/cpp-pr-info';
if (!fs.existsSync(temp)){
fs.mkdirSync(temp, { recursive: true });
}
fs.writeFileSync(path.join(temp, 'cpp-pr-info.zip'), Buffer.from(download.data));
console.log("PR information downloaded");
- name: Extract PR Information
run: |
mkdir -p ${{ runner.temp }}/cpp-pr-info-extracted
unzip -q ${{ runner.temp }}/cpp-pr-info/cpp-pr-info.zip -d ${{ runner.temp }}/cpp-pr-info-extracted
REPO_NAME=$(cat ${{ runner.temp }}/cpp-pr-info-extracted/repo-name)
HEAD_REF=$(cat ${{ runner.temp }}/cpp-pr-info-extracted/head-ref)
HEAD_SHA=$(cat ${{ runner.temp }}/cpp-pr-info-extracted/head-sha)
PR_NUMBER=$(cat ${{ runner.temp }}/cpp-pr-info-extracted/pr-number)
BASE_REF=$(cat ${{ runner.temp }}/cpp-pr-info-extracted/base-ref)
echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV
echo "HEAD_REF=$HEAD_REF" >> $GITHUB_ENV
echo "HEAD_SHA=$HEAD_SHA" >> $GITHUB_ENV
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
echo "BASE_REF=$BASE_REF" >> $GITHUB_ENV
echo "PR information extracted: $REPO_NAME $HEAD_REF $HEAD_SHA $PR_NUMBER $BASE_REF"
- name: Checkout sources
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: ${{ env.HEAD_REF }}
repository: ${{ env.REPO_NAME }}
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
with:
distribution: 'temurin'
java-version: '21'
- name: Download C++ artifact
uses: actions/github-script@v7
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("cpp-data-for-sonar-analysis-")
})[0];
if (!matchArtifact) {
core.setFailed("❌ No matching artifact found");
return;
}
const prNumber = matchArtifact.name.replace("cpp-data-for-sonar-analysis-", "");
console.log(`PR number: ${prNumber}`);
core.exportVariable('PR_NUMBER', prNumber);
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/artifacts';
if (!fs.existsSync(temp)){
fs.mkdirSync(temp);
}
fs.writeFileSync(path.join(temp, 'cpp-sonar-data.zip'), Buffer.from(download.data));
- name: Extract Sonar Analysis Data
run: |
mkdir -p ${{ runner.temp }}/extracted
unzip -q ${{ runner.temp }}/artifacts/cpp-sonar-data.zip -d ${{ runner.temp }}/extracted
mkdir -p ./metrix-simulator/build
cp -r ${{ runner.temp }}/extracted/* ./metrix-simulator/build/
ls -la metrix-simulator/build/ || echo "build directory not found"
- name: Install Sonar wrapper
working-directory: ${{ runner.workspace }}
run: |
wget https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip
unzip build-wrapper-linux-x86.zip
- name: Install Sonar scanner
working-directory: ${{ runner.workspace }}
run: |
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}.zip
unzip sonar-scanner-cli-${SONAR_SCANNER_VERSION}.zip
ln -s sonar-scanner-${SONAR_SCANNER_VERSION} sonar
rm sonar-scanner-cli-${SONAR_SCANNER_VERSION}.zip
env:
SONAR_SCANNER_VERSION: 3.3.0.1492
# This step uses the sonar-project.properties file to get some parameters for the Sonar analysis
- name: Run Sonar Analysis (C++)
working-directory: ${{ runner.workspace }}/powsybl-metrix/metrix-simulator
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: >
${{ runner.workspace }}/sonar/bin/sonar-scanner
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.pullrequest.key="${{ env.PR_NUMBER }}"
-Dsonar.pullrequest.branch="${{ env.HEAD_REF }}"
-Dsonar.pullrequest.base="${{ env.BASE_REF }}"
-Dsonar.pullrequest.provider=github
-Dsonar.pullrequest.github.repository=${{ github.repository }}
-Dsonar.scm.provider=git
-Dsonar.qualitygate.wait=true
-Dsonar.scm.revision=${{ env.HEAD_SHA }}
- name: Delete artifacts used in analysis
if: always()
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of artifacts.data.artifacts) {
if (
artifact.name.startsWith("cpp-data-for-sonar-analysis-") ||
artifact.name.startsWith("cpp-pr-info-")
) {
console.log(`Deleting artifact: ${artifact.name} (ID: ${artifact.id})`);
await github.rest.actions.deleteArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id
});
}
}