Nightly version/mx/10 Branch Pipeline #1494
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Run Native Pipeline | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| run_name: | |
| description: "Provide a name for the run" | |
| required: false | |
| default: "" | |
| mendix_version: | |
| description: "Provide the SP version to be used (e.g., 10.14.0.43709) - has to be a released version (Default: latest from Mendix versions.json)" | |
| required: false | |
| default: "" | |
| nt_branch: | |
| description: "Native Template branch/tag to use (Leave empty to auto-select based on Mendix version)" | |
| default: "" | |
| required: false | |
| type: string | |
| LOCAL_TEST_ARTIFACT_RUN_ID: | |
| description: "Workflow run ID for local artifact download (leave empty for normal CI). Use the full run ID from the URL, not the run number displayed in UI." | |
| required: false | |
| default: "" | |
| workspace: | |
| description: "Select a widget to test (Default will run all)" | |
| required: true | |
| default: "*-native" | |
| type: choice | |
| options: | |
| - "*-native" | |
| - js-actions | |
| - accordion-native | |
| - activity-indicator-native | |
| - animation-native | |
| - app-events-native | |
| - background-gradient-native | |
| - background-image-native | |
| - badge-native | |
| - bar-chart-native | |
| - barcode-scanner-native | |
| - bottom-sheet-native | |
| - carousel-native | |
| - color-picker-native | |
| - column-chart-native | |
| - feedback-native | |
| - floating-action-button-native | |
| - gallery-native | |
| - gallery-text-filter-native | |
| - image-native | |
| - intro-screen-native | |
| - line-chart-native | |
| - listview-swipe-native | |
| - maps-native | |
| - pie-doughnut-chart-native | |
| - popup-menu-native | |
| - progress-bar-native | |
| - progress-circle-native | |
| - qr-code-native | |
| - radio-buttons-native | |
| - range-slider-native | |
| - rating-native | |
| - repeater-native | |
| - safe-area-view-native | |
| - signature-native | |
| - slider-native | |
| - switch-native | |
| - toggle-buttons-native | |
| - video-player-native | |
| - web-view-native | |
| # Trigger on PR | |
| pull_request: | |
| # Use default name in case no input | |
| run-name: ${{ github.event.inputs.run_name || 'Run Native Pipeline' }} | |
| env: | |
| LOCAL_TEST_ARTIFACT_RUN_ID: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID || '' }} | |
| permissions: | |
| packages: write | |
| jobs: | |
| scope: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| scope: ${{ steps.scope.outputs.scope }} | |
| widgets: ${{ steps.scope.outputs.widgets }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 2 # Fetch the latest two commits and its parent commit | |
| - name: "Determine scope" | |
| id: scope | |
| run: | | |
| chmod +x ./.github/scripts/determine-widget-scope.sh | |
| ./.github/scripts/determine-widget-scope.sh "${{ github.event_name }}" "${{ github.event.inputs.workspace }}" "${{ github.event.before }}" "${{ github.sha }}" | |
| - name: "Debug Scope Output" | |
| run: | | |
| echo "Scope is: ${{ steps.scope.outputs.scope }}" | |
| echo "Widgets or js actions are: ${{ steps.scope.outputs.widgets }}" | |
| mendix-version: | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| mendix_version: ${{ steps.set-mendix-version.outputs.MENDIX_VERSION }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| - name: "Get Mendix version from JSON" | |
| id: get-mendix-version | |
| uses: notiz-dev/github-action-json-property@7a701887f4b568b23eb7b78bb0fc49aaeb1b68d3 # v0.2.0 | |
| with: | |
| path: configs/e2e/mendix-versions.json | |
| prop_path: latest | |
| - name: Set Mendix version | |
| id: set-mendix-version | |
| run: | | |
| if [[ -n "${{ github.event.inputs.mendix_version }}" ]]; then | |
| echo "MENDIX_VERSION=${{ github.event.inputs.mendix_version }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "MENDIX_VERSION=${{ steps.get-mendix-version.outputs.prop }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: "Debug Mendix Version" | |
| run: | | |
| echo "Mendix Version: ${{ steps.set-mendix-version.outputs.MENDIX_VERSION }}" | |
| determine-nt-version: | |
| needs: [mendix-version] | |
| runs-on: ubuntu-latest | |
| outputs: | |
| nt_branch: ${{ steps.set-output.outputs.nt_branch }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| - name: "Check if nt_branch was specified" | |
| id: check-input | |
| run: | | |
| if [[ -n "${{ github.event.inputs.nt_branch }}" ]]; then | |
| echo "Using specified nt_branch: ${{ github.event.inputs.nt_branch }}" | |
| echo "nt_branch=${{ github.event.inputs.nt_branch }}" >> $GITHUB_OUTPUT | |
| echo "source=input" >> $GITHUB_OUTPUT | |
| else | |
| echo "No nt_branch specified, will determine from mendix_version" | |
| echo "source=auto" >> $GITHUB_OUTPUT | |
| fi | |
| - name: "Download mendix_version.json from native-template repo" | |
| if: steps.check-input.outputs.source == 'auto' | |
| run: | | |
| curl -s -o mendix_version.json https://raw.githubusercontent.com/mendix/native-template/master/mendix_version.json | |
| cat mendix_version.json | |
| - name: "Determine Native Template version based on Mendix version" | |
| if: steps.check-input.outputs.source == 'auto' | |
| id: determine-nt-branch | |
| run: | | |
| pip install requests packaging | |
| python ./.github/scripts/determine-nt-version.py "${{ needs.mendix-version.outputs.mendix_version }}" | |
| - name: "Set output nt_branch" | |
| id: set-output | |
| run: | | |
| if [[ "${{ steps.check-input.outputs.source }}" == "input" ]]; then | |
| echo "nt_branch=${{ github.event.inputs.nt_branch }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "nt_branch=${{ steps.determine-nt-branch.outputs.nt_branch }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: "Debug final branch output" | |
| run: | | |
| echo "Final nt_branch value: ${{ steps.set-output.outputs.nt_branch }}" | |
| docker-images: | |
| needs: [mendix-version] | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: "Login to GitHub Container Registry" | |
| uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: "Check if docker image already exists" | |
| run: | | |
| docker manifest inspect ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} || EXIT_CODE=$? | |
| echo "IMAGE_MISSING=$EXIT_CODE" >> $GITHUB_ENV | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| if: ${{ env.IMAGE_MISSING != 0 }} | |
| - name: "Build mxbuild image" | |
| if: ${{ env.IMAGE_MISSING != 0 }} | |
| uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 | |
| with: | |
| file: ./.github/scripts/mxbuild.Dockerfile | |
| context: ./.github/scripts | |
| build-args: | | |
| MENDIX_VERSION=${{ needs.mendix-version.outputs.mendix_version }} | |
| push: true | |
| tags: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} | |
| resources: | |
| needs: [scope, mendix-version] | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| packages: read | |
| contents: read | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: "Set up node" | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: yarn | |
| - name: "Install dependencies" | |
| run: yarn install --immutable | |
| - name: "Force rebuild resources" | |
| run: | | |
| # Build JS actions if needed | |
| if [ "${{ github.event.inputs.workspace }}" = "js-actions" ] || \ | |
| [ "${{ github.event.inputs.workspace }}" = "*-native" ] || \ | |
| [ "${{ github.event_name }}" = "schedule" ]; then | |
| yarn workspace mobile-resources-native run build | |
| yarn workspace nanoflow-actions-native run build | |
| fi | |
| # Build widgets if needed (any specific widget, *-native, or nightly) | |
| if [ "${{ github.event.inputs.workspace }}" != "js-actions" ] || \ | |
| [ "${{ github.event.inputs.workspace }}" = "*-native" ] || \ | |
| [ "${{ github.event_name }}" = "schedule" ]; then | |
| widgets=$(echo '${{ needs.scope.outputs.widgets }}' | jq -r '.[]') | |
| for w in $widgets; do | |
| yarn workspace $w run build | |
| done | |
| fi | |
| - name: "Unit test" | |
| run: yarn workspaces foreach ${{ needs.scope.outputs.scope }} run test | |
| - name: "Upload JS actions resources artifact" | |
| if: ${{ github.event.inputs.workspace == 'js-actions' }} | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: resources | |
| path: | | |
| packages/jsActions/mobile-resources-native/dist/**/* | |
| packages/jsActions/nanoflow-actions-native/dist/**/* | |
| - name: "Upload widget and JS actions resources artifact" | |
| if: ${{ github.event.inputs.workspace != 'js-actions' }} | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: resources | |
| path: | | |
| packages/pluggableWidgets/**/dist/*/*.mpk | |
| packages/jsActions/mobile-resources-native/dist/**/* | |
| packages/jsActions/nanoflow-actions-native/dist/**/* | |
| project: | |
| needs: [resources, mendix-version] | |
| runs-on: ubuntu-24.04 | |
| container: | |
| image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - name: "Make sure curl is installed" | |
| run: | | |
| apt update && apt upgrade -y | |
| apt install curl -y | |
| - name: "Download test project" | |
| run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/mx-version/10.zip | |
| - name: "Extract test project" | |
| uses: montudor/action-zip@0852c26906e00f8a315c704958823928d8018b28 # v1.0.0 | |
| with: | |
| args: unzip -qq project.zip -d . | |
| - name: "Rename extracted directory" # Doing this since mxbuild fails with - path too long | |
| run: mv Native-Mobile-Resources-mx-version-10 Native-Mobile-Resources-mx10 | |
| - name: "Download resources artifact" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: resources | |
| path: resources | |
| - name: "List resources" | |
| run: ls -R resources | |
| - name: "Move widgets" | |
| if: ${{ github.event.inputs.workspace != 'js-actions' }} | |
| shell: bash | |
| run: | | |
| if compgen -G 'resources/pluggableWidgets/**/dist/*/*.mpk' > /dev/null; then | |
| for oldPath in resources/pluggableWidgets/**/dist/*/*.mpk; do | |
| newPath=Native-Mobile-Resources-mx10/widgets/$(basename $oldPath) | |
| mv -f $oldPath $newPath | |
| done | |
| mx update-widgets --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr | |
| fi | |
| - name: "Move mobile-resources" | |
| shell: bash | |
| run: | | |
| if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then | |
| mv -f resources/jsActions/mobile-resources-native/* Native-Mobile-Resources-mx10/javascriptsource/nativemobileresources/actions/ | |
| fi | |
| - name: "Move nanoflow-actions" | |
| shell: bash | |
| run: | | |
| if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then | |
| mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-mx10/javascriptsource/nanoflowcommons/actions/ | |
| fi | |
| - name: "Force rebuild test project" | |
| run: | | |
| mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr | |
| - name: "Upload MDA" | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: mda | |
| path: automation.mda | |
| android-bundle: | |
| needs: [project, mendix-version] | |
| runs-on: ubuntu-24.04 | |
| # Skip this job if we're using artifacts from a specific run | |
| if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| container: | |
| image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| - name: "Download deployment package" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| - name: "Create Android bundle" | |
| uses: ./.github/actions/create-native-bundle | |
| with: | |
| platform: android | |
| mda-file: automation.mda | |
| ios-bundle: | |
| needs: [project, mendix-version] | |
| runs-on: ubuntu-24.04 | |
| # Skip this job if we're using artifacts from a specific run | |
| if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| container: | |
| image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| - name: "Download project MDA file" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| - name: "Create iOS bundle" | |
| uses: ./.github/actions/create-native-bundle | |
| with: | |
| platform: ios | |
| mda-file: automation.mda | |
| android-app: | |
| needs: [android-bundle, determine-nt-version] | |
| runs-on: ubuntu-24.04 | |
| # Skip this job if we're using artifacts from a specific run, but allow it to run if android-bundle was skipped | |
| if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' && always() && (needs.android-bundle.result == 'success') }} | |
| steps: | |
| - name: Debug branch value | |
| run: echo "Using branch ${{ needs.determine-nt-version.outputs.nt_branch }}" | |
| - name: "Check out Native Template for Native Components Test Project" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| repository: mendix/native-template | |
| ref: ${{ needs.determine-nt-version.outputs.nt_branch }} | |
| path: native-template | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| path: native-widgets | |
| - name: "Download Android bundle and assets" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: android-bundle | |
| path: bundles/android | |
| - name: "Set up Node" | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 | |
| with: | |
| node-version-file: native-template/.nvmrc | |
| cache: npm | |
| cache-dependency-path: native-template/package-lock.json | |
| - name: "Cache Android Build" | |
| uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 | |
| with: | |
| path: native-template/android/app/build | |
| key: ${{ runner.os }}-android-build-${{ hashFiles('native-template/android/app/src/**/*.java', 'native-template/android/app/src/**/*.kt', 'native-template/android/app/build.gradle') }} | |
| restore-keys: | | |
| ${{ runner.os }}-android-build- | |
| - name: "Copy files to the right location" | |
| run: | | |
| mv bundles/android/index.android.bundle native-template/android/app/src/main/assets/index.android.bundle | |
| cp -r bundles/android/assets/* native-template/android/app/src/main/res/ | |
| mv native-widgets/configs/e2e/config.json native-template | |
| mv native-widgets/configs/e2e/google-services.json native-template/android/app | |
| node native-widgets/scripts/test/add-native-dependencies.js | |
| - name: "Install dependencies" | |
| working-directory: native-template | |
| run: npm i | |
| - name: "Setup JDK " | |
| uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 #v4 | |
| with: | |
| java-version: 21 | |
| distribution: temurin | |
| cache: gradle | |
| - name: "Build Android app" | |
| working-directory: native-template/android | |
| run: | | |
| ./gradlew assembleAppstoreDebug assembleAppstoreDebugAndroidTest | |
| if [ $? -ne 0 ]; then | |
| echo "Build failed!" | |
| exit 1 | |
| fi | |
| - name: "List APK files" | |
| run: | | |
| echo "Listing APK files in the output directory:" | |
| ls -R native-template/android/app/build/outputs/apk/ | |
| - name: "Archive Android app" | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: android-app | |
| path: native-template/android/app/build/outputs/apk/**/*.apk | |
| ios-app: | |
| needs: [ios-bundle, determine-nt-version] | |
| runs-on: macos-15 | |
| # Skip this job if we're using artifacts from a specific run, but allow it to run if ios-bundle was skipped | |
| if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' && always() && (needs.ios-bundle.result == 'success') }} | |
| steps: | |
| - name: "Check out Native Template for Native Components Test Project" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| repository: mendix/native-template | |
| ref: ${{ needs.determine-nt-version.outputs.nt_branch }} | |
| path: native-template | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| path: native-widgets | |
| - name: "Download iOS bundle and assets" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: ios-bundle | |
| path: bundles/ios | |
| - name: "Set up Node" | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 | |
| with: | |
| node-version-file: native-template/.nvmrc | |
| cache: npm | |
| cache-dependency-path: native-template/package-lock.json | |
| - name: "Cache iOS Build" | |
| uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 | |
| with: | |
| path: native-template/ios/build | |
| key: ${{ runner.os }}-ios-build-${{ hashFiles('native-template/ios/**/*.swift', 'native-template/ios/**/*.h', 'native-template/ios/Podfile.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-ios-build- | |
| - name: "Copy files to the right location" | |
| run: | | |
| mv bundles/ios/index.ios.bundle native-template/ios/Bundle/index.ios.bundle | |
| mv bundles/ios/assets/assets native-template/ios/Bundle/ | |
| mv native-widgets/configs/e2e/config.json native-template | |
| node native-widgets/scripts/test/add-native-dependencies.js | |
| - name: "Install Node dependencies" | |
| working-directory: native-template | |
| run: npm i | |
| - name: "Setup Pods cache" | |
| uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 | |
| with: | |
| path: native-template/Pods | |
| key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pods- | |
| - name: "Install Pod dependencies" | |
| working-directory: native-template/ios | |
| run: pod install | |
| - name: "Build iOS app" | |
| working-directory: native-template/ios | |
| run: xcodebuild -workspace NativeTemplate.xcworkspace -scheme nativeTemplate -configuration Debug -sdk iphonesimulator -derivedDataPath build ONLY_ACTIVE_ARCH=YES VALID_ARCHS="i386 x86_64" | |
| - name: "Archive iOS app" | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: ios-app | |
| path: native-template/ios/build/Build/Products/**/*.app | |
| android-widget-tests: | |
| needs: [scope, mendix-version, project, android-app] | |
| # Run if project succeeds and either android-app succeeds OR we're using custom artifacts (android-app was skipped) | |
| if: ${{ (github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule') && always() && needs.project.result == 'success' && (needs.android-app.result == 'success' || needs.android-app.result == 'skipped') }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 60 | |
| strategy: | |
| max-parallel: 5 | |
| matrix: | |
| widget: ${{ fromJson(needs.scope.outputs.widgets) }} | |
| fail-fast: false | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: "Download project MDA file" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| # Used only when specific run id is provided when triggering the jbo | |
| - name: "Download Android app from specific run" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} | |
| uses: ./.github/actions/use-arficats-from-specific-run | |
| with: | |
| artifact_name: android-app | |
| run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} | |
| output_dir: android-app | |
| platform: android | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: "Download Android app" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: android-app | |
| path: android-app | |
| - name: "Setup needed tools" | |
| id: setup-needed-tools | |
| uses: ./.github/actions/setup-tools | |
| with: | |
| mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} | |
| - name: "Start runtime with retry" | |
| uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 | |
| with: | |
| timeout_minutes: 20 | |
| max_attempts: 3 | |
| command: | | |
| chmod +x .github/scripts/start-runtime-with-verification.sh | |
| .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" | |
| - name: Enable KVM | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| - name: "Run android tests" | |
| uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 | |
| with: | |
| api-level: 35 | |
| target: google_apis | |
| arch: x86_64 | |
| profile: pixel | |
| emulator-options: "-no-window -gpu swiftshader_indirect -no-boot-anim -no-snapshot -memory 4096 -cores 4" | |
| disable-animations: true | |
| script: | | |
| chmod +x maestro/helpers/prepare_android.sh | |
| chmod +x maestro/run_maestro_widget_tests.sh | |
| bash maestro/helpers/prepare_android.sh | |
| bash maestro/run_maestro_widget_tests.sh android "${{ matrix.widget }}" | |
| - name: Archive test results | |
| uses: ./.github/actions/archive-test-results | |
| with: | |
| platform: android | |
| test-type: ${{ matrix.widget }} | |
| ios-widget-tests: | |
| needs: [scope, mendix-version, project, ios-app] | |
| # Run if project succeeds and either ios-app succeeds OR we're using custom artifacts (ios-app was skipped) | |
| if: ${{ (github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule') && always() && needs.project.result == 'success' && (needs.ios-app.result == 'success' || needs.ios-app.result == 'skipped') }} | |
| runs-on: macos-15 | |
| timeout-minutes: 60 | |
| strategy: | |
| max-parallel: 5 | |
| matrix: | |
| widget: ${{ fromJson(needs.scope.outputs.widgets) }} | |
| fail-fast: false | |
| steps: | |
| - name: "Force cleanup workspace" | |
| run: | | |
| # Kill all Git and Xcode processes aggressively | |
| sudo pkill -9 -f git || true | |
| sudo pkill -9 -f xcodebuild || true | |
| sudo pkill -9 -f node || true | |
| # Wait for processes to be killed | |
| sleep 5 | |
| # Clean the workspace contents while preserving directory structure | |
| cd /Users/runner/work/native-widgets | |
| if [ -d "native-widgets" ]; then | |
| cd native-widgets | |
| # Force remove all git state and locks with extreme prejudice | |
| sudo rm -rf .git || true | |
| find . -name "*.lock" -type f -exec sudo rm -f {} \; 2>/dev/null || true | |
| find . -name ".git*" -exec sudo rm -rf {} \; 2>/dev/null || true | |
| # Remove all other contents | |
| sudo find . -mindepth 1 -not -path "./.git*" -delete 2>/dev/null || true | |
| fi | |
| # Final wait and process cleanup | |
| sudo pkill -9 -f git || true | |
| sleep 3 | |
| continue-on-error: true | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 1 | |
| fetch-tags: false | |
| clean: true | |
| ref: ${{ github.sha }} | |
| - name: "Download project MDA file" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| # Used only for local testing, will be empty on GitHub | |
| - name: "Download iOS app from specific run" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} | |
| uses: ./.github/actions/use-arficats-from-specific-run | |
| with: | |
| artifact_name: ios-app | |
| run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} | |
| output_dir: ios-app | |
| platform: ios | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: "Download iOS app" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: ios-app | |
| path: ios-app | |
| - name: "Setup needed tools" | |
| id: setup-needed-tools | |
| uses: ./.github/actions/setup-tools | |
| with: | |
| mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} | |
| - name: "Start runtime with retry" | |
| uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 | |
| with: | |
| timeout_minutes: 10 | |
| max_attempts: 3 | |
| command: | | |
| chmod +x .github/scripts/start-runtime-with-verification.sh | |
| .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" | |
| - name: "Setup Xcode CLI Tools" | |
| uses: ./.github/actions/setup-xcode-cli-tools | |
| - name: "Run iOS tests" | |
| run: | | |
| chmod +x maestro/helpers/prepare_ios.sh | |
| chmod +x maestro/run_maestro_widget_tests.sh | |
| bash maestro/helpers/prepare_ios.sh | |
| bash maestro/run_maestro_widget_tests.sh ios "${{ matrix.widget }}" | |
| - name: Archive test results | |
| uses: ./.github/actions/archive-test-results | |
| with: | |
| platform: ios | |
| test-type: ${{ matrix.widget }} | |
| android-js-tests: | |
| needs: [scope, mendix-version, project, android-app] | |
| # Run if project succeeds and either android-app succeeds OR we're using custom artifacts (android-app was skipped) | |
| if: ${{ (github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions' || contains(needs.scope.outputs.widgets, 'mobile-resources-native') || contains(needs.scope.outputs.widgets, 'nanoflow-actions-native')) && always() && needs.project.result == 'success' && (needs.android-app.result == 'success' || needs.android-app.result == 'skipped') }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 90 | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: "Download project MDA file" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| # Used only for local testing, will be empty on GitHub | |
| - name: "Download Android app from specific run" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} | |
| uses: ./.github/actions/use-arficats-from-specific-run | |
| with: | |
| artifact_name: android-app | |
| run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} | |
| output_dir: android-app | |
| platform: android | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: "Download Android app" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: android-app | |
| path: android-app | |
| - name: "Setup needed tools" | |
| id: setup-needed-tools | |
| uses: ./.github/actions/setup-tools | |
| with: | |
| mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} | |
| - name: "Start runtime with retry" | |
| uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 | |
| with: | |
| timeout_minutes: 10 | |
| max_attempts: 3 | |
| command: | | |
| chmod +x .github/scripts/start-runtime-with-verification.sh | |
| .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" | |
| - name: Enable KVM | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| - name: "Run android tests" | |
| uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 | |
| with: | |
| api-level: 35 | |
| target: google_apis | |
| arch: x86_64 | |
| profile: pixel | |
| emulator-options: "-no-window -gpu swiftshader_indirect -no-boot-anim -no-snapshot -memory 4096 -cores 4" | |
| disable-animations: true | |
| script: | | |
| chmod +x maestro/helpers/prepare_android.sh | |
| chmod +x maestro/run_maestro_jsactions_tests.sh | |
| bash maestro/helpers/prepare_android.sh | |
| bash maestro/run_maestro_jsactions_tests.sh android | |
| - name: Archive test results | |
| uses: ./.github/actions/archive-test-results | |
| with: | |
| platform: android | |
| test-type: js-actions | |
| ios-js-tests: | |
| needs: [scope, mendix-version, project, ios-app] | |
| # Run if project succeeds and either ios-app succeeds OR we're using custom artifacts (ios-app was skipped) | |
| if: ${{ (github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions' || contains(needs.scope.outputs.widgets, 'mobile-resources-native') || contains(needs.scope.outputs.widgets, 'nanoflow-actions-native')) && always() && needs.project.result == 'success' && (needs.ios-app.result == 'success' || needs.ios-app.result == 'skipped') }} | |
| runs-on: macos-15 | |
| timeout-minutes: 90 | |
| steps: | |
| - name: "Clean up any Git locks" | |
| run: | | |
| # Kill all git and related processes aggressively | |
| sudo pkill -9 -f git || true | |
| sudo pkill -9 -f node || true | |
| # Wait for processes to be killed | |
| sleep 5 | |
| # Clean the workspace contents while preserving directory structure | |
| cd /Users/runner/work/native-widgets | |
| if [ -d "native-widgets" ]; then | |
| cd native-widgets | |
| # Force remove git state and locks | |
| sudo rm -rf .git || true | |
| find . -name "*.lock" -type f -exec sudo rm -f {} \; 2>/dev/null || true | |
| find . -name ".git*" -exec sudo rm -rf {} \; 2>/dev/null || true | |
| # Remove all other contents | |
| sudo find . -mindepth 1 -not -path "./.git*" -delete 2>/dev/null || true | |
| fi | |
| # Final cleanup | |
| sudo pkill -9 -f git || true | |
| sleep $((RANDOM % 5 + 3)) | |
| continue-on-error: true | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| with: | |
| fetch-depth: 1 | |
| fetch-tags: false | |
| clean: true | |
| - name: "Download project MDA file" | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: mda | |
| # Used only for local testing, will be empty on GitHub | |
| - name: "Download iOS app from specific run" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} | |
| uses: ./.github/actions/use-arficats-from-specific-run | |
| with: | |
| artifact_name: ios-app | |
| run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} | |
| output_dir: ios-app | |
| platform: ios | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: "Download iOS app" | |
| if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} | |
| uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 | |
| with: | |
| name: ios-app | |
| path: ios-app | |
| - name: "Setup needed tools" | |
| id: setup-needed-tools | |
| uses: ./.github/actions/setup-tools | |
| with: | |
| mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} | |
| - name: "Start runtime with retry" | |
| uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 | |
| with: | |
| timeout_minutes: 10 | |
| max_attempts: 3 | |
| command: | | |
| chmod +x .github/scripts/start-runtime-with-verification.sh | |
| .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" | |
| - name: "Setup Xcode CLI Tools" | |
| uses: ./.github/actions/setup-xcode-cli-tools | |
| - name: "Run iOS tests" | |
| run: | | |
| chmod +x maestro/helpers/prepare_ios.sh | |
| chmod +x maestro/run_maestro_jsactions_tests.sh | |
| bash maestro/helpers/prepare_ios.sh | |
| bash maestro/run_maestro_jsactions_tests.sh ios | |
| - name: Archive test results | |
| uses: ./.github/actions/archive-test-results | |
| with: | |
| platform: ios | |
| test-type: js-actions | |
| compare-screenshots: | |
| needs: [scope, android-widget-tests, ios-widget-tests, android-js-tests, ios-js-tests] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - name: "Check out code" | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
| - name: "Download Android screenshots" | |
| run: | | |
| widgets=$(echo '${{ needs.scope.outputs.widgets }}' | jq -r '.[]') | |
| mkdir -p images/actual/android/ | |
| for widget in $widgets; do | |
| echo "Downloading android-screenshots-${widget}" | |
| gh run download ${{ github.run_id }} --name android-screenshots-${widget} --dir images/actual/android/ || true | |
| ls -l images/actual/android/ | |
| done | |
| # Download JS actions screenshots | |
| echo "Downloading android-screenshots-js-actions" | |
| gh run download ${{ github.run_id }} --name android-screenshots-js-actions --dir images/actual/android/ || true | |
| ls -l images/actual/android/ | |
| - name: "Download iOS screenshots" | |
| run: | | |
| widgets=$(echo '${{ needs.scope.outputs.widgets }}' | jq -r '.[]') | |
| mkdir -p images/actual/ios/ | |
| for widget in $widgets; do | |
| echo "Downloading ios-screenshots-${widget}" | |
| gh run download ${{ github.run_id }} --name ios-screenshots-${widget} --dir images/actual/ios/ || true | |
| ls -l images/actual/ios/ | |
| done | |
| # Download JS actions screenshots | |
| echo "Downloading ios-screenshots-js-actions" | |
| gh run download ${{ github.run_id }} --name ios-screenshots-js-actions --dir images/actual/ios/ || true | |
| ls -l images/actual/ios/ | |
| - name: "Setup Node and dependencies" | |
| uses: ./.github/actions/setup-node-with-cache | |
| - name: "Compare Android screenshots" | |
| continue-on-error: true | |
| run: node ${{ github.workspace }}/maestro/helpers/compare_screenshots.js android | |
| - name: "Compare iOS screenshots" | |
| continue-on-error: true | |
| run: node ${{ github.workspace }}/maestro/helpers/compare_screenshots.js ios | |
| - name: "Archive diff results" | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: screenshot-diffs | |
| path: images/diffs | |
| if-no-files-found: ignore | |
| - name: "Archive comparison results" | |
| uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 | |
| with: | |
| name: comparison-results | |
| path: compare_output.txt | |
| if-no-files-found: ignore | |
| - name: "Fail if comparisons failed" | |
| run: | | |
| if [ "$ANDROID_COMPARISON_FAILED" == "true" ] || [ "$IOS_COMPARISON_FAILED" == "true" ]; then | |
| echo "One or more comparisons failed." | |
| exit 1 | |
| fi |