diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml index 8abd6e220a..b9bc6e2126 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.yml @@ -4,16 +4,15 @@ on: types: [opened, synchronize, reopened] env: - HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }} HEAD_REF: ${{ github.event.pull_request.head.ref }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }} jobs: push: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Checkout ${{ env.HEAD_REF }} from repository ${{ env.HEAD_REPOSITORY }} + name: Checkout ${{ env.HEAD_REPOSITORY }}:${{ env.HEAD_REF }} with: ref: ${{ env.HEAD_REF }} repository: ${{ env.HEAD_REPOSITORY }} @@ -25,10 +24,10 @@ jobs: - name: Set up the dev container uses: ./.github/actions/setup-dev-container - - name: Scan scanner prototype for openchallenges-app - run: ./tools/sonar-scanner-for-pr.sh sage-monorepo apps/openchallenges/app ${{github.event.pull_request.number}} "${{env.HEAD_REPOSITORY}}:${{env.HEAD_REF}}" - - # - name: Scan the affected projects with Sonar - # run: | - # devcontainer exec --workspace-folder ../sage-monorepo bash -c ". ./dev-env.sh \ - # && nx affected --target=sonar" \ No newline at end of file + - name: Scan the affected projects with Sonar + env: + SONAR_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + devcontainer exec --workspace-folder ../sage-monorepo bash -c ". ./dev-env.sh \ + && nx affected --target=sonar" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1a41e85328..e618a91398 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ !.yarn/sdks !.yarn/versions .nx-container/ +.nx/ .pnpm-store/ .scannerwork/ playwright-report/ diff --git a/apps/openchallenges/app/project.json b/apps/openchallenges/app/project.json index 25ecfc2c8b..7d49265a12 100644 --- a/apps/openchallenges/app/project.json +++ b/apps/openchallenges/app/project.json @@ -15,18 +15,22 @@ "sonar": { "executor": "nx:run-commands", "options": { - "command": "bash $WORKSPACE_DIR/tools/sonar-scanner.sh {projectName}", + "command": "bash $WORKSPACE_DIR/tools/sonar-scanner.sh --project-key {projectName} --project-dir .", "cwd": "{projectRoot}" } }, "build": { "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], + "outputs": [ + "{options.outputPath}" + ], "options": { "outputPath": "dist/apps/openchallenges/app/browser/browser", "index": "apps/openchallenges/app/src/index.html", "main": "apps/openchallenges/app/src/main.ts", - "polyfills": ["zone.js"], + "polyfills": [ + "zone.js" + ], "tsConfig": "apps/openchallenges/app/tsconfig.app.json", "inlineStyleLanguage": "scss", "assets": [ @@ -119,7 +123,10 @@ "lint": { "executor": "@nx/linter:eslint", "options": { - "lintFilePatterns": ["apps/openchallenges/app/**/*.ts", "apps/openchallenges/app/**/*.html"] + "lintFilePatterns": [ + "apps/openchallenges/app/**/*.ts", + "apps/openchallenges/app/**/*.html" + ] } }, "lint-fix": { @@ -134,7 +141,9 @@ }, "test": { "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/apps/openchallenges/app"], + "outputs": [ + "{workspaceRoot}/coverage/apps/openchallenges/app" + ], "options": { "jestConfig": "apps/openchallenges/app/jest.config.ts", "passWithNoTests": true @@ -145,24 +154,39 @@ "options": { "context": ".", "metadata": { - "images": ["ghcr.io/sage-bionetworks/openchallenges-app"], - "tags": ["type=edge,branch=main", "type=raw,value=local", "type=sha"] + "images": [ + "ghcr.io/sage-bionetworks/openchallenges-app" + ], + "tags": [ + "type=edge,branch=main", + "type=raw,value=local", + "type=sha" + ] }, "push": false }, - "dependsOn": ["server"] + "dependsOn": [ + "server" + ] }, "publish-image": { "executor": "@nx-tools/nx-container:build", "options": { "context": ".", "metadata": { - "images": ["ghcr.io/sage-bionetworks/openchallenges-app"], - "tags": ["type=edge,branch=main", "type=sha"] + "images": [ + "ghcr.io/sage-bionetworks/openchallenges-app" + ], + "tags": [ + "type=edge,branch=main", + "type=sha" + ] }, "push": true }, - "dependsOn": ["build-image"] + "dependsOn": [ + "build-image" + ] }, "scan-image": { "executor": "nx:run-commands", @@ -172,7 +196,9 @@ } }, "server": { - "dependsOn": ["build"], + "dependsOn": [ + "build" + ], "executor": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/apps/openchallenges/app/browser/server", @@ -211,7 +237,9 @@ "prerender": { "executor": "@nguniversal/builders:prerender", "options": { - "routes": ["/"] + "routes": [ + "/" + ] }, "configurations": { "development": { @@ -233,16 +261,22 @@ }, "e2e": { "executor": "@nx/playwright:playwright", - "outputs": ["{workspaceRoot}/dist/.playwright/apps/openchallenges/app"], + "outputs": [ + "{workspaceRoot}/dist/.playwright/apps/openchallenges/app" + ], "options": { "config": "apps/openchallenges/app/playwright.config.ts" } } }, - "tags": ["type:app", "scope:client", "language:typescript"], + "tags": [ + "type:app", + "scope:client", + "language:typescript" + ], "implicitDependencies": [ "openchallenges-styles", "openchallenges-themes", "shared-typescript-assets" ] -} +} \ No newline at end of file diff --git a/apps/openchallenges/app/src/app/app.component.html b/apps/openchallenges/app/src/app/app.component.html index 390f087df0..968b56dcd4 100644 --- a/apps/openchallenges/app/src/app/app.component.html +++ b/apps/openchallenges/app/src/app/app.component.html @@ -1,4 +1,5 @@ + must be specified." - exit 1 -fi - -PROJECT_KEY="$1" -SOURCES="$2" -PULL_REQUEST_KEY="$3" -PULL_REQUEST_BRANCH="$4" -PULL_REQUEST_BASE="${5:-main}" - -echo "Project key: $PROJECT_KEY" -echo "Sources: $SOURCES" - -sonar-scanner \ - -Dsonar.organization=sage-bionetworks \ - -Dsonar.projectKey=$PROJECT_KEY \ - -Dsonar.sources=$SOURCES \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.python.coverage.reportPaths=coverage.xml \ - -Dsonar.pullrequest.key=$PULL_REQUEST_KEY \ - -Dsonar.pullrequest.branch=$PULL_REQUEST_BRANCH \ - -Dsonar.pullrequest.base=$PULL_REQUEST_BASE \ \ No newline at end of file diff --git a/tools/sonar-scanner.sh b/tools/sonar-scanner.sh index d4cd04a82a..ecf6445467 100755 --- a/tools/sonar-scanner.sh +++ b/tools/sonar-scanner.sh @@ -1,20 +1,115 @@ #!/usr/bin/env bash -if [ $# -lt 1 ] -then - echo "The argument must be specified." - exit 1 -fi +# This script scan a project of the monorepo with Sonar. +# +# Prefer using scanners for specific languages provided by Sonar instead of this script when +# available. E.g. SonarScanner for Gradle. +# +# Requires the environment variable SONAR_TOKEN to be set. +# +# Run locally, e.g. nx sonar openchallenges-app + +# Default variable values +## The Sonar host receiving scan results +sonar_host="https://sonarcloud.io" +## The organization on SonarCloud that owns the project +organization="sage-bionetworks" +## The key of the project on SonarCloud (must match the name of the project in the monorepo) +project_key="" +## The path to the project folder +project_dir="" +## The pull request number (if the scan is triggered by a PR event) +pull_request_number="$SONAR_PULL_REQUEST_NUMBER" + +# Function to display script usage +usage() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " -h, --help Display this help message" + echo " --project-key [key] The key of the project on SonarCloud" + echo " --project-dir [path] The path to the project folder" + echo " --pull-request-number [number] The pull request number (if the scan is triggered by a PR event)" +} + +has_argument() { + [[ ("$1" == *=* && -n ${1#*=}) || ( ! -z "$2" && "$2" != -*) ]]; +} + +# Note: Does not support --key=value, only --key value +extract_argument() { + echo "${2:-${1#*=}}" +} + +# Function to handle options and arguments +handle_options() { + while [ $# -gt 0 ]; do + case $1 in + -h | --help) + usage + exit 0 + ;; + --project-key*) + if ! has_argument $@; then + echo "Project key not specified." >&2 + usage + exit 1 + fi + + project_key=$(extract_argument $@) + + shift + ;; + --project-dir*) + if ! has_argument $@; then + echo "Project dir not specified." >&2 + usage + exit 1 + fi -PROJECT_KEY="$1" -SOURCES="${2:-$PWD}" + project_dir=$(extract_argument $@) -echo "Project key: $PROJECT_KEY" -echo "Sources: $SOURCES" + shift + ;; + --pull-request-number*) + if ! has_argument $@; then + echo "Pull request number not specified." >&2 + usage + exit 1 + fi + + pull_request_number=$(extract_argument $@) + + shift + ;; + *) + echo "Invalid option: $1" >&2 + usage + exit 1 + ;; + esac + shift + done +} + +# Main script execution +handle_options "$@" + +# Build the scanner options +args=( + -Dsonar.host.url=$sonar_host + -Dsonar.organization=$organization + -Dsonar.projectKey=$project_key + -Dsonar.sources=$project_dir + -Dsonar.python.coverage.reportPaths=${project_dir}/coverage.xml +) + +pull_request_number=2458 + +# Include the PR key if specified +if [[ ! -z ${pull_request_number+z} ]]; +then + args+=("-Dsonar.pullrequest.key=${pull_request_number}") +fi -sonar-scanner \ - -Dsonar.organization=sage-bionetworks \ - -Dsonar.projectKey=$PROJECT_KEY \ - -Dsonar.sources=$SOURCES \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.python.coverage.reportPaths=coverage.xml \ No newline at end of file +# Run the Sonar scanner +sonar-scanner "${args[@]}"