refactor(ci): enhance static code validation workflow and improve err… #71
This file contains hidden or 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: Run static code validation | ||
| concurrency: | ||
| group: static-code-validation-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| validateEntireRepo: | ||
| description: Validate entire repo (setting to false will only validate the diff against main) | ||
| default: true | ||
| required: false | ||
| type: boolean | ||
| gitRef: | ||
| description: Which git ref to use | ||
| default: ${{ github.ref }} | ||
| required: false | ||
| type: string | ||
| secrets: | ||
| GITHUB_TOKEN: | ||
|
Check failure on line 19 in .github/workflows/ciStaticCodeValidation.yml
|
||
| description: GitHub token for authentication | ||
| required: false | ||
| workflow_dispatch: | ||
| inputs: | ||
| validateEntireRepo: | ||
| description: Validate entire repo (unchecking will only validate the diff against main) | ||
| default: true | ||
| required: false | ||
| type: boolean | ||
| jobs: | ||
| validate: | ||
| name: Static code validation | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| security-events: write | ||
| pull-requests: write | ||
| defaults: | ||
| run: | ||
| shell: bash | ||
| steps: | ||
| - name: Install SF CLI | ||
| uses: navikt/sf-platform/.github/actions/installSfCli@eb5b379e3b162280de8f5b9566cb41c25f0832f5 | ||
| with: | ||
| version: ${{ vars.SF_CLI_VERSION }} | ||
| - name: Checkout | ||
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | ||
| with: | ||
| ref: ${{ inputs.gitRef }} | ||
| fetch-depth: "0" | ||
| persist-credentials: false | ||
| - name: "Install dev dependencies" | ||
| run: | | ||
| npm ci | ||
| - name: "Set variables" | ||
| id: paths | ||
| run: | | ||
| prettierPathsToValidate='**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}' | ||
| sfCodeAnalyzerPathToValidate='src' | ||
| if [ "$VALIDATE_ENTIRE_REPO" = "false" ]; then | ||
| mapfile -t prettier_diffed_files_to_lint < <(git diff --name-only --diff-filter=d HEAD~ -- \*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}) | ||
| mapfile -t codeAnalyzer_diffed_sf_files < <(git diff --name-only --diff-filter=d HEAD~ -- src/**/*.{cls,cmp,component,css,html,js,json,page,trigger,xml}) | ||
| codeAnalyzer_json=$(jq -c -n '$ARGS.positional' --args "${codeAnalyzer_diffed_sf_files[@]}") | ||
| prettierPathsToValidate="$(printf "%s\n" "${prettier_diffed_files_to_lint[@]}")" | ||
| sfCodeAnalyzerPathToValidate="$codeAnalyzer_json" | ||
| fi | ||
| echo "prettierPathsToValidate=$prettierPathsToValidate" >> "$GITHUB_OUTPUT" | ||
| echo "sfCodeAnalyzerPathToValidate=$sfCodeAnalyzerPathToValidate" >> "$GITHUB_OUTPUT" | ||
| env: | ||
| VALIDATE_ENTIRE_REPO: ${{ inputs.validateEntireRepo }} | ||
| - name: Prettier Check | ||
| if: ${{ !cancelled() && steps.paths.outcome == 'success' }} | ||
| uses: navikt/sf-platform/.github/actions/prettierCheck@eb5b379e3b162280de8f5b9566cb41c25f0832f5 | ||
| with: | ||
| pathToValidate: ${{ steps.paths.outputs.prettierPathsToValidate }} | ||
| - name: Run Salesforce Code Analyzer | ||
| id: run-code-analyzer | ||
| if: ${{ !cancelled() && steps.paths.outcome == 'success' }} | ||
| uses: forcedotcom/run-code-analyzer@e88e434ef258c182fe4cb5d8f0c9f282384fd4b5 | ||
| with: | ||
| run-arguments: --workspace ${{ steps.paths.outputs.sfCodeAnalyzerPathToValidate }} --view detail --output-file sfca_results.html --output-file sfca_results.json --output-file code-analyzer-report.sarif | ||
| results-artifact-name: salesforce-code-analyzer-results | ||
| github-token: ${{ github.event_name == 'pull_request' && secrets.GITHUB_TOKEN || '' }} | ||
| # Code Analyser generates an empty SARIF file if no violations are found. | ||
| # In that case this step ensures that the SARIF file is valid and contains a default structure. | ||
| # This is required for the SARIF file to be uploaded to GitHub. | ||
| - name: Check SARIF file | ||
| if: ${{ !cancelled() && steps.paths.outcome == 'success' }} | ||
| run: | | ||
| echo "::group::Print SARIF file before check" | ||
| cat code-analyzer-report.sarif | ||
| echo "::endgroup::" | ||
| echo "::group::Check SARIF file" | ||
| jq --arg wd "$GITHUB_WORKSPACE" ' | ||
| if .runs == [] then | ||
| .runs = [ | ||
| { | ||
| "tool": { | ||
| "driver": { | ||
| "name": "pmd", | ||
| "rules": [] | ||
| } | ||
| }, | ||
| "results": [], | ||
| "invocations": [ | ||
| { | ||
| "executionSuccessful": true, | ||
| "workingDirectory": { | ||
| "uri": $wd | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| else | ||
| . | ||
| end | ||
| ' code-analyzer-report.sarif > temp.sarif && mv temp.sarif code-analyzer-report.sarif | ||
| echo "::endgroup::" | ||
| echo "::group::Print SARIF file after check" | ||
| cat code-analyzer-report.sarif | ||
| echo "::endgroup::" | ||
| - name: Upload SARIF file | ||
| uses: github/codeql-action/upload-sarif@7e3036b9cd87fc26dd06747b7aa4b96c27aaef3a | ||
| if: ${{ !cancelled() && steps.paths.outcome == 'success' && github.ref_name == 'main' }} | ||
| with: | ||
| sarif_file: code-analyzer-report.sarif | ||
| category: salesforce-code-analyzer | ||
| - name: Check the Salesforce Code Analyzer outputs to determine whether to fail | ||
| if: ${{ !cancelled() && steps.paths.outcome == 'success' && ( steps.run-code-analyzer.outputs.exit-code > 0 || steps.run-code-analyzer.outputs.num-sev1-violations > 0 || steps.run-code-analyzer.outputs.num-violations > 10) }} | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| # Normalize (default to 0 if unset/empty) | ||
| EXIT_CODE=${EXIT_CODE:-0} | ||
| NUM_SEV1_VIOLATIONS=${NUM_SEV1_VIOLATIONS:-0} | ||
| NUM_SEV2_VIOLATIONS=${NUM_SEV2_VIOLATIONS:-0} | ||
| NUM_SEV3_VIOLATIONS=${NUM_SEV3_VIOLATIONS:-0} | ||
| NUM_SEV4_VIOLATIONS=${NUM_SEV4_VIOLATIONS:-0} | ||
| NUM_SEV5_VIOLATIONS=${NUM_SEV5_VIOLATIONS:-0} | ||
| NUM_VIOLATIONS=${NUM_VIOLATIONS:-0} | ||
| # Exclude Sev5 (Info) from total count threshold | ||
| totalViolations=$(( NUM_VIOLATIONS - NUM_SEV5_VIOLATIONS )) | ||
| if (( EXIT_CODE > 0 )); then | ||
| echo "::error title=Salesforce Code Analyzer failed::Exit code: ${EXIT_CODE}" | ||
| fi | ||
| if (( NUM_SEV1_VIOLATIONS > 0 )) || (( totalViolations > MAX_ALLOWED_VIOLATIONS )); then | ||
| printf -v details \ | ||
| "Number of Sev1 Critical violations: %s\n \ | ||
| Number of Sev2 High violations: %s\n \ | ||
| Number of Sev3 Medium violations: %s\n \ | ||
| Number of Sev4 Low violations: %s\n \ | ||
| Number of Sev5 Info violations: %s\n \ | ||
| Total (excluding Sev5): %s (max %s)" \ | ||
| "$NUM_SEV1_VIOLATIONS" "$NUM_SEV2_VIOLATIONS" "$NUM_SEV3_VIOLATIONS" "$NUM_SEV4_VIOLATIONS" "$NUM_SEV5_VIOLATIONS" "$totalViolations" "$MAX_ALLOWED_VIOLATIONS" | ||
| # GitHub command: replace literal newlines with %0A | ||
| echo "::error title=Salesforce Code Analyzer threshold exceeded::${details//$'\n'/%0A}" | ||
| fi | ||
| if (( EXIT_CODE > 0 )) || (( NUM_SEV1_VIOLATIONS > 0 )) || (( totalViolations > MAX_ALLOWED_VIOLATIONS )); then | ||
| exit 1 | ||
| fi | ||
| env: | ||
| MAX_ALLOWED_VIOLATIONS: 10 | ||
| EXIT_CODE: ${{ steps.run-code-analyzer.outputs.exit-code }} | ||
| NUM_SEV1_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-sev1-violations }} | ||
| NUM_SEV2_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-sev2-violations }} | ||
| NUM_SEV3_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-sev3-violations }} | ||
| NUM_SEV4_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-sev4-violations }} | ||
| NUM_SEV5_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-sev5-violations }} | ||
| NUM_VIOLATIONS: ${{ steps.run-code-analyzer.outputs.num-violations }} | ||