Skip to content

Fix JavaDoc snippet validator and the snippets it surfaced (#4944) #3080

Fix JavaDoc snippet validator and the snippets it surfaced (#4944)

Fix JavaDoc snippet validator and the snippets it surfaced (#4944) #3080

Workflow file for this run

name: Test iOS UI build scripts
on:
pull_request:
paths:
- '.github/workflows/scripts-ios.yml'
- '.github/workflows/_build-ios-port.yml'
- 'scripts/setup-workspace.sh'
- 'scripts/build-ios-port.sh'
- 'scripts/build-ios-app.sh'
- 'scripts/run-ios-ui-tests.sh'
- 'scripts/run-ios-native-tests.sh'
- 'scripts/ios/notification-tests/native-tests/**'
- 'scripts/ios/notification-tests/install-native-notification-tests.sh'
- 'scripts/ios/notification-tests/**'
- 'scripts/hellocodenameone/**'
- 'scripts/ios/tests/**'
- 'scripts/ios/screenshots/**'
- 'scripts/ios/screenshots-metal/**'
- 'scripts/templates/**'
- '!scripts/templates/**/*.md'
- 'CodenameOne/src/**'
- '!CodenameOne/src/**/*.md'
- 'Ports/iOSPort/**'
- '!Ports/iOSPort/**/*.md'
- 'native-themes/ios-modern/**'
- '!native-themes/ios-modern/**/*.md'
- 'vm/**'
- '!vm/**/*.md'
- 'tests/**'
- '!tests/**/*.md'
- '!docs/**'
- 'maven/**'
- '!maven/core-unittests/**'
push:
branches: [ master ]
paths:
- '.github/workflows/scripts-ios.yml'
- '.github/workflows/_build-ios-port.yml'
- 'scripts/setup-workspace.sh'
- 'scripts/build-ios-port.sh'
- 'scripts/build-ios-app.sh'
- 'scripts/run-ios-ui-tests.sh'
- 'scripts/run-ios-native-tests.sh'
- 'scripts/ios/notification-tests/native-tests/**'
- 'scripts/ios/notification-tests/install-native-notification-tests.sh'
- 'scripts/ios/notification-tests/**'
- 'scripts/hellocodenameone/**'
- 'scripts/ios/tests/**'
- 'scripts/ios/screenshots/**'
- 'scripts/ios/screenshots-metal/**'
- 'scripts/templates/**'
- '!scripts/templates/**/*.md'
- 'CodenameOne/src/**'
- '!CodenameOne/src/**/*.md'
- 'Ports/iOSPort/**'
- '!Ports/iOSPort/**/*.md'
- 'native-themes/ios-modern/**'
- '!native-themes/ios-modern/**/*.md'
- 'vm/**'
- '!vm/**/*.md'
- 'tests/**'
- '!tests/**/*.md'
- '!docs/**'
- 'maven/**'
- '!maven/core-unittests/**'
jobs:
build-port:
uses: ./.github/workflows/_build-ios-port.yml
build-ios:
needs: build-port
permissions:
contents: read
pull-requests: write
issues: write
runs-on: macos-15 # pinning macos-15 avoids surprises during the cutover window
timeout-minutes: 45 # only sample app build + UI tests now; iOS port build runs in build-port
concurrency: # ensure only one mac build runs at once
group: mac-ci-${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
env:
GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Cache CocoaPods and user gems
uses: actions/cache@v4
with:
path: |
~/.gem
~/Library/Caches/CocoaPods
~/.cocoapods/repos
key: ${{ runner.os }}-pods-v1-${{ hashFiles('scripts/setup-workspace.sh') }}
restore-keys: |
${{ runner.os }}-pods-v1-
- name: Ensure CocoaPods tooling
run: |
mkdir -p ~/.codenameone
cp maven/UpdateCodenameOne.jar ~/.codenameone/
set -euo pipefail
if ! command -v ruby >/dev/null; then
echo "ruby not found"; exit 1
fi
GEM_USER_DIR="$(ruby -e 'print Gem.user_dir')"
export PATH="$GEM_USER_DIR/bin:$PATH"
if ! command -v pod >/dev/null 2>&1; then
gem install cocoapods xcodeproj --no-document --user-install
fi
pod --version
- name: Compute setup-workspace hash
id: setup_hash
run: |
set -euo pipefail
echo "hash=$(shasum -a 256 scripts/setup-workspace.sh | awk '{print $1}')" >> "$GITHUB_OUTPUT"
- name: Compute CN1 source hash
id: src_hash
run: |
set -euo pipefail
SRC_HASH=$(find CodenameOne/src Ports/iOSPort vm/JavaAPI vm/ByteCodeTranslator Themes native-themes \
-type f \( -name '*.java' -o -name '*.m' -o -name '*.h' -o -name '*.xml' -o -name '*.properties' -o -name '*.css' \) 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
POM_HASH=$(find . -name 'pom.xml' -not -path './scripts/*' 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
SCRIPT_HASH=$(shasum -a 256 \
scripts/setup-workspace.sh \
scripts/build-ios-port.sh \
scripts/build-native-themes.sh \
.github/workflows/_build-ios-port.yml \
| shasum -a 256 | awk '{print $1}')
echo "hash=${SRC_HASH:0:16}-${POM_HASH:0:16}-${SCRIPT_HASH:0:16}" >> "$GITHUB_OUTPUT"
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV
- name: Cache codenameone-tools
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/codenameone-tools
key: ${{ runner.os }}-cn1-tools-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
${{ runner.os }}-cn1-tools-
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2-
- name: Restore cn1-binaries cache
uses: actions/cache@v4
with:
path: ../cn1-binaries
key: cn1-binaries-${{ runner.os }}-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
cn1-binaries-${{ runner.os }}-
- name: Restore built CN1 + iOS port artifacts
uses: actions/cache/restore@v4
with:
path: |
~/.m2/repository/com/codenameone
Themes
Ports/iOSPort/nativeSources
key: cn1-built-${{ runner.os }}-${{ steps.src_hash.outputs.hash }}
fail-on-cache-miss: true
- name: Build sample iOS app and compile workspace
id: build-ios-app
run: ./scripts/build-ios-app.sh -q -DskipTests
timeout-minutes: 30
- name: Run iOS UI screenshot tests
env:
ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/ios-ui-tests
run: |
set -euo pipefail
mkdir -p "${ARTIFACTS_DIR}"
echo "workspace='${{ steps.build-ios-app.outputs.workspace }}'"
echo "scheme='${{ steps.build-ios-app.outputs.scheme }}'"
./scripts/run-ios-ui-tests.sh \
"${{ steps.build-ios-app.outputs.workspace }}" \
"" \
"${{ steps.build-ios-app.outputs.scheme }}"
timeout-minutes: 30
- name: Upload iOS artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: ios-ui-tests
path: artifacts
if-no-files-found: warn
retention-days: 14
build-ios-metal:
# Mirrors build-ios but enables the Metal rendering backend via the
# codename1.arg.ios.metal=true build hint. Keeps the GL path untouched
# so a regression on either path is isolated in its own job. Part of
# the iOS Metal port migration -- see Ports/iOSPort/METAL_PORT_STATUS.md.
#
# continue-on-error while the Metal port is still in progress:
# screenshot comparisons will differ from golden images until DrawString
# is ported and ClipRect is re-enabled (Phase 2 follow-ups tracked in
# METAL_PORT_STATUS.md). The Metal job still runs on every PR that
# touches the paths below so we can watch for new regressions and
# download artifacts for comparison, but a failure here won't block
# the PR. Flip this to false (or remove the line) once the Metal
# variant matches the GL variant's screenshot set.
continue-on-error: true
needs: build-port
permissions:
contents: read
pull-requests: write
issues: write
runs-on: macos-15
timeout-minutes: 45
concurrency:
group: mac-ci-${{ github.workflow }}-metal-${{ github.ref_name }}
cancel-in-progress: true
env:
GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Cache CocoaPods and user gems
uses: actions/cache@v4
with:
path: |
~/.gem
~/Library/Caches/CocoaPods
~/.cocoapods/repos
key: ${{ runner.os }}-pods-v1-${{ hashFiles('scripts/setup-workspace.sh') }}
restore-keys: |
${{ runner.os }}-pods-v1-
- name: Ensure CocoaPods tooling
run: |
mkdir -p ~/.codenameone
cp maven/UpdateCodenameOne.jar ~/.codenameone/
set -euo pipefail
if ! command -v ruby >/dev/null; then
echo "ruby not found"; exit 1
fi
GEM_USER_DIR="$(ruby -e 'print Gem.user_dir')"
export PATH="$GEM_USER_DIR/bin:$PATH"
if ! command -v pod >/dev/null 2>&1; then
gem install cocoapods xcodeproj --no-document --user-install
fi
pod --version
- name: Compute setup-workspace hash
id: setup_hash
run: |
set -euo pipefail
echo "hash=$(shasum -a 256 scripts/setup-workspace.sh | awk '{print $1}')" >> "$GITHUB_OUTPUT"
- name: Compute CN1 source hash
id: src_hash
run: |
set -euo pipefail
SRC_HASH=$(find CodenameOne/src Ports/iOSPort vm/JavaAPI vm/ByteCodeTranslator Themes native-themes \
-type f \( -name '*.java' -o -name '*.m' -o -name '*.h' -o -name '*.xml' -o -name '*.properties' -o -name '*.css' \) 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
POM_HASH=$(find . -name 'pom.xml' -not -path './scripts/*' 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
SCRIPT_HASH=$(shasum -a 256 \
scripts/setup-workspace.sh \
scripts/build-ios-port.sh \
scripts/build-native-themes.sh \
.github/workflows/_build-ios-port.yml \
| shasum -a 256 | awk '{print $1}')
echo "hash=${SRC_HASH:0:16}-${POM_HASH:0:16}-${SCRIPT_HASH:0:16}" >> "$GITHUB_OUTPUT"
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV
- name: Cache codenameone-tools
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/codenameone-tools
key: ${{ runner.os }}-cn1-tools-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
${{ runner.os }}-cn1-tools-
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2-
- name: Restore cn1-binaries cache
uses: actions/cache@v4
with:
path: ../cn1-binaries
key: cn1-binaries-${{ runner.os }}-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
cn1-binaries-${{ runner.os }}-
- name: Restore built CN1 + iOS port artifacts
# build-port (the reusable workflow at .github/workflows/_build-ios-port.yml)
# populates this cache with the iOS port artifact + native themes + cn1
# Use the exact key the build-port job saved against. Recomputing
# the hash on this runner has been observed to produce a different
# value than build-port on the same SHA (suspected: find traversal
# picks up runner-specific filesystem metadata), causing a spurious
# cache miss. Reusing the published key sidesteps that.
uses: actions/cache/restore@v4
with:
path: |
~/.m2/repository/com/codenameone
Themes
Ports/iOSPort/nativeSources
key: ${{ needs.build-port.outputs.cn1_built_cache_key }}
fail-on-cache-miss: true
- name: Install Metal Toolchain
# Xcode 26+ requires the Metal Toolchain component to be downloaded
# explicitly before .metal files can compile. The runner's default
# xcodebuild is often an older Xcode whose -downloadComponent flag
# doesn't exist, so we point DEVELOPER_DIR at Xcode 26 first (same
# selection logic build-ios-app.sh uses). If the component is
# already cached on the runner image, xcodebuild exits quickly
# without re-downloading.
run: |
set -euo pipefail
XCODE_APP="$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -V | tail -n 1 || true)"
if [ ! -x "$XCODE_APP/Contents/Developer/usr/bin/xcodebuild" ]; then
echo "Xcode 26 not found under /Applications. Cannot install Metal Toolchain." >&2
exit 1
fi
echo "Using $XCODE_APP"
export DEVELOPER_DIR="$XCODE_APP/Contents/Developer"
"$DEVELOPER_DIR/usr/bin/xcodebuild" -downloadComponent MetalToolchain
timeout-minutes: 10
- name: Enable Metal backend for hellocodenameone
# -Dcodename1.arg.* on the mvnw CLI doesn't flow into the Codename
# One Maven plugin's BuildRequest -- the plugin reads build args
# from the codenameone_settings.properties file on disk. Inject the
# Metal flag there so IPhoneBuilder's useMetal path activates.
run: |
set -euo pipefail
SETTINGS=scripts/hellocodenameone/common/codenameone_settings.properties
if grep -q '^codename1\.arg\.ios\.metal=' "$SETTINGS"; then
sed -i '' 's|^codename1.arg.ios.metal=.*|codename1.arg.ios.metal=true|' "$SETTINGS"
else
# Insert next to the other ios.* keys (after applicationQueriesSchemes).
awk '
/^codename1\.arg\.ios\.applicationQueriesSchemes=/ {
print
print "codename1.arg.ios.metal=true"
next
}
{ print }
' "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS"
fi
echo "--- codenameone_settings.properties (ios.* keys after patch) ---"
grep -n 'codename1\.arg\.ios' "$SETTINGS" || true
- name: Build sample iOS app and compile workspace (Metal)
id: build-ios-app
run: ./scripts/build-ios-app.sh -q -DskipTests
timeout-minutes: 30
- name: Run iOS UI screenshot tests (Metal)
env:
ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/ios-ui-tests-metal
# Compare Metal output against the Metal-specific golden set.
# See scripts/ios/screenshots-metal/README.md for the rationale:
# the Metal backend will not be pixel-identical to the GL
# baselines (especially once CoreText glyph rendering lands).
SCREENSHOT_REF_DIR: ${{ github.workspace }}/scripts/ios/screenshots-metal
# Override the PR comment marker / preview path / title so this
# job posts its own comment instead of overwriting the GL job's
# comment (both jobs ran with the same default marker before, so
# whichever finished last clobbered the other's results).
CN1SS_COMMENT_MARKER: '<!-- CN1SS_IOS_METAL_COMMENT -->'
CN1SS_PREVIEW_SUBDIR: ios-metal
CN1SS_REPORT_TITLE: 'iOS Metal screenshot updates'
CN1SS_SUCCESS_MESSAGE: '✅ Native iOS Metal screenshot tests passed.'
CN1SS_COMMENT_LOG_PREFIX: '[run-ios-device-tests-metal]'
run: |
set -euo pipefail
mkdir -p "${ARTIFACTS_DIR}"
echo "workspace='${{ steps.build-ios-app.outputs.workspace }}'"
echo "scheme='${{ steps.build-ios-app.outputs.scheme }}'"
echo "reference dir='${SCREENSHOT_REF_DIR}'"
./scripts/run-ios-ui-tests.sh \
"${{ steps.build-ios-app.outputs.workspace }}" \
"" \
"${{ steps.build-ios-app.outputs.scheme }}"
timeout-minutes: 30
- name: Publish Metal screenshot summary
# Surfaces run-ios-ui-tests.sh's comparison result in the job's
# GitHub Actions summary page so the Metal port status is visible
# at a glance without digging into the artifact zip. Always runs
# so a failed or cancelled tests step still reports whatever got
# captured. The Python helper lives in scripts/ci/ because
# embedding Python heredocs inside a YAML "run: |" block is
# fragile -- unindented Python breaks the block scalar.
if: always()
env:
COMPARE_JSON: ${{ github.workspace }}/artifacts/ios-ui-tests-metal/screenshot-compare.json
COMMENT_MD: ${{ github.workspace }}/artifacts/ios-ui-tests-metal/screenshot-comment.md
run: |
set -eu
{
echo "## iOS Metal screenshot comparison"
echo
echo "Ran against \`scripts/hellocodenameone\` on the iOS simulator with \`codename1.arg.ios.metal=true\`."
echo "Golden images: \`scripts/ios/screenshots-metal/\` (Metal-specific baseline; see the README there for why it is separate from the GL set)."
echo
if [ -s "$COMPARE_JSON" ]; then
python3 scripts/ci/metal-screenshot-summary.py --markdown "$COMPARE_JSON"
elif [ -s "$COMMENT_MD" ]; then
cat "$COMMENT_MD"
else
echo "_No screenshot comparison artifact was produced. See the upload step output for details._"
fi
} >> "$GITHUB_STEP_SUMMARY"
if [ -s "$COMPARE_JSON" ]; then
NOTICE="$(python3 scripts/ci/metal-screenshot-summary.py --headline "$COMPARE_JSON" || true)"
if [ -n "$NOTICE" ]; then
echo "::notice title=Metal screenshot comparison::${NOTICE}"
fi
fi
- name: Upload iOS Metal artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: ios-ui-tests-metal
path: artifacts
if-no-files-found: warn
retention-days: 14