Skip to content

Conversation

teodorciuraru
Copy link
Contributor

Summary

  • Bumped Ditto SDK version to 4.11.6-rc.3 across all quickstart projects
  • Updated dependencies and lockfiles for all platforms

Projects Updated

  • JavaScript/TypeScript (React Native, React Native Expo, JavaScript TUI, JavaScript Web)
  • Android (Kotlin, Java, C++)
  • Flutter
  • Rust TUI
  • .NET (TUI, MAUI, WinForms)
  • Java Spring

Test plan

  • Build and test React Native apps (iOS & Android)
  • Build and test React Native Expo apps (iOS & Android)
  • Build and test JavaScript Web
  • Build and test JavaScript TUI
  • Build and test Android apps (Kotlin, Java, C++)
  • Build and test Flutter app
  • Build and test Rust TUI
  • Build and test .NET apps
  • Build and test Java Spring
  • Verify sync functionality across platforms

🤖 Generated with Claude Code

teodorciuraru and others added 30 commits October 2, 2025 13:08
…ming

- Remove PR comments from android-java-ci.yml and android-cpp-ci.yml
- Add summary jobs to all CI workflows with consistent format
- Rename javascript-web-browserstack.yml to javascript-web-ci.yml for consistency
- All 16 CI workflows now use GITHUB_STEP_SUMMARY instead of PR comments
- Summary includes: overall status, job status table, BrowserStack links

Each workflow now displays a clean summary with:
- Overall status badge (✅/❌)
- Job status table (Lint, Build, BrowserStack Tests)
- Direct links to BrowserStack dashboard with project and build number
- List of tested devices/browsers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Create .github/actions/seed-ditto-document composite action
- Replace ~480 lines of duplicated seed logic across 16 workflows
- Standardize output naming to 'document-title' across all workflows
- Maintain consistent data model: _id, title, done, deleted

Benefits:
- DRY: Single source of truth for seeding test documents
- Consistency: All workflows use identical seeding logic
- Maintainability: Changes to seed logic only need updating in one place
- Standardization: All apps verified to use title/done/deleted fields

Updated workflows:
- android-cpp-ci.yml
- android-java-ci.yml
- android-kotlin-ci.yml
- cpp-tui-ci.yml
- dotnet-maui-ci.yml
- dotnet-tui-ci.yml
- dotnet-winforms-ci.yml
- flutter-ci.yml
- java-spring-ci.yml
- javascript-tui-ci.yml
- javascript-web-ci.yml
- kotlin-multiplatform-ci.yml
- react-native-ci.yml
- react-native-expo-ci.yml
- rust-tui-ci.yml
- swift-ci.yml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The javascript-web app was sorting tasks by completion status instead of
by the inverted timestamp _id field. This caused CI test documents (which
use inverted timestamps to appear first) to not show up at the top of the list,
breaking BrowserStack tests.

Changed query from:
  ORDER BY done
To:
  ORDER BY _id ASC

This matches the ordering used in all other quickstart apps and ensures
CI-seeded test documents appear at the top of the task list.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Changed javascript-web from ORDER BY _id ASC to ORDER BY title ASC
- Changed rust-tui from ORDER BY _id to ORDER BY title ASC
- All 16 apps now consistently use ORDER BY title ASC
- This ensures CI test documents (with inverted timestamp in title) appear at top of list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Removed incorrect "GitHub Test Task" string check that doesn't exist in seeded documents
- Document title is just the ID itself (e.g., 8240590183_javascript-web_ci_test_18193630918_4)
- Fixed array indexing to match actual document ID format: INVERTED_TIMESTAMP_app-name_ci_test_RUNID_RUNNUMBER
- Test now looks for either the full doc_id or the run_id portion in task text

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
1. Fixed seed-ditto-document action for macOS compatibility
   - Changed `head -n -1` to `sed '$d'` (BSD/GNU portable)
   - macOS BSD head doesn't support negative line counts
   - This fixes "illegal line count" error on KMP iOS and other macOS jobs

2. Fixed javascript-web BrowserStack test for exact document matching
   - Changed from substring/partial matching to exact match: `element_text == doc_id`
   - Removed extraction logic that was looking for run_id substring
   - Document title IS the document ID, so exact match is correct
   - Ensures only the seeded CI test document is matched, not user tasks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…uilds

- Remove seed steps from build-android (lines 105-111) and build-ios (lines 175-181)
- Remove test_doc_title output from both build jobs
- Add single seed-task-data job that depends on both build-android and build-ios
- Update browserstack-android to depend on seed-task-data instead of just build-android
- Change browserstack-android to read test_task_title from seed-task-data outputs
- Update build-summary to include seed-task-data in dependencies

This brings KMP workflow in line with the standard pattern used by other CI workflows:
1. Lint runs first
2. Build jobs (android, ios, desktop) run in parallel after lint
3. Single seed-task-data job runs after both android and ios builds complete
4. BrowserStack tests depend on seed-task-data (which depends on builds)

The composite action .github/actions/seed-ditto-document correctly seeds
documents with title, done, and deleted fields matching the KMP app model.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed kotlin-multiplatform and dotnet-maui workflows to use consistent
`seed-ditto-cloud` job name instead of `seed-task-data`.

This is part of standardizing all CI workflows to use the same pattern:
- Job name: `seed-ditto-cloud`
- Job display name: "Seed Test Task to Ditto Cloud"
- Step name: "Seed test task to Ditto Cloud"
- Runs after all build jobs complete
- BrowserStack tests depend on seed-ditto-cloud + build jobs

Changes:
- kotlin-multiplatform-ci.yml: Renamed seed-task-data → seed-ditto-cloud
- dotnet-maui-ci.yml: Renamed seed-task-data → seed-ditto-cloud

Remaining workflows with inline seeding will be updated in follow-up commits.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…kotlin

Standardized android-kotlin-ci.yml to follow the pattern:
1. Lint runs first
2. Build job (renamed from build-and-test, removed seed step and output)
3. seed-ditto-cloud job runs after build completes
4. BrowserStack tests depend on both [build, seed-ditto-cloud]

Changes:
- Renamed build-and-test job → build
- Removed inline seed step (lines 90-96) from build job
- Removed document-title output from build job
- Created new seed-ditto-cloud job after build
- Updated browserstack-test needs: [build, seed-ditto-cloud]
- Updated all references: needs.build-and-test → needs.build and needs.seed-ditto-cloud
- Updated summary job dependencies

This ensures seeding only happens after successful build,
and BrowserStack tests only run after both build and seed complete.

Part of standardizing all 16 CI workflows to use consistent seed pattern.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…java and android-cpp

- Remove inline seed steps from browserstack-test job
- Create separate seed-ditto-cloud job after build
- Update browserstack job to depend on [build, seed-ditto-cloud]
- Standardize output reference: test_task_title
- Update summary job dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Swift:
- Extract inline seed from browserstack job
- Create separate seed-ditto-cloud job after builds
- Update browserstack job to depend on [build-ios, seed-ditto-cloud]
- Update references to needs.seed-ditto-cloud.outputs.test_task_title

Flutter:
- Rename seed-data → seed-ditto-cloud
- Rename "Seed Test Data" → "Seed Test Task to Ditto Cloud"
- Update output: test_title → test_task_title
- Update all references

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Remove seed step and output from build job
- Create separate seed-ditto-cloud job after build
- Update browserstack-test to depend on [build, seed-ditto-cloud]
- Update all references to needs.seed-ditto-cloud.outputs.test_task_title
- Update summary job dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Summary jobs should only depend on the final test jobs (browserstack/maestro),
not on intermediate jobs like lint, build, or seed-ditto-cloud. GitHub Actions
automatically waits for transitive dependencies.

Changes:
- android-cpp: Extract inline seed to separate job, update summary to only depend on browserstack-appium-test
- android-java: Add seed-ditto-cloud to browserstack-test deps, update summary
- android-kotlin: Update summary to only depend on browserstack-test
- dotnet-maui: Update summary to only depend on browserstack jobs
- java-spring: Update summary to only depend on browserstack-test
- kotlin-multiplatform: Update build-summary to only depend on browserstack-android
- swift: Update summary to only depend on browserstack

Pattern now: lint → builds → seed-ditto-cloud → browserstack/maestro → summary

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The Spring Boot app was being built with DITTO_ENABLE_CLOUD_SYNC=true
but started without it at runtime. This caused sync to be disabled by default.

Also add generic retry-browserstack.sh script for handling BrowserStack
queue full errors with exponential backoff (5 attempts, 1-5min waits).

Changes:
- Add env vars to Spring Boot app startup (including DITTO_ENABLE_CLOUD_SYNC)
- Create .github/scripts/retry-browserstack.sh for generic retry logic
- Update android-java to use generic retry script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…tform summary

- Remove retry-browserstack.sh wrapper from android-java-ci.yml
- Fix kotlin-multiplatform build-summary to depend on all jobs it references
- Add paths filter to swift-ci.yml push trigger for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Embed seed-ditto-document step directly in each BrowserStack test job
- Remove standalone seed-ditto-cloud jobs from all workflows
- Update job dependencies to remove seed-ditto-cloud from needs arrays
- Change output references from needs.seed-ditto-cloud.outputs to steps.seed_task.outputs

This ensures that retrying a BrowserStack job re-seeds fresh test data,
preventing task accumulation and improving test isolation.

Workflows updated:
- android-cpp-ci.yml: browserstack-appium-test job
- android-java-ci.yml: browserstack-test job
- android-kotlin-ci.yml: browserstack-test job
- java-spring-ci.yml: browserstack-test job
- kotlin-multiplatform-ci.yml: browserstack-android job
- swift-ci.yml: browserstack job
- dotnet-maui-ci.yml: browserstack-android and browserstack-ios jobs
- flutter-ci.yml: browserstack-android and browserstack-ios jobs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…ng summaries

Replace generic BrowserStack dashboard links with specific project+build URLs
to make it easier to find test results for each CI run.

- android-cpp: Use project=Ditto+Android+C%2B%2B&build=Build+#{run_number}
- java-spring: Use project=Ditto+Java+Spring+Tasks&build=Java+Spring+Selenium+Tests+#{run_number}

This matches the pattern used in other workflows (android-java, android-kotlin,
dotnet-maui, kotlin-multiplatform, swift).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Standardize project names and build names across all CI workflows with BrowserStack integration:

**Build Name Standardization:**
- Unified all build names to "CI Build #N" format
- Previously used inconsistent names like "Build #N", "Android Build #N", "iOS Build #N", "Java Spring Selenium Tests #N"
- Consistent format improves recognition and dashboard filtering

**Project Name Standardization:**
- Changed all project names from "Ditto [Platform]" to "QuickStart [Platform]" format
- Updated 10 workflows: Android (C++, Java, Kotlin), .NET MAUI, Flutter, Java Spring, Kotlin Multiplatform, React Native, React Native Expo, Swift
- Aligns with repository naming convention

**Dashboard URL Standardization:**
- Updated all BrowserStack dashboard URLs to use standardized project and build names
- Proper URL encoding for special characters (e.g., "QuickStart+Android+C%2B%2B")
- Consistent format makes test session tracking easier

This improves organization and consistency across the BrowserStack dashboard for all platforms.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Allow CI workflows to run on all branches, not just main:
- Removed 'branches: [main]' restrictions from push and pull_request triggers
- Workflows still filtered by path changes for efficiency
- Enables testing on feature branches and PRs from any branch

Updated 11 workflow files to run on all branches.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Update Python test script to use "QuickStart JavaScript Web" project name
- Update Python test script to use "CI Build #N" build name format
- Remove branch restrictions (allow all branches, not just main/sdk-*)
- Fix workflow file path references (javascript-web-browserstack.yml → javascript-web-ci.yml)
- Update dashboard link to point to specific build instead of generic dashboard
- Now all 11 CI workflows have links to exact BrowserStack builds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Remove separate seed-ditto-cloud job from both workflows
- Add seed-ditto-document step as first step in each BrowserStack test job
- Update job dependencies to only depend on build jobs
- Change references from needs.seed-ditto-cloud.outputs to steps.seed-document.outputs

Benefits:
- Each test job is now self-contained and retryable
- Test jobs seed their own documents on retry
- Parallel test execution starts immediately after builds complete

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Split build-and-test job into separate lint, build, browserstack-test, summary jobs
- Changed workflow name from "javascript-web-browserstack" to "JavaScript Web CI"
- Build job now uploads dist/ artifact for test job to download
- BrowserStack test job now seeds its own document (self-contained, retryable)
- Summary job references all upstream job results for accurate status reporting

Benefits:
- Matches standard structure used by all other CI workflows
- Better separation of concerns (lint, build, test, report)
- Improved artifact handling between jobs
- Self-contained test job can be retried independently

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The browserstack-test job needs Node.js to run npx http-server.
This was missing after the workflow refactoring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The issue was that `npx http-server` sometimes took longer than 5
seconds to download and install the package, causing the curl check
to fail. By pre-installing http-server globally, it's immediately
available and starts consistently within the timeout window.

Changes:
- Add step to install http-server globally with npm
- Change command from `npx http-server` to `http-server`
- This eliminates the npx download time race condition

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The BrowserStack Local tunnel needs more time to establish. 10 seconds
was insufficient, causing tests to fail with "local testing through
BrowserStack is not connected". Increasing to 20 seconds should allow
the tunnel to fully establish before tests run.

Note: The http-server changes in the previous commit work perfectly.
This is a separate BS Local timing issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Rename final job to 'summary' with 'CI Report' name for consistency:
- kotlin-multiplatform-ci.yml: build-summary → summary
- react-native-ci.yml: report-results → summary
- react-native-expo-ci.yml: report-results → summary

All 9 BrowserStack CI workflows now follow the standard pattern:
lint → build → browserstack-test → summary

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
**High Priority Fixes:**
1. Add BrowserStack capacity management (concurrency control to all 9 workflows)
2. Fix summary job dependencies (add lint, build to needs arrays)
3. Create centralized device configuration (.github/browserstack-devices.json)

**Changes:**
- All BrowserStack test jobs now use shared concurrency group "browserstack-tests"
  with cancel-in-progress: false to queue tests instead of failing
- Fixed 4 workflows with incomplete summary job dependencies:
  - android-cpp-ci.yml: Added [lint, build] to summary needs
  - android-java-ci.yml: Added [lint, build] to summary needs
  - android-kotlin-ci.yml: Added [lint, build] to summary needs
  - flutter-ci.yml: Added all build jobs to summary needs
- Created `.github/browserstack-devices.json` with device lists for:
  - android-espresso (full + compact)
  - android-appium, android-maestro
  - ios-xcuitest (full + compact)
  - ios-appium, ios-maestro
  - web-selenium

**Impact:**
- Prevents BrowserStack "all parallels in use" queue errors
- Ensures summary jobs have access to all job results they reference
- Centralizes device configuration for future maintenance

**Still TODO (per REFACTOR_PLAN.md):**
- Standardize job names to browserstack-{platform}
- Parameterize device lists (use browserstack-devices.json)
- Standardize instrumentationOptions keys
- Standardize wait times across workflows

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed device configuration structure from framework-based (espresso, appium, maestro)
to SDK/app-based (android-java, flutter, react-native, etc.).

Multi-platform SDKs have nested android/ios objects for better organization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…tform}

Renamed BrowserStack test jobs to follow consistent pattern:
- android-cpp: browserstack-appium-test → browserstack-android
- android-java: browserstack-test → browserstack-android
- android-kotlin: browserstack-test → browserstack-android
- kotlin-multiplatform: test-android → browserstack-android
- javascript-web: browserstack-test → browserstack-web
- react-native: test-android-maestro → browserstack-android, test-ios-maestro → browserstack-ios
- react-native-expo: test-android-maestro → browserstack-android, test-ios-maestro → browserstack-ios

All summary job dependencies updated to reference new names.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The Google Pixel 6 with Android 12.0 consistently fails tests in the
Kotlin Multiplatform CI workflow. Removing it from the device list
to improve test reliability.

Updated both the workflow file and centralized device configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
teodorciuraru and others added 27 commits October 7, 2025 19:43
…names under 100 char limit

BrowserStack API requires project names to be <= 100 characters.
The format 'quickstart PR XXX: <title>' requires truncating the PR title
to max 75 characters to stay within the limit.

Applied to all 11 BrowserStack workflows and the Python test script.

Error was:
{"message":"project length should be less than or equal to 100 characters."}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
This script was added in PR #181 but was never actually used by any workflow.
All workflows now use nick-fields/retry@v3 action for retry logic instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Remove default fallback of 'Google Pixel 7-13.0' for BROWSERSTACK_DEVICE.
Now throws IllegalStateException if the environment variable is not set,
ensuring tests fail fast with clear error message instead of silently
using wrong device configuration.

Also improved error message for invalid device format.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed naming scheme for better dashboard organization:
- Project Name: quickstart - [Platform] (static, groups by platform)
- Build Name: PR #185: [PR Title] (dynamic, shows PR context)

Benefits:
- Easy filtering by platform on BrowserStack dashboard
- All builds for a platform grouped together
- PR context in build name for quick identification
- No 100-char limit issues (project ~30 chars, build ~70 chars)

Applied to all 11 workflows + Python script:
- Android C++, Java, Kotlin
- MAUI (Android + iOS builds)
- Flutter (Android + iOS builds)
- Java Spring
- JavaScript Web
- Kotlin Multiplatform
- React Native (Android + iOS builds)
- React Native Expo (Android + iOS builds)
- Swift

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…issues

Changed build name format to show commit context:
- Build Name: PR #185: [commit message truncated to 75 chars]
- Shows what specific commit triggered the build (more granular than PR title)

Fixes:
1. android-cpp test now uses BROWSERSTACK_PROJECT and BROWSERSTACK_BUILD env vars
   instead of hardcoded values
2. java-spring test now reads browserstack-devices.yml instead of .json
3. Added jackson-dataformat-yaml dependency to java-spring for YAML parsing

This ensures BrowserStack dashboard shows:
- Project Name: quickstart - [Platform] (for filtering/grouping)
- Build Name: PR #185: commit message... (for identification)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
BrowserStack ignores # character in build names. Changed format from:
  PR #185: commit message...
To:
  PR-185: commit message...

Also fixed react-native-expo workflow which was still using old PR title format.

All 10 BrowserStack workflows now use consistent format:
- Project Name: quickstart - [Platform]
- Build Name: PR-185: [commit message truncated to 75 chars]

This ensures the PR number and commit context are visible on BrowserStack dashboard.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
… with sanitization

Enhanced build name format to include both PR context and commit info:
- Old: PR-185: [commit message truncated to 75 chars]
- New: PR-185: [PR title 90 chars] - [commit message 130 chars]

Added character sanitization to comply with BrowserStack restrictions:
- Allowed: A-Z a-z 0-9 . : - [ ] / @ & ' _
- Removes: # * ! $ % ^ ( ) " ` , ; and other special chars

Total length stays under 255 char limit:
- Simple workflows: 8 + 100 + 3 + 140 = 251 chars
- Platform workflows: 8 + 90 + 3 + 130 + 10 = 241 chars

Benefits:
- Full context: Both what the PR is about AND what commit triggered the build
- BrowserStack compatible: All special characters sanitized
- Maximum info: Uses 240+ of the 255 available characters

Updated all 10 BrowserStack workflows:
- android-cpp, android-java, android-kotlin
- dotnet-maui (Android + iOS)
- flutter (Android + iOS)
- java-spring
- kotlin-multiplatform
- react-native (Android + iOS)
- react-native-expo (Android + iOS)
- swift

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed from single quotes with escape sequence '\'' to double quotes
to avoid YAML/bash parsing issues:
- Before: sed 's/[^A-Za-z0-9.:[\]/@&'\'' _-]//g'
- After: sed "s/[^A-Za-z0-9.:[\]/@&' _-]//g"

This fixes the "bad flag in substitute command" error in java-spring
and all other workflows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…atibility

macOS runners use BSD sed which was interpreting the unescaped / in
the character class [^A-Za-z0-9.:[\]/@&' _-] as the pattern delimiter,
causing error: "bad flag in substitute command: '/'"

Escaped the forward slash to [\]\/ so BSD sed treats it as a literal
character to match rather than a delimiter.

Applied to all 10 BrowserStack workflows:
- android-cpp-ci.yml
- android-java-ci.yml
- android-kotlin-ci.yml
- java-spring-ci.yml
- kotlin-multiplatform-ci.yml
- swift-ci.yml
- dotnet-maui-ci.yml (Android + iOS sections)
- flutter-ci.yml (Android + iOS sections)
- react-native-ci.yml (Android + iOS sections)
- react-native-expo-ci.yml (Android + iOS sections)
React Native, React Native Expo, and Flutter workflows had incorrect
syntax with spaces in variable references:
  PR_NUMBER="${ github.event.pull_request.number }"

This caused variables to not expand, resulting in empty PR_NUMBER
values and fallback to generic "Build #123" format on BrowserStack
instead of "PR-185: [title] - [message]" format.

Fixed to correct syntax:
  PR_NUMBER="${{ github.event.pull_request.number }}"

Applied to:
- react-native-ci.yml (Android + iOS sections)
- react-native-expo-ci.yml (Android + iOS sections)
- flutter-ci.yml (Android + iOS sections)
BrowserStack does not accept # character in build names. Changed all
fallback build names from "Build #123" to "Build-123" format.

Changed in all 10 BrowserStack workflows:
- android-cpp-ci.yml
- android-java-ci.yml
- android-kotlin-ci.yml
- dotnet-maui-ci.yml (Android + iOS)
- flutter-ci.yml (Android + iOS)
- java-spring-ci.yml
- kotlin-multiplatform-ci.yml
- react-native-ci.yml (Android + iOS)
- react-native-expo-ci.yml (Android + iOS)
- swift-ci.yml
When workflows run on push events (commits pushed to PR branches),
github.event.pull_request context is null, causing PR_NUMBER and
PR_TITLE to be empty and falling back to generic "Build-123" format.

Added logic to detect event type and fetch PR info using GitHub API
for push events:
- pull_request events: use github.event.pull_request directly
- push events: use gh pr view to fetch PR number and title

This ensures build names show "PR-185: [title] - [message]" format
for both pull_request and push events on PR branches.

Applied to all 10 BrowserStack workflows:
- android-cpp-ci.yml
- android-java-ci.yml
- android-kotlin-ci.yml
- dotnet-maui-ci.yml (Android + iOS sections)
- flutter-ci.yml (Android + iOS sections)
- java-spring-ci.yml
- kotlin-multiplatform-ci.yml
- react-native-ci.yml (Android + iOS sections)
- react-native-expo-ci.yml (Android + iOS sections)
- swift-ci.yml
Replaced conditional logic with simpler approach that always uses
gh pr view with branch name. This works reliably for both pull_request
and push events without needing to check event type.

Before: Check event_name and use different methods
After: Always use "gh pr view ${{ github.ref_name }}"

This is more robust and reduces complexity while maintaining the same
functionality across all event types.

Applied to all 10 BrowserStack workflows.
Created .github/actions/get-browserstack-build-info composite action that:
- Fetches PR info using gh CLI (works for both pull_request and push events)
- Sanitizes PR title and commit message for BrowserStack compatibility
- Generates project and build names with proper formatting
- Supports configurable truncation lengths and platform suffixes

Usage example:
```yaml
- name: Get BrowserStack build info
  id: bs-info
  uses: ./.github/actions/get-browserstack-build-info
  with:
    project-name: 'quickstart - Flutter'
    platform-suffix: ' (Android)'
    title-max-length: '90'
    commit-max-length: '130'

- name: Execute tests
  run: |
    curl ... -d "{
      \"project\": \"\${{ steps.bs-info.outputs.project-name }}\",
      \"buildName\": \"\${{ steps.bs-info.outputs.build-name }}\"
    }"
```

This centralizes the build name logic and makes workflows cleaner.
Future work: migrate existing workflows to use this action.
Changed from github.ref_name to "github.head_ref || github.ref_name"
because:
- pull_request events: github.ref_name = "185/merge" (invalid)
- pull_request events: github.head_ref = "branch-name" (correct)
- push events: github.head_ref = empty, github.ref_name = "branch-name"

The fallback operator || ensures we always get a valid branch name
that gh pr view can use to fetch PR information.

This fixes the issue where build names defaulted to "Build-123" instead
of showing "PR-185: [title] - [message]" format.

Applied to:
- All 10 BrowserStack workflows (inline code)
- Composite action (.github/actions/get-browserstack-build-info)

Also updated buildTag references to use same pattern for consistency.
Changed from hardcoded build numbers to project-based filtering:
- Removed build=CI+Build+%23{run_number} (won't match new format)
- Now using project=quickstart+-+{Platform} (URL-encoded spaces)
- Links now show all builds for the project instead of failing to find specific build

This matches the actual PROJECT_NAME format we set in workflows:
"quickstart - Android CPP" → "quickstart+-+Android+CPP"

Updated 8 workflows:
- android-cpp-ci.yml
- android-java-ci.yml
- android-kotlin-ci.yml
- dotnet-maui-ci.yml (Android + iOS + All Sessions)
- java-spring-ci.yml
- javascript-web-ci.yml
- kotlin-multiplatform-ci.yml
- swift-ci.yml

Flutter, React Native, React Native Expo already use dynamic BUILD_ID
approach and don't need this change.
… info

Replaced duplicate PR fetching and sanitization logic across all 10
BrowserStack workflows with centralized composite action.

Changes:
- Added composite action step before retry blocks in all workflows
- Removed ~306 lines of duplicate code (PR_INFO, sanitization, truncation)
- Replaced PROJECT_NAME/BUILD_NAME variables with composite action outputs
- Fixed Python script build name format (removed # symbol)

Workflows migrated:
✅ android-cpp-ci.yml - single platform
✅ android-java-ci.yml - single platform
✅ android-kotlin-ci.yml - single platform
✅ dotnet-maui-ci.yml - multi-platform (Android + iOS)
✅ flutter-ci.yml - multi-platform (Android + iOS)
✅ java-spring-ci.yml - single platform (uses browserstack.yml config)
✅ kotlin-multiplatform-ci.yml - single platform
✅ react-native-ci.yml - multi-platform (Android + iOS)
✅ react-native-expo-ci.yml - multi-platform (Android + iOS)
✅ swift-ci.yml - single platform

Benefits:
- Single source of truth for build name generation
- Consistent sanitization and truncation logic
- Easy to maintain and update in one place
- No more duplicate BUILD_NAME if/else blocks

Multi-platform workflows use:
- Distinct step IDs: build-info-android, build-info-ios
- Platform suffixes: ' (Android)', ' (iOS)'
- Shorter lengths: title-max-length=90, commit-max-length=130

Single-platform workflows use:
- Step ID: build-info
- No platform suffix
- Default lengths: title-max-length=100, commit-max-length=140
…UILD_ID

Updated 4 workflows to use direct build links instead of project filter:
- android-java-ci.yml
- android-kotlin-ci.yml
- kotlin-multiplatform-ci.yml
- swift-ci.yml

Changes:
- Added job outputs to expose build_id from BrowserStack API response
- Added echo "build_id=$BUILD_ID" >> "$GITHUB_OUTPUT" after extraction
- Updated summary links from project filter to direct build URL

Before: https://app-automate.browserstack.com/builds?project=quickstart+-+{Platform}
After:  https://app-automate.browserstack.com/dashboard/v2/builds/$BUILD_ID

Benefits:
- Direct link to specific build session (more accurate)
- No need to search/filter on BrowserStack dashboard
- Consistent with Flutter, React Native, React Native Expo workflows

Summary link approaches across all workflows:
✅ Dynamic BUILD_ID (7 workflows): android-java, android-kotlin,
   kotlin-multiplatform, swift, flutter, react-native, react-native-expo
✅ Project filter (4 workflows): android-cpp, dotnet-maui, java-spring,
   javascript-web (these don't expose BUILD_ID from their test frameworks)
Added BUILD_ID extraction by querying BrowserStack API after tests complete
for 4 workflows that use SDK/WebDriver (android-cpp, dotnet-maui, java-spring,
javascript-web).

All 11 BrowserStack workflows now use direct BUILD_ID links in summaries with
fallback to project filter for reliability.

Changes:
- Query BrowserStack API after tests to get build_id
- Add job outputs for build_id
- Update summary links to use BUILD_ID with fallback logic
- Use correct API endpoints (app-automate vs automate)

Result: All BrowserStack summary links now route directly to specific build
sessions for maximum accuracy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…names

Standardized all BrowserStack workflows to use consistent link format
and fixed project/build naming issues across all workflows.

Changes:
- Standardized all BrowserStack links to use trailing slash format:
  https://[app-]automate.browserstack.com/dashboard/v2/builds/$BUILD_ID/
- Removed fallback links (only show link when BUILD_ID is available)
- Fixed Android CPP project name: "Android C++" → "Android CPP"
- Fixed .NET MAUI project name: "MAUI" → ".NET MAUI"
- Fixed Java Spring to use composite action's build name (removed hardcoded override)
- Fixed Java Spring summary to include lint and build jobs
- Fixed React Native Expo to output build_id and use job result instead of non-existent status output
- Standardized all workflows (android-java, android-kotlin, kotlin-multiplatform, swift, flutter, dotnet-maui) to use trailing slash

Result: All 11 BrowserStack workflows now have:
- Consistent link format with trailing slash
- Correct project names
- Build names using composite action (includes PR title/commit message)
- Working summary links that route to correct build sessions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed JavaScript Web and Java Spring workflows to only display the
BrowserStack Session section when build_id is available, preventing
empty sections with headers but no links.

Changes:
- JavaScript Web: wrapped entire BrowserStack section in build_id check
- Java Spring: combined not-skipped and build_id checks in single condition

Result: Clean summaries that only show BrowserStack info when links are available
Root cause: composite action was missing GH_TOKEN, causing gh pr view
to fail silently and fall back to 'Build-XXX' format.

Changes:
1. Composite action (.github/actions/get-browserstack-build-info):
   - Added GH_TOKEN env var so gh pr view can authenticate
   - Added debug output to show fetched PR info
   - This fixes ALL 10 workflows using this action

2. .NET MAUI workflow:
   - Changed to separate platform-specific links
   - Removed aggregated 'View All Sessions' link
   - Each platform now links directly to its build ID

3. Android Kotlin workflow:
   - Pass BUILD_NAME/PROJECT_NAME via env vars to retry action
   - Use jq to properly escape values for JSON payload
   - Fixes buildName not being passed to BrowserStack API

4. Kotlin Multiplatform workflow:
   - Same fix as Android Kotlin for proper JSON escaping
   - Ensures PR title shows in BrowserStack build name

5. Test workflow (test-build-info-action.yml):
   - New workflow to test composite action in isolation
   - Shows all outputs in step summary for verification
Improvements to composite action:
1. Replaced sed with tr for character filtering (more portable)
2. Added reference link to BrowserStack docs
3. Added 255 character limit enforcement
4. Better documentation of allowed characters

Character handling:
- Allowed: A-Z a-z 0-9 . : - [ ] / @ & ' _
- Using tr -cd (complement delete) for reliable filtering
- Single quote escaped properly: '\''

Reference: https://www.browserstack.com/docs/automate/selenium/organize-tests
JavaScript Web workflow now uses the centralized get-browserstack-build-info
action, making it consistent with all other BrowserStack workflows.

Changes:
- Added build-info action step to javascript-web-ci.yml
- Removed duplicate PR/build name logic from browserstack-test.py (13 lines)
- Pass project and build names via environment variables
- Improved string sanitization (now handled by build-info action)

Benefits:
- Consistent naming across all 11 BrowserStack workflows
- Proper character sanitization for BrowserStack requirements
- Centralized logic for easier maintenance
- More reliable PR info fetching via GitHub CLI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…ntext

Renamed action from get-browserstack-build-info to generate-browserstack-names
and made it auto-derive the project name from the workflow name instead of
requiring it as input.

Changes:
- Renamed action directory and updated metadata
- Project name now auto-derived: "JavaScript Web CI" → "quickstart - JavaScript Web"
- Removed project-name input from all 11 BrowserStack workflows
- Added special case for "Android C++" → "Android CPP"
- Added FIXME comments: build-name generation is broken, returns empty string
- Simplified action: removed unused PR fetching logic, sanitization, etc.

Benefits:
- Zero configuration needed - workflows just call the action
- Eliminates hardcoded project names across 11 workflows
- Ensures naming consistency automatically (follows pattern)
- Less chance for typos/mistakes
- Single source of truth for project naming

Build name generation status:
- FIXME: Currently returns empty string (broken)
- TODO: Needs proper implementation in future PR
- Documented limitations in action comments

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Kotlin Multiplatform only runs Android tests on BrowserStack, so it needs
the ' (Android)' platform suffix to distinguish it from potential iOS tests
in the future.

This ensures the BrowserStack project name will be:
'quickstart - Kotlin Multiplatform (Android)'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Updated Ditto SDK version across all quickstart projects:
- JavaScript/TypeScript (React Native, React Native Expo, TUI, Web)
- Android (Kotlin, Java, C++)
- Flutter
- Rust TUI
- .NET (TUI, MAUI, WinForms)
- Java Spring

All lockfiles and dependencies have been updated accordingly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@teodorciuraru teodorciuraru self-assigned this Oct 13, 2025
@teodorciuraru
Copy link
Contributor Author

BS pipelines seem to work and confirm that our apps work. The objective was reached; closing PR.

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.

1 participant