Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4bfbacc
Simplify DeviceRunner sample sources
shai-almog Oct 30, 2025
cc9d17f
Fix DeviceRunner integration for local builds
shai-almog Oct 30, 2025
20b0c42
Replace DeviceRunner tests with Codename One compliant APIs
shai-almog Oct 31, 2025
8471d57
Avoid regex sanitization in DeviceRunner helper
shai-almog Nov 1, 2025
fd83919
Use CLDC-safe string helpers in DeviceRunner
shai-almog Nov 1, 2025
48fb368
Restore lambdas and CLDC-safe stack traces
shai-almog Nov 2, 2025
1ef8910
Guard DeviceRunner EDT usage and locate iOS simulator app
shai-almog Nov 3, 2025
dc1f7e0
Fix CN1SS chunk parsing and simulator destination handling
shai-almog Nov 3, 2025
bd7490e
Fix CN1SS base64 emission and improve simulator selection
shai-almog Nov 3, 2025
f9e0751
Improve browser test readiness and simulator selection
shai-almog Nov 3, 2025
3b13302
Fix BrowserComponent load listener for DeviceRunner
shai-almog Nov 3, 2025
5e9ce14
Harden iOS simulator launch and BrowserComponent test
shai-almog Nov 3, 2025
7121b7f
Simplify iOS destination parsing without awk
shai-almog Nov 4, 2025
5fbecb2
Refine iOS simulator destination handling
shai-almog Nov 4, 2025
cfe54c2
Testing changes
shai-almog Nov 4, 2025
fcafc2c
Fixed truncated lines
shai-almog Nov 5, 2025
2e6f8c2
Tried to fix Android/iOS comment editing logic
shai-almog Nov 5, 2025
d8db565
Fixed comment posting logic
shai-almog Nov 5, 2025
c0992f3
Merge branch 'master' into codex/task-title
shai-almog Nov 5, 2025
f2194b3
Updated screenshot process to use native screenshots
shai-almog Nov 5, 2025
6115d1d
Fixed iOS build pom generation
shai-almog Nov 5, 2025
8196b20
Fixed compile issue
shai-almog Nov 5, 2025
5519e9a
Added device screenshots with known bug
shai-almog Nov 5, 2025
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
23 changes: 14 additions & 9 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,26 @@ workflows to build and validate Codename One ports.
- `build-android-app.sh` / `build-ios-app.sh` – generate a "Hello Codename One"
sample application and build it against the freshly compiled port.
- `run-android-instrumentation-tests.sh` – launches the Android emulator,
executes instrumentation tests, and prepares screenshot reports for pull
requests.
drives the Codename One DeviceRunner suite, and prepares screenshot
reports for pull requests.
- `run-ios-ui-tests.sh` – runs the Codename One DeviceRunner suite on the iOS
simulator and emits matching screenshot reports.

## Subdirectories

- `android/` – Python helpers, baseline screenshots, and utilities that power
the Android instrumentation test workflow.
- `android/lib/` – library-style Python modules shared across Android
automation scripts.
- `android/` – Java helpers, baseline screenshots, and utilities that power the
Android DeviceRunner test workflow.
- `android/lib/` – standalone Java sources invoked directly by the shell
scripts for Gradle patching and similar tasks.
- `android/tests/` – command-line tools used by CI for processing screenshots
and posting feedback to pull requests.
- `android/screenshots/` – reference images used when comparing emulator
output.
- `templates/` – code templates consumed by the sample app builders.
- `ios/` – Helpers and screenshot baselines used by the iOS DeviceRunner
workflow.
- `device-runner-app/` – Java sources for the shared sample application and its
DeviceRunner UI tests.

These scripts are designed so that shell logic focuses on orchestration, while
Python modules encapsulate the heavier data processing steps. This separation
keeps the entry points easy to follow and simplifies maintenance.
small Java utilities encapsulate the heavier data processing steps. This
separation keeps the entry points easy to follow and simplifies maintenance.
Binary file modified scripts/android/screenshots/BrowserComponent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified scripts/android/screenshots/MainActivity.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion scripts/android/tests/Cn1ssChunkTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Cn1ssChunkTools {
private static final String DEFAULT_TEST_NAME = "default";
private static final String DEFAULT_CHANNEL = "";
private static final Pattern CHUNK_PATTERN = Pattern.compile(
"CN1SS(?:(?<channel>[A-Z]+))?:(?:(?<test>[A-Za-z0-9_.-]+):)?(?<index>\\d{6}):(?<payload>.*)");
"CN1SS(?:(?<channel>[A-Z]+))?:(?:(?<test>[A-Za-z0-9_.-]+):)?(?<index>\\d{6,}):(?<payload>.*)");

public static void main(String[] args) throws Exception {
if (args.length == 0) {
Expand Down
15 changes: 15 additions & 0 deletions scripts/android/tests/PostPrComment.java
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,28 @@ private static String readStream(java.io.InputStream stream) throws IOException
}

private static AttachmentReplacement replaceAttachments(String body, Map<String, String> urls) {
// Build a case-insensitive lookup alongside the original map
Map<String, String> urlsCI = new HashMap<>();
for (Map.Entry<String, String> e : urls.entrySet()) {
if (e.getKey() != null && e.getValue() != null) {
urlsCI.put(e.getKey().toLowerCase(), e.getValue());
}
}

Pattern pattern = Pattern.compile("\\(attachment:([^\\)]+)\\)");
Matcher matcher = pattern.matcher(body);
StringBuffer sb = new StringBuffer();
List<String> missing = new ArrayList<>();
while (matcher.find()) {
String name = matcher.group(1);
if (name != null) {
name = name.trim();
}
String url = urls.get(name);
if (url == null && name != null) {
// try case-insensitive match
url = urlsCI.get(name.toLowerCase());
}
if (url != null) {
matcher.appendReplacement(sb, Matcher.quoteReplacement("(" + url + ")"));
} else {
Expand Down
94 changes: 36 additions & 58 deletions scripts/build-android-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ rm -rf "$WORK_DIR"; mkdir -p "$WORK_DIR"

GROUP_ID="com.codenameone.examples"
ARTIFACT_ID="hello-codenameone"
PACKAGE_NAME="com.codenameone.examples.hellocodenameone"
MAIN_NAME="HelloCodenameOne"

SOURCE_PROJECT="$REPO_ROOT/Samples/SampleProjectTemplate"
Expand Down Expand Up @@ -204,48 +205,49 @@ SETTINGS_FILE="$APP_DIR/common/codenameone_settings.properties"
echo "codename1.arg.android.useAndroidX=true" >> "$SETTINGS_FILE"
[ -f "$SETTINGS_FILE" ] || { ba_log "codenameone_settings.properties not found at $SETTINGS_FILE" >&2; exit 1; }

# --- Read settings ---
read_prop() { grep -E "^$1=" "$SETTINGS_FILE" | head -n1 | cut -d'=' -f2- | sed 's/^[[:space:]]*//'; }

PACKAGE_NAME="$(read_prop 'codename1.packageName' || true)"
CURRENT_MAIN_NAME="$(read_prop 'codename1.mainName' || true)"

if [ -z "$PACKAGE_NAME" ]; then
PACKAGE_NAME="$GROUP_ID"
ba_log "Package name not found in settings. Falling back to groupId $PACKAGE_NAME"
fi
if [ -z "$CURRENT_MAIN_NAME" ]; then
CURRENT_MAIN_NAME="$MAIN_NAME"
ba_log "Main class name not found in settings. Falling back to target $CURRENT_MAIN_NAME"
fi
set_prop() {
local key="$1" value="$2"
if grep -q "^${key}=" "$SETTINGS_FILE"; then
if sed --version >/dev/null 2>&1; then
sed -i -E "s|^${key}=.*$|${key}=${value}|" "$SETTINGS_FILE"
else
sed -i '' -E "s|^${key}=.*$|${key}=${value}|" "$SETTINGS_FILE"
fi
else
printf '\n%s=%s\n' "$key" "$value" >> "$SETTINGS_FILE"
fi
}

# --- Generate Java from external template ---
# --- Install Codename One application sources ---
PACKAGE_PATH="${PACKAGE_NAME//.//}"
JAVA_DIR="$APP_DIR/common/src/main/java/${PACKAGE_PATH}"
mkdir -p "$JAVA_DIR"
MAIN_FILE="$JAVA_DIR/${MAIN_NAME}.java"

TEMPLATE="$SCRIPT_DIR/templates/HelloCodenameOne.java.tmpl"
if [ ! -f "$TEMPLATE" ]; then
ba_log "Template not found: $TEMPLATE" >&2
MAIN_FILE_SOURCE="$SCRIPT_DIR/device-runner-app/main/${MAIN_NAME}.java"
if [ ! -f "$MAIN_FILE_SOURCE" ]; then
ba_log "Sample application source not found: $MAIN_FILE_SOURCE" >&2
exit 1
fi
cp "$MAIN_FILE_SOURCE" "$JAVA_DIR/${MAIN_NAME}.java"

sed -e "s|@PACKAGE@|$PACKAGE_NAME|g" \
-e "s|@MAIN_NAME@|$MAIN_NAME|g" \
"$TEMPLATE" > "$MAIN_FILE"

# --- Ensure codename1.mainName is set ---
ba_log "Setting codename1.mainName to $MAIN_NAME"
if grep -q '^codename1.mainName=' "$SETTINGS_FILE"; then
# GNU sed in CI: in-place edit without backup
sed -E -i 's|^codename1\.mainName=.*$|codename1.mainName='"$MAIN_NAME"'|' "$SETTINGS_FILE"
else
printf '\ncodename1.mainName=%s\n' "$MAIN_NAME" >> "$SETTINGS_FILE"
fi
ba_log "Setting Codename One application metadata"
set_prop "codename1.packageName" "$PACKAGE_NAME"
set_prop "codename1.mainName" "$MAIN_NAME"
# DeviceRunner integration is handled inside the copied sources, so unit test
# build mode is not required (and is unsupported for local Android builds).
# Ensure trailing newline
tail -c1 "$SETTINGS_FILE" | read -r _ || echo >> "$SETTINGS_FILE"

# --- Install DeviceRunner UI tests ---
TEST_SOURCE_DIR="$SCRIPT_DIR/device-runner-app/tests"
TEST_JAVA_DIR="$APP_DIR/common/src/main/java/${PACKAGE_PATH}/tests"
mkdir -p "$TEST_JAVA_DIR"
if [ ! -d "$TEST_SOURCE_DIR" ]; then
ba_log "DeviceRunner test sources not found: $TEST_SOURCE_DIR" >&2
exit 1
fi
cp "$TEST_SOURCE_DIR"/*.java "$TEST_JAVA_DIR"/
ba_log "Installed DeviceRunner UI tests in $TEST_JAVA_DIR"

# --- Normalize Codename One versions (use Maven Versions Plugin) ---
ba_log "Normalizing Codename One Maven coordinates to $CN1_VERSION"

Expand All @@ -266,7 +268,7 @@ if [ -z "$GRADLE_PROJECT_DIR" ]; then
exit 1
fi

ba_log "Configuring instrumentation test sources in $GRADLE_PROJECT_DIR"
ba_log "Normalizing Android Gradle project in $GRADLE_PROJECT_DIR"

# Ensure AndroidX flags in gradle.properties
# --- BEGIN: robust Gradle patch for AndroidX tests ---
Expand Down Expand Up @@ -301,30 +303,6 @@ echo "----- app/build.gradle tail -----"
tail -n 80 "$APP_BUILD_GRADLE" | sed 's/^/| /'
echo "---------------------------------"

TEST_SRC_DIR="$GRADLE_PROJECT_DIR/app/src/androidTest/java/${PACKAGE_PATH}"
mkdir -p "$TEST_SRC_DIR"
TEST_CLASS="$TEST_SRC_DIR/HelloCodenameOneInstrumentedTest.java"
TEST_TEMPLATE="$SCRIPT_DIR/android/tests/HelloCodenameOneInstrumentedTest.java"

if [ ! -f "$TEST_TEMPLATE" ]; then
ba_log "Missing instrumentation test template: $TEST_TEMPLATE" >&2
exit 1
fi

sed "s|@PACKAGE@|$PACKAGE_NAME|g" "$TEST_TEMPLATE" > "$TEST_CLASS"
ba_log "Created instrumentation test at $TEST_CLASS"

DEFAULT_ANDROID_TEST="$GRADLE_PROJECT_DIR/app/src/androidTest/java/com/example/myapplication2/ExampleInstrumentedTest.java"
if [ -f "$DEFAULT_ANDROID_TEST" ]; then
rm -f "$DEFAULT_ANDROID_TEST"
ba_log "Removed default instrumentation stub at $DEFAULT_ANDROID_TEST"
DEFAULT_ANDROID_TEST_DIR="$(dirname "$DEFAULT_ANDROID_TEST")"
DEFAULT_ANDROID_TEST_PARENT="$(dirname "$DEFAULT_ANDROID_TEST_DIR")"
rmdir "$DEFAULT_ANDROID_TEST_DIR" 2>/dev/null || true
rmdir "$DEFAULT_ANDROID_TEST_PARENT" 2>/dev/null || true
rmdir "$(dirname "$DEFAULT_ANDROID_TEST_PARENT")" 2>/dev/null || true
fi

ba_log "Invoking Gradle build in $GRADLE_PROJECT_DIR"
chmod +x "$GRADLE_PROJECT_DIR/gradlew"
ORIGINAL_JAVA_HOME="$JAVA_HOME"
Expand All @@ -348,7 +326,7 @@ if [ -n "${GITHUB_OUTPUT:-}" ]; then
{
echo "gradle_project_dir=$GRADLE_PROJECT_DIR"
echo "apk_path=$APK_PATH"
echo "instrumentation_test_class=$PACKAGE_NAME.HelloCodenameOneInstrumentedTest"
echo "package_name=$PACKAGE_NAME"
} >> "$GITHUB_OUTPUT"
ba_log "Published GitHub Actions outputs for downstream steps"
fi
Loading
Loading