Skip to content

Fix finding external Musical Text Fonts and their metadata.json files#33757

Open
Jojo-Schmitz wants to merge 2 commits into
musescore:mainfrom
Jojo-Schmitz:external-smulf-fonts
Open

Fix finding external Musical Text Fonts and their metadata.json files#33757
Jojo-Schmitz wants to merge 2 commits into
musescore:mainfrom
Jojo-Schmitz:external-smulf-fonts

Conversation

@Jojo-Schmitz

@Jojo-Schmitz Jojo-Schmitz commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Fix finding external Musical Text Fonts, if those don't have a space before the "Text" in their filename.

Pretty much looks like the original code had a copy/paste error here.

Log before the change (tested with private fonts):

2026-06-09T18:41:44.295 | INFO  | main_thread     | EngravingFontsController::scanDirectory | Adding custom SMuFL font: "Bettenhoven" 
    symbol font path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/Bettenhoven.otf
    text font path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/Bettenhoven.otf
    metadata path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/metadata.json

So instead of BettenhovenText.otf it finds (and loads) Bettenhoven.otf.

Log after:

2026-06-09T19:18:12.608 | INFO  | main_thread     | EngravingFontsController::scanDirectory | Adding custom SMuFL font: "Bettenhoven" 
    symbol font path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/Bettenhoven.otf
    text font path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/BettenhovenText.otf
    metadata path: C:/Users/USERNAME/Documents/MuseScore5Studio/Score Fonts/Bettenhoven/metadata.json

Avoids the need to rename those Text font files

Also make sure their metadata.json files' names follow common naming conventions rather that doing a wildcard search on "*.json" and picking the last match

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR changes EngravingFontsController::scanDirectory() to alter metadata discovery and font resolution. Metadata is now looked up first as .json; private directories get additional fallbacks (lowercased/no-spaces _metadata.json, metadata.json, then any *.json), while non-private dirs are skipped if .json is missing. For fonts, symbolFontPath must be found via findFontPath(fontName) or the entry is skipped; textFontPath is tried as fontName + " Text", then with spaces removed + "Text", and finally falls back to symbolFontPath if unresolved.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning PR description identifies the issue and provides before/after logs, but omits required template sections. Add issue number (Resolves: #33757), CLA acknowledgment, confirm PR title/commit quality, and verify testing completed per template.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main changes: fixing detection of external Musical Text Fonts and their metadata.json files, which directly matches the changeset's focus on resolving text font paths and metadata discovery.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Linked repositories: Your configuration references 1 linked repositories, but your current plan allows 0. Analyzed ``, skipped musescore/muse_framework.git.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Jojo-Schmitz Jojo-Schmitz changed the title Fix finding external (private) Musical Text Fonts Fix finding external Musical Text Fonts Jun 9, 2026
Comment thread src/notation/internal/engravingfontscontroller.cpp
@Jojo-Schmitz

Copy link
Copy Markdown
Contributor Author

@cbjeukendrup mind to review? Seems to have been your code.

@cbjeukendrup cbjeukendrup left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to make sense to me. Probably indeed a copy paste mistake...

Comment thread src/notation/internal/engravingfontscontroller.cpp Outdated
@Jojo-Schmitz

Jojo-Schmitz commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

There another quirk, MuseScore look for the metadata.json files in an (inner) iterator, picking the last one it finds matching "*.json".
IMHO instead it should be looking for 3 different variants only and in a specific order:

  1. iterator.filename() + ".json", e.g.: "FontName.json", probably stop here, if isPrivate is true (IIRC it is documented that the name has to match the font name for system SMuFL fonts).
  2. iterator.filename().tolower() + "_metadata.json", e.g.: "fontname_metadata.json".
  3. "metadata.json"
  4. Optional, as an emergency exit, that old (inner) iterator might get used after that, maybe.

It should stop at the 1st find.

@cbjeukendrup ?

Example (taken all files from https://github.com/mikkopatama/eugenefont):
image
Here it (correctly) loads Eugene.otf, incorrectly doesn't load EugeneText.otf (fixed by this PR already) and incorrectly loads EugeneStrong.json instead of Eugene.json (it should only load EugeneStrong.otf and EugeneStrong.json if the directory's name were EugeneStrong).

@cbjeukendrup

Copy link
Copy Markdown
Collaborator

I haven't seen enough fonts to be able to judge whether those three variants are enough. If we want to be really thorough, we should perhaps consider all json files in the folder and use muse::strings::levenshteinDistance to determine which one is closest to either FontName.json, FontName_metadata.json, or metadata.json. That way, it would hopefully correctly handle differences in capitalisation and in space/underscore/hyphen/nothing.

@Jojo-Schmitz

Copy link
Copy Markdown
Contributor Author

I've so far only come accross those 3 variants, in 18 external and all the builtin fonts

@cbjeukendrup

Copy link
Copy Markdown
Collaborator

In that case let's go with your suggestion

if those don't have a space before the "Text" in their filename
@Jojo-Schmitz

Copy link
Copy Markdown
Contributor Author

@Jojo-Schmitz Jojo-Schmitz force-pushed the external-smulf-fonts branch 2 times, most recently from 05241c6 to 075ed44 Compare June 11, 2026 16:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/notation/internal/engravingfontscontroller.cpp`:
- Around line 117-124: The metadata fallback loop using QDirIterator populates
metadataPath by taking the last iterated JSON and then only checks
metadataPath.empty(), which can register an invalid/nonexistent metadata path
and is unstable when multiple JSONs exist; change the loop in the code that
builds metadataPath (the QDirIterator block) to deterministically select a
single metadata file (e.g., prefer a known filename like "metadata.json" or
immediately take the first matching file) and after selection verify the file
actually exists with QFileInfo::exists() before calling addExternalFont();
ensure addExternalFont() receives a validated, existing metadataPath so
EngravingFont::ensureLoad() won’t fail on missing/incorrect metadata.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 60b3d1d5-95ff-4091-b3b8-8180c3802bcb

📥 Commits

Reviewing files that changed from the base of the PR and between 05bca93 and 05241c6.

📒 Files selected for processing (1)
  • src/notation/internal/engravingfontscontroller.cpp

Comment thread src/notation/internal/engravingfontscontroller.cpp
@Jojo-Schmitz Jojo-Schmitz force-pushed the external-smulf-fonts branch from 075ed44 to c7e5fa4 Compare June 11, 2026 16:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/notation/internal/engravingfontscontroller.cpp`:
- Line 123: The single-line "continue;" in
src/notation/internal/engravingfontscontroller.cpp is mis-indented and failing
uncrustify; locate the continue statement inside the affected loop in the
EngravingFontsController implementation (the method containing the loop that
handles font resolution) and adjust its indentation to match the surrounding
block scope (align it with other statements inside that conditional/loop), then
re-run the codestyle check to confirm it passes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c675925-47b0-4a2f-a676-30de7f00037b

📥 Commits

Reviewing files that changed from the base of the PR and between 05241c6 and 075ed44.

📒 Files selected for processing (1)
  • src/notation/internal/engravingfontscontroller.cpp

Comment thread src/notation/internal/engravingfontscontroller.cpp Outdated
@Jojo-Schmitz

Jojo-Schmitz commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

I don't understand the unit test failure, I don't think my changes are the culprit. @coderabbitai?

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the check runs/status for PR `#33757`
gh pr checks 33757 --repo musescore/MuseScore 2>&1 | head -80

Length of output: 1596


🏁 Script executed:

#!/bin/bash
# Get recent PR comments and reviews to find any CI failure details
gh pr view 33757 --repo musescore/MuseScore --json statusCheckRollup 2>&1 | head -100

Length of output: 4242


🏁 Script executed:

#!/bin/bash
# Get the failing job log from the utest run
gh api /repos/musescore/MuseScore/actions/jobs/80854436260/logs 2>&1 | head -300

Length of output: 22806


🏁 Script executed:

#!/bin/bash
# Also check if there are annotations/failure details on the job
gh api /repos/musescore/MuseScore/actions/runs/27362803918/jobs 2>&1 | python3 -c "
import sys, json
data = json.load(sys.stdin)
for job in data.get('jobs', []):
    if job.get('conclusion') == 'failure':
        print('Job:', job['name'])
        print('Steps:')
        for step in job.get('steps', []):
            if step.get('conclusion') == 'failure':
                print('  FAILED step:', step['name'])
        print('Annotations:')
" 2>&1

gh api /repos/musescore/MuseScore/actions/runs/27362803918/jobs --jq '.jobs[] | select(.conclusion=="failure") | {name: .name, steps: [.steps[] | select(.conclusion=="failure") | .name]}' 2>&1

Length of output: 867


🏁 Script executed:

#!/bin/bash
# Get just the failure-relevant portion of the log
gh api /repos/musescore/MuseScore/actions/jobs/80854436260/logs 2>&1 | grep -A 30 -i "FAILED\|error\|assert\|fail\|PASS\|RUN\|test" | tail -200

Length of output: 21541


🏁 Script executed:

#!/bin/bash
# Check annotations on the run for test failure details
gh api /repos/musescore/MuseScore/check-runs/80854436260/annotations 2>&1 | head -100

Length of output: 504


🏁 Script executed:

#!/bin/bash
# Get the log and search specifically around muse_global_tests
gh api /repos/musescore/MuseScore/actions/jobs/80854436260/logs 2>&1 | grep -A 80 "muse_global_tests" | head -120

Length of output: 10687


🏁 Script executed:

#!/bin/bash
# Check if this test also fails on main branch (recent runs)
gh api /repos/musescore/MuseScore/actions/workflows --jq '.workflows[] | select(.name | test("Unit Tests|utest"; "i")) | {id: .id, name: .name}' 2>&1

Length of output: 319


🏁 Script executed:

#!/bin/bash
# Look for the actual muse_global_tests runtime output (CTest prefixes lines with "1: ")
gh api /repos/musescore/MuseScore/actions/jobs/80854436260/logs 2>&1 | grep -E "^\s*(2026-[^ ]+ 1: |.*1: .*FAILED|.*1: .*PASSED|.*1: \[)" | head -100

Length of output: 9900


🏁 Script executed:

#!/bin/bash
# Also check recent runs of the utest workflow on main to see if this is a pre-existing failure
gh api "/repos/musescore/MuseScore/actions/workflows/111488818/runs?branch=main&per_page=5" \
  --jq '.workflow_runs[] | {id: .id, conclusion: .conclusion, created_at: .created_at}' 2>&1

Length of output: 729



@Jojo-Schmitz: Your changes are not the culprit. The failing test is muse_global_tests (from the muse_framework submodule, under muse/framework/global/tests/), which is completely unrelated to your changes in src/notation/internal/engravingfontscontroller.cpp.

More importantly, checking the scheduled main branch runs of the same workflow shows this test has been failing on main itself for at least four consecutive weekly runs before your PR was even created:

Run date Conclusion
2026-06-11 ❌ failure
2026-06-04 ❌ failure
2026-05-28 ❌ failure
2026-05-21 ❌ failure
2026-05-14 ✅ success

So this is a pre-existing, persistent failure on main that predates this PR by weeks. You can safely ignore it for the purposes of reviewing and merging this PR.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the check runs / status for PR `#33757`
gh pr checks 33757 --repo musescore/MuseScore 2>&1 | head -80

Length of output: 1598


🏁 Script executed:

#!/bin/bash
# Get recent workflow run failures linked to this PR
gh run list --repo musescore/MuseScore --branch external-smulf-fonts --limit 10 2>&1

Length of output: 1686


🏁 Script executed:

#!/bin/bash
# Get jobs and steps for the failing unit test run
gh run view 27362803918 --repo musescore/MuseScore 2>&1

Length of output: 933


🏁 Script executed:

#!/bin/bash
# Get the failed job log output (truncated)
gh run view 27362803918 --repo musescore/MuseScore --log-failed 2>&1 | head -200

Length of output: 19707


🏁 Script executed:

#!/bin/bash
# Get more of the failed log, focusing on the test failure section
gh run view 27362803918 --repo musescore/MuseScore --log-failed 2>&1 | grep -A 5 -i "FAILED\|error\|assert\|test.*fail\|fail.*test\|CRASH\|segfault\|exit code\|Run tests" | head -150

Length of output: 19787


🏁 Script executed:

#!/bin/bash
# Also check if the same test failure exists on main branch recently
gh run list --repo musescore/MuseScore --branch main --workflow "Check: Unit Tests (utest)" --limit 5 2>&1

Length of output: 860


🏁 Script executed:

#!/bin/bash
# Check the most recent main branch failure - get the specific test failures
gh run view 27323913973 --repo musescore/MuseScore --log-failed 2>&1 | grep -i "FAILED\|PASS\|ERROR\|\*\*\*\|assertion\| fail\b" | grep -v "warning\|unused param\|Wunused" | head -80

Length of output: 13633


🏁 Script executed:

#!/bin/bash
# Same for the PR run
gh run view 27362803918 --repo musescore/MuseScore --log-failed 2>&1 | grep -i "FAILED\|PASS\|ERROR\|\*\*\*\|assertion\| fail\b" | grep -v "warning\|unused param\|Wunused" | head -80

Length of output: 13822


🏁 Script executed:

#!/bin/bash
# Get last portion of the failed log to see actual test failures
gh run view 27362803918 --repo musescore/MuseScore --log-failed 2>&1 | tail -150

Length of output: 18772


🏁 Script executed:

#!/bin/bash
# Also get the last part of the main branch failure for comparison
gh run view 27323913973 --repo musescore/MuseScore --log-failed 2>&1 | tail -60

Length of output: 8984



@Jojo-Schmitz You're right — your changes are not the culprit. Here's what the logs show:

The failing test: muse_global_tests (1 out of 29 tests failed, exit code 8).

It's a pre-existing failure on main: The "Check: Unit Tests (utest)" workflow has been failing on the main branch on every scheduled run for the past several weeks:

Run date Result
2026-06-11 ❌ failure
2026-06-04 ❌ failure
2026-05-28 ❌ failure
2026-05-21 ❌ failure
2026-05-14 ✅ success

The muse_global_tests failure has existed in main since at least May 21st — weeks before this PR was opened. Your changes only touch src/notation/internal/engravingfontscontroller.cpp, which has no relationship to muse_global_tests. The CI failure can be safely ignored for the purpose of reviewing this PR.

🐇 ₍ᐢ. .ᐢ₎

@Jojo-Schmitz

Jojo-Schmitz commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai: why then are other recent PRs if mine are not faíling the same way?

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# List recent open/merged PRs targeting main
gh pr list --repo musescore/MuseScore --base main --limit 10 --state all \
  --json number,title,headRefName,createdAt,state,statusCheckRollup 2>&1 | \
  python3 -c "
import sys, json
prs = json.load(sys.stdin)
for pr in prs:
    checks = pr.get('statusCheckRollup') or []
    utest = [c for c in checks if 'utest' in c.get('name','').lower() or 'unit' in c.get('name','').lower()]
    status = [(c.get('name'), c.get('conclusion') or c.get('state')) for c in utest]
    print(f\"PR #{pr['number']} ({pr['state']}): {pr['title'][:60]}\")
    print(f\"  utest checks: {status}\")
"

Length of output: 1441


🏁 Script executed:

#!/bin/bash
# Check what triggered the utest run on this PR specifically
gh run list --repo musescore/MuseScore --branch external-smulf-fonts --limit 20 2>&1

echo "---"
# Check what event triggered run 27362803918
gh run view 27362803918 --repo musescore/MuseScore --json event,triggerActor,headBranch,workflowName 2>&1

echo "---"
# Check the utest workflow triggers
gh api /repos/musescore/MuseScore/actions/workflows/111488818 --jq '{name:.name, path:.path}' 2>&1

echo "---"
# List all workflow runs for utest on PR branches (not main/scheduled)
gh api "/repos/musescore/MuseScore/actions/workflows/111488818/runs?per_page=10" \
  --jq '.workflow_runs[] | {id:.id, event:.event, branch:.head_branch, conclusion:.conclusion, created_at:.created_at}' 2>&1

Length of output: 5408



@Jojo-Schmitz I owe you a correction — my previous analysis was incomplete. The utest workflow does run on all PRs, and it passes on other PRs. Here's what the data actually shows:

Branch utest result Time
external-smulf-fonts (this PR) ❌ failure 2026-06-11 16:45
date-macros ✅ success 2026-06-11 18:18
framework_update ✅ success 2026-06-11 16:09
page-locks ✅ success 2026-06-11 13:57

So the failing muse_global_tests is intermittent/flaky, not a hardcoded broken test on main. It fails on some runs and passes on others, regardless of what code is being changed. The scheduled main runs happened to catch several failures in a row, but PR runs show it can pass just fine.

Your changes are still not the cause (they're completely unrelated to muse_global_tests), but I should have been clearer earlier: it's a flaky test that sometimes fails, not a reliably broken one. You could simply re-run the failing CI job to likely get a green result.

🐇 ₍ᐢ. .ᐢ₎

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get recent PRs on the main branch to compare their CI status
gh pr list --repo musescore/MuseScore --base main --limit 10 --json number,title,headRefName,statusCheckRollup 2>&1 | python3 -c "
import sys, json
data = json.load(sys.stdin)
for pr in data:
    print(f\"PR #{pr['number']}: {pr['title'][:60]}\")
    checks = pr.get('statusCheckRollup', [])
    for c in checks:
        name = c.get('name', c.get('context', '?'))
        status = c.get('conclusion') or c.get('state') or c.get('status', '?')
        if 'test' in name.lower() or 'utest' in name.lower() or 'unit' in name.lower():
            print(f\"  CHECK: {name} -> {status}\")
    print()
" 2>&1

Length of output: 2272


🏁 Script executed:

#!/bin/bash
# Check when PR `#33779` (Framework update) was merged, and its details
gh pr view 33779 --repo musescore/MuseScore --json number,title,mergedAt,mergeCommit,baseRefName 2>&1

echo "---"

# Check current status of PR `#33757` checks in more detail
gh pr checks 33757 --repo musescore/MuseScore 2>&1

echo "---"

# Check if there have been any newer CI runs on this PR branch
gh run list --repo musescore/MuseScore --branch external-smulf-fonts --limit 5 2>&1

Length of output: 2787


🏁 Script executed:

#!/bin/bash
# Get the run_tests workflow runs for PR `#33780` to compare with `#33757`
gh run list --repo musescore/MuseScore --branch fix-date-macros-format --limit 5 2>&1 || true

# Also check which branch PR `#33780` is on
gh pr view 33780 --repo musescore/MuseScore --json headRefName,statusCheckRollup 2>&1 | python3 -c "
import sys, json
data = json.load(sys.stdin)
print('Branch:', data['headRefName'])
for c in data.get('statusCheckRollup', []):
    name = c.get('name', c.get('context', '?'))
    status = c.get('conclusion') or c.get('state') or '?'
    url = c.get('detailsUrl', c.get('targetUrl', ''))
    print(f'  {name} -> {status}  {url}')
" 2>&1

echo "==="
# Now check the actual job IDs for the failing utest run on `#33757` vs a passing one
# Get created_at timestamps for the runs
gh api /repos/musescore/MuseScore/actions/runs/27362803918 --jq '{id: .id, name: .name, created_at: .created_at, head_sha: .head_sha}' 2>&1
echo "---"
# And check what muse_framework submodule commit the PR is at vs main
gh api /repos/musescore/MuseScore/contents/muse --ref external-smulf-fonts --jq '{sha: .sha}' 2>&1 || true
gh api /repos/musescore/MuseScore/contents/muse --ref main --jq '{sha: .sha}' 2>&1 || true

Length of output: 5710


🏁 Script executed:

#!/bin/bash
# Check when `#33780`'s utest run was created
gh api /repos/musescore/MuseScore/actions/runs/27368123783 --jq '{id: .id, name: .name, created_at: .created_at, head_sha: .head_sha}' 2>&1

echo "---"

# Check recent scheduled utest runs on main to see if the failure was fixed
gh api "/repos/musescore/MuseScore/actions/workflows/111488818/runs?per_page=8" \
  --jq '.workflow_runs[] | {id: .id, conclusion: .conclusion, created_at: .created_at, event: .event, head_branch: .head_branch}' 2>&1

Length of output: 1755



@Jojo-Schmitz: Mystery solved — it's a flaky test. Here's the timeline of the muse_global_tests utest runs on PR branches yesterday:

Time (UTC) Branch Result
16:45:25 external-smulf-fonts (your PR) ❌ failure
18:18:04 date-macros (#33780) ✅ success

There was no code change on main between these two runs — they're just 1.5 hours apart and triggered by normal PR push events. The test simply passed on one run and failed on the other. That's a textbook flaky test.

This is also consistent with the scheduled main runs: the test wasn't failing 100% of the time (it passed on May 14th), so it's not a hard regression — just an unreliable test in muse_global_tests that fails non-deterministically. You were unlucky that your CI run happened to hit a bad run window, while the other PRs ran during a clean window.

🐰 ¯_(ツ)_/¯

So far all fonts I've encountered have their metadata.json named "FontName.json" (mixed case, possible containing spaces, same as the fontname itself, the only documented option for non-private fonts), "fontname_metadata.json" (all lowercase, no spaces) or "metadata.json" (lowercase), so let's search for these, in that order and stop at the 1st hit.
As a last reseort leave the previous iteration method (which stops at the last match for "*.json").
@Jojo-Schmitz Jojo-Schmitz force-pushed the external-smulf-fonts branch from 2f9b456 to 5909a28 Compare June 11, 2026 22:37
@Jojo-Schmitz

Jojo-Schmitz commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

OK, let's see whether another run succeeds

Edit: it does indeed

@Jojo-Schmitz Jojo-Schmitz changed the title Fix finding external Musical Text Fonts Fix finding external Musical Text Fonts and their metadata.json files Jun 11, 2026
@mathesoncalum mathesoncalum self-requested a review June 15, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants