Conversation
Add comprehensive documentation for migrating from v4 to v5 formula schema. The v5 schema introduces: - Multi-format font support (TTF, WOFF2, variable fonts) - Explicit schema_version attribute - Format metadata on resources - Variable axes for variable font filtering - Better import provenance with commit_id tracking This documentation outlines the migration strategy and benefits of the v5 schema.
- Add schema_version: 5 to all formulas - Add format metadata to resources (ttf, otf, woff2, ttc, etc.) - Add variable_axes metadata where detected from filenames - 3206 formulas migrated from v4 - 474 formulas already had v5 schema Generated with: fontist migrate-formulas Formulas Formulas --verbose
Adds a two-tier testing system for formula validation: Tier 1 (Daily): - Schema v5 validation - URL accessibility checks Tier 2 (Every other day): - Full installation tests - Rotation by source (Google A-M / N-Z + others) - Multi-platform testing (ubuntu, macos, windows) Features: - Auto-creates GitHub issues on failures - Auto-closes issues when health checks pass - Manual trigger support with group selection
| name: Tier 1 - Schema & URL Validation | ||
| runs-on: ubuntu-latest | ||
| # Run daily at 6am UTC, or when manually triggered | ||
| if: | | ||
| (github.event_name == 'schedule' && | ||
| github.event.schedule == '0 6 * * *') || | ||
| (github.event_name == 'workflow_dispatch' && | ||
| (github.event.inputs.tier == 'both' || | ||
| github.event.inputs.tier == 'tier1-validation')) | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: ${{ env.RUBY_VERSION }} | ||
| bundler-cache: true | ||
|
|
||
| - name: Install concurrent-ruby for URL checking | ||
| run: gem install concurrent-ruby | ||
|
|
||
| - name: Schema Validation | ||
| id: schema | ||
| run: | | ||
| echo "::group::Schema Validation" | ||
| ruby .github/scripts/validate_schema.rb --directory Formulas 2>&1 | tee schema-results.txt | ||
| echo "::endgroup::" | ||
|
|
||
| # Check for failures | ||
| if grep -q "Schema validation FAILED" schema-results.txt; then | ||
| echo "schema_passed=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "schema_passed=true" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: URL Accessibility Check (Google fonts sample) | ||
| id: urls | ||
| run: | | ||
| echo "::group::URL Check - Google Fonts" | ||
| # Check all Google fonts (they share same URL pattern) | ||
| ruby .github/scripts/check_urls.rb \ | ||
| --directory Formulas/google \ | ||
| --timeout 15 \ | ||
| --verbose 2>&1 | tee url-results.txt | ||
| echo "::endgroup::" | ||
|
|
||
| # Check for failures | ||
| if grep -q "URL check FAILED" url-results.txt; then | ||
| echo "urls_passed=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "urls_passed=true" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Upload validation results | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: tier1-validation-results | ||
| path: | | ||
| schema-results.txt | ||
| url-results.txt | ||
| retention-days: 30 | ||
|
|
||
| - name: Summary | ||
| run: | | ||
| echo "## Tier 1 Validation Results" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY | ||
| echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY | ||
| echo "| Schema | ${{ steps.schema.outputs.schema_passed == 'true' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | ||
| echo "| URLs | ${{ steps.urls.outputs.urls_passed == 'true' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| - name: Fail if validation failed | ||
| if: steps.schema.outputs.schema_passed != 'true' || steps.urls.outputs.urls_passed != 'true' | ||
| run: exit 1 | ||
|
|
||
| # =========================================================================== | ||
| # TIER 2: Full Installation Test | ||
| # =========================================================================== | ||
| tier2-installation: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
To fix the problem, explicitly declare a minimal permissions block that limits the GITHUB_TOKEN to read-only access where possible. Since this workflow only checks out code, runs local Ruby scripts, and uploads artifacts, it does not need write access to repository contents, issues, or pull requests.
The best, least-intrusive fix is to add a root-level permissions block near the top of .github/workflows/formula-health.yml, so it applies to all jobs. Set contents: read as the baseline, which matches GitHub’s recommended minimal permissions for most read-only workflows. None of the shown steps require additional permissions (they use actions/checkout, ruby/setup-ruby, and actions/upload-artifact, all of which work with contents: read), so no further scopes are necessary.
Concretely: in .github/workflows/formula-health.yml, insert a permissions: section between the env: block and the jobs: block (around line 49). The new section should be:
permissions:
contents: readNo imports or additional definitions are needed, and no existing functionality or logic in the jobs needs to be changed.
| @@ -46,6 +46,9 @@ | ||
| env: | ||
| RUBY_VERSION: '3.3' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| # =========================================================================== | ||
| # TIER 1: Fast Validation |
- Tier 1 (schema validation + URL check) works correctly - Tier 2 (installation test) disabled until Fontist gem supports v5 schema formulas in index rebuild - Fix formula path copying in install_formulas.rb
| name: Tier 2 - Installation Test (${{ matrix.os }}) | ||
| runs-on: ${{ matrix.os }} | ||
| # Disabled until Fontist v5 schema index rebuild is fixed | ||
| if: false | ||
| # Run every other day at 7am UTC, or when manually triggered | ||
| # if: | | ||
| # (github.event_name == 'schedule' && | ||
| # github.event.schedule == '0 7 */2 * *') || | ||
| # (github.event_name == 'workflow_dispatch' && | ||
| # (github.event.inputs.tier == 'both' || | ||
| # github.event.inputs.tier == 'tier2-installation')) | ||
|
|
||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ubuntu-latest, macos-latest, windows-latest] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: ${{ env.RUBY_VERSION }} | ||
| bundler-cache: true | ||
|
|
||
| - name: Determine rotation and platform | ||
| id: config | ||
| shell: bash | ||
| run: | | ||
| # Calculate rotation day (1 or 2) based on current day of year | ||
| ROTATION_DAY=$(( $(date +%j) % 2 + 1 )) | ||
| echo "rotation_day=${ROTATION_DAY}" >> $GITHUB_OUTPUT | ||
|
|
||
| # Map OS to platform | ||
| case "${{ matrix.os }}" in | ||
| ubuntu-latest) PLATFORM="linux" ;; | ||
| macos-latest) PLATFORM="macos" ;; | ||
| windows-latest) PLATFORM="windows" ;; | ||
| esac | ||
| echo "platform=${PLATFORM}" >> $GITHUB_OUTPUT | ||
|
|
||
| # Build extra args from inputs | ||
| EXTRA_ARGS="" | ||
| if [ -n "${{ github.event.inputs.group }}" ]; then | ||
| EXTRA_ARGS="${EXTRA_ARGS} --group ${{ github.event.inputs.group }}" | ||
| fi | ||
| if [ -n "${{ github.event.inputs.sample_size }}" ]; then | ||
| EXTRA_ARGS="${EXTRA_ARGS} --sample ${{ github.event.inputs.sample_size }}" | ||
| fi | ||
| echo "extra_args=${EXTRA_ARGS}" >> $GITHUB_OUTPUT | ||
|
|
||
| echo "Rotation day: ${ROTATION_DAY}" | ||
| echo "Platform: ${PLATFORM}" | ||
|
|
||
| - name: Run installation test (Day ${{ steps.config.outputs.rotation_day }}) | ||
| id: install | ||
| shell: bash | ||
| continue-on-error: true | ||
| run: | | ||
| echo "::group::Installation Test - Rotation Day ${{ steps.config.outputs.rotation_day }}" | ||
|
|
||
| # Build the command | ||
| CMD="ruby .github/scripts/install_formulas.rb" | ||
| CMD="${CMD} --directory Formulas" | ||
| CMD="${CMD} --rotation ${{ steps.config.outputs.rotation_day }}" | ||
| CMD="${CMD} --platform ${{ steps.config.outputs.platform }}" | ||
| CMD="${CMD} --continue-on-error" | ||
| CMD="${CMD} ${{ steps.config.outputs.extra_args }}" | ||
| CMD="${CMD} --output install-results-${{ steps.config.outputs.platform }}.yml" | ||
|
|
||
| echo "Running: ${CMD}" | ||
| ${CMD} 2>&1 | tee install-output.txt | ||
|
|
||
| echo "::endgroup::" | ||
|
|
||
| # Check for failures | ||
| if grep -q "Installation test FAILED" install-output.txt; then | ||
| echo "install_passed=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "install_passed=true" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Upload installation results | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: tier2-install-results-${{ steps.config.outputs.platform }} | ||
| path: | | ||
| install-output.txt | ||
| install-results-${{ steps.config.outputs.platform }}.yml | ||
| retention-days: 30 | ||
|
|
||
| - name: Summary | ||
| shell: bash | ||
| run: | | ||
| echo "## Tier 2 Installation Results (${{ steps.config.outputs.platform }})" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "- Rotation Day: ${{ steps.config.outputs.rotation_day }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- Platform: ${{ steps.config.outputs.platform }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- Status: ${{ steps.install.outputs.install_passed == 'true' && '✅ Passed' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| if [ -f "install-results-${{ steps.config.outputs.platform }}.yml" ]; then | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### Statistics" >> $GITHUB_STEP_SUMMARY | ||
| echo '```yaml' >> $GITHUB_STEP_SUMMARY | ||
| cat "install-results-${{ steps.config.outputs.platform }}.yml" >> $GITHUB_STEP_SUMMARY | ||
| echo '```' >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| # =========================================================================== | ||
| # Report: Aggregate results and create issue on failure | ||
| # =========================================================================== | ||
| report: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
In general, the fix is to explicitly declare GITHUB_TOKEN permissions at the workflow root (or per job) and scope them to the minimal required capabilities. For this workflow, most jobs only need to read repository contents and use artifacts. The report and close-issue-on-success jobs interact with issues via the GitHub CLI and therefore require issues: write, but they do not need broader write access such as contents: write.
The best fix without changing functionality is:
- Add a root‑level
permissionsblock that applies to all jobs by default, e.g.permissions: { contents: read }. - Then override permissions for the
reportandclose-issue-on-successjobs to allow creating/updating and closing issues by settingpermissions: { contents: read, issues: write }for those specific jobs. - The
tier2-installationjob (line 135) will then inherit the safe defaultcontents: read, satisfying CodeQL’s requirement for explicit, least‑privilege permissions.
Concretely:
- In
.github/workflows/formula-health.yml, insert apermissions:section near the top, aftername:and comments, before theon:block. - Add a
permissionssection under thereport:job. - Add a
permissionssection under theclose-issue-on-success:job.
No new imports or external libraries are needed; this is purely a YAML/workflow configuration change.
| @@ -3,6 +3,9 @@ | ||
| # Periodic health check for fontist formulas | ||
| # Runs every other day to validate formula integrity | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| @@ -249,6 +252,9 @@ | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'failure' | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| @@ -330,6 +336,9 @@ | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'success' | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Close existing health check issues |
| name: Report Results | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'failure' | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Download all artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: results | ||
|
|
||
| - name: Check for repeated failures | ||
| id: check | ||
| run: | | ||
| # Look for existing open issue with same title pattern | ||
| ISSUE_NUMBER=$(gh issue list \ | ||
| --repo ${{ github.repository }} \ | ||
| --state open \ | ||
| --label "formula-health-failure" \ | ||
| --limit 1 \ | ||
| --json number \ | ||
| --jq '.[0].number // empty') | ||
|
|
||
| if [ -n "$ISSUE_NUMBER" ]; then | ||
| echo "issue_number=${ISSUE_NUMBER}" >> $GITHUB_OUTPUT | ||
| echo "is_existing=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "is_existing=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
|
|
||
| - name: Create or update issue | ||
| run: | | ||
| # Build issue body | ||
| cat > issue-body.md << 'EOF' | ||
| ## Formula Health Check Failed | ||
|
|
||
| The periodic formula health check detected failures. | ||
|
|
||
| **Workflow Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
|
|
||
| ### Tier 1 Validation | ||
| Status: ${{ needs.tier1-validation.result }} | ||
|
|
||
| ### Artifacts | ||
| - [Download results](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}#artifacts) | ||
|
|
||
| --- | ||
| *This issue was automatically created by the formula-health workflow.* | ||
| *It will be auto-closed when all health checks pass.* | ||
| EOF | ||
|
|
||
| if [ "${{ steps.check.outputs.is_existing }}" == "true" ]; then | ||
| # Update existing issue with comment | ||
| gh issue comment ${{ steps.check.outputs.issue_number }} \ | ||
| --repo ${{ github.repository }} \ | ||
| --body-file issue-body.md | ||
| else | ||
| # Create new issue | ||
| gh issue create \ | ||
| --repo ${{ github.repository }} \ | ||
| --title "Formula Health Check Failed - $(date +%Y-%m-%d)" \ | ||
| --body-file issue-body.md \ | ||
| --label "formula-health-failure,automated" | ||
| fi | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
|
|
||
| - name: Summary | ||
| run: | | ||
| echo "## Health Check Report" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "Issues detected. A GitHub issue has been created/updated." >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| # =========================================================================== | ||
| # Close issue on success (optional) | ||
| # =========================================================================== | ||
| close-issue-on-success: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
To fix the problem, explicitly declare a permissions block that grants only the scopes needed by this workflow. The minimal safe baseline is contents: read so jobs can read the repository, plus more specific write scopes where required. The report and close-issue-on-success jobs use the GitHub CLI to list, create, comment on, and close issues, so they require issues: write. Other jobs that only read code and run checks can operate with contents: read and no additional write permissions.
The best fix with minimal functional change is to add a workflow-level permissions block near the top (after name: and before/after on: is fine) that sets a read-only default, and then override it for the two issue-management jobs. Concretely:
- Add at the root of
.github/workflows/formula-health.yml:
permissions:
contents: readThis ensures all jobs default to read-only repository access.
- In the
reportjob definition, add:
permissions:
contents: read
issues: writeimmediately under name: Report Results.
- In the
close-issue-on-successjob definition, add:
permissions:
contents: read
issues: writeimmediately under name: Close Issue on Success.
No additional imports, tools, or structural changes are required; we are only constraining GITHUB_TOKEN scopes.
| @@ -3,6 +3,9 @@ | ||
| # Periodic health check for fontist formulas | ||
| # Runs every other day to validate formula integrity | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| @@ -249,6 +252,9 @@ | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'failure' | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| @@ -330,6 +336,9 @@ | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'success' | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Close existing health check issues |
| name: Close Issue on Success | ||
| runs-on: ubuntu-latest | ||
| needs: [tier1-validation] | ||
| if: always() && needs.tier1-validation.result == 'success' | ||
|
|
||
| steps: | ||
| - name: Close existing health check issues | ||
| run: | | ||
| # Find and close open health check issues | ||
| gh issue list \ | ||
| --repo ${{ github.repository }} \ | ||
| --state open \ | ||
| --label "formula-health-failure" \ | ||
| --json number \ | ||
| --jq '.[].number' | while read issue_number; do | ||
| gh issue close $issue_number \ | ||
| --repo ${{ github.repository }} \ | ||
| --comment "✅ All formula health checks are now passing. Closing this issue." | ||
| done | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| continue-on-error: true |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
In general, the fix is to add an explicit permissions block limiting the GITHUB_TOKEN to only the scopes needed by this workflow. Since parts of the workflow use gh to create, comment on, and close issues, they require issues: write. They do not appear to need contents: write or other elevated scopes, so we can set contents: read (safe default) and issues: write. The cleanest way, without altering behavior, is to add a workflow-level permissions block near the top so it applies to all jobs, including close-issue-on-success (the job CodeQL flagged) and report, which also writes issues. If some jobs only need read access, they can later override with a more restrictive block, but that is not necessary for this fix.
Concretely, in .github/workflows/formula-health.yml, just below the env: block (after line 48), add:
permissions:
contents: read
issues: writeThis keeps the existing functionality (creating/updating/closing issues still works) while ensuring that the token is not granted unnecessary write access outside of issues and only has read access to repository contents. No additional imports or external libraries are needed, and no job steps need to change.
| @@ -46,6 +46,10 @@ | ||
| env: | ||
| RUBY_VERSION: '3.3' | ||
|
|
||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| jobs: | ||
| # =========================================================================== | ||
| # TIER 1: Fast Validation |
- Add schema_version: 5 to all formulas - Add format metadata to resources (ttf, otf, woff2, ttc, etc.) - Add variable_axes metadata for variable fonts - Separate resources by format (woff2_variable, ttf_variable, etc.) - Re-imported Google, macOS, and SIL formulas with v5 schema
- Remove dependency on ../fontist working directory - Use formulas repo bundle directly (points to feat/v5-schema-multi-format) - Remove prepare job dependency - Add error handling and issue creation for google.yml - Add --formulas-dir option to sil.yml import command - Consistent ruby-version 3.3 across all workflows
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - os: macos-15 | ||
| framework: font7 | ||
| catalog_url: https://mesu.apple.com/assets/macos/com_apple_MobileAsset_Font7/com_apple_MobileAsset_Font7.xml | ||
| output_dir: Formulas/macos/font7 | ||
| - os: macos-26 | ||
| framework: font8 | ||
| catalog_url: https://mesu.apple.com/assets/macos/com_apple_MobileAsset_Font8/com_apple_MobileAsset_Font8.xml | ||
| output_dir: Formulas/macos/font8 | ||
|
|
||
| steps: | ||
| - name: Checkout formulas repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.3' | ||
| bundler-cache: true | ||
|
|
||
| - name: Download macOS font catalog | ||
| id: download-catalog | ||
| run: | | ||
| CATALOG_FILE="com_apple_MobileAsset_${{ matrix.framework }}.xml" | ||
| echo "Downloading ${{ matrix.framework }} catalog..." | ||
|
|
||
| curl -f -o "$CATALOG_FILE" "${{ matrix.catalog_url }}" | ||
|
|
||
| if [ -f "$CATALOG_FILE" ]; then | ||
| echo "catalog_file=$CATALOG_FILE" >> $GITHUB_OUTPUT | ||
| echo "✅ Downloaded $CATALOG_FILE" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "❌ Failed to download catalog" >> $GITHUB_STEP_SUMMARY | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Import macOS ${{ matrix.framework }} fonts | ||
| id: import | ||
| continue-on-error: true | ||
| run: | | ||
| # Run import with timing | ||
| START_TIME=$(date +%s) | ||
|
|
||
| # Execute the import command | ||
| bundle exec fontist import macos \ | ||
| --plist "${{ steps.download-catalog.outputs.catalog_file }}" \ | ||
| --formulas-dir "${{ matrix.output_dir }}" \ | ||
| 2>&1 | tee import-output.log | ||
|
|
||
| EXIT_CODE=${PIPESTATUS[0]} | ||
|
|
||
| END_TIME=$(date +%s) | ||
| DURATION=$((END_TIME - START_TIME)) | ||
|
|
||
| # Save metrics | ||
| echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT | ||
| echo "duration=$DURATION" >> $GITHUB_OUTPUT | ||
|
|
||
| # Count generated formulas | ||
| FORMULA_COUNT=$(find "${{ matrix.output_dir }}" -name "*.yml" 2>/dev/null | wc -l) | ||
| echo "formula_count=$FORMULA_COUNT" >> $GITHUB_OUTPUT | ||
|
|
||
| exit $EXIT_CODE | ||
|
|
||
| - name: Generate import report | ||
| if: always() | ||
| run: | | ||
| echo "## macOS ${{ matrix.framework }} Import Report" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### Platform" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Runner:** ${{ matrix.os }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Framework:** ${{ matrix.framework }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Output:** ${{ matrix.output_dir }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### Results" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Exit code:** ${{ steps.import.outputs.exit_code }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Duration:** ${{ steps.import.outputs.duration }}s" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Formulas generated:** ${{ steps.import.outputs.formula_count }}" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| if [ "${{ steps.import.outputs.exit_code }}" != "0" ]; then | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### ⚠️ Import completed with errors" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### ✅ Import completed successfully" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| - name: Upload import logs | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: macos-${{ matrix.framework }}-import-logs-${{ github.run_id }} | ||
| path: import-output.log | ||
| retention-days: 7 | ||
|
|
||
| - name: Check for formula changes | ||
| id: check-changes | ||
| if: success() | ||
| run: | | ||
| if [ -n "$(git status --porcelain ${{ matrix.output_dir }})" ]; then | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "### 📝 Formula Changes Detected" >> $GITHUB_STEP_SUMMARY | ||
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | ||
| git status --short ${{ matrix.output_dir }} | head -20 >> $GITHUB_STEP_SUMMARY | ||
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||
| echo "### ℹ️ No formula changes" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| - name: Commit changes | ||
| if: success() && steps.check-changes.outputs.has_changes == 'true' | ||
| uses: EndBug/add-and-commit@v7 | ||
| with: | ||
| add: ${{ matrix.output_dir }} | ||
| default_author: github_actions | ||
| message: 'chore(formulas): update macOS ${{ matrix.framework }} fonts' | ||
|
|
||
| - name: Create issue on repeated failures | ||
| if: failure() && github.event_name == 'schedule' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const issueTitle = `🔴 macOS ${{ matrix.framework }} Import Failed`; | ||
| const issueBody = ` | ||
| ## Import Failure Report | ||
|
|
||
| The scheduled macOS ${{ matrix.framework }} import failed on ${{ matrix.os }}. | ||
|
|
||
| ### Details | ||
| - **Platform:** ${{ matrix.os }} | ||
| - **Framework:** ${{ matrix.framework }} | ||
| - **Run ID:** ${{ github.run_id }} | ||
| - **Run URL:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| - **Duration:** ${{ steps.import.outputs.duration }}s | ||
|
|
||
| ### Action Required | ||
| - Review the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | ||
| - Check the uploaded artifacts for detailed error information | ||
| - Verify macOS catalog URL is accessible | ||
|
|
||
| ### Artifacts | ||
| - Import logs: \`macos-${{ matrix.framework }}-import-logs-${{ github.run_id }}\` | ||
| `; | ||
|
|
||
| // Check for existing open issues | ||
| const issues = await github.rest.issues.listForRepo({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| labels: `macos-import,automated,${{ matrix.framework }}` | ||
| }); | ||
|
|
||
| const existingIssue = issues.data.find(issue => | ||
| issue.title === issueTitle | ||
| ); | ||
|
|
||
| if (existingIssue) { | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: existingIssue.number, | ||
| body: `Another failure occurred:\n\n${issueBody}` | ||
| }); | ||
| } else { | ||
| await github.rest.issues.create({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| title: issueTitle, | ||
| body: issueBody, | ||
| labels: ['macos-import', 'automated', 'bug', '${{ matrix.framework }}'] | ||
| }); | ||
| } No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
To fix the problem, add an explicit permissions block that grants the minimal required scopes to the GITHUB_TOKEN. This can be done at the workflow root (applies to all jobs) or at the job level. Since this workflow has a single job (import), either is fine; using the workflow‑root permissions is simpler and fully addresses the warning on this job.
The workflow requires:
contents: writeforEndBug/add-and-commit@v7to add and commit changes.issues: writeforactions/github-script@v7to list issues and create/comment on them.
Other operations (checkout, uploading artifacts, reading repo contents) are covered by contents and/or do not need additional explicit scopes. Therefore, the best minimal explicit block is:
permissions:
contents: write
issues: writeThis should be added near the top of .github/workflows/macos.yml, after the name: and on: section but before jobs:. No imports or other code changes are needed.
| @@ -15,6 +15,10 @@ | ||
| - macos-15 | ||
| - macos-26 | ||
|
|
||
| permissions: | ||
| contents: write | ||
| issues: write | ||
|
|
||
| jobs: | ||
| import: | ||
| runs-on: ${{ matrix.os }} |
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout formulas repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.3' | ||
| bundler-cache: true | ||
|
|
||
| - name: Import SIL fonts | ||
| id: import | ||
| continue-on-error: true | ||
| run: | | ||
| # Run import with timing | ||
| START_TIME=$(date +%s) | ||
|
|
||
| # Execute the import command | ||
| bundle exec fontist import sil --formulas-dir Formulas/sil 2>&1 | tee import-output.log | ||
| EXIT_CODE=${PIPESTATUS[0]} | ||
|
|
||
| END_TIME=$(date +%s) | ||
| DURATION=$((END_TIME - START_TIME)) | ||
|
|
||
| # Save metrics | ||
| echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT | ||
| echo "duration=$DURATION" >> $GITHUB_OUTPUT | ||
|
|
||
| # Count generated formulas | ||
| FORMULA_COUNT=$(find Formulas/sil -name "*.yml" 2>/dev/null | wc -l) | ||
| echo "formula_count=$FORMULA_COUNT" >> $GITHUB_OUTPUT | ||
|
|
||
| exit $EXIT_CODE | ||
|
|
||
| - name: Generate import report | ||
| if: always() | ||
| run: | | ||
| echo "## SIL Import Report" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### Results" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Exit code:** ${{ steps.import.outputs.exit_code }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Duration:** ${{ steps.import.outputs.duration }}s" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Formulas generated:** ${{ steps.import.outputs.formula_count }}" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| if [ "${{ steps.import.outputs.exit_code }}" != "0" ]; then | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### ⚠️ Import completed with errors" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "### ✅ Import completed successfully" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| - name: Upload import logs | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: sil-import-logs-${{ github.run_id }} | ||
| path: import-output.log | ||
| retention-days: 7 | ||
|
|
||
| - name: Check for formula changes | ||
| id: check-changes | ||
| if: success() | ||
| run: | | ||
| if [ -n "$(git status --porcelain Formulas/sil)" ]; then | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "### 📝 Formula Changes Detected" >> $GITHUB_STEP_SUMMARY | ||
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | ||
| git status --short Formulas/sil | head -20 >> $GITHUB_STEP_SUMMARY | ||
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||
| echo "### ℹ️ No formula changes" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| - name: Commit changes | ||
| if: success() && steps.check-changes.outputs.has_changes == 'true' | ||
| uses: EndBug/add-and-commit@v7 | ||
| with: | ||
| add: Formulas/sil | ||
| default_author: github_actions | ||
| message: 'chore(formulas): update SIL fonts' | ||
|
|
||
| - name: Create issue on repeated failures | ||
| if: failure() && github.event_name == 'schedule' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const issueTitle = '🔴 SIL Import Failed'; | ||
| const issueBody = ` | ||
| ## Import Failure Report | ||
|
|
||
| The scheduled SIL fonts import failed. | ||
|
|
||
| ### Details | ||
| - **Run ID:** ${{ github.run_id }} | ||
| - **Run URL:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| - **Duration:** ${{ steps.import.outputs.duration }}s | ||
|
|
||
| ### Action Required | ||
| - Review the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | ||
| - Check the uploaded artifacts for detailed error information | ||
| - SIL website structure may have changed | ||
|
|
||
| ### Artifacts | ||
| - Import logs: \`sil-import-logs-${{ github.run_id }}\` | ||
| `; | ||
|
|
||
| // Check for existing open issues | ||
| const issues = await github.rest.issues.listForRepo({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| labels: 'sil-import,automated' | ||
| }); | ||
|
|
||
| const existingIssue = issues.data.find(issue => | ||
| issue.title === issueTitle | ||
| ); | ||
|
|
||
| if (existingIssue) { | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: existingIssue.number, | ||
| body: `Another failure occurred:\n\n${issueBody}` | ||
| }); | ||
| } else { | ||
| await github.rest.issues.create({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| title: issueTitle, | ||
| body: issueBody, | ||
| labels: ['sil-import', 'automated', 'bug'] | ||
| }); | ||
| } No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
In general, fix this class of issue by adding an explicit permissions: block either at the workflow root (to apply to all jobs) or inside each job, granting only the scopes actually required. This documents required access and prevents the workflow from silently acquiring broader privileges if repository defaults change.
For this specific workflow in .github/workflows/sil.yml, the import job needs:
contents: writeto commit changes viaEndBug/add-and-commit@v7.issues: writeto create or comment on issues viaactions/github-script@v7.
No other elevated scopes are required. The rest of the steps only need read access to the repository and the ability to upload artifacts (which does not require extra token scopes).
The best minimal fix is to add a permissions: block under jobs.import (around line 10–11), e.g.:
jobs:
import:
runs-on: ubuntu-latest
permissions:
contents: write
issues: writeThis preserves existing functionality (committing changes and managing issues) while constraining the token so that it cannot, for example, write to pull requests or workflows. No additional imports or dependencies are needed, as this is purely a workflow configuration change.
| @@ -8,6 +8,9 @@ | ||
| jobs: | ||
| import: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Checkout formulas repository |
- google: use --formulas-path and --schema-version 5 - sil: use --output-path and --schema-version 5 - macos: use --output-path instead of deprecated --formulas-dir
- Clone google/fonts repository instead of using API key - Use --source-path and --output-path options - Add cache for google/fonts repo clone
3690da3 to
bdff1f0
Compare
There was a problem hiding this comment.
Pull request overview
Adds Fontist formula schema v5 support across the repository, including updated formulas and new automation/workflows to import and validate formulas under the new schema.
Changes:
- Migrate many existing formulas to
schema_version: 5and add multi-format resources (TTF/WOFF2) + variable font metadata where applicable. - Add scheduled import workflows for Google/macOS/SIL formulas and a new “formula health” workflow with schema + URL validation scripts.
- Introduce repository scripts to validate schema structure and check resource URL accessibility.
Reviewed changes
Copilot reviewed 105 out of 4289 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| Formulas/google/allerta_stencil.yml | Migrates formula to schema v5 and adds multi-format (ttf/woff2) resources. |
| Formulas/google/allerta.yml | Migrates formula to schema v5 and adds multi-format (ttf/woff2) resources. |
| Formulas/google/alkalami.yml | Migrates formula to schema v5 and adds multi-format resources; updates license fields. |
| Formulas/google/alike.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/aldrich.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/alatsi.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/alata.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/akaya_kanadaka.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/agu_display.yml | Adds new schema v5 formula with variable font resources/axes. |
| Formulas/google/agbalumo.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/adlam_display.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/actor.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/acme.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/aclonica.yml | Migrates formula to schema v5 and restructures licensing metadata. |
| Formulas/google/aboreto.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/google/abel.yml | Migrates formula to schema v5 and adds multi-format resources. |
| Formulas/gnu_freefont.yml | Sets schema_version: 5 on existing formula. |
| Formulas/georgia.yml | Sets schema_version: 5 on existing formula. |
| Formulas/genkaimincho.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoposunnyday.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoposubway.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoposolid.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontopooriental.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoponikukyu.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoponihongo.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontoponeutral.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fontopofontopo.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fixedsys_excelsior.yml | Adds schema_version: 5 and resource format metadata. |
| Formulas/fira_code.yml | Sets schema_version: 5 on existing formula. |
| Formulas/ferrum.yml | Sets schema_version: 5 on existing formula. |
| Formulas/fa-1.yml | Sets schema_version: 5 on existing formula. |
| Formulas/f1.8.yml | Sets schema_version: 5 on existing formula. |
| Formulas/eurofix.yml | Sets schema_version: 5 on existing formula. |
| Formulas/euphemia.yml | Sets schema_version: 5 on existing formula. |
| Formulas/eunomia.yml | Sets schema_version: 5 on existing formula. |
| Formulas/emoir-kaku.yml | Sets schema_version: 5 on existing formula. |
| Formulas/eb_garamond.yml | Sets schema_version: 5 on existing formula. |
| Formulas/dmca_sans_serif_10.0_dev1.yml | Sets schema_version: 5 and tweaks license block formatting. |
| Formulas/dmca_sans_serif.yml | Sets schema_version: 5 and tweaks license block formatting. |
| Formulas/dengxian.yml | Sets schema_version: 5 on existing formula. |
| Formulas/dejavu.yml | Sets schema_version: 5 and wraps description across lines. |
| Formulas/courier_prime_sans.yml | Sets schema_version: 5 on existing formula. |
| Formulas/courier_prime_medium_and_semibold.yml | Sets schema_version: 5 on existing formula. |
| Formulas/courier_prime_code.yml | Sets schema_version: 5 on existing formula. |
| Formulas/courier_prime.yml | Sets schema_version: 5 on existing formula. |
| Formulas/courier.yml | Sets schema_version: 5 on existing formula. |
| Formulas/comic.yml | Sets schema_version: 5 on existing formula. |
| Formulas/cleartype.yml | Sets schema_version: 5 and adjusts license agreement scalar formatting. |
| Formulas/cinderella.yml | Sets schema_version: 5 on existing formula. |
| Formulas/chinese_traditional.yml | Sets schema_version: 5 on existing formula. |
| Formulas/chinese_simplified.yml | Sets schema_version: 5 on existing formula. |
| Formulas/carlito.yml | Sets schema_version: 5 on existing formula. |
| Formulas/buddhism.yml | Sets schema_version: 5 on existing formula. |
| Formulas/bokutachinogothic2regular.yml | Sets schema_version: 5 on existing formula. |
| Formulas/bokutachinogothic2bold.yml | Sets schema_version: 5 on existing formula. |
| Formulas/bokutachinogothic.yml | Sets schema_version: 5 on existing formula. |
| Formulas/au_passata_oblique.yml | Sets schema_version: 5 and collapses open_license to a single-line scalar. |
| Formulas/au_passata_light_bold.yml | Sets schema_version: 5 and collapses open_license to a single-line scalar. |
| Formulas/au.yml | Sets schema_version: 5 and collapses open_license to a single-line scalar. |
| Formulas/asatte.yml | Sets schema_version: 5 on existing formula. |
| Formulas/arial_black.yml | Sets schema_version: 5 on existing formula. |
| Formulas/arabic.yml | Sets schema_version: 5 on existing formula. |
| Formulas/andale.yml | Sets schema_version: 5 on existing formula. |
| Formulas/akabara-cinderella.yml | Sets schema_version: 5 on existing formula. |
| Formulas/adobe_reader_20.yml | Sets schema_version: 5 on existing formula. |
| Formulas/adobe_reader_19.yml | Sets schema_version: 5 on existing formula. |
| .github/workflows/sil.yml | Adds scheduled SIL import workflow using schema v5. |
| .github/workflows/metanorma.yml | Overrides fontist gem source during CI to use v5 schema branch. |
| .github/workflows/macos.yml | Adds scheduled macOS import workflow with matrix for font frameworks and schema v5 output. |
| .github/workflows/google.yml | Refactors Google import workflow to use local google/fonts repo cache and schema v5 output. |
| .github/workflows/formula-health.yml | Adds tiered “health check” workflow for schema and URL validation (tier2 currently disabled). |
| .github/scripts/validate_schema.rb | Adds schema validator for v5/v4 formulas. |
| .github/scripts/install_formulas.rb | Adds installation test script (used by formula-health tier2; currently disabled). |
| .github/scripts/check_urls.rb | Adds concurrent URL accessibility checker for formula resources. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@ronaldtse I'd like to hand this back to you. The remaining spec failures are due to private Metanorma fonts. We'll need a PAT token to fix them with Failures:
1) Metanorma::Compile allow mapping of tastes to implemented flavors
Failure/Error:
expect do
Metanorma::Compile.new.compile("spec/assets/test.adoc",
type: "oiml",
extension_keys: %i[xml presentation],
agree_to_terms: true)
end.not_to raise_error
expected no Exception, got #<SystemExit: exit> with backtrace:
# ./lib/metanorma/util/util.rb:12:in `abort'
# ./lib/metanorma/util/util.rb:12:in `log'
# ./lib/metanorma/util/fontist_helper.rb:36:in `rescue in install_fonts_safe'
# ./lib/metanorma/util/fontist_helper.rb:30:in `install_fonts_safe'
# ./lib/metanorma/util/fontist_helper.rb:98:in `install_fonts'
# ./lib/metanorma/compile/compile_options.rb:89:in `font_install'
# ./lib/metanorma/compile/render.rb:61:in `block in gather_and_install_fonts'
# ./lib/metanorma/compile/render.rb:59:in `each'
# ./lib/metanorma/compile/render.rb:59:in `gather_and_install_fonts'
# ./lib/metanorma/compile/render.rb:16:in `generate_outputs_parallel'
# ./lib/metanorma/compile/compile.rb:162:in `generate_outputs'
# ./lib/metanorma/compile/compile.rb:70:in `compile'
# ./spec/compile/compile_spec.rb:704:in `block (3 levels) in <top (required)>'
# ./spec/compile/compile_spec.rb:703:in `block (2 levels) in <top (required)>'
# ./spec/compile/compile_spec.rb:16:in `block (2 levels) in <top (required)>'
# ./vendor/bundle/ruby/3.2.0/gems/rspec-command-1.0.3/lib/rspec_command.rb:47:in `block (2 levels) in <module:RSpecCommand>'
# ./vendor/bundle/ruby/3.2.0/gems/rspec-command-1.0.3/lib/rspec_command.rb:45:in `block in <module:RSpecCommand>'
# ./spec/spec_helper.rb:37:in `block (4 levels) in <top (required)>'
# ./spec/spec_helper.rb:37:in `chdir'
# ./spec/spec_helper.rb:37:in `block (3 levels) in <top (required)>'
# ./spec/spec_helper.rb:30:in `block (2 levels) in <top (required)>'
# ./spec/compile/compile_spec.rb:703:in `block (2 levels) in <top (required)>'
# ./spec/compile/compile_spec.rb:16:in `block (2 levels) in <top (required)>'
# ./vendor/bundle/ruby/3.2.0/gems/rspec-command-1.0.3/lib/rspec_command.rb:47:in `block (2 levels) in <module:RSpecCommand>'
# ./vendor/bundle/ruby/3.2.0/gems/rspec-command-1.0.3/lib/rspec_command.rb:45:in `block in <module:RSpecCommand>'
# ./spec/spec_helper.rb:37:in `block (4 levels) in <top (required)>'
# ./spec/spec_helper.rb:37:in `chdir'
# ./spec/spec_helper.rb:37:in `block (3 levels) in <top (required)>'
# ./spec/spec_helper.rb:30:in `block (2 levels) in <top (required)>'
Finished in 12 minutes 33 seconds (files took 2.91 seconds to load)
117 examples, 1 failure |
|
The private font issue was fixed here already: Anything else blocking us @HassanAkbar from merging? Thanks. |
|
@ronaldtse This is ready now. All spec failures are coming from Metanorma (failing Relaton specs). Instead of merging this into |
Agree that this is completed. So we can close this now as the code is already in v5, and we directly use v5. |
Summary
Changes
docs/V5_MIGRATION_PLAN.mdwith comprehensive migration strategyfontist/fontist#feat/v5-schema-multi-formatSchema v5 Features
schema_version: 5attributeformat: ttf,format: woff2)variable_axes: ["wght", "wdth"])Next Steps
--schema-version=5Testing
Dependencies