Add generic font family to inline font-family in macOS Help #96
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: "Build & Analyze" | |
| on: | |
| push: | |
| branches: [ master ] | |
| pull_request: | |
| branches: [ master ] | |
| jobs: | |
| # ============================================================ | |
| # Compilability check + shared compilation database for SAST | |
| # ============================================================ | |
| build: | |
| name: Build + Compilation Database | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| bear \ | |
| build-essential autoconf \ | |
| libaspell-dev libbrotli-dev libfl-dev libfontconfig-dev \ | |
| libfreetype-dev libglib2.0-dev libkrb5-dev libldap-dev \ | |
| libpcre3-dev libsodium-dev libssl-dev libunistring-dev libxml2-dev \ | |
| libx11-dev libxext-dev libxft-dev libxpm-dev libzstd-dev \ | |
| pkg-config python3 unicode-cldr-core zlib1g-dev | |
| - name: Configure | |
| run: | | |
| autoconf | |
| ./configure | |
| - name: Build and generate compilation database | |
| run: bear -- make -j$(nproc) | |
| - name: Upload compilation database | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: compilation-database | |
| path: compile_commands.json | |
| # ============================================================ | |
| # CodeChecker: Clang SA + Clang-Tidy + cppcheck + GCC -fanalyzer + Infer | |
| # ============================================================ | |
| codechecker: | |
| name: Static Analysis (CodeChecker) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| permissions: | |
| security-events: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| cppcheck python3 unicode-cldr-core \ | |
| libaspell-dev libbrotli-dev libfl-dev libfontconfig-dev \ | |
| libfreetype-dev libglib2.0-dev libkrb5-dev libldap-dev \ | |
| libpcre3-dev libsodium-dev libssl-dev libunistring-dev libxml2-dev \ | |
| libx11-dev libxext-dev libxft-dev libxpm-dev libzstd-dev | |
| - name: Install Infer | |
| run: | | |
| INFER_VERSION=$(curl -sL https://api.github.com/repos/facebook/infer/releases/latest \ | |
| | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])") | |
| echo "Installing Infer ${INFER_VERSION}" | |
| curl -sL "https://github.com/facebook/infer/releases/download/${INFER_VERSION}/infer-linux-x86_64-${INFER_VERSION}.tar.xz" \ | |
| | sudo tar xJ -C /opt | |
| sudo mv "/opt/infer-linux-x86_64-${INFER_VERSION}" /opt/infer | |
| sudo ln -sf /opt/infer/bin/infer /usr/local/bin/infer | |
| infer --version | |
| - name: Download compilation database | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: compilation-database | |
| - name: Generate build artifacts required for analysis | |
| run: | | |
| # Emoji table (generated from CLDR data at build time, gitignored) | |
| python3 scripts/generate-emoji-table.py \ | |
| Sources_Common/i18n/Charsets/CEmojiTable.h \ | |
| /usr/share/unicode/cldr/common/annotations/en.xml \ | |
| /usr/share/unicode/cldr/common/annotationsDerived/en.xml | |
| # Mulberry header symlinks (same as build process) | |
| mkdir -p Linux/Includes | |
| cd Linux && bash links.sh && cd .. | |
| # JX include dirs (populated by JX build, not tracked in git) | |
| mkdir -p Libraries/JX/include/jx Libraries/JX/include/jcore Libraries/JX/include/jximage | |
| for f in Libraries/JX/libjx/code/*; do | |
| ln -sf "../../libjx/code/$(basename "$f")" "Libraries/JX/include/jx/$(basename "$f")" | |
| done | |
| for f in Libraries/JX/libjcore/code/*; do | |
| ln -sf "../../libjcore/code/$(basename "$f")" "Libraries/JX/include/jcore/$(basename "$f")" | |
| done | |
| for f in Libraries/JX/libjx/image/*; do | |
| ln -sf "../../libjx/image/$(basename "$f")" "Libraries/JX/include/jximage/$(basename "$f")" | |
| done | |
| # JX/ACE config symlinks (created by configure) | |
| ln -sf config-linux.h Libraries/JX/ACE/ACE_wrappers/ace/config.h | |
| ln -sf ../include/make/sys/Linux-Intel-x86_64-gcc3 Libraries/JX/include/make/jx_config | |
| # Fix CodeChecker report hash path resolution — it strips directory | |
| # components from the workspace path, looking for prefix headers at | |
| # wrong relative paths. Create symlinks at all resolved locations. | |
| sudo mkdir -p /home/runner/work/mulberry-main/Common | |
| sudo ln -sf ${{ github.workspace }}/Plug-ins/Common/Mac2Linux.h /home/runner/work/mulberry-main/Common/Mac2Linux.h | |
| sudo ln -sf ${{ github.workspace }}/Plug-ins/Common/Plugin_Prefix_Linux.h /home/runner/work/mulberry-main/Common/Plugin_Prefix_Linux.h | |
| sudo ln -sf ${{ github.workspace }}/Plug-ins/Common/os_dep.h /home/runner/work/mulberry-main/Common/os_dep.h | |
| sudo mkdir -p /home/runner/work/Linux/Sources | |
| sudo ln -sf ${{ github.workspace }}/Linux/Sources/Mulberry_Prefix.h /home/runner/work/Linux/Sources/Mulberry_Prefix.h | |
| ln -sf Linux/Sources Sources | |
| echo "Symlinks: $(find Linux/Includes -type l | wc -l) Mulberry, $(ls Libraries/JX/include/jx/*.h | wc -l) jx, $(ls Libraries/JX/include/jcore/*.h | wc -l) jcore" | |
| - name: Filter compilation database to exclude third-party libraries | |
| run: | | |
| python3 -c " | |
| import json | |
| EXCLUDE = ['/Libraries/JX/', '/Libraries/vendor/', '/Libraries/vzic/', '/Libraries/include/', '/Libraries/openssl/'] | |
| db = json.load(open('compile_commands.json')) | |
| filtered = [e for e in db if not any(x in e.get('file', '') for x in EXCLUDE)] | |
| json.dump(filtered, open('compile_commands.json', 'w'), indent=2) | |
| print(f'Filtered: {len(db)} -> {len(filtered)} entries (removed {len(db)-len(filtered)} third-party entries)') | |
| " | |
| - name: Run CodeChecker analysis | |
| uses: whisperity/codechecker-analysis-action@v1 | |
| id: codechecker | |
| with: | |
| config: ${{ github.workspace }}/.codechecker/config.json | |
| logfile: ${{ github.workspace }}/compile_commands.json | |
| ctu: true | |
| llvm-version: latest | |
| ignore-analyze-crashes: true | |
| - name: Convert results to SARIF | |
| if: always() | |
| run: | | |
| ~/.local/bin/CodeChecker parse \ | |
| ${{ steps.codechecker.outputs.analyze-output }} \ | |
| --export sarif \ | |
| --output ${{ github.workspace }}/codechecker-raw.sarif \ | |
| || true | |
| # Fix CodeChecker SARIF bug: startColumn/endColumn of 0 violates | |
| # SARIF spec (must be >= 1). Clamp to 1. | |
| python3 -c " | |
| import json | |
| with open('${{ github.workspace }}/codechecker-raw.sarif') as f: | |
| sarif = json.load(f) | |
| fixed = 0 | |
| for run in sarif.get('runs', []): | |
| for result in run.get('results', []): | |
| for cf in result.get('codeFlows', []): | |
| for tf in cf.get('threadFlows', []): | |
| for loc in tf.get('locations', []): | |
| region = loc.get('location', {}).get('physicalLocation', {}).get('region', {}) | |
| for key in ('startColumn', 'endColumn'): | |
| if key in region and region[key] < 1: | |
| region[key] = 1 | |
| fixed += 1 | |
| with open('${{ github.workspace }}/codechecker.sarif', 'w') as f: | |
| json.dump(sarif, f) | |
| print(f'SARIF fixed: {fixed} column values clamped to 1') | |
| results = sum(len(r.get('results', [])) for r in sarif.get('runs', [])) | |
| print(f'Total results: {results}') | |
| " | |
| - name: Upload SARIF to GitHub Security | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@v4 | |
| with: | |
| sarif_file: codechecker.sarif | |
| category: codechecker | |
| continue-on-error: true | |
| - name: Upload HTML reports | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: codechecker-reports | |
| path: ${{ steps.codechecker.outputs.result-html-dir }} | |
| if-no-files-found: ignore | |
| - name: Upload raw analysis results (backup) | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: codechecker-raw-results | |
| path: ${{ steps.codechecker.outputs.analyze-output }} | |
| if-no-files-found: ignore | |
| # ============================================================ | |
| # PVS-Studio: deep C++ logic analysis (FOSS license) | |
| # ============================================================ | |
| pvs-studio: | |
| name: Static Analysis (PVS-Studio) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| permissions: | |
| security-events: write | |
| steps: | |
| - name: Check for credentials | |
| id: check-creds | |
| run: | | |
| if [ -z "${{ secrets.PVS_STUDIO_CREDENTIALS }}" ]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| echo "::notice::PVS-Studio skipped — PVS_STUDIO_CREDENTIALS secret not set" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout repository | |
| if: steps.check-creds.outputs.skip != 'true' | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install dependencies | |
| if: steps.check-creds.outputs.skip != 'true' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| python3 unicode-cldr-core \ | |
| libaspell-dev libbrotli-dev libfl-dev libfontconfig-dev \ | |
| libfreetype-dev libglib2.0-dev libkrb5-dev libldap-dev \ | |
| libpcre3-dev libsodium-dev libssl-dev libunistring-dev libxml2-dev \ | |
| libx11-dev libxext-dev libxft-dev libxpm-dev libzstd-dev | |
| - name: Install PVS-Studio | |
| if: steps.check-creds.outputs.skip != 'true' | |
| run: | | |
| wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt \ | |
| | sudo apt-key add - | |
| sudo wget -O /etc/apt/sources.list.d/viva64.list \ | |
| https://files.pvs-studio.com/etc/viva64.list | |
| sudo apt-get update | |
| sudo apt-get install -y pvs-studio | |
| pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} | |
| - name: Download compilation database | |
| if: steps.check-creds.outputs.skip != 'true' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: compilation-database | |
| - name: Generate build artifacts required for analysis | |
| if: steps.check-creds.outputs.skip != 'true' | |
| run: | | |
| python3 scripts/generate-emoji-table.py \ | |
| Sources_Common/i18n/Charsets/CEmojiTable.h \ | |
| /usr/share/unicode/cldr/common/annotations/en.xml \ | |
| /usr/share/unicode/cldr/common/annotationsDerived/en.xml | |
| mkdir -p Linux/Includes | |
| cd Linux && bash links.sh && cd .. | |
| mkdir -p Libraries/JX/include/jx Libraries/JX/include/jcore Libraries/JX/include/jximage | |
| for f in Libraries/JX/libjx/code/*; do | |
| ln -sf "../../libjx/code/$(basename "$f")" "Libraries/JX/include/jx/$(basename "$f")" | |
| done | |
| for f in Libraries/JX/libjcore/code/*; do | |
| ln -sf "../../libjcore/code/$(basename "$f")" "Libraries/JX/include/jcore/$(basename "$f")" | |
| done | |
| for f in Libraries/JX/libjx/image/*; do | |
| ln -sf "../../libjx/image/$(basename "$f")" "Libraries/JX/include/jximage/$(basename "$f")" | |
| done | |
| ln -sf config-linux.h Libraries/JX/ACE/ACE_wrappers/ace/config.h | |
| ln -sf ../include/make/sys/Linux-Intel-x86_64-gcc3 Libraries/JX/include/make/jx_config | |
| - name: Run PVS-Studio analysis | |
| if: steps.check-creds.outputs.skip != 'true' | |
| run: | | |
| pvs-studio-analyzer analyze -f compile_commands.json -j \ | |
| -e Libraries/JX/ \ | |
| -e Libraries/vendor/ \ | |
| -e Libraries/vzic/ \ | |
| -e Libraries/include/ \ | |
| -e Libraries/openssl/ | |
| - name: Convert results to SARIF | |
| if: steps.check-creds.outputs.skip != 'true' | |
| run: | | |
| plog-converter PVS-Studio.log \ | |
| -t json -n relative -R toRelative -r "$PWD" | |
| plog-converter relative.json \ | |
| -t sarif -n pvs-report -r file:// | |
| - name: Upload SARIF to GitHub Security | |
| if: steps.check-creds.outputs.skip != 'true' | |
| uses: github/codeql-action/upload-sarif@v4 | |
| with: | |
| sarif_file: pvs-report.sarif | |
| category: PVS-Studio | |
| continue-on-error: true | |
| # ============================================================ | |
| # SonarCloud: technical debt and quality tracking | |
| # ============================================================ | |
| sonarcloud: | |
| name: Analyze (SonarCloud) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Download compilation database | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: compilation-database | |
| - name: Normalize compilation database paths | |
| run: | | |
| python3 -c " | |
| import json, os | |
| db = json.load(open('compile_commands.json')) | |
| changed = 0 | |
| for entry in db: | |
| d = entry.get('directory', '') | |
| f = entry.get('file', '') | |
| resolved = os.path.normpath(os.path.join(d, f)) | |
| if resolved != f: | |
| changed += 1 | |
| entry['file'] = resolved | |
| if d: | |
| entry['directory'] = os.path.normpath(d) | |
| json.dump(db, open('compile_commands.json', 'w'), indent=2) | |
| print(f'Normalized {len(db)} entries ({changed} paths resolved)') | |
| " | |
| - name: SonarCloud scan | |
| uses: SonarSource/sonarqube-scan-action@v8 | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| with: | |
| args: > | |
| --define sonar.cfamily.compile-commands=compile_commands.json | |
| - name: Export SonarCloud issues to SARIF | |
| if: success() | |
| run: python3 scripts/sonarcloud-to-sarif.py | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| - name: Upload SonarCloud SARIF | |
| if: success() | |
| uses: github/codeql-action/upload-sarif@v4 | |
| with: | |
| sarif_file: sonarcloud.sarif | |
| category: sonarcloud | |
| # ============================================================ | |
| # OSV-Scanner: dependency CVE scanning (git submodules) | |
| # ============================================================ | |
| osv-scanner: | |
| name: Dependency CVE Scan (OSV) | |
| uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v2.3.8 | |
| permissions: | |
| actions: read | |
| contents: read | |
| security-events: write | |
| with: | |
| scan-args: "-r ./ --allow-no-lockfiles" | |
| checkout-submodules: true | |
| fail-on-vuln: false |