diff --git a/.github/composite_actions/run_xcodebuild/action.yml b/.github/composite_actions/run_xcodebuild/action.yml index 1a39188604..d5567939bf 100644 --- a/.github/composite_actions/run_xcodebuild/action.yml +++ b/.github/composite_actions/run_xcodebuild/action.yml @@ -19,6 +19,14 @@ inputs: required: false type: string default: 'iphonesimulator' + cloned_source_packages_path: + required: false + type: string + default: '' + derived_data_path: + required: false + type: string + default: '' disable_package_resolution: required: false type: boolean @@ -36,6 +44,8 @@ runs: SCHEME: ${{ inputs.scheme }} PROJECT_PATH: ${{ inputs.project_path }} XCODE_PATH: ${{ inputs.xcode_path }} + CLONED_SOURCE_PACKAGES_PATH: ${{ inputs.cloned_source_packages_path }} + DERIVED_DATA_PATH: ${{ inputs.derived_data_path }} run: | if [ ! -z "$PROJECT_PATH" ]; then cd $PROJECT_PATH @@ -46,8 +56,20 @@ runs: otherFlags="${{ inputs.other_flags }}" if [ "${{ inputs.disable_package_resolution }}" == "true" ]; then + echo "Disabling Automatic Package Resolution" otherFlags+=" -disableAutomaticPackageResolution" fi + + if [ ! -z "$DERIVED_DATA_PATH" ]; then + echo "Using custom DerivedData path" + otherFlags+=" -derivedDataPath $DERIVED_DATA_PATH" + fi + + if [ ! -z "$CLONED_SOURCE_PACKAGES_PATH" ]; then + echo "Using custom cloned source packages path" + otherFlags+=" -clonedSourcePackagesDirPath $CLONED_SOURCE_PACKAGES_PATH" + fi + xcodebuild -version xcodebuild build -scheme $SCHEME -sdk '${{ inputs.sdk }}' -destination '${{ inputs.destination }}' $otherFlags | xcpretty --simple --color --report junit && exit ${PIPESTATUS[0]} shell: bash \ No newline at end of file diff --git a/.github/workflows/build_and_test_amplify.yml b/.github/workflows/build_and_test_amplify.yml new file mode 100644 index 0000000000..5fc255e63c --- /dev/null +++ b/.github/workflows/build_and_test_amplify.yml @@ -0,0 +1,150 @@ +name: Build and Test the Amplify Package +on: + - push + +permissions: + contents: read + actions: write + +jobs: + build-amplify-swift: + name: Build for ${{ matrix.platform }} + runs-on: macos-13 + strategy: + fail-fast: false + matrix: + platform: [iOS, macOS, tvOS, watchOS] + steps: + - name: Checkout repository + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 #v3.5.3 + with: + persist-credentials: false + + - name: Get build parameters for ${{ matrix.platform }} + id: platform + uses: ./.github/composite_actions/get_platform_parameters + with: + platform: ${{ matrix.platform }} + xcode_version: '14.3' + + - name: Attempt to use the dependencies cache + id: dependencies-cache + timeout-minutes: 4 + continue-on-error: true + uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ~/Library/Developer/Xcode/DerivedData/Amplify + key: amplify-packages-${{ hashFiles('Package.resolved') }} + restore-keys: | + amplify-packages- + + - name: Attempt to restore the build cache from main + id: build-cache + timeout-minutes: 4 + continue-on-error: true + uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ${{ github.workspace }}/Build + key: Amplify-${{ matrix.platform }}-cache-main + + - name: Build Amplify-Package + id: build-package + continue-on-error: true + uses: ./.github/composite_actions/run_xcodebuild + with: + scheme: Amplify-Package + destination: ${{ steps.platform.outputs.destination }} + sdk: ${{ steps.platform.outputs.sdk }} + xcode_path: /Applications/Xcode_14.3.app + cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify + derived_data_path: ${{ github.workspace }}/Build + disable_package_resolution: ${{ steps.dependencies-cache.outputs.cache-hit }} + + - name: Save the build cache + uses: actions/cache/save@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ${{ github.workspace }}/Build + key: Amplify-${{ matrix.platform }}-cache-${{ github.ref_name }} + + run-unit-tests: + name: ${{ matrix.scheme }} Unit Tests + needs: [build-amplify-swift] + strategy: + fail-fast: false + matrix: + platform: [iOS, macOS, tvOS, watchOS] + scheme: [ + { name: Amplify, reportCoverage: true }, + { name: AWSPluginsCore, reportCoverage: true }, + { name: AWSAPIPlugin, reportCoverage: true }, + { name: AWSCloudWatchLoggingPlugin, reportCoverage: true }, + { name: AWSCognitoAuthPlugin, reportCoverage: true }, + { name: AWSDataStorePlugin, reportCoverage: true }, + { name: AWSLocationGeoPlugin, reportCoverage: true }, + { name: AWSPredictionsPlugin, reportCoverage: true }, + { name: AWSPinpointAnalyticsPlugin, reportCoverage: true }, + { name: AWSPinpointPushNotificationsPlugin, reportCoverage: true }, + { name: AWSS3StoragePlugin, reportCoverage: true }, + { name: CoreMLPredictionsPlugin, reportCoverage: true }, + { name: InternalAWSPinpointUnitTests, reportCoverage: false }, + ] + uses: ./.github/workflows/run_unit_tests.yml + with: + scheme: ${{ matrix.scheme.name }} + platform: ${{ matrix.platform }} + xcode_version: '14.3' + generate_coverage_report: ${{ matrix.platform == 'iOS' && matrix.scheme.reportCoverage }} + build_cache_key: Amplify-${{ matrix.platform }}-cache-${{ github.ref_name }} + test_without_building: true + + report-coverage: + name: ${{ matrix.file.scheme }} Coverage Report + needs: [run-unit-tests] + strategy: + fail-fast: false + matrix: + file: [ + { scheme: Amplify, flags: 'Amplify,unit_tests' }, + { scheme: AWSPluginsCore, flags: 'AWSPluginsCore,unit_tests' }, + { scheme: AWSAPIPlugin, flags: 'API_plugin_unit_test,unit_tests' }, + { scheme: AWSCloudWatchLoggingPlugin, flags: 'Logging_plugin_unit_test,unit_tests' }, + { scheme: AWSCognitoAuthPlugin, flags: 'Auth_plugin_unit_test,unit_tests' }, + { scheme: AWSDataStorePlugin, flags: 'DataStore_plugin_unit_test,unit_tests' }, + { scheme: AWSLocationGeoPlugin, flags: 'Geo_plugin_unit_test,unit_tests' }, + { scheme: AWSPredictionsPlugin, flags: 'Predictions_plugin_unit_test,unit_tests' }, + { scheme: AWSPinpointAnalyticsPlugin, flags: 'Analytics_plugin_unit_test,unit_tests' }, + { scheme: AWSPinpointPushNotificationsPlugin, flags: 'PushNotifications_plugin_unit_test,unit_tests' }, + { scheme: AWSS3StoragePlugin, flags: 'Storage_plugin_unit_test,unit_tests' }, + { scheme: CoreMLPredictionsPlugin, flags: 'CoreMLPredictions_plugin_unit_test,unit_tests' } + ] + uses: ./.github/workflows/upload_coverage_report.yml + with: + scheme: ${{ matrix.file.scheme }} + flags: ${{ matrix.file.flags }} + + delete-package-cache: + if: github.ref_name != 'main' + name: Delete ${{ matrix.platform }} cache + runs-on: ubuntu-latest + needs: [run-unit-tests] + continue-on-error: true + env: + GH_TOKEN: ${{ github.token }} + strategy: + fail-fast: false + matrix: + platform: [iOS, macOS, tvOS, watchOS] + steps: + - run: | + gh cache delete Amplify-${{ matrix.platform }}-cache-${{ github.ref_name }} + shell: bash + + unit-test-pass-confirmation: + runs-on: ubuntu-latest + name: Confirm Passing Unit Tests + if: ${{ !cancelled() }} + needs: [ run-unit-tests ] + env: + EXIT_CODE: ${{ contains(needs.*.result, 'failure') && 1 || 0 }} + steps: + - run: exit $EXIT_CODE diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml new file mode 100644 index 0000000000..af5c6b739b --- /dev/null +++ b/.github/workflows/run_unit_tests.yml @@ -0,0 +1,138 @@ +name: Run Unit Tests for the given parameters +on: + workflow_call: + inputs: + scheme: + description: 'The scheme to run the tests' + required: true + type: string + platform: + description: 'The platform in which to run these tests' + required: true + type: string + project_path: + required: false + type: string + xcode_version: + description: 'The version of Xcode used to run these tests' + required: true + type: string + timeout-minutes: + description: 'The timeout for each execution' + required: false + type: number + default: 30 + generate_coverage_report: + description: 'Whether to generate and report code coverage' + required: false + type: boolean + default: false + build_cache_key: + description: 'The key used to retrieve the build cache' + required: false + default: '' + type: string + test_without_building: + type: boolean + required: false + default: false + +permissions: + contents: read + actions: write + +jobs: + unit-tests: + name: ${{ inputs.platform }} Tests | ${{ inputs.scheme }} + runs-on: macos-13 + timeout-minutes: ${{ inputs.timeout-minutes }} + steps: + - name: Checkout repository + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 #v3.5.3 + with: + persist-credentials: false + + - name: Get build parameters for ${{ inputs.platform}} + id: platform + uses: ./.github/composite_actions/get_platform_parameters + with: + platform: ${{ inputs.platform }} + xcode_version: ${{ inputs.xcode_version }} + + - name: Attempt to use the dependencies cache + id: dependencies-cache + timeout-minutes: 4 + continue-on-error: true + uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ~/Library/Developer/Xcode/DerivedData/Amplify + key: amplify-packages-${{ hashFiles('Package.resolved') }} + restore-keys: | + amplify-packages- + + - name: Attempt to restore the build cache + id: build-cache + timeout-minutes: 4 + continue-on-error: true + uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ${{ github.workspace }}/Build + key: ${{ inputs.build_cache_key || format('{0}-{1}-latest-build-main', inputs.scheme, inputs.platform) }} + + - name: Run ${{ inputs.platform }} Unit Tests + id: run-tests + continue-on-error: true + uses: ./.github/composite_actions/run_xcodebuild_test + with: + scheme: ${{ inputs.scheme }} + destination: ${{ steps.platform.outputs.destination }} + sdk: ${{ steps.platform.outputs.sdk }} + xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + generate_coverage: ${{ inputs.generate_coverage_report }} + cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify + derived_data_path: ${{ github.workspace }}/Build + disable_package_resolution: ${{ steps.dependencies-cache.outputs.cache-hit }} + test_without_building: ${{ inputs.test_without_building && steps.dependencies-cache.outputs.cache-hit }} + other_flags: -test-iterations 3 -retry-tests-on-failure + + - name: Retry ${{ inputs.platform }} Unit Tests + if: steps.run-tests.outcome=='failure' + id: retry-tests + uses: ./.github/composite_actions/run_xcodebuild_test + with: + scheme: ${{ inputs.scheme }} + destination: ${{ steps.platform.outputs.destination }} + sdk: ${{ steps.platform.outputs.sdk }} + xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + project_path: ${{ inputs.project_path }} + generate_coverage: true + cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify + derived_data_path: ${{ github.workspace }}/Build + disable_package_resolution: true + test_without_building: ${{ inputs.test_without_building && steps.dependencies-cache.outputs.cache-hit}} + other_flags: -test-iterations 3 -retry-tests-on-failure + + - name: Delete the old build cache on main + if: github.ref_name == 'main' && steps.build-cache.outputs.cache-hit + env: + GH_TOKEN: ${{ github.token }} + continue-on-error: true + run: | + gh cache delete ${{ steps.build-cache.outputs.cache-primary-key }} + shell: bash + + - name: Save the new build cache on main + if: github.ref_name == 'main' + uses: actions/cache/save@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: ${{ github.workspace }}/Build + key: ${{ steps.build-cache.outputs.cache-primary-key }} + + - name: Store Coverage Report File + if: ${{ inputs.generate_coverage_report == true }} + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce #v3.1.2 + with: + name: ${{ inputs.scheme }}-Coverage-${{ github.sha }} + path: ${{ github.workspace }}/${{ inputs.scheme }}-Coverage.lcov + if-no-files-found: error + retention-days: 1