Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/actions/setup-windows-opengl/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Set up Windows software OpenGL
description: Install a pinned Mesa driver on the runner for native graphics smoke checks.
runs:
using: composite
steps:
- shell: pwsh
run: |
# Hyper-V's inbox OpenGL driver lacks Processing's framebuffer support.
# Install the CI host driver after packaging; downloads keep their own runtime.
$mesaDirectory = Join-Path $env:RUNNER_TEMP 'scratch4j-mesa'
$mesaArchive = Join-Path $env:RUNNER_TEMP 'mesa3d-26.2.4-release-msvc.7z'
Invoke-WebRequest 'https://github.com/pal1000/mesa-dist-win/releases/download/26.2.4/mesa3d-26.2.4-release-msvc.7z' -OutFile $mesaArchive
$expectedHash = '351fc8c8b695878ffb3eaa044b3ead08672a48b1a045e3c3e3975811df0f6695'
if ((Get-FileHash $mesaArchive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expectedHash) {
throw 'Mesa archive checksum mismatch'
}
& 7z x -y "-o$mesaDirectory" $mesaArchive | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'Mesa archive extraction failed' }
& (Join-Path $mesaDirectory 'systemwidedeploy.cmd') 1
if ($LASTEXITCODE -ne 0) { throw 'Mesa driver installation failed' }
if (!(Test-Path (Join-Path $env:SystemRoot 'System32/mesadrv.dll'))) {
throw 'Mesa system OpenGL driver is missing'
}
'GALLIUM_DRIVER=llvmpipe' >> $env:GITHUB_ENV
'LIBGL_ALWAYS_SOFTWARE=1' >> $env:GITHUB_ENV
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,26 @@ jobs:
- name: Build and test
run: mvn --batch-mode --no-transfer-progress verify

- name: Identify the bundled library release
if: runner.os == 'Linux'
id: library-release
run: |
python3 - <<'PY'
import os
import xml.etree.ElementTree as ET
namespace = '{http://maven.apache.org/POM/4.0.0}'
version = ET.parse('pom.xml').findtext(f'{namespace}properties/{namespace}scratch.version')
if not version:
raise SystemExit('Missing bundled library version')
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
print('ref=v' + version, file=output)
PY
- name: Check shared release metadata
if: runner.os == 'Linux'
uses: actions/checkout@v7
with:
repository: openpatch/scratch-for-java
ref: ${{ steps.library-release.outputs.ref }}
path: .validation/library
- name: Set up the catalog toolchain
if: runner.os == 'Linux'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ jobs:
& $signtool.FullName sign /f $pfx /p $env:WINDOWS_CERTIFICATE_PASSWORD /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 $_.FullName
}

- name: Set up Windows software OpenGL
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-opengl

- name: Start packaged Studio and run offline projects
shell: bash
run: |
Expand Down
2 changes: 1 addition & 1 deletion scripts/smoke-packaged.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
report = Path(temporary) / "report.txt"
message = report.read_text() if report.is_file() else "No packaged smoke report"
if result.returncode or not message.startswith("PASS:"):
raise SystemExit(message + "\n" + result.stdout[-2000:] + result.stderr[-4000:])
raise SystemExit(message + "\n" + result.stdout[-64000:] + result.stderr[-10000:])
print(message.strip())
18 changes: 17 additions & 1 deletion ui/src/main/java/org/openpatch/scratch4j/ui/PackagedSmoke.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,32 @@ static void start(StudioApp app, javafx.stage.Stage stage, Path output) {
Files.writeString(project.root().resolve("List.java"), "public class List<T> {}\n");
}
List<String> errors = new java.util.concurrent.CopyOnWriteArrayList<>();
List<String> outputLines = new java.util.concurrent.CopyOnWriteArrayList<>();
AtomicLong frames = new AtomicLong(-1);
RunHandle handle = new ProjectRunner().run(project,
RunConfig.of(project.startStage()).withJava(java).withControl().withExitAfter(4),
new RunListener() {
public void onStderr(String line) { errors.add(line); }
public void onStdout(String line) { outputLines.add(line); }
public void onFrames(long count) { frames.set(count); }
});
int code;
try { code = handle.exitFuture().get(40, TimeUnit.SECONDS); }
catch (Exception e) { handle.stop(); throw e; }
catch (Exception e) {
Path jcmd = java.resolveSibling(isWindows() ? "jcmd.exe" : "jcmd");
try {
if (Files.isRegularFile(jcmd)) {
Process dump = new ProcessBuilder(jcmd.toString(), Long.toString(handle.pid()),
"Thread.print").inheritIO().start();
if (!dump.waitFor(5, TimeUnit.SECONDS)) dump.destroyForcibly();
}
} catch (Exception diagnosticError) {
System.err.println("Thread diagnostic failed: " + diagnosticError);
}
handle.stop();
throw new IllegalStateException(name + " timed out; frames=" + frames.get()
+ "; stdout=" + outputLines + "; stderr=" + errors, e);
}
if (code != 0 || frames.get() <= 0) throw new IllegalStateException(name + " did not draw: " + code + " " + errors);
Path source = project.root().resolve("MyStage.java");
String saved = Files.readString(source);
Expand Down
Loading