diff --git a/.github/actions/gen_code/action.yml b/.github/actions/gen_code/action.yml new file mode 100644 index 000000000..207a1dc95 --- /dev/null +++ b/.github/actions/gen_code/action.yml @@ -0,0 +1,47 @@ +name: Gen code +description: 'Generate code for the given public headers' + +inputs: + code_gen_public_headers: + description: 'The public headers to generate, e.g. rtc_4.5.0, leave empty will use the same as the target branch' + required: false + default: '' + + flutter_channel: + description: 'Target Flutter channel, e.g. stable(default), beta, dev, master (or main), or any other channel name' + required: false + default: 'stable' + + flutter_version: + description: 'Target Flutter version, e.g. 3.24.5, 3.24.x, commit hash, or leave empty to use the latest release version of specified channel by flutter_version(default)' + required: false + # we should use the latest stable version for build and gen code, but the 3.19.6 is the latest version which will gen compatible code for our flutter project, + # so we fixed use the 3.19.6 version here for now + default: '3.19.6' + + working_directory: + description: 'The working directory of the action' + required: false + default: './' + +runs: + using: composite + steps: + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: ${{ inputs.flutter_channel }} + flutter-version: ${{ inputs.flutter_version }} + cache: true + + - name: Gen + uses: AgoraIO-Extensions/actions/.github/actions/generate@main + with: + generate-code: true + generate-comment: false + working-directory: ${{ inputs.working_directory }} + generate-code-command: | + corepack enable && bash scripts/code_gen.sh ${{ inputs.code_gen_public_headers }} + generate-comment-command: "" + github-token: "" + diff --git a/.github/actions/prepare_branch/action.yml b/.github/actions/prepare_branch/action.yml new file mode 100644 index 000000000..7b6532688 --- /dev/null +++ b/.github/actions/prepare_branch/action.yml @@ -0,0 +1,69 @@ +name: Prepare branch +description: 'Prepare a branch for the given pub version' + +inputs: + target_branch: + description: 'The target branch to prepare the branch for' + required: true + + pub_version: + description: 'The pub version to prepare the branch for' + required: true + + branch_group: + description: 'The group of the branch name, e.g. special or dev, default is special' + required: false + default: 'special' + + working_directory: + description: 'The working directory of the action' + required: false + default: './' + +outputs: + final_target_branch: + description: 'The final target branch' + value: ${{ steps.prepare.outputs.final_target_branch }} + +runs: + using: composite + steps: + - name: Prepare branch + id: prepare + shell: bash + working-directory: ${{ inputs.working_directory }} + run: | + # Fetch all remote refs + git fetch --all + + # Function to check if branch exists remotely + check_remote_branch() { + git ls-remote --heads origin "refs/heads/$1" | grep -q "refs/heads/$1$" + return $? + } + + # Check if target_branch exists as a remote branch + check_remote_branch "${{ inputs.target_branch }}" + if [ $? -ne 0 ]; then + echo "Target branch does not exist as a remote branch, treating as a commit/tag reference" + + # get pub_version from pubspec.yaml if inputs.pub_version is empty + pub_version=${{ inputs.pub_version }} + if [ -z "${pub_version}" ]; then + pub_version=$(grep 'version: ' pubspec.yaml | sed -e 's,.*: \(.*\),\1,') + fi + + final_target_branch=${{ inputs.branch_group }}/${pub_version} + + # create a new branch named "${{ inputs.branch_group }}/${pub_version}" from the reference + git checkout -B ${final_target_branch} + + # push the new branch to the remote repository, set the result always as success even if the push failed + git push -u origin HEAD:${final_target_branch} || true + else + echo "Target branch exists as a remote branch" + final_target_branch="${{ inputs.target_branch }}" + + fi + + echo "final_target_branch=${final_target_branch}" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/actions/pub/Dockerfile b/.github/actions/pub/Dockerfile new file mode 100644 index 000000000..ee6a83e64 --- /dev/null +++ b/.github/actions/pub/Dockerfile @@ -0,0 +1,13 @@ +FROM dart:latest + +RUN pwd + +# RUN echo "Files in current directory:" && ls -la . + +COPY . / + +RUN chmod +x /entrypoint.sh + +# RUN echo "Files after COPY:" && ls -la / + +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/.github/actions/pub/action.yml b/.github/actions/pub/action.yml new file mode 100644 index 000000000..dbca7fb53 --- /dev/null +++ b/.github/actions/pub/action.yml @@ -0,0 +1,69 @@ +# https://github.com/k-paxian/dart-package-publisher +name: 'Dart and Flutter Package Publisher' +description: 'Continuously Test & Publish Dart and Flutter Package To Pub.dev When Version Changed' +author: 'k-paxian' +branding: + color: 'blue' + icon: 'package' +inputs: + accessToken: + description: '(Required) Token from ~/.pub-cache/credentials.json. Use secrets.OAUTH_ACCESS_TOKEN' + required: true + refreshToken: + description: '(Required) Token from ~/.pub-cache/credentials.json. Use secrets.OAUTH_REFRESH_TOKEN' + required: true + credentialJson: + description: '(Optional) Overrides accessToken and refreshToken. Whole content of ~/.pub-cache/credentials.json. Use secrets.CREDENTIAL_JSON' + required: false + relativePath: + description: '(Optional) Path to your package root in your repository' + required: false + default: '' + dryRunOnly: + description: '(Optional) Perform dry run only, no real publishing' + required: false + default: false + testRunOnly: + description: '(Optional) Perform unit tests run only, no real publishing' + required: false + default: false + skipTests: + description: '(Optional) Skip unit tests run' + required: false + default: false + suppressBuildRunner: + description: '(Optional) Suppress using `build_runner` for unit tests run' + required: false + default: false + format: + description: '(Optional) Format code of project to get better score in pub.dev' + required: false + default: false + force: + description: '(Optional) Force publishing even if pub tool throws warnings, hints, etc' + required: false + default: false + flutter: + description: '(Optional) Flutter package type' + required: false + default: false + flutterBranch: + description: '(Optional) Flutter branch to use, stable, master, main, dev, etc.' + required: false + default: 'stable' +outputs: + success: + description: 'Result, "true" if actual publishing happened, "false" otherwise' + package: + description: 'Package name from pubspec' + localVersion: + description: 'Package local version from pubspec' + remoteVersion: + description: 'Package remote version from pub.dev' + dartVersion: + description: 'Dart SDK version which is being used to run tests & publish' + flutterVersion: + description: 'Flutter SDK version which is being used to run tests & publish' +runs: + using: 'docker' + image: 'Dockerfile' \ No newline at end of file diff --git a/.github/actions/pub/entrypoint.sh b/.github/actions/pub/entrypoint.sh new file mode 100644 index 000000000..fbcde0579 --- /dev/null +++ b/.github/actions/pub/entrypoint.sh @@ -0,0 +1,200 @@ +#!/bin/bash + +set -e + +export PATH="$PATH":"$HOME/.pub-cache/bin" + +trace() { + local message=$1 + local summary=$2 + + if [ -z "$message" ]; then + : + else + echo "$message" + fi + + if [ -z "$summary" ]; then + : + else + echo "$summary" >> $GITHUB_STEP_SUMMARY + fi +} + +check_required_inputs() { + trace "πŸ”‘ Check credentials..." + if [ -z "$INPUT_CREDENTIALJSON" ]; then + trace "Missing credentialJson, using tokens" + if [ -z "$INPUT_ACCESSTOKEN" ]; then + trace "❌ Missing accessToken" + exit 1 + fi + if [ -z "$INPUT_REFRESHTOKEN" ]; then + trace "❌ Missing refreshToken" + exit 1 + fi + fi +} + +switch_working_directory() { + if [ -z "$INPUT_RELATIVEPATH" ]; then + : + else + trace "Switching to package directory '$INPUT_RELATIVEPATH'" + cd "$INPUT_RELATIVEPATH" + fi + trace "Package dir: $PWD" +} + +detect_flutter_package() { + GET_OUTPUT=`dart pub get` + if [ "$?" = 69 ] || [ "$GET_OUTPUT" = "Resolving dependencies..." ] || [ "$INPUT_FLUTTER" = "true" ]; then + INPUT_FLUTTER="true" + export PATH="$PATH":"/flutter/bin" + trace "Flutter package detected. Installing Flutter from $INPUT_FLUTTERBRANCH branch..." + git clone -b $INPUT_FLUTTERBRANCH https://github.com/flutter/flutter.git /flutter + flutter doctor + fi +} + +get_local_package_version() { + if [ "$INPUT_FLUTTER" = "true" ]; then + GET_OUTPUT=`flutter pub get` + DEPS_OUTPUT=`flutter pub deps` + else + GET_OUTPUT=`dart pub get` + DEPS_OUTPUT=`dart pub deps` + fi + PACKAGE_INFO=`echo "$DEPS_OUTPUT" | perl -0777 -pe 's/(β””|β”‚|(?> $GITHUB_OUTPUT + if [ "$FLUTTER_VERSION" != "" ]; then + echo "flutterVersion=$FLUTTER_VERSION" >> $GITHUB_OUTPUT + fi + echo "package=$PACKAGE" >> $GITHUB_OUTPUT + echo "localVersion=$LOCAL_PACKAGE_VERSION" >> $GITHUB_OUTPUT +} + +run_unit_tests() { + if [ "$INPUT_SKIPTESTS" = "true" ]; then + trace "::notice::Skip unit tests set to true, skip unit testing." + else + HAS_BUILD_RUNNER=`echo "$DEPS_OUTPUT" | perl -n -e'/^.* build_runner (.*)/ && print $1'` + HAS_BUILD_TEST=`echo "$DEPS_OUTPUT" | perl -n -e'/^.* build_test (.*)/ && print $1'` + HAS_TEST=`echo "$DEPS_OUTPUT" | perl -n -e'/^.* (test|flutter_test) (.*)/ && print $2'` + if [ "$HAS_BUILD_RUNNER" != "" ] && [ "$HAS_BUILD_TEST" != "" ] && [ "$INPUT_SUPPRESSBUILDRUNNER" != "true" ]; then + if [ "$INPUT_FLUTTER" = "true" ]; then + trace "::notice::flutter tests with build_runner" + flutter pub run build_runner build --delete-conflicting-outputs + flutter test + else + dart pub run build_runner test --delete-conflicting-outputs + fi + else + if [ "$HAS_TEST" != "" ]; then + if [ "$INPUT_FLUTTER" = "true" ]; then + flutter test + else + dart pub run test + fi + else + trace "::notice::No unit test related dependencies detected, skip unit testing." "No unit test related dependencies detected, skip unit testing." + fi + fi + fi +} + +get_remote_package_version() { + if [ "$INPUT_FLUTTER" = "true" ]; then + ACTIVATE_OUTPUT=`flutter pub global activate $PACKAGE` + else + ACTIVATE_OUTPUT=`dart pub global activate $PACKAGE` + fi + REMOTE_PACKAGE_VERSION=`echo "$ACTIVATE_OUTPUT" | perl -n -e'/^Activated .* (.*)\./ && print $1'` + if [ -z "$REMOTE_PACKAGE_VERSION" ]; then + REMOTE_PACKAGE_VERSION="βœ—" + fi + trace "::notice::Local version: [$LOCAL_PACKAGE_VERSION]" "Local version: [$LOCAL_PACKAGE_VERSION]" + trace "::notice::Remote version: [$REMOTE_PACKAGE_VERSION]" "Remote version: [$REMOTE_PACKAGE_VERSION]" + echo "remoteVersion=$REMOTE_PACKAGE_VERSION" >> $GITHUB_OUTPUT +} + +format() { + if [ "$INPUT_FORMAT" = "true" ]; then + if [ "$INPUT_FLUTTER" = "true" ]; then + flutter format . + else + dart format . + fi + fi +} + +publish() { + if [ "$LOCAL_PACKAGE_VERSION" = "$REMOTE_PACKAGE_VERSION" ]; then + trace "::notice::Remote & Local versions are equal, skip publishing." "πŸ“Remote & Local versions are equal, skip publishing." + else + mkdir -p ~/.config/dart + if [ -z "$INPUT_CREDENTIALJSON" ]; then + cat <<-EOF > ~/.config/dart/pub-credentials.json + { + "accessToken":"$INPUT_ACCESSTOKEN", + "refreshToken":"$INPUT_REFRESHTOKEN", + "tokenEndpoint":"https://accounts.google.com/o/oauth2/token", + "scopes": [ "openid", "https://www.googleapis.com/auth/userinfo.email" ], + "expiration": 1577149838000 + } +EOF + else + echo "$INPUT_CREDENTIALJSON" > ~/.config/dart/pub-credentials.json + fi + trace "Dry πŸƒ..." + if [ "$INPUT_FLUTTER" = "true" ]; then + flutter pub publish --dry-run + else + dart pub lish --dry-run + fi + if [ $? -eq 0 ]; then + trace "::notice::Dry πŸƒ Successfull." + else + if [ "$INPUT_FORCE" != "true" ] && [ "$INPUT_TESTRUNONLY" != "true" ]; then + trace "::error::Dry πŸƒ Failed, skip real publishing." "❌ Dry πŸƒ Failed, skip real publishing." + exit 1 + fi + fi + if [ "$INPUT_DRYRUNONLY" = "true" ]; then + trace "::notice::Dry πŸƒ only, skip publishing." "Dry πŸƒ only, skip publishing." + else + trace "πŸ“¦ Publishing..." + if [ "$INPUT_FLUTTER" = "true" ]; then + flutter pub publish -f + else + dart pub lish -f + fi + if [ $? -eq 0 ]; then + echo "success=true" >> $GITHUB_OUTPUT + trace "πŸš€" "πŸš€" + else + echo "success=false" >> $GITHUB_OUTPUT + trace "❌" "❌" + fi + fi + fi +} + +check_required_inputs +switch_working_directory +detect_flutter_package || true +get_local_package_version +run_unit_tests +get_remote_package_version || true +format || true +publish || true diff --git a/.github/workflows/ triage-agora-support.yaml b/.github/workflows/ triage-agora-support.yaml deleted file mode 100644 index 0c1bf2db3..000000000 --- a/.github/workflows/ triage-agora-support.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: Triage to Agora Support -on: - issues: - types: - - labeled -jobs: - add-comment: - if: github.event.label.name == 'triage agora support' - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Add comment - uses: peter-evans/create-or-update-comment@v3 - with: - issue-number: ${{ github.event.issue.number }} - body: | - Please submit a ticket to [Agora Support](https://www.agora.io/en/customer-support/) for further investigation of this issue. If you have any conclusions, you can share them here which may help other developers. Thanks! \ No newline at end of file diff --git a/.github/workflows/auto-close-daily-doc-update.yaml b/.github/workflows/auto-close-daily-doc-update.yaml deleted file mode 100644 index c90658830..000000000 --- a/.github/workflows/auto-close-daily-doc-update.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: Auto-close Stale Daily Doc Update Pull Requests - -on: - schedule: - - cron: '0 16 * * *' # Runs daily at midnight Beijing time - -permissions: - contents: write # only for delete-branch option - pull-requests: write - -jobs: - close-stale-pr: - runs-on: ubuntu-latest - steps: - - name: Close Stale Pull Requests - uses: actions/stale@v8 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-pr-message: 'This auto daily doc update PR is stale because it has been open for 3 days with no activity. Close.' - days-before-stale: 1 - days-before-close: 1 - remove-stale-when-updated: false - delete-branch: true - only-labels: 'ci:doc' \ No newline at end of file diff --git a/.github/workflows/code-gen.yaml b/.github/workflows/code-gen.yaml deleted file mode 100644 index 9a7549c2a..000000000 --- a/.github/workflows/code-gen.yaml +++ /dev/null @@ -1,71 +0,0 @@ -name: Code gen - -on: - workflow_dispatch: - inputs: - target_branch: - description: The branch to run code-gen - type: string - required: true - default: 'main' - - version: - description: 'The version of native sdk in terra-script' - required: false - type: string - default: '' - -jobs: - run_code_gen: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ inputs.target_branch }} - fetch-depth: 0 - - name: enable corepack - run: corepack enable - - name: set node - uses: actions/setup-node@v4 - with: - node-version: 'lts/*' - - name: Reconfigure git to use HTTP authentication - run: | - git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf ssh://git@github.com/ - - name: Install LLVM and Clang - uses: KyleMayes/install-llvm-action@v1 - with: - version: "15.0.6" # Need ping version to 15.x - directory: ${{ runner.temp }}/llvm - - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - - name: Run code-gen - run: | - bash scripts/code_gen.sh ${{ inputs.version }} - - - name: Get current date - id: date - run: echo "date=$(date +'%Y%m%d')" >> "$GITHUB_OUTPUT" - - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "Auto generate codes for native sdk version ${{ inputs.version }}" - committer: GitHub - author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - signoff: false - branch: auto-code-gen-${{ steps.date.outputs.date }} - base: ${{ inputs.target_branch }} - delete-branch: true - title: "Auto generate codes for native sdk ${{ inputs.version }}" - body: | - Auto generate codes for native sdk version ${{ inputs.version }} - - *This pull request is opened by bot* - labels: | - ci:skip - reviewers: | - littleGnAl diff --git a/.github/workflows/integration-test-iris-artifacts.yml b/.github/workflows/integration-test-iris-artifacts.yml deleted file mode 100644 index 6999804d3..000000000 --- a/.github/workflows/integration-test-iris-artifacts.yml +++ /dev/null @@ -1,206 +0,0 @@ -name: Integration test with iris artifacts - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -on: - pull_request: - types: [labeled, synchronize] - branches: - - main - - release/** - - special/** - - dev/** - -jobs: - integration_test_android: - name: Run Flutter Android Integration Tests - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - strategy: - matrix: - version: ['2.10.5', '3.0.0'] - runs-on: macos-latest - timeout-minutes: 60 - env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v1 - with: - java-version: '11' - - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ matrix.version }} - cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=android,macos \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-android-cdn-url=${IRIS_CDN_URL_ANDROID} \ - --iris-macos-cdn-url=${IRIS_CDN_URL_MACOS} - - run: flutter config --enable-macos-desktop - - name: run flutter android integration tests - uses: reactivecircus/android-emulator-runner@v2.21.0 - with: - api-level: 31 - arch: x86_64 - profile: Nexus 6 - ram-size: 2048M - heap-size: 4096M - disk-size: 8192M - script: bash ci/run_flutter_integration_test_android.sh 0 - - integration_test_ios: - name: Run Flutter iOS Integration Tests - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - strategy: - matrix: - version: ['2.10.5', '3.0.0'] - runs-on: macos-latest - timeout-minutes: 60 - env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} - steps: - - uses: actions/checkout@v3 - - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ matrix.version }} - cache: true - - uses: futureware-tech/simulator-action@v3 - with: - model: 'iPhone 15' - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=ios \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-ios-cdn-url=${IRIS_CDN_URL_IOS} - - run: bash ci/run_flutter_integration_test_ios.sh 0 - - integration_test_macos: - name: Run Flutter macOS Integration Tests - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - strategy: - matrix: - version: ['2.10.5', '3.0.0'] - runs-on: macos-latest - timeout-minutes: 60 - env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} - steps: - - uses: actions/checkout@v3 - - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ matrix.version }} - cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - echo "project dir: ${PROJECT_DIR}" - - ls ${PROJECT_DIR} - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=macos \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-macos-cdn-url=${IRIS_CDN_URL_MACOS} - - run: flutter config --enable-macos-desktop - - run: bash ci/run_flutter_macos_integration_test.sh 0 - - integration_test_windows: - name: Run Flutter Windows Integration Tests - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - strategy: - matrix: - version: ['2.10.5', '3.0.0'] - runs-on: windows-2019 - timeout-minutes: 60 - env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} - steps: - - uses: actions/checkout@v3 - - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ matrix.version }} - cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - shell: bash - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=windows \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-windows-cdn-url=${IRIS_CDN_URL_WINDOWS} - - run: flutter config --enable-windows-desktop - - name: Run windows integration test - shell: bash - run: | - bash ci/run_flutter_windows_integration_test.sh 0 \ No newline at end of file diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml deleted file mode 100644 index 585c0277b..000000000 --- a/.github/workflows/lock.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Borrow from https://github.com/flutter/flutter/blob/master/.github/workflows/lock.yaml -# Configuration for Lock Threads - https://github.com/dessant/lock-threads - -name: 'Lock Threads' - -# By specifying the access of one of the scopes, all of those that are not -# specified are set to 'none'. -permissions: - issues: write - -on: - schedule: - - cron: '0 * * * *' - -jobs: - lock: - permissions: - issues: write - runs-on: ubuntu-latest - if: ${{ github.repository == 'AgoraIO-Extensions/Agora-Flutter-SDK' }} - steps: - - uses: dessant/lock-threads@c1b35aecc5cdb1a34539d14196df55838bb2f836 - with: - process-only: 'issues' - github-token: ${{ github.token }} - # Number of days of inactivity before a closed issue is locked. - issue-inactive-days: '7' - issue-comment: > - This thread has been automatically locked since there has not been - any recent activity after it was closed. If you are still experiencing a - similar issue, please raise a new issue. \ No newline at end of file diff --git a/.github/workflows/more-detail-wanted.yaml b/.github/workflows/more-detail-wanted.yaml deleted file mode 100644 index 2e873b87f..000000000 --- a/.github/workflows/more-detail-wanted.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Ask the user for more detail of the issue -on: - issues: - types: - - labeled -jobs: - add-comment: - if: github.event.label.name == 'more detail wanted' - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Add comment - uses: peter-evans/create-or-update-comment@v3 - with: - issue-number: ${{ github.event.issue.number }} - - body: | - Please follow the [issue template](https://github.com/AgoraIO-Extensions/Agora-Flutter-SDK/blob/main/.github/ISSUE_TEMPLATE/bug_report.md) to fill in more details about this issue so that we can investigate this issue more easily, thanks! - \ No newline at end of file diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml deleted file mode 100644 index 511622e1a..000000000 --- a/.github/workflows/no-response.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Borrow from https://github.com/flutter/flutter/blob/master/.github/workflows/no-response.yaml -name: No Response - -# Both `issue_comment` and `scheduled` event types are required for this Action -# to work properly. -on: - issue_comment: - types: [created] - schedule: - # Schedule for five minutes after the hour, every hour - - cron: '5 * * * *' - -# By specifying the access of one of the scopes, all of those that are not -# specified are set to 'none'. -permissions: - issues: write - -jobs: - noResponse: - runs-on: ubuntu-latest - if: ${{ github.repository == 'AgoraIO-Extensions/Agora-Flutter-SDK' }} - steps: - - uses: godofredoc/no-response@0ce2dc0e63e1c7d2b87752ceed091f6d32c9df09 - with: - token: ${{ github.token }} - # Comment to post when closing an Issue for lack of response. Set to `false` to disable - closeComment: > - Without additional information, we are unfortunately not sure how to - resolve this issue. We are therefore reluctantly going to close this - bug for now. - If you find this problem please file a new issue with the same description, - what happens, logs and the output. All system setups - can be slightly different so it's always better to open new issues and reference - the related ones. - Thanks for your contribution. - # Number of days of inactivity before an issue is closed for lack of response. - daysUntilClose: 14 - # Label requiring a response. - responseRequiredLabel: "waiting for customer response" diff --git a/.github/workflows/on_issue_labeled.yml b/.github/workflows/on_issue_labeled.yml new file mode 100644 index 000000000..4bd47c665 --- /dev/null +++ b/.github/workflows/on_issue_labeled.yml @@ -0,0 +1,41 @@ +name: 'on: issue labeled' + +on: + issues: + types: [labeled] + +jobs: + + # Triage to Agora Support + # + # This job will be triggered when the issue is labeled with `triage agora support` label. + # It will add a comment to the issue to ask the user to provide more details about the issue. + triage-to-agora-support: + if: ${{ github.event.type == 'labeled' && github.event.label.name == 'triage agora support' }} + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Please submit a ticket to [Agora Support](https://www.agora.io/en/customer-support/) for further investigation of this issue. If you have any conclusions, you can share them here which may help other developers. Thanks! + + # Ask the user for more detail of the issue + # + # This job will be triggered when the issue is labeled with `more detail wanted` label. + # It will add a comment to the issue to ask the user to provide more details about the issue. + ask-for-more-detail: + if: ${{ github.event.type == 'labeled' && github.event.label.name == 'more detail wanted' }} + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Please follow the [issue template](https://github.com/AgoraIO-Extensions/Agora-Flutter-SDK/blob/main/.github/ISSUE_TEMPLATE/bug_report.yml) to fill in more details about this issue so that we can investigate this issue more easily, thanks! \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/on_pr_closed.yml similarity index 63% rename from .github/workflows/release.yml rename to .github/workflows/on_pr_closed.yml index d2c4868de..5a05ab936 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/on_pr_closed.yml @@ -1,4 +1,4 @@ -name: Release to Github release/pub.dev and tag πŸš€ +name: 'on: pr closed' on: pull_request: @@ -6,6 +6,10 @@ on: - closed jobs: + # Release to pub.dev and Github release with below conditions + # 1. The PR is merged + # 2. The PR is based on `main` branch + # 3. The PR has `ci:prepare_release` label release_if_merged: if: ${{ github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' && @@ -54,6 +58,7 @@ jobs: refreshToken: ${{ secrets.OAUTH_REFRESH_TOKEN }} force: true # We have checked the `dart pub publish --dry-run` `in build.yaml`, it's ok to force publish here. skipTests: true + attach_docs: name: Attach dartdoc runs-on: ubuntu-latest @@ -63,6 +68,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: 'stable' + cache: true - name: Build DartDoc πŸ“– run: | dart pub get @@ -81,3 +87,42 @@ jobs: file: agora_rtc_engine_docs.zip asset_name: agora_rtc_engine_docs.zip tag: ${{ needs.release_if_merged.outputs.release_version }} + + + # Only auto tag on base branch with below conditions + # 1. The PR is merged + # 2. The PR has `ci:ready_release_special` label + release_special_if_merged: + if: ${{ github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'ci:ready_release_special') }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.base.ref }} + fetch-depth: 0 + - name: Install release-it + run: | + npm install -g release-it + npm install -g release-it/bumper + npm install -g release-it/conventional-changelog + - name: git config + run: | + git config user.name "${GITHUB_ACTOR}" + git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" + - run: | + PUBSPEC_VERSION=$(grep 'version: ' pubspec.yaml | sed -e 's,.*: \(.*\),\1,') + echo "pubspec version: ${PUBSPEC_VERSION}" + + release-it ${PUBSPEC_VERSION} \ + --no-git.commit \ + --'git.commitMessage="chore: release ${version}"' \ + --git.tag \ + --'git.tagName="${version}"' \ + --'git.tagAnnotation="Release ${version}"' \ + --git.push \ + --no-github.release \ + --no-github.web \ + --ci + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/schedule-run-ci-external.yml b/.github/workflows/on_pr_external.yml similarity index 88% rename from .github/workflows/schedule-run-ci-external.yml rename to .github/workflows/on_pr_external.yml index 90c263ff3..cdac41034 100644 --- a/.github/workflows/schedule-run-ci-external.yml +++ b/.github/workflows/on_pr_external.yml @@ -1,11 +1,11 @@ # This workflow is aim to let external contributors to run the integration tests. # * Check if the user is a external or internal contributor or not (who is in the org or not). # * If the user is a external contributor, remove the label "ci:schedule_run_ci" for each push. -# * The PR with label "ci:schedule_run_ci" can trigger the `workflows/build.yml`. +# * The PR with label "ci:schedule_run_ci" can trigger the `workflows/run_test.yml`. # # If the user is a external contributor, the repo owener or the users with write access should response for add the # label "ci:schedule_run_ci" to allow the external contributor to run the CI. -name: Schedule run ci external +name: 'on: pr external' on: pull_request_target: @@ -22,7 +22,7 @@ jobs: id: check-contributors-result uses: actions/github-script@v6 with: - github-token: ${{ secrets.LABEL_ACTION_PAT }} + github-token: ${{ secrets.GITHUB_TOKEN }} debug: true script: | const org = "AgoraIO-Extensions" @@ -65,16 +65,16 @@ jobs: if: ${{ github.event.action == 'synchronize' && steps.check-contributors-result.outputs.result > 0 }} uses: actions-ecosystem/action-remove-labels@v1 with: - github_token: ${{ secrets.LABEL_ACTION_PAT }} - repo: 'AgoraIO-Extensions' - number: 'Agora-Flutter-SDK' + github_token: ${{ secrets.GITHUB_TOKEN }} + number: ${{ github.event.pull_request.number }} labels: ci:schedule_run_ci + fail_on_error: false - schedule_ci: - name: Schedule run ci for external contributors + run_test: + name: Run test needs: check_permission if: ${{ contains(github.event.pull_request.labels.*.name, 'ci:schedule_run_ci') }} - uses: ./.github/workflows/build.yml + uses: ./.github/workflows/run_test.yml secrets: - MY_APP_ID: ${{ secrets.MY_APP_ID }} + APP_ID: ${{ secrets.APP_ID }} \ No newline at end of file diff --git a/.github/workflows/on_pr_internal.yml b/.github/workflows/on_pr_internal.yml new file mode 100644 index 000000000..e68540645 --- /dev/null +++ b/.github/workflows/on_pr_internal.yml @@ -0,0 +1,57 @@ +name: 'on: pr internal' + +on: + pull_request: + +jobs: + check_permission: + name: Check permission + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ci:skip') || contains(github.event.pull_request.labels.*.name, 'ci:build_example') }} + runs-on: ubuntu-latest + timeout-minutes: 60 + outputs: + has_permission: ${{ steps.check_permission_by_secret.outputs.has_permission }} + steps: + - name: Check for Secret availability + id: check_permission_by_secret + # perform secret check & put boolean result as an output + shell: bash + run: | + APP_ID="${{ secrets.APP_ID }}" + if [ ! -z "${APP_ID}" ]; then + echo "has_permission=1" >> $GITHUB_OUTPUT; + echo "secrets.APP_ID is not empty, PR opened by the internal contributors" + else + echo "has_permission=-1" >> $GITHUB_OUTPUT; + echo "secrets.APP_ID is empty, PR opened by the external contributors" + fi + + build_example: + name: Build example + needs: check_permission + if: ${{ needs.check_permission.outputs.has_permission == 1 && contains(github.event.pull_request.labels.*.name, 'ci:build_example') }} + uses: ./.github/workflows/run_build_example.yml + with: + target_branch: ${{ github.event.pull_request.head.ref }} + issue_number: ${{ github.event.pull_request.number }} + secrets: + APP_ID: ${{ secrets.APP_ID }} + BUILD_PROVISION_PROFILE_UUID: ${{ secrets.BUILD_PROVISION_PROFILE_UUID }} + BUILD_PROVISION_PROFILE_NAME: ${{ secrets.BUILD_PROVISION_PROFILE_NAME }} + BUILD_PROVISION_PROFILE_TEAMID: ${{ secrets.BUILD_PROVISION_PROFILE_TEAMID }} + BUILD_PROVISION_PROFILE_IDENTITY: ${{ secrets.BUILD_PROVISION_PROFILE_IDENTITY }} + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + + + run_test: + name: Run test + needs: check_permission + # If the PR requested by a external contributor, the secrets.APP_ID should be empty, and skip this workflow + if: ${{ needs.check_permission.outputs.has_permission == 1 && !contains(github.event.pull_request.labels.*.name, 'ci:skip') }} + uses: ./.github/workflows/run_test.yml + secrets: + APP_ID: ${{ secrets.APP_ID }} + \ No newline at end of file diff --git a/.github/workflows/release_special_version.yml b/.github/workflows/release_special_version.yml deleted file mode 100644 index 5d1a0a8db..000000000 --- a/.github/workflows/release_special_version.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Tag the special version πŸš€ - -on: - pull_request: - types: - - closed - -jobs: - release_special_if_merged: - if: ${{ github.event.pull_request.merged == true && - contains(github.event.pull_request.labels.*.name, 'ci:ready_release_special') }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.base.ref }} - fetch-depth: 0 - - name: Install release-it - run: | - npm install -g release-it - npm install -g release-it/bumper - npm install -g release-it/conventional-changelog - - name: git config - run: | - git config user.name "${GITHUB_ACTOR}" - git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" - - run: | - PUBSPEC_VERSION=$(grep 'version: ' pubspec.yaml | sed -e 's,.*: \(.*\),\1,') - echo "pubspec version: ${PUBSPEC_VERSION}" - - release-it ${PUBSPEC_VERSION} \ - --no-git.commit \ - --'git.commitMessage="chore: release ${version}"' \ - --git.tag \ - --'git.tagName="${version}"' \ - --'git.tagAnnotation="Release ${version}"' \ - --git.push \ - --no-github.release \ - --no-github.web \ - --ci - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/run_build_example.yml b/.github/workflows/run_build_example.yml new file mode 100644 index 000000000..329c85e6f --- /dev/null +++ b/.github/workflows/run_build_example.yml @@ -0,0 +1,394 @@ +name: 'run: build example' + +on: + workflow_dispatch: + inputs: + target_platforms: + description: 'Target platforms, e.g. android, ios, macos, windows, web, etc; separated by comma, default is all platforms' + type: string + required: true + default: 'android, ios, macos, windows, web' + target_branch: + description: 'Target branch, leave empty will use the same as the workflow trigger branch' + type: string + issue_number: + description: 'The number of the issue or pull request to comment build results on, leave empty will not comment on any PR' + type: number + required: false + extra_build_options: + description: 'Extra build options when running `flutter build`, e.g. --verbose, --device-id' + type: string + required: false + default: '' + extra_build_arguments: + description: 'Extra build arguments when running `flutter build apk/ipa/other sub-commands`, e.g. --debug, --dart-define=APP_ID=1234567890, --dart-define-from-file=path/to/file.dart' + type: string + required: false + default: '' + flutter_channel: + description: 'Target Flutter channel, e.g. stable(default), beta, dev, master (or main), or any other channel name' + type: string + required: false + default: 'stable' + flutter_version: + description: 'Target Flutter version, e.g. 3.24.5, 3.24.x, commit hash, or leave empty to use the latest release version of specified channel by flutter_version(default)' + type: string + required: false + # we should use the latest stable version for building example later, however, the android build will fail with the latest stable version, so we fixed use the 3.24.5 version here for now + # Here is the error log: + # Caused by: org.gradle.api.GradleException: You are applying Flutter's app_plugin_loader Gradle plugin imperatively using the apply script method, which is not possible anymore. Migrate to applying Gradle plugins with the declarative plugins block: https://flutter.dev/to/flutter-gradle-plugin-apply + default: '3.24.5' + workflow_call: + inputs: + target_platforms: + description: 'Target platforms, e.g. android, ios, macos, windows, web, etc; separated by comma, default is all platforms' + type: string + default: 'android, ios, macos, windows, web' + target_branch: + description: 'Target branch, leave empty will use the same as the workflow trigger branch' + type: string + issue_number: + description: 'The number of the issue or pull request to comment build results on, leave empty will not comment on any PR' + type: number + required: false + extra_build_options: + description: 'Extra build options when running `flutter build`, e.g. --verbose, --device-id' + type: string + required: false + default: '' + extra_build_arguments: + description: 'Extra build arguments when running `flutter build apk/ipa/other sub-commands`, e.g. --debug, --dart-define=APP_ID=1234567890, --dart-define-from-file=path/to/file.dart' + type: string + required: false + default: '' + flutter_channel: + description: 'Target Flutter channel, e.g. stable(default), beta, dev, master (or main), or any other channel name' + type: string + required: false + default: 'stable' + flutter_version: + description: 'Target Flutter version, e.g. 3.24.5, 3.24.x, commit hash, or leave empty to use the latest release version of specified channel by flutter_version(default)' + type: string + required: false + # we should use the latest stable version for building example later, however, the android build will fail with the latest stable version, so we fixed use the 3.24.5 version here for now + # Here is the error log: + # Caused by: org.gradle.api.GradleException: You are applying Flutter's app_plugin_loader Gradle plugin imperatively using the apply script method, which is not possible anymore. Migrate to applying Gradle plugins with the declarative plugins block: https://flutter.dev/to/flutter-gradle-plugin-apply + default: '3.24.5' + secrets: + APP_ID: + required: true + BUILD_PROVISION_PROFILE_UUID: + required: true + BUILD_PROVISION_PROFILE_NAME: + required: true + BUILD_PROVISION_PROFILE_TEAMID: + required: true + BUILD_PROVISION_PROFILE_IDENTITY: + required: true + BUILD_CERTIFICATE_BASE64: + required: true + P12_PASSWORD: + required: true + BUILD_PROVISION_PROFILE_BASE64: + required: true + KEYCHAIN_PASSWORD: + required: true + + +jobs: + # remove label ci:build_example if the issue_number is not null and the workflow is run by workflow_call not workflow_dispatch + remove-label: + if: ${{ inputs.issue_number != null}} + runs-on: ubuntu-latest + steps: + - name: Remove label + uses: actions-ecosystem/action-remove-labels@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + number: ${{ inputs.issue_number }} + labels: ci:build_example + fail_on_error: false + + split-platforms: + runs-on: ubuntu-latest + outputs: + platforms: ${{ steps.split-platforms.outputs.platforms }} + steps: + - id: split-platforms + env: + target_platforms: ${{ inputs.target_platforms }} + run: | + platforms=$(echo "$target_platforms" | sed 's/ //g' | tr ',' '\n' | sort -u | sed '/^$/d' | jq -R -s -c 'split("\n")[:-1]') + echo "splited platforms: $platforms" + # remove not supported platforms, only keep supported platforms: android, ios, macos, windows, web + platforms=$(echo "$platforms" | jq -e 'map(select(. == "android" or . == "ios" or . == "macos" or . == "windows" or . == "web"))') + # make platforms in oneline, and keep json format + platforms=$(echo "$platforms" | jq -c .) + echo "final jsonlized platforms: $platforms" + echo "platforms=$platforms" >> $GITHUB_OUTPUT + + build: + runs-on: ${{ matrix.os }} + needs: split-platforms + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + platform: ${{ fromJson(needs.split-platforms.outputs.platforms) }} + exclude: + - os: ubuntu-latest + platform: android + - os: ubuntu-latest + platform: ios + - os: ubuntu-latest + platform: macos + - os: ubuntu-latest + platform: windows + - os: macos-latest + platform: windows + - os: macos-latest + platform: web + - os: windows-latest + platform: android + - os: windows-latest + platform: ios + - os: windows-latest + platform: macos + - os: windows-latest + platform: web + env: + platform: ${{ matrix.platform }} + extra_build_options: ${{ inputs.extra_build_options }} + extra_build_arguments: ${{ inputs.extra_build_arguments }} + outputs: + artifact_nightly_link_android: ${{ steps.setup_output.outputs.artifact_nightly_link_android }} + artifact_nightly_link_ios: ${{ steps.setup_output.outputs.artifact_nightly_link_ios }} + artifact_nightly_link_macos: ${{ steps.setup_output.outputs.artifact_nightly_link_macos }} + artifact_nightly_link_windows: ${{ steps.setup_output.outputs.artifact_nightly_link_windows }} + artifact_nightly_link_web: ${{ steps.setup_output.outputs.artifact_nightly_link_web }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.target_branch }} + fetch-depth: '1' + lfs: 'true' + submodules: 'true' + + - name: Setup JDK for Android + if: ${{ matrix.platform == 'android' }} + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: Setup signing key for iOS + if: ${{ matrix.platform == 'ios' }} + working-directory: example/ios + env: + DEFAULT_BUILD_PROVISION_PROFILE_NAME: ${{ secrets.BUILD_PROVISION_PROFILE_NAME }} + DEFAULT_BUILD_PROVISION_PROFILE_TEAMID: ${{ secrets.BUILD_PROVISION_PROFILE_TEAMID }} + DEFAULT_BUILD_PROVISION_PROFILE_IDENTITY: ${{ secrets.BUILD_PROVISION_PROFILE_IDENTITY }} + DEFAULT_BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + DEFAULT_BUILD_P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + DEFAULT_BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} + DEFAULT_BUILD_KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/${{ secrets.BUILD_PROVISION_PROFILE_UUID }}.mobileprovision + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$DEFAULT_BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH + echo -n "$DEFAULT_BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH + + # create temporary keychain + security create-keychain -p "$DEFAULT_BUILD_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$DEFAULT_BUILD_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$DEFAULT_BUILD_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # apply provisioning profile + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles + + # update project settings for Runner target + bundle exec fastlane run update_code_signing_settings use_automatic_signing:false path:Runner.xcodeproj bundle_identifier:io.agora.agoraRtcEngineExample team_id:$DEFAULT_BUILD_PROVISION_PROFILE_TEAMID profile_name:$DEFAULT_BUILD_PROVISION_PROFILE_NAME code_sign_identity:$DEFAULT_BUILD_PROVISION_PROFILE_IDENTITY targets:Runner + + # update project settings for ScreenSharing target + bundle exec fastlane run update_code_signing_settings use_automatic_signing:false path:Runner.xcodeproj bundle_identifier:io.agora.agoraRtcEngineExample.ScreenSharing team_id:$DEFAULT_BUILD_PROVISION_PROFILE_TEAMID profile_name:$DEFAULT_BUILD_PROVISION_PROFILE_NAME code_sign_identity:$DEFAULT_BUILD_PROVISION_PROFILE_IDENTITY targets:ScreenSharing + + # replace all DEFAULT_BUILD_PROVISION_PROFILE_NAME in export.plist with $DEFAULT_BUILD_PROVISION_PROFILE_NAME + sed -i '' "s/DEFAULT_BUILD_PROVISION_PROFILE_NAME/$DEFAULT_BUILD_PROVISION_PROFILE_NAME/g" export.plist + + - name: Update pod repo + if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }} + run: pod repo update + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: ${{ inputs.flutter_channel }} + flutter-version: ${{ inputs.flutter_version }} + cache: true + + - name: Build + env: + DEFAULT_BUILD_APP_ID: ${{ secrets.APP_ID }} + shell: bash + working-directory: example + run: | + # show flutter version + flutter --version && which flutter + + # install dependencies + flutter pub get + + # prepare build command, android: apk, ios: ipa, macos: macos, windows: (empty), web: web + build_command="" + if [ "$platform" == "android" ]; then + build_command="flutter build apk" + elif [ "$platform" == "ios" ]; then + build_command="flutter build ipa" + elif [ "$platform" == "macos" ]; then + build_command="flutter build macos" + elif [ "$platform" == "windows" ]; then + build_command="flutter build windows" + elif [ "$platform" == "web" ]; then + build_command="flutter build web" + fi + + # prepare build options + build_options="" + + # append extra build options + if [ -n "$extra_build_options" ]; then + build_options="$build_options $extra_build_options" + fi + + # prepare default build arguments, if current platform is web, set DEFAULT_BUILD_APP_ID to empty string + if [ "$platform" == "web" ]; then + DEFAULT_BUILD_APP_ID="" + fi + + build_arguments="--dart-define=TEST_APP_ID=$DEFAULT_BUILD_APP_ID --dart-define=TEST_TOKEN="" --dart-define=TEST_CHANNEL_ID="testapi" --dart-define=INTERNAL_TESTING=true" + + # append extra build arguments + if [ -n "$extra_build_arguments" ]; then + build_arguments="$build_arguments $extra_build_arguments" + fi + + # append build arguments for ios + if [ "$platform" == "ios" ]; then + build_arguments="--export-options-plist ios/export.plist $build_arguments" + fi + + # run build command + $build_command $build_options $build_arguments + + # create output directory if it doesn't exist + if [ ! -d "../output" ]; then + mkdir -p ../output + fi + + # copy build result to output directory by different platforms + if [ "$platform" == "android" ]; then + # copy files in build/app/outputs/flutter-apk directory to ../output directory + cp build/app/outputs/flutter-apk/* ../output + + # copy whole symbol directory to ../output directory + cp -r build/app/outputs/native-debug-symbols ../output + elif [ "$platform" == "ios" ]; then + # copy build/ios/ipa/agora_rtc_engine_example.ipa to ../output directory + cp build/ios/ipa/agora_rtc_engine_example.ipa ../output + + # copy dSYMs in build/ios/archive/Runner.xcarchive/dSYMs directory to ../output directory + cp -RP build/ios/archive/Runner.xcarchive/dSYMs ../output + elif [ "$platform" == "macos" ]; then + # cp example/build/macos/Build/Products/*/agora_rtc_engine_example.app to ../output directory + cp -RP build/macos/Build/Products/*/agora_rtc_engine_example.app ../output + + # mkdir dSYMs directory in ../output directory if it doesn't exist + if [ ! -d "../output/dSYMs" ]; then + mkdir -p ../output/dSYMs + fi + + # copy all dSYM files from example/build/macos/Build/Products and subdirectories to ../output/dSYMs directory + cp -RP build/macos/Build/Products/**/*.dSYM ../output/dSYMs + elif [ "$platform" == "windows" ]; then + # since flutter have no plain to support to build to run on 32-bit windows, we only need concern about the 64-bit windows + + # copy whole build/windows/x64/runner/Release directory to ../output if the directory exists + if [ -d "build/windows/x64/runner/Release" ]; then + cp -r build/windows/x64/runner/Release ../output + + # copy all pdb files in build/windows/x64/plugins/**/Release/ to ../output/Release + cp -r build/windows/x64/plugins/**/Release/*.pdb ../output/Release + fi + + # copy whole build/windows/x64/runner/Debug directory to ../output if the directory exists + if [ -d "build/windows/x64/runner/Debug" ]; then + cp -r build/windows/x64/runner/Debug ../output + + # copy all pdb files in build/windows/x64/plugins/**/Debug/ to ../output/Debug + cp -r build/windows/x64/plugins/**/Debug/*.pdb ../output/Debug + fi + elif [ "$platform" == "web" ]; then + # copy all files and files in subdirectories to ../output directory + cp -r build/web/* ../output + fi + + - name: Generate artifact name + id: generate_artifact_name + shell: bash + run: | + # get pub_version from pubspec.yaml + pub_version=$(grep 'version: ' pubspec.yaml | sed -e 's,.*: \(.*\),\1,') + + # get build_timestamp + build_timestamp=$(date +%Y%m%d%H%M%S) + + # generate artifact_name + artifact_name="agora_rtc_engine_example_${{ matrix.platform }}_${pub_version}_${build_timestamp}_${{ github.run_id }}" + echo "artifact_name=$artifact_name" >> $GITHUB_OUTPUT + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.generate_artifact_name.outputs.artifact_name }} + path: output + if-no-files-found: error + + - name: Setup download url + id: setup_output + shell: bash + run: | + # see https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs + current_platform="${{ matrix.platform }}" + echo "artifact_nightly_link_${current_platform}=https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/${{ steps.generate_artifact_name.outputs.artifact_name }}.zip" >> $GITHUB_OUTPUT + + comment: + runs-on: ubuntu-latest + if: ${{ inputs.issue_number != null && !cancelled() }} + needs: [build] + steps: + - uses: peter-evans/create-or-update-comment@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ inputs.issue_number }} + body: | + Build Job: + https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + + Build Results: + - ${{ needs.build.outputs.artifact_nightly_link_android }} + - ${{ needs.build.outputs.artifact_nightly_link_ios }} + - ${{ needs.build.outputs.artifact_nightly_link_macos }} + - ${{ needs.build.outputs.artifact_nightly_link_windows }} + - ${{ needs.build.outputs.artifact_nightly_link_web }} + + > This comment is commented by bot, do not edit it directly \ No newline at end of file diff --git a/.github/workflows/run_gen_code.yml b/.github/workflows/run_gen_code.yml new file mode 100644 index 000000000..134952d74 --- /dev/null +++ b/.github/workflows/run_gen_code.yml @@ -0,0 +1,80 @@ +name: 'run: gen code' + +on: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch to compare against. If a branch name, will compare directly against it. If a commit hash or tag, a new branch named "special/" will be created from that ref. The pub_version will be either the input pub_version or latest version from target branch pubspec.yaml. Defaults to "main".' + type: string + required: true + default: 'main' + code_gen_public_headers: + description: 'The public headers to generate, e.g. rtc_4.5.0, leave empty will use the same as the target branch' + type: string + required: false + default: '' + flutter_channel: + description: 'Target Flutter channel, e.g. stable(default), beta, dev, master (or main), or any other channel name' + type: string + required: false + default: 'stable' + flutter_version: + description: 'Target Flutter version, e.g. 3.24.5, 3.24.x, commit hash, or leave empty to use the latest release version of specified channel by flutter_version(default)' + type: string + required: false + # we should use the latest stable version for build and gen code, but the 3.19.6 is the latest version which will gen compatible code for our flutter project, + # so we fixed use the 3.19.6 version here for now + default: '3.19.6' + +jobs: + gen_code: + runs-on: macos-latest + steps: + - name: Checkout target branch + uses: actions/checkout@v4 + with: + ref: ${{ inputs.target_branch }} + fetch-depth: '1' + lfs: 'true' + submodules: 'true' + + - name: Prepare target branch + id: prepare_target_branch + uses: ./.github/actions/prepare_branch + with: + target_branch: ${{ inputs.target_branch }} + pub_version: "" + branch_group: "special" + working_directory: ./ + + - name: Run gen code + uses: ./.github/actions/gen_code + with: + code_gen_public_headers: ${{ inputs.code_gen_public_headers }} + flutter_channel: ${{ inputs.flutter_channel }} + flutter_version: ${{ inputs.flutter_version }} + working_directory: ./ + + - name: Commit and create pull request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "feat: generate code" + committer: GitHub + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + signoff: false + branch: gen/${{ steps.prepare_target_branch.outputs.final_target_branch }} + base: ${{ steps.prepare_target_branch.outputs.final_target_branch }} + delete-branch: true + draft: false + title: "feat: generate code" + body: | + Generate code with the following content: + + base branch: ${{ steps.prepare_target_branch.outputs.final_target_branch }} + + public headers: ${{ inputs.code_gen_public_headers }} + + > This pull request is trigger by bot, you can checkout this branch and update it. + labels: | + ci:skip \ No newline at end of file diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/run_prepare_release.yml similarity index 96% rename from .github/workflows/prepare-release.yml rename to .github/workflows/run_prepare_release.yml index 49cc5ab5d..f67f8150b 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/run_prepare_release.yml @@ -1,6 +1,6 @@ # This action will create a change logs via release-it and open a pull request, # after the PR is merged, the action release.yml will be trigger. -name: Prepare release +name: 'run: prepare release official' on: workflow_dispatch: @@ -61,7 +61,7 @@ jobs: author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> signoff: false branch: prepare-release-${{ inputs.version }} - base: main + base: ${{ inputs.release_branch }} delete-branch: true title: "chore: release ${{ inputs.version }}" body: | @@ -77,5 +77,3 @@ jobs: labels: | ci:skip ci:prepare_release - reviewers: | - littleGnAl diff --git a/.github/workflows/pubdev-publishing.yml b/.github/workflows/run_pub.yml similarity index 91% rename from .github/workflows/pubdev-publishing.yml rename to .github/workflows/run_pub.yml index ae2fe729f..c281a7615 100644 --- a/.github/workflows/pubdev-publishing.yml +++ b/.github/workflows/run_pub.yml @@ -1,4 +1,4 @@ -name: Publish to Pub.dev πŸš€ +name: 'run: publish to pub.dev' on: workflow_dispatch: @@ -22,7 +22,7 @@ jobs: - name: Check Versions πŸ”Ž run: | set -eo pipefail - export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1 HEAD`) echo "LIB_VERSION: ${LIB_VERSION}" export PUBSPEC_VERSION=$(grep 'version: ' pubspec.yaml | sed -e 's,.*: \(.*\),\1,') echo "PUBSPEC_VERSION: ${PUBSPEC_VERSION}" @@ -32,7 +32,7 @@ jobs: fi - name: Publish Dart Package 🚒 id: publish - uses: k-paxian/dart-package-publisher@1.5 + uses: k-paxian/dart-package-publisher@master with: accessToken: ${{ secrets.OAUTH_ACCESS_TOKEN }} refreshToken: ${{ secrets.OAUTH_REFRESH_TOKEN }} diff --git a/.github/workflows/run_sync_shengwang.yml b/.github/workflows/run_sync_shengwang.yml new file mode 100644 index 000000000..bfb2e56db --- /dev/null +++ b/.github/workflows/run_sync_shengwang.yml @@ -0,0 +1,22 @@ +name: 'run: sync to shengwang' + +on: + workflow_dispatch: + +jobs: + move-to-shengwang: + runs-on: ubuntu-latest + steps: + - name: Sync to shengwang + uses: AgoraIO-Extensions/actions/.github/actions/shengwang-sync@main + with: + target-repo: 'Shengwang-Flutter-SDK' + source-repo: 'Agora-Flutter-SDK' + github-token: ${{ secrets.GH_TOKEN }} + target-branch: ${{ github.ref_name }} + github-email: ${{ secrets.GIT_EMAIL }} + github-private-key: ${{ secrets.GH_PRIVATE_KEY }} + github-username: ${{ secrets.GIT_USERNAME }} + pre-command: | + bash scripts/change_publisher.sh + create-pr: true diff --git a/.github/workflows/build.yml b/.github/workflows/run_test.yml similarity index 77% rename from .github/workflows/build.yml rename to .github/workflows/run_test.yml index 6798f6688..e6c376b74 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/run_test.yml @@ -1,4 +1,4 @@ -name: CI +name: 'run: test' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -7,7 +7,7 @@ concurrency: on: workflow_call: secrets: - MY_APP_ID: + APP_ID: required: true jobs: @@ -20,6 +20,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: 'stable' + cache: true - name: Check Dart Format run: bash ci/dart_pub_publish_check.sh - uses: axel-op/dart-package-analyzer@v3 @@ -47,6 +48,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: 'stable' + cache: true - run: flutter test attach_docs: @@ -57,6 +59,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: 'stable' + cache: true - name: Build DartDoc πŸ“– run: | dart pub get @@ -89,9 +92,9 @@ jobs: matrix: version: ["3.7.0", "3.24.5"] runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - name: Install JDK @@ -102,6 +105,7 @@ jobs: - uses: subosito/flutter-action@v2 with: flutter-version: ${{ matrix.version }} + cache: true - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -126,9 +130,9 @@ jobs: matrix: version: ["3.7.0", "3.16"] runs-on: macos-latest - timeout-minutes: 60 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -143,12 +147,15 @@ jobs: if: always() run: | sleep 30 + mkdir logs-ios + CRASH_DIR="${HOME}/Library/Logs/DiagnosticReports/" OUTPUT_CRASH_DIR=./logs-ios/crash mkdir -p ${OUTPUT_CRASH_DIR} + # Copy all files - cp -RP $CRASH_DIR* $OUTPUT_CRASH_DIR + cp -RP $CRASH_DIR* $OUTPUT_CRASH_DIR || true - name: Upload ios logs uses: actions/upload-artifact@v4 @@ -165,9 +172,9 @@ jobs: matrix: version: ["3.7.0"] runs-on: macos-latest - timeout-minutes: 60 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -176,6 +183,60 @@ jobs: cache: true - run: flutter config --enable-macos-desktop - run: bash ci/run_flutter_macos_integration_test.sh + - name: Get iris logs macos + if: always() + run: | + sleep 30 + + mkdir iris-logs-macos + if [ -f "${HOME}/Library/Containers/com.example.fakeTestApp/Data/Library/agora-iris.log" ]; then + cp -RP ${HOME}/Library/Containers/com.example.fakeTestApp/Data/Library/agora-iris.log ./iris-logs-macos/agora-iris-fake-test.log || true + fi + if [ -f "${HOME}/Library/Containers/com.example.integrationTestApp/Data/Library/agora-iris.log" ]; then + cp -RP ${HOME}/Library/Containers/com.example.integrationTestApp/Data/Library/agora-iris.log ./iris-logs-macos/agora-iris-integration-test.log || true + fi + + CRASH_DIR="${HOME}/Library/Logs/DiagnosticReports/" + OUTPUT_CRASH_DIR=./iris-logs-macos/crash + mkdir -p ${OUTPUT_CRASH_DIR} + + # Copy all files + cp -RP $CRASH_DIR* $OUTPUT_CRASH_DIR || true + + - name: Upload iris logs macos + uses: actions/upload-artifact@v4 + if: always() + with: + name: iris-logs-macos-${{ matrix.version }} + path: iris-logs-macos/* + + integration_test_swiftpm: + name: Run Flutter SwiftPM Integration Tests + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ci:skip') }} + strategy: + fail-fast: false + matrix: + os: ["macos", "ios"] + runs-on: macos-latest + timeout-minutes: 120 + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' + cache: true + - name: Run flutter integration test swiftpm for ${{ matrix.os }} + if: ${{ matrix.os == 'macos' }} + run: | + flutter pub get + flutter build ${{ matrix.os }} + working-directory: test_shard/integration_test_swiftpm + - name: Run flutter integration test swiftpm for ${{ matrix.os }} + if: ${{ matrix.os == 'ios' }} + run: | + flutter pub get + flutter build ${{ matrix.os }} --no-codesign + working-directory: test_shard/integration_test_swiftpm integration_test_windows: name: Run Flutter Windows Integration Tests @@ -184,10 +245,10 @@ jobs: fail-fast: false matrix: version: ["3.7.0", "3.24.5"] - runs-on: windows-2019 - timeout-minutes: 60 + runs-on: windows-2022 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -209,7 +270,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -220,7 +281,7 @@ jobs: shell: bash run: | chromedriver --port=4444 --trace-buffer-size=100000 & - bash ci/run_flutter_integration_test.sh web + bash ci/run_flutter_integration_test_web.sh build_android_ubuntu: name: Build Android on Ubuntu @@ -240,6 +301,7 @@ jobs: - uses: subosito/flutter-action@v2 with: flutter-version: ${{ matrix.version }} + cache: true - run: flutter pub get - name: Run flutter build apk run: flutter build apk @@ -252,7 +314,7 @@ jobs: fail-fast: false matrix: version: ["3.7.12", "3.24.5"] # Need 3.7.12 to build with Gradle 8.x https://github.com/flutter/flutter/issues/124838 - runs-on: windows-2019 + runs-on: windows-2022 steps: - uses: actions/checkout@v3 - name: Install JDK @@ -275,9 +337,9 @@ jobs: strategy: fail-fast: false matrix: - version: ["3.7.0"] + version: ["3.7.12"] runs-on: macos-latest - timeout-minutes: 60 + timeout-minutes: 120 steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -297,7 +359,7 @@ jobs: matrix: version: ["3.24.5"] runs-on: macos-13 - timeout-minutes: 60 + timeout-minutes: 120 steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -323,7 +385,7 @@ jobs: matrix: version: ["3.7.0", "3.24.5"] runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 120 steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 @@ -339,9 +401,9 @@ jobs: name: Run Flutter Android Rendering Tests if: ${{ !contains(github.event.pull_request.labels.*.name, 'ci:skip') }} runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - name: Install JDK @@ -353,31 +415,6 @@ jobs: with: flutter-version: "3.24.5" cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=android,macos \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-android-cdn-url=${IRIS_CDN_URL_ANDROID} \ - --iris-macos-cdn-url=${IRIS_CDN_URL_MACOS} - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -409,34 +446,13 @@ jobs: runs-on: macos-13 # Rendering test on ios simulator need macos 13+ timeout-minutes: 60 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v1 - uses: subosito/flutter-action@v2 with: flutter-version: ${{ matrix.version }} - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - run: | - source scripts/artifacts_version.sh - PROJECT_DIR=$(pwd) - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=ios \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-ios-cdn-url=${IRIS_CDN_URL_IOS} + cache: true - uses: futureware-tech/simulator-action@v3 with: model: 'iPhone 15' @@ -455,43 +471,15 @@ jobs: matrix: version: ["3.24.5"] runs-on: macos-latest - timeout-minutes: 60 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 with: flutter-version: ${{ matrix.version }} cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - echo "project dir: ${PROJECT_DIR}" - - ls ${PROJECT_DIR} - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=macos \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-macos-cdn-url=${IRIS_CDN_URL_MACOS} - run: flutter config --enable-macos-desktop - name: Run macos rendering test run: | @@ -509,41 +497,16 @@ jobs: strategy: matrix: version: ["3.24.5"] - runs-on: windows-2019 - timeout-minutes: 60 + runs-on: windows-2022 + timeout-minutes: 120 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 with: flutter-version: ${{ matrix.version }} cache: true - - name: Checkout hoe - uses: actions/checkout@v3 - with: - repository: littleGnAl/hoe - ref: littlegnal/update - path: hoe - - name: Download iris artifacts - if: ${{ contains(github.event.pull_request.labels.*.name, 'integration_test:iris_artifacts') }} - shell: bash - run: | - source scripts/artifacts_version.sh - - PROJECT_DIR=$(pwd) - - mkdir -p output - cd hoe - dart pub get - dart run bin/hoe.dart build-agora-flutter-example \ - --setup-local-dev \ - --project-dir=${PROJECT_DIR} \ - --artifacts-output-dir=${PROJECT_DIR}/output \ - --platforms=windows \ - --apple-package-name=io.agora.agoraRtcEngineExample \ - --flutter-package-name=agora_rtc_engine \ - --iris-windows-cdn-url=${IRIS_CDN_URL_WINDOWS} - run: flutter config --enable-windows-desktop - name: Run windows integration test shell: bash @@ -564,7 +527,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 env: - TEST_APP_ID: ${{ secrets.MY_APP_ID }} + TEST_APP_ID: ${{ secrets.APP_ID }} steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 diff --git a/.github/workflows/run_update_deps.yml b/.github/workflows/run_update_deps.yml new file mode 100644 index 000000000..0c863254e --- /dev/null +++ b/.github/workflows/run_update_deps.yml @@ -0,0 +1,153 @@ +name: 'run: update dependencies' + +on: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch to compare against. If a branch name, will compare directly against it. If a commit hash or tag, a new branch named "special/" will be created from that ref. The pub_version will be either the input pub_version or latest version from target branch pubspec.yaml. Defaults to "main".' + type: string + required: true + default: 'main' + pub_version: + description: 'Target pub version to update dependencies to. If empty, will use the latest version from target branch pubspec.yaml.' + type: string + required: false + default: '' + dependencies_content: + description: 'The dependencies content to update, including native SDKs and Iris dependencies across Maven, CocoaPods, and CDN links' + type: string + required: true + default: '' + run_gen_code: + description: 'Whether to run gen code, default is false' + type: boolean + required: false + default: false + code_gen_public_headers: + description: 'The public headers to generate, e.g. rtc_4.5.0, leave empty will use the same as the target branch' + type: string + required: false + default: '' + flutter_channel: + description: 'Target Flutter channel, e.g. stable(default), beta, dev, master (or main), or any other channel name' + type: string + required: false + default: 'stable' + flutter_version: + description: 'Target Flutter version, e.g. 3.24.5, 3.24.x, commit hash, or leave empty to use the latest release version of specified channel by flutter_version(default)' + type: string + required: false + # we should use the latest stable version for build and gen code, but the 3.19.6 is the latest version which will gen compatible code for our flutter project, + # so we fixed use the 3.19.6 version here for now + default: '3.19.6' + +jobs: + update_deps: + runs-on: macos-latest + steps: + - name: Checkout target branch + uses: actions/checkout@v4 + with: + ref: ${{ inputs.target_branch }} + fetch-depth: '1' + lfs: 'true' + submodules: 'true' + + - name: Parse dependencies content + id: parse_dependencies_content + if: ${{ inputs.dependencies_content != '' }} + uses: AgoraIO-Extensions/actions/.github/actions/dep@main + with: + dependencies-content: ${{ inputs.dependencies_content }} + # Output: {steps.parse_dependencies_content.outputs.matches}, the parsed dependencies content in json format, the format is as follows: + # [ + # { + # "iris_cdn": [ + # "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_Unity_20250217_0847_579.zip", + # "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_Standalone_20250217_0847_579.zip", + # "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_20250217_0847_579.zip" + # ], + # "cdn": [ + # "https://download.agora.io/sdk/release/AgoraRtcEngine_macOS_Preview_4.5.0-gxz.119.zip" + # ], + # "iris_cocoapods": [ + # "pod 'AgoraIrisRTC_macOS', '4.5.0-gxz.119'" + # ], + # "iris_maven": [ + # "implementation 'io.agora.rtc:iris-rtc:4.5.0-gxz.119'" + # ], + # "maven": [ + # "implementation 'io.agora.rtc:agora-full-preview:4.5.0-gxz.119'", + # "implementation 'io.agora.rtc:full-screen-sharing-special:4.5.0-gxz.119'" + # ], + # "platform": "macOS", // iOS, macOS, Android, Windows, Web + # "cocoapods": [ + # "pod 'AgoraRtcEngine_macOS_Preview', '4.5.0-gxz.119'" + # ] + # }, + # ] + + - name: Prepare target branch + id: prepare_target_branch + uses: ./.github/actions/prepare_branch + with: + target_branch: ${{ inputs.target_branch }} + pub_version: ${{ inputs.pub_version }} + branch_group: "special" + working_directory: ./ + + - name: Update dependencies with parsed dependencies content + if: ${{ inputs.dependencies_content != '' }} + shell: bash + run: | + # call ci/run_update_deps.sh with output of steps.parse_dependencies_content.outputs.matches + bash ci/run_update_deps.sh ${{ steps.parse_dependencies_content.outputs.matches }} + + - name: Update pub version into pubspec.yaml + if: ${{ inputs.pub_version != '' }} + shell: bash + run: | + # Update pub version into pubspec.yaml + sed -i '' "s/version: .*/version: ${{ inputs.pub_version }}/" pubspec.yaml + + - name: Run gen code + if: ${{ inputs.run_gen_code == true }} + uses: ./.github/actions/gen_code + with: + code_gen_public_headers: ${{ inputs.code_gen_public_headers }} + flutter_channel: ${{ inputs.flutter_channel }} + flutter_version: ${{ inputs.flutter_version }} + working_directory: ./ + + + - name: Commit and create pull request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "feat: update dependencies" + committer: GitHub + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + signoff: false + branch: dev/${{ steps.prepare_target_branch.outputs.final_target_branch }} + base: ${{ steps.prepare_target_branch.outputs.final_target_branch }} + delete-branch: true + draft: false + title: "feat: update dependencies" + body: | + Update dependencies with the following content: + + ${{ inputs.dependencies_content }} + + > This pull request is trigger by bot, you can checkout this branch and update it. + labels: | + ci:ready_release_special + + + + + + + + + + diff --git a/.github/workflows/schedule-run-ci-internal.yml b/.github/workflows/schedule-run-ci-internal.yml deleted file mode 100644 index 10e3f1755..000000000 --- a/.github/workflows/schedule-run-ci-internal.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Schedule run ci internal - -on: - pull_request: - -jobs: - check_permission: - name: Check permission - if: ${{ !contains(github.event.pull_request.labels.*.name, 'ci:skip') }} - runs-on: ubuntu-latest - timeout-minutes: 60 - outputs: - is_schedule_run_ci: ${{ steps.check-label-step.outputs.is_schedule_run_ci }} - steps: - - name: Check for Secret availability - id: check-label-step - # perform secret check & put boolean result as an output - shell: bash - run: | - APP_ID="${{ secrets.MY_APP_ID }}" - if [ ! -z "${APP_ID}" ]; then - echo "is_schedule_run_ci=1" >> $GITHUB_OUTPUT; - echo "secrets.MY_APP_ID is not empty, PR opened by the internal contributors" - else - echo "is_schedule_run_ci=-1" >> $GITHUB_OUTPUT; - echo "secrets.MY_APP_ID is empty, PR opened by the external contributors" - fi - - schedule_ci: - name: Schedule run ci - needs: check_permission - # If the PR requested by a external contributor, the secrets.MY_APP_ID should be empty, and skip this workflow - if: ${{ needs.check_permission.outputs.is_schedule_run_ci == 1 }} - uses: ./.github/workflows/build.yml - secrets: - MY_APP_ID: ${{ secrets.MY_APP_ID }} - \ No newline at end of file diff --git a/.github/workflows/schedule_stale_issues.yml b/.github/workflows/schedule_stale_issues.yml new file mode 100644 index 000000000..8d88fb1da --- /dev/null +++ b/.github/workflows/schedule_stale_issues.yml @@ -0,0 +1,46 @@ +# Cron syntax +# β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0 - 59) +# β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour (0 - 23) +# β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of the month (1 - 31) +# β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ month (1 - 12 or JAN-DEC) +# β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of the week (0 - 6 or SUN-SAT) +# β”‚ β”‚ β”‚ β”‚ β”‚ +# β”‚ β”‚ β”‚ β”‚ β”‚ +# β”‚ β”‚ β”‚ β”‚ β”‚ +# * * * * * + +name: 'schedule: stale issues' + +on: + workflow_dispatch: + + schedule: + - cron: '30 8 * * *' # This workflow will run every day at 8:30 AM + +permissions: + issues: write + +jobs: + schedule_stals_issues: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + repo-token: ${{ github.token }} + # Idle number of days before marking issues/PRs stale + # If set to a negative number like -1, no issues or pull requests will be marked as stale automatically. + days-before-stale: -1 + # Idle number of days before closing stale issues/PRs + # If set to a negative number like -1, the issues or the pull requests will never be closed automatically. + days-before-close: -1 + # Override days-before-stale for issues only + days-before-issue-stale: 14 + # Override days-before-close for issues only + days-before-issue-close: 5 + # Comment on the staled issues + stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + # Comment on the staled issues while closed + close-issue-message: 'This PR was closed because it has been stalled for 5 days with no activity.' + # If set to true, the issues or the pull requests with an assignee will not be marked as stale automatically. + exempt-all-assignees: true + \ No newline at end of file diff --git a/ci/run_android_test.sh b/ci/run_android_test.sh deleted file mode 100644 index 7336fd5d9..000000000 --- a/ci/run_android_test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd example/android - -./gradlew test \ No newline at end of file diff --git a/ci/run_flutter_integration_test.sh b/ci/run_flutter_integration_test.sh deleted file mode 100644 index 3fdb587ee..000000000 --- a/ci/run_flutter_integration_test.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -MY_PATH=$(realpath $(dirname "$0")) -PROJECT_ROOT=$(realpath ${MY_PATH}/..) -PLATFORM=$1 # android/ios/macos/windows/web - -if [[ ${PLATFORM} == "web" ]];then - pushd ${PROJECT_ROOT}/test_shard/fake_test_app - - IRIS_WEB_VERSION_PATH=${PROJECT_ROOT}/scripts/iris_web_version.js - rm -rf web/iris_web_version.js - cp -RP ${IRIS_WEB_VERSION_PATH} web/ - - echo "Run integration test on web" - echo "If you want to run integration test on your local machine, please follow the https://docs.flutter.dev/testing/integration-tests#test-in-a-web-browser to setup first." - - flutter packages get - - for filename in integration_test/*.dart; do - if [[ "$filename" == *.generated.dart ]]; then - continue - fi - - flutter drive \ - --verbose-system-logs \ - -d web-server \ - --driver=test_driver/integration_test.dart \ - --target=${filename} - done - - popd - -elif [[ ${PLATFORM} == "android" || ${PLATFORM} == "ios" ]];then - echo "Not implemented" -else - echo "Not implemented" -fi \ No newline at end of file diff --git a/ci/run_flutter_integration_test_android.sh b/ci/run_flutter_integration_test_android.sh index 999577d42..d7f46773d 100644 --- a/ci/run_flutter_integration_test_android.sh +++ b/ci/run_flutter_integration_test_android.sh @@ -5,25 +5,6 @@ set -x MY_PATH=$(dirname "$0") -DOWNLOAD_IRIS_DEBUGGER=${1:-1} - -if [[ ${DOWNLOAD_IRIS_DEBUGGER} == 1 ]];then - source ${MY_PATH}/../scripts/artifacts_version.sh - - bash ${MY_PATH}/../scripts/download_unzip_iris_cdn_artifacts.sh ${IRIS_CDN_URL_ANDROID} "Android" -fi - -pushd ${MY_PATH}/../test_shard/fake_test_app - -flutter packages get - -flutter test integration_test --verbose - -# Remove the build directory to save disk space -rm -rf build/ - -popd - pushd ${MY_PATH}/../test_shard/integration_test_app flutter packages get diff --git a/ci/run_flutter_integration_test_ios.sh b/ci/run_flutter_integration_test_ios.sh index 146aeff19..d16425113 100644 --- a/ci/run_flutter_integration_test_ios.sh +++ b/ci/run_flutter_integration_test_ios.sh @@ -5,22 +5,6 @@ set -x MY_PATH=$(dirname "$0") -DOWNLOAD_IRIS_DEBUGGER=${1:-1} - -if [[ ${DOWNLOAD_IRIS_DEBUGGER} == 1 ]];then - source ${MY_PATH}/../scripts/artifacts_version.sh - - bash ${MY_PATH}/../scripts/download_unzip_iris_cdn_artifacts.sh ${IRIS_CDN_URL_IOS} "iOS" -fi - -pushd ${MY_PATH}/../test_shard/fake_test_app - -flutter packages get - -flutter test integration_test - -popd - pushd ${MY_PATH}/../test_shard/integration_test_app flutter packages get diff --git a/ci/run_flutter_integration_test_web.sh b/ci/run_flutter_integration_test_web.sh new file mode 100644 index 000000000..dd3b4f55c --- /dev/null +++ b/ci/run_flutter_integration_test_web.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e +set -x + +MY_PATH=$(realpath $(dirname "$0")) +PROJECT_ROOT=$(realpath ${MY_PATH}/..) + +pushd ${PROJECT_ROOT}/test_shard/fake_test_app + +IRIS_WEB_VERSION_PATH=${PROJECT_ROOT}/scripts/iris_web_version.js +rm -rf web/iris_web_version.js +cp -RP ${IRIS_WEB_VERSION_PATH} web/ + +echo "Run integration test on web" +echo "If you want to run integration test on your local machine, please follow the https://docs.flutter.dev/testing/integration-tests#test-in-a-web-browser to setup first." + +flutter packages get + +for filename in integration_test/*.dart; do + if [[ "$filename" == *.generated.dart ]]; then + continue + fi + + flutter drive \ + --verbose-system-logs \ + -d web-server \ + --driver=test_driver/integration_test.dart \ + --target=${filename} +done + +popd \ No newline at end of file diff --git a/ci/run_flutter_macos_integration_test.sh b/ci/run_flutter_macos_integration_test.sh index 1c53a92ef..dab0bccb3 100644 --- a/ci/run_flutter_macos_integration_test.sh +++ b/ci/run_flutter_macos_integration_test.sh @@ -5,28 +5,6 @@ set -x MY_PATH=$(dirname "$0") -DOWNLOAD_IRIS_DEBUGGER=${1:-1} - -if [[ ${DOWNLOAD_IRIS_DEBUGGER} == 1 ]];then - source ${MY_PATH}/../scripts/artifacts_version.sh - - bash ${MY_PATH}/../scripts/download_unzip_iris_cdn_artifacts.sh ${IRIS_CDN_URL_MACOS} "MAC" -fi - -pushd ${MY_PATH}/../test_shard/fake_test_app - -flutter packages get - -# It's a little tricky that you should run integration test one by one on flutter macOS/Windows -for filename in integration_test/*.dart; do - if [[ "$filename" == *.generated.dart ]]; then - continue - fi - flutter test $filename -d macos -done - -popd - pushd ${MY_PATH}/../test_shard/integration_test_app flutter packages get diff --git a/ci/run_flutter_windows_integration_test.sh b/ci/run_flutter_windows_integration_test.sh index 42b488afe..a586f1636 100644 --- a/ci/run_flutter_windows_integration_test.sh +++ b/ci/run_flutter_windows_integration_test.sh @@ -5,28 +5,6 @@ set -x MY_PATH=$(dirname "$0") -DOWNLOAD_IRIS_DEBUGGER=${1:-1} - -if [[ ${DOWNLOAD_IRIS_DEBUGGER} == 1 ]];then - source ${MY_PATH}/../scripts/artifacts_version.sh - - bash ${MY_PATH}/../scripts/download_unzip_iris_cdn_artifacts.sh ${IRIS_CDN_URL_WINDOWS} "Windows" -fi - -pushd ${MY_PATH}/../test_shard/fake_test_app - -flutter packages get - -# It's a little tricky that you should run integration test one by one on flutter macOS/Windows -for filename in integration_test/*.dart; do - if [[ "$filename" == *.generated.dart ]]; then - continue - fi - flutter test $filename -d windows --verbose -done - -popd - pushd ${MY_PATH}/../test_shard/integration_test_app flutter packages get diff --git a/ci/run_ios_test.sh b/ci/run_ios_test.sh deleted file mode 100644 index f0df63e78..000000000 --- a/ci/run_ios_test.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd example/ios - -pod install - -bundle install -bundle exec fastlane tests - \ No newline at end of file diff --git a/ci/run_update_deps.sh b/ci/run_update_deps.sh new file mode 100644 index 000000000..427152c05 --- /dev/null +++ b/ci/run_update_deps.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# get current directory +current_dir=$(pwd) +echo "current_dir=${current_dir}" + +# const variables +dep_file_ios=ios/agora_rtc_engine.podspec +dep_file_macos=macos/agora_rtc_engine.podspec +dep_file_android=android/build.gradle +dep_file_windows=windows/cmake/DownloadSDK.cmake + +# get parsed dependencies content from argument 1, the format is as follows: +# [ +# { +# "iris_cdn": [ +# "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_Unity_20250217_0847_579.zip", +# "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_Standalone_20250217_0847_579.zip", +# "https://download.agora.io/sdk/release/iris_4.5.0-gxz.119_DCG_Mac_Video_20250217_0847_579.zip" +# ], +# "cdn": [ +# "https://download.agora.io/sdk/release/AgoraRtcEngine_macOS_Preview_4.5.0-gxz.119.zip" +# ], +# "iris_cocoapods": [ +# "pod 'AgoraIrisRTC_macOS', '4.5.0-gxz.119'" +# ], +# "iris_maven": [ +# "implementation 'io.agora.rtc:iris-rtc:4.5.0-gxz.119'" +# ], +# "maven": [ +# "implementation 'io.agora.rtc:agora-full-preview:4.5.0-gxz.119'", +# "implementation 'io.agora.rtc:full-screen-sharing-special:4.5.0-gxz.119'" +# ], +# "platform": "macOS", // iOS, macOS, Android, Windows, Web +# "cocoapods": [ +# "pod 'AgoraRtcEngine_macOS_Preview', '4.5.0-gxz.119'" +# ] +# }, +# ] +dependencies_content=$1 + + +# function to update podspec file +function update_podspec_file() { + local dep_file=$1 + local dep_item=$2 + + # Handle iris dependencies + iris_cocoapods=$(echo "${dep_item}" | jq -r '.iris_cocoapods[]') + if [ "${iris_cocoapods}" != "" ]; then + # replace 'pod' with 's.dependency' and remove quotes + iris_deps=$(echo "${iris_cocoapods}" | sed 's/pod/s.dependency/g' | sed 's/"//g') + # Add indentation + iris_deps=$(echo "${iris_deps}" | sed 's/^/ /') + + perl -0777 -pe "s/# iris dependencies start.*# iris dependencies end/# iris dependencies start\n${iris_deps}\n # iris dependencies end/ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi + + # Handle native dependencies + cocoapods=$(echo "${dep_item}" | jq -r '.cocoapods[]') + if [ "${cocoapods}" != "" ]; then + # replace 'pod' with 's.dependency' and remove quotes + native_deps=$(echo "${cocoapods}" | sed 's/pod/s.dependency/g' | sed 's/"//g') + # Add indentation + native_deps=$(echo "${native_deps}" | sed 's/^/ /') + + perl -0777 -pe "s/# native dependencies start.*# native dependencies end/# native dependencies start\n${native_deps}\n # native dependencies end/ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi +} + +# function to update gradle file +function update_gradle_file() { + local dep_file=$1 + local dep_item=$2 + + # Handle iris dependencies + iris_maven=$(echo "${dep_item}" | jq -r '.iris_maven[]') + if [ "${iris_maven}" != "" ]; then + # replace 'implementation' with 'api' and remove quotes + iris_deps=$(echo "${iris_maven}" | sed 's/implementation/api/g' | sed 's/"//g') + # Add indentation + iris_deps=$(echo "${iris_deps}" | sed 's/^/ /') + + perl -0777 -pe "s/ \/\/ iris dependencies start.* \/\/ iris dependencies end/ \/\/ iris dependencies start\n${iris_deps}\n \/\/ iris dependencies end/ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi + + # Handle native dependencies + maven=$(echo "${dep_item}" | jq -r '.maven[]') + if [ "${maven}" != "" ]; then + # replace 'implementation' with 'api' and remove quotes + native_deps=$(echo "${maven}" | sed 's/implementation/api/g' | sed 's/"//g') + # Add indentation + native_deps=$(echo "${native_deps}" | sed 's/^/ /') + + perl -0777 -pe "s/ \/\/ native dependencies start.* \/\/ native dependencies end/ \/\/ native dependencies start\n${native_deps}\n \/\/ native dependencies end/ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi +} + +# function to update cmake file +function update_cmake_file() { + local dep_file=$1 + local dep_item=$2 + + # Handle iris dependencies + iris_cdn_standalone=$(echo "${dep_item}" | jq -r '.iris_cdn[] | select(. | contains("Standalone"))') + if [ "${iris_cdn_standalone}" != "" ]; then + escaped_iris_cdn=$(printf '%s\n' "$iris_cdn_standalone" | sed 's/[\/&]/\\&/g') + iris_content="set(IRIS_SDK_DOWNLOAD_URL \"${escaped_iris_cdn}\")" + + perl -0777 -pe "s~# iris dependencies start.*# iris dependencies end~# iris dependencies start\n${iris_content}\n# iris dependencies end~ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi + + # Handle native dependencies + cdn=$(echo "${dep_item}" | jq -r '.cdn[0]') + if [ "${cdn}" != "null" ]; then + escaped_cdn=$(printf '%s\n' "$cdn" | sed 's/[\/&]/\\&/g') + native_content="set(NATIVE_SDK_DOWNLOAD_URL \"${escaped_cdn}\")" + + perl -0777 -pe "s~# native dependencies start.*# native dependencies end~# native dependencies start\n${native_content}\n# native dependencies end~ms" "${dep_file}" > "${dep_file}.tmp" + mv "${dep_file}.tmp" "${dep_file}" + fi +} + + +echo "${dependencies_content}" | jq -c '.[]' | while read -r dep_item; do + # get platform from dep_item + platform=$(echo "${dep_item}" | jq -r '.platform') + + # update dependencies file by platform + if [ "${platform}" == "iOS" ]; then + update_podspec_file "${dep_file_ios}" "${dep_item}" + elif [ "${platform}" == "macOS" ]; then + update_podspec_file "${dep_file_macos}" "${dep_item}" + elif [ "${platform}" == "Android" ]; then + update_gradle_file "${dep_file_android}" "${dep_item}" + elif [ "${platform}" == "Windows" ]; then + update_cmake_file "${dep_file_windows}" "${dep_item}" + fi +done + diff --git a/example/ios/export.plist b/example/ios/export.plist new file mode 100644 index 000000000..bf0dc3427 --- /dev/null +++ b/example/ios/export.plist @@ -0,0 +1,17 @@ + + + + + method + development + compileBitcode + + provisioningProfiles + + io.agora.agoraRtcEngineExample + DEFAULT_BUILD_PROVISION_PROFILE_NAME + io.agora.agoraRtcEngineExample.ScreenSharing + DEFAULT_BUILD_PROVISION_PROFILE_NAME + + + \ No newline at end of file diff --git a/scripts/artifacts_version.sh b/scripts/artifacts_version.sh deleted file mode 100644 index 7ae028361..000000000 --- a/scripts/artifacts_version.sh +++ /dev/null @@ -1,6 +0,0 @@ -set -e - -export IRIS_CDN_URL_ANDROID="https://download.agora.io/sdk/release/iris_4.2.6.20-build.1_DCG_Android_Video_20241217_0416.zip" -export IRIS_CDN_URL_IOS="https://download.agora.io/sdk/release/iris_4.2.6.20-build.1_DCG_iOS_Video_20241217_0419.zip" -export IRIS_CDN_URL_MACOS="https://download.agora.io/sdk/release/iris_4.2.6.20-build.1_DCG_Mac_Video_20241217_0416.zip" -export IRIS_CDN_URL_WINDOWS="https://download.agora.io/sdk/release/iris_4.2.6.20-build.1_DCG_Windows_Video_20241217_0416.zip" diff --git a/scripts/build-android-arch.sh b/scripts/build-android-arch.sh deleted file mode 100644 index 344660726..000000000 --- a/scripts/build-android-arch.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -set -ex - -IRIS_PATH=$1 - -# shell_path=$( -# cd "$(dirname "$0")" || exit -# pwd -# ) -root_path=$IRIS_PATH - -build() { - cd "$root_path" || exit - mkdir -p ./build/android/"$1" - cd ./build/android/"$1" || exit - cmake \ - -G "Ninja" \ - -DANDROID_ABI="$1" \ - -DANDROID_NDK="$ANDROID_NDK" \ - -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK"/build/cmake/android.toolchain.cmake \ - -DANDROID_TOOLCHAIN=clang \ - -DANDROID_PLATFORM=android-16 \ - -DCMAKE_BUILD_TYPE="$2" \ - "$root_path" - cmake --build . --config "$2" -} - -# e.g., -# build-android.sh ALL Debug -# build-android.sh arm64-v8a Debug -ARCH=$2 -BUILD_TYPE=$3 -if [[ -z $ARCH ]]; then - ARCH="ALL" -fi - -if [[ -z $BUILD_TYPE ]]; then - BUILD_TYPE="Release" -fi - -BUILD_TYPE_LOWER_CASE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]") -if [ $ARCH = "ALL" ]; then - pushd $IRIS_PATH/dcg/android - echo "start build aar ----------" - chmod +x ./gradlew - ./gradlew assemble$BUILD_TYPE_LOWER_CASE - echo "start copy outputs ----------" - mkdir -p "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/$BUILD_TYPE" - cp "app/build/outputs/aar/app-${BUILD_TYPE_LOWER_CASE}.aar" "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}/AgoraRtcWrapper.aar" - cp -rp app/build/intermediates/merged_native_libs/${BUILD_TYPE_LOWER_CASE}/out/lib/ "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}" - cp -RP app/build/intermediates/aar_main_jar/${BUILD_TYPE_LOWER_CASE}/classes.jar "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}/AgoraRtcWrapper.jar" - popd -else - build $ARCH $BUILD_TYPE -fi \ No newline at end of file diff --git a/scripts/build-android.sh b/scripts/build-android.sh deleted file mode 100755 index 9101ef46f..000000000 --- a/scripts/build-android.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -set -ex - -shell_path=$( - cd "$(dirname "$0")" || exit - pwd -) -root_path="$shell_path/../.." - -build() { - cd "$root_path" || exit - mkdir -p ./build/android/"$1" - cd ./build/android/"$1" || exit - cmake \ - -G "Ninja" \ - -DANDROID_ABI="$1" \ - -DANDROID_NDK="$ANDROID_NDK" \ - -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK"/build/cmake/android.toolchain.cmake \ - -DANDROID_TOOLCHAIN=clang \ - -DANDROID_PLATFORM=android-16 \ - -DCMAKE_BUILD_TYPE="$2" \ - "$root_path" - cmake --build . --config "$2" -} - -# build-android.sh ALL Debug -# build-android.sh arm64-v8a Debug -ARCH=$1 -BUILD_TYPE=$2 -if [[ -z $ARCH ]]; then - ARCH = "ALL" -fi - -if [[ -z $BUILD_TYPE ]]; then - BUILD_TYPE = "Release" -fi - -BUILD_TYPE_LOWER_CASE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]") -if [ $ARCH = "ALL" ]; then - pushd "$shell_path"/../android - echo "start build aar ----------" - chmod +x ./gradlew - ./gradlew assemble$BUILD_TYPE_LOWER_CASE - echo "start copy outputs ----------" - mkdir -p "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/$BUILD_TYPE" - cp "app/build/outputs/aar/app-${BUILD_TYPE_LOWER_CASE}.aar" "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}/AgoraRtcWrapper.aar" - cp -rp app/build/intermediates/merged_native_libs/${BUILD_TYPE_LOWER_CASE}/out/lib/ "$root_path/build/android/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}" - popd -else - build $ARCH $BUILD_TYPE -fi diff --git a/scripts/build-internal-testing-macos.sh b/scripts/build-internal-testing-macos.sh deleted file mode 100644 index 5e0830838..000000000 --- a/scripts/build-internal-testing-macos.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -e - -ROOT_PATH=$(pwd) -EXAMPLE_PATH=$ROOT_PATH/example - -cd $EXAMPLE_PATH - -flutter build macos --release --dart-define TEST_APP_ID="$TEST_APP_ID" --dart-define TEST_TOEKN="$TEST_TOEKN" --dart-define TEST_CHANNEL_ID="$TEST_CHANNEL_ID" -mkdir -p $EXAMPLE_PATH/build/internal_testing_artifacts/macos -mkdir -p $EXAMPLE_PATH/build/internal_testing_artifacts/macos/dSYMs - -cp -r $EXAMPLE_PATH/build/macos/Build/Products/Release/agora_rtc_engine_example.app "$EXAMPLE_PATH/build/internal_testing_artifacts/macos" -cp -r $EXAMPLE_PATH/build/macos/Build/Products/Release/agora_rtc_engine "$EXAMPLE_PATH/build/internal_testing_artifacts/macos/dSYMs" -cp -r $EXAMPLE_PATH/build/macos/Build/Products/Release/agora_rtc_engine_example.app.dSYM "$EXAMPLE_PATH/build/internal_testing_artifacts/macos/dSYMs" \ No newline at end of file diff --git a/scripts/build-internal-testing.sh b/scripts/build-internal-testing.sh deleted file mode 100644 index 3a0c3235d..000000000 --- a/scripts/build-internal-testing.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -e - -ROOT_PATH=$(pwd) -EXAMPLE_PATH=$ROOT_PATH/example - -cd $EXAMPLE_PATH - -flutter clean -flutter packages get - -mkdir build/internal_testing_artifacts -mkdir build/internal_testing_artifacts/ios -mkdir build/internal_testing_artifacts/android - -flutter build ipa --dart-define TEST_APP_ID="$TEST_APP_ID" --dart-define TEST_TOEKN="$TEST_TOEKN" --dart-define TEST_CHANNEL_ID="$TEST_CHANNEL_ID" --export-options-plist $exportPList -cp -r $EXAMPLE_PATH/build/app/outputs/flutter-apk/app-release.apk $EXAMPLE_PATH/build/internal_testing_artifacts/android/agora_rtc_engine_example.apk - -bash $ROOT_PATH/scripts/build-internal-testing-ios.sh - -dt=$(date '+%d/%m/%Y %H:%M:%S') -zip -r -y "$EXAMPLE_PATH/build/internal_testing_artifacts_${dt}.zip" "$EXAMPLE_PATH/build/internal_testing_artifacts" diff --git a/scripts/build-ios-arch.sh b/scripts/build-ios-arch.sh deleted file mode 100644 index 01bf98eb4..000000000 --- a/scripts/build-ios-arch.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -set -ex - -IRIS_PATH=$1 - -# shell_path=$( -# cd "$(dirname "$0")" || exit -# pwd -# ) -root_path=$IRIS_PATH - -build() { - cd "$root_path" || exit - mkdir -p ./build/ios/"$1" - cd ./build/ios/"$1" || exit - if [ "$1" = "OS64COMBINED" ]; then - archs="arm64" - elif [ "$1" = "SIMULATOR64" ]; then - archs="x86_64" - # archs="arm64 x86_64" - fi - cmake \ - -G "Xcode" \ - -DCMAKE_TOOLCHAIN_FILE="$root_path"/cmake/ios.toolchain.cmake \ - -DPLATFORM="$1" \ - -DARCHS="$archs" \ - -DDEPLOYMENT_TARGET="9.0" \ - -DCMAKE_BUILD_TYPE="$2" \ - "$root_path" - cmake --build . --config "$2" - unset archs -} - -ARCH=$2 -BUILD_TYPE=$3 - -if [[ -z $ARCH ]]; then - ARCH="ALL" -fi - -if [[ -z $BUILD_TYPE ]]; then - BUILD_TYPE="Release" -fi - -if [[ "$ARCH" = "ALL" ]]; then - echo "start build OS64COMBINED ----------" - build OS64COMBINED $BUILD_TYPE - echo "start build SIMULATOR64 ----------" - build SIMULATOR64 $BUILD_TYPE - echo "start create .xcframework ----------" - mkdir -p "$root_path/build/ios/ALL_ARCHITECTURE/output/dcg/$BUILD_TYPE" - xcodebuild -create-xcframework \ - -framework "$root_path/build/ios/OS64COMBINED/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework" \ - -debug-symbols "$root_path/build/ios/OS64COMBINED/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework.dSYM" \ - -framework "$root_path/build/ios/SIMULATOR64/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework" \ - -debug-symbols "$root_path/build/ios/SIMULATOR64/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework.dSYM" \ - -output "$root_path/build/ios/ALL_ARCHITECTURE/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.xcframework" - echo "start create .framework ----------" - cp -rp "$root_path"/build/ios/OS64COMBINED/output/dcg/$BUILD_TYPE "$root_path/build/ios/ALL_ARCHITECTURE/output/dcg" - # lipo -remove arm64 \ - # "$root_path/build/ios/SIMULATOR64/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework/AgoraRtcWrapper" \ - # -output "$root_path/build/ios/SIMULATOR64/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework/AgoraRtcWrapper" - lipo -create \ - "$root_path/build/ios/OS64COMBINED/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework/AgoraRtcWrapper" \ - "$root_path/build/ios/SIMULATOR64/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework/AgoraRtcWrapper" \ - -output "$root_path/build/ios/ALL_ARCHITECTURE/output/dcg/$BUILD_TYPE/AgoraRtcWrapper.framework/AgoraRtcWrapper" -else - build $ARCH $BUILD_TYPE -fi diff --git a/scripts/build-iris-all.sh b/scripts/build-iris-all.sh deleted file mode 100644 index debea2cef..000000000 --- a/scripts/build-iris-all.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -BUILD_TYPE=$1 -IRIS_PROJECT_PATH=$2 - -if [[ -z "$BUILD_TYPE" ]]; then - BUILD_TYPE="Debug" -fi - -bash scripts/build-iris-android.sh $IRIS_PROJECT_PATH $BUILD_TYPE -bash scripts/build-iris-ios.sh $BUILD_TYPE -bash scripts/build-iris-macos.sh $BUILD_TYPE \ No newline at end of file diff --git a/scripts/build-iris-android.sh b/scripts/build-iris-android.sh deleted file mode 100644 index ecfd51c48..000000000 --- a/scripts/build-iris-android.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -AGORA_FLUTTER_PROJECT_PATH=$(pwd) -IRIS_PROJECT_PATH=$1 -BUILD_TYPE=$2 -ABIS="arm64-v8a armeabi-v7a x86_64" -IRIS_TYPE="dcg" -NATIVE_SDK_PATH_NAME=$3 # Agora_Native_SDK_for_Mac_rel.v3.8.201.2_39877_full_20220608_2158 -SCRIPTS_PATH=$(dirname "$0") - -bash $IRIS_PROJECT_PATH/ci/build-android.sh buildALL $BUILD_TYPE - - # build/android/DCG/ALL_ARCHITECTURE/output/Debug - -IRIS_OUTPUT=${IRIS_PROJECT_PATH}/build/android/$IRIS_TYPE/ALL_ARCHITECTURE/output/$BUILD_TYPE - -for ABI in ${ABIS}; -do - echo "Copying $IRIS_PROJECT_PATH/build/android/$ABI/output/$IRIS_TYPE/$BUILD_TYPE/libAgoraRtcWrapper.so to $AGORA_FLUTTER_PROJECT_PATH/android/libs/$ABI/libAgoraRtcWrapper.so" - # bash $IRIS_PROJECT_PATH/$IRIS_TYPE/ci/build-android.sh build $ABI $BUILD_TYPE - mkdir -p "$AGORA_FLUTTER_PROJECT_PATH/android/libs/$ABI/" - - cp -RP "${IRIS_OUTPUT}/$ABI/libAgoraRtcWrapper.so" \ - "$AGORA_FLUTTER_PROJECT_PATH/android/libs/$ABI/libAgoraRtcWrapper.so" - - if [ -f "${IRIS_PROJECT_PATH}/build/android/ALL_ARCHITECTURE/output/${IRIS_TYPE}/${BUILD_TYPE}/${ABI}/libIrisDebugger.so" ]; then - mkdir -p ${AGORA_FLUTTER_PROJECT_PATH}/test_shard/iris_tester/android/libs/${ABI} - cp -RP "${IRIS_OUTPUT}/$ABI/libIrisDebugger.so" "${AGORA_FLUTTER_PROJECT_PATH}/test_shard/iris_tester/android/libs/${ABI}/libIrisDebugger.so" - fi -done; - -# echo "Copying $IRIS_PROJECT_PATH/build/android/ALL_ARCHITECTURE/output/$IRIS_TYPE/$BUILD_TYPE/AgoraRtcWrapper.aar to $AGORA_FLUTTER_PROJECT_PATH/android/libs/AgoraRtcWrapper.aar" -# cp -r "$IRIS_PROJECT_PATH/build/android/ALL_ARCHITECTURE/output/$IRIS_TYPE/$BUILD_TYPE/AgoraRtcWrapper.aar" "$AGORA_FLUTTER_PROJECT_PATH/android/libs/AgoraRtcWrapper.aar" - -echo "Copying ${IRIS_OUTPUT}/AgoraRtcWrapper.jar to $AGORA_FLUTTER_PROJECT_PATH/android/libs/AgoraRtcWrapper.jar" -cp -r "${IRIS_OUTPUT}/AgoraRtcWrapper.jar" "$AGORA_FLUTTER_PROJECT_PATH/android/libs/AgoraRtcWrapper.jar" - -for ABI in ${ABIS}; -do - echo "Copying $IRIS_PROJECT_PATH/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/libs/$ABI/ to $AGORA_FLUTTER_PROJECT_PATH/android/libs/$ABI/" - # third_party/agora/rtc/libs/Agora_Native_SDK_for_Android_FULL - cp -r "$IRIS_PROJECT_PATH/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/rtc/sdk/$ABI/" \ - "$AGORA_FLUTTER_PROJECT_PATH/android/libs/$ABI/" -done; - -if [[ ! -d "$AGORA_FLUTTER_PROJECT_PATH/third_party/include/" ]]; then - mkdir -p "$AGORA_FLUTTER_PROJECT_PATH/third_party/include/" -fi - -echo "Copying $IRIS_PROJECT_PATH/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/libs/agora-rtc-sdk.jar to $AGORA_FLUTTER_PROJECT_PATH/android/libs/libs/agora-rtc-sdk.jar" -cp -r "$IRIS_PROJECT_PATH/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/rtc/sdk/agora-rtc-sdk.jar" "$AGORA_FLUTTER_PROJECT_PATH/android/libs/agora-rtc-sdk.jar" - -# /Users/fenglang/codes/aw/iris/third_party/agora/dcg/libs/Agora_Native_SDK_for_Android_FULL/rtc/sdk/AgoraScreenShareExtension.aar -cp -r "$IRIS_PROJECT_PATH/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/rtc/sdk/AgoraScreenShareExtension.aar" "$AGORA_FLUTTER_PROJECT_PATH/android/libs/AgoraScreenShareExtension.aar" diff --git a/scripts/build-iris-ios.sh b/scripts/build-iris-ios.sh deleted file mode 100644 index ff3165a65..000000000 --- a/scripts/build-iris-ios.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -# e.g., bash scripts/build-iris-ios.sh Agora_Native_SDK_for_iOS_FULL - -AGORA_FLUTTER_PROJECT_PATH=$(pwd) -IRIS_PROJECT_PATH=$1 -ARCH_TYPE="SIMULATOR64" -BUILD_TYPE=$2 -NATIVE_SDK_PATH_NAME=$3 # Agora_Native_SDK_for_Mac_rel.v3.8.201.2_39877_full_20220608_2158 -SCRIPTS_PATH=$(dirname "$0") - -rm -rf "${IRIS_PROJECT_PATH}/build/ios/ALL_ARCHITECTURE/output/dcg/${BUILD_TYPE}/AgoraRtcWrapper.xcframework" - -bash $IRIS_PROJECT_PATH/ci/build-ios.sh buildALL $BUILD_TYPE - -if [[ -d "${AGORA_FLUTTER_PROJECT_PATH}/ios/libs" ]]; then - rm -rf "${AGORA_FLUTTER_PROJECT_PATH}/ios/libs" -fi - -mkdir -p "${AGORA_FLUTTER_PROJECT_PATH}/ios/libs" - -echo "Copying Agora RTC engine frameworks" -cp -RP ${IRIS_PROJECT_PATH}/third_party/agora/dcg/libs/$NATIVE_SDK_PATH_NAME/libs/* "${AGORA_FLUTTER_PROJECT_PATH}/ios/libs/" -rm -rf ${AGORA_FLUTTER_PROJECT_PATH}/ios/libs/ALL_ARCHITECTURE - -cp -RP "${IRIS_PROJECT_PATH}/build/ios/DCG/ALL_ARCHITECTURE/output/${BUILD_TYPE}/AgoraRtcWrapper.xcframework" "$AGORA_FLUTTER_PROJECT_PATH/ios/libs" \ No newline at end of file diff --git a/scripts/build-iris-macos-arch.sh b/scripts/build-iris-macos-arch.sh deleted file mode 100644 index d4f2160e8..000000000 --- a/scripts/build-iris-macos-arch.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -ex - -IRIS_PATH=$1 - -# shell_path=$( -# cd "$(dirname "$0")" || exit -# pwd -# ) -root_path=$IRIS_PATH - -build() { - cd "$root_path" || exit - mkdir -p ./build/mac/"$1" - cd ./build/mac/"$1" || exit - archs="x86_64" - cmake \ - -G "Xcode" \ - -DCMAKE_TOOLCHAIN_FILE="$root_path"/cmake/ios.toolchain.cmake \ - -DPLATFORM="$1" \ - -DARCHS="$archs" \ - -DCMAKE_BUILD_TYPE="$2" \ - "$root_path" - cmake --build . --config "$2" - unset archs -} - -ARCH=$2 -BUILD_TYPE=$3 - -if [[ -z $ARCH ]]; then - ARCH="ALL" -fi - -if [[ -z $BUILD_TYPE ]]; then - BUILD_TYPE="Release" -fi - -if [[ "$ARCH" = "ALL" ]]; then - build MAC $BUILD_TYPE -else - build $ARCH $BUILD_TYPE -fi \ No newline at end of file diff --git a/scripts/build-iris-macos.sh b/scripts/build-iris-macos.sh deleted file mode 100644 index e1a1b16c7..000000000 --- a/scripts/build-iris-macos.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -AGORA_FLUTTER_PROJECT_PATH=$(pwd) -IRIS_PROJECT_PATH=$1 -BUILD_TYPE=$2 -NATIVE_SDK_PATH_NAME=$3 # Agora_Native_SDK_for_Mac_rel.v3.8.201.2_39877_full_20220608_2158 -IRIS_TYPE="dcg" -SCRIPTS_PATH=$(dirname "$0") - -echo "Cleaning build cache..." -rm -rf $IRIS_PROJECT_PATH/build - -echo "Building iris for mac..." -bash $SCRIPTS_PATH/build-iris-macos-arch.sh $IRIS_PROJECT_PATH MAC $BUILD_TYPE - -if [[ -d "$AGORA_FLUTTER_PROJECT_PATH/macos/AgoraRtcWrapper.framework" ]]; then - rm -rf $AGORA_FLUTTER_PROJECT_PATH/macos/AgoraRtcWrapper.framework -fi - -if [[ -d "${AGORA_FLUTTER_PROJECT_PATH}/macos/libs" ]]; then - rm -rf "${AGORA_FLUTTER_PROJECT_PATH}/macos/libs" -fi - -mkdir -p "${AGORA_FLUTTER_PROJECT_PATH}/macos/libs" - -# /Users/fenglang/codes/aw/iris/build/mac/MAC/output/dcg/Debug/AgoraRtcWrapper.framework -echo "Copying $IRIS_PROJECT_PATH/build/mac/MAC/output/$IRIS_TYPE/$BUILD_TYPE/AgoraRtcWrapper.framework $AGORA_FLUTTER_PROJECT_PATH/macos/AgoraRtcWrapper.framework" -cp -RP "$IRIS_PROJECT_PATH/build/mac/MAC/output/$IRIS_TYPE/$BUILD_TYPE/AgoraRtcWrapper.framework" "$AGORA_FLUTTER_PROJECT_PATH/macos/libs" -cp -RP "$IRIS_PROJECT_PATH/build/mac/MAC/output/$IRIS_TYPE/$BUILD_TYPE/$BUILD_TYPE/IrisDebugger.framework" "$AGORA_FLUTTER_PROJECT_PATH/test_shard/iris_tester/macos/" - -rm -rf $AGORA_FLUTTER_PROJECT_PATH/third_party/include -mkdir -p $AGORA_FLUTTER_PROJECT_PATH/third_party/include -cp -RP $IRIS_PROJECT_PATH/build/mac/MAC/output/$IRIS_TYPE/$BUILD_TYPE/AgoraRtcWrapper.framework/Headers/* $AGORA_FLUTTER_PROJECT_PATH/third_party/include/ - -echo "Copying Agora RTC engine frameworks" -cp -RP ${IRIS_PROJECT_PATH}/third_party/agora/$IRIS_TYPE/libs/$NATIVE_SDK_PATH_NAME/libs/* "${AGORA_FLUTTER_PROJECT_PATH}/macos/libs/" \ No newline at end of file diff --git a/scripts/build-iris-web.sh b/scripts/build-iris-web.sh deleted file mode 100644 index ec67104ff..000000000 --- a/scripts/build-iris-web.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e - -AGORA_FLUTTER_PROJECT_PATH=$(pwd) -IRIS_PROJECT_PATH=$(pwd)/web - -pushd "$AGORA_FLUTTER_PROJECT_PATH" -echo "Updating submodule web" -git submodule update --remote -popd - -pushd "$IRIS_PROJECT_PATH" -echo "Building Iris-Rtc-Web" -yarn -yarn build -echo "Copying $IRIS_PROJECT_PATH/dist/ to $AGORA_FLUTTER_PROJECT_PATH/assets/" -cp -r "$IRIS_PROJECT_PATH/dist/" \ - "$AGORA_FLUTTER_PROJECT_PATH/assets/" -popd diff --git a/scripts/build-iris-windows.sh b/scripts/build-iris-windows.sh deleted file mode 100644 index 66521e795..000000000 --- a/scripts/build-iris-windows.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e - -AGORA_FLUTTER_PROJECT_PATH=$(pwd) -WINDOWS_PATH=$AGORA_FLUTTER_PROJECT_PATH/windows - -DOWNLOAD_IRIS_URL=$1 - -cd $WINDOWS_PATH - -mkdir -p iris_windows - -curl -u "$ARTIFACTORY_USER":"$ARTIFACTORY_PWD" -o "iris_windows/iris_windows.zip" -L $DOWNLOAD_IRIS_URL - -unzip $WINDOWS_PATH/iris_windows/iris_windows.zip -d $WINDOWS_PATH/iris_windows - -files=($WINDOWS_PATH/iris_windows/*) -echo "${files[0]}" -IRIS_ZIP="${files[0]}" - -cp -r $IRIS_ZIP/x64/include third_party/iris - -cp -r $IRIS_ZIP/x64/Debug/AgoraRtcScreenSharing.exe third_party/iris/AgoraRtcScreenSharing.exe -cp -r $IRIS_ZIP/x64/Debug/AgoraRtcWrapper.dll third_party/iris/AgoraRtcWrapper.dll -cp -r $IRIS_ZIP/x64/Debug/AgoraRtcWrapper.lib third_party/iris/AgoraRtcWrapper.lib - -rm -rf $WINDOWS_PATH/iris_windows - diff --git a/scripts/build-mac.sh b/scripts/build-mac.sh deleted file mode 100644 index 2542c6373..000000000 --- a/scripts/build-mac.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -set -ex - -shell_path=$( - cd "$(dirname "$0")" || exit - pwd -) -root_path="$shell_path/../.." - -build() { - cd "$root_path" || exit - mkdir -p ./build/mac/"$1" - cd ./build/mac/"$1" || exit - archs="arm64 x86_64" - cmake \ - -G "Xcode" \ - -DCMAKE_TOOLCHAIN_FILE="$root_path"/cmake/ios.toolchain.cmake \ - -DPLATFORM="$1" \ - -DARCHS="$archs" \ - -DCMAKE_BUILD_TYPE="$2" \ - "$root_path" - cmake --build . --config "$2" - unset archs -} - -ARCH=$1 -BUILD_TYPE=$2 - -if [[ -z $ARCH ]]; then - ARCH = "ALL" -fi - -if [[ -z $BUILD_TYPE ]]; then - BUILD_TYPE = "Release" -fi - -if [[ "$ARCH" = "ALL" ]]; then - build MAC $BUILD_TYPE -else - build $ARCH $BUILD_TYPE -fi diff --git a/scripts/change_publisher.sh b/scripts/change_publisher.sh new file mode 100644 index 000000000..6ab12acdb --- /dev/null +++ b/scripts/change_publisher.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +set -e + +old_package_name='Agora-Flutter-SDK' +new_package_name='Shengwang-Flutter-SDK' + +old_name="agora_rtc_engine" +new_name="shengwang_rtc_engine" + +old_description="Flutter plugin of Agora RTC SDK, allow you to simply integrate Agora" +new_description="Flutter plugin of Shengwang RTC SDK, allow you to simply integrate Shengwang" + +old_link="www.agora.io" +new_link="www.shengwang.cn" + +MY_PATH=$(realpath $(dirname "$0")) +PROJECT_ROOT=$(realpath ${MY_PATH}/..) + +# ./ +change_file=${PROJECT_ROOT}/pubspec.yaml + +sed "s/name: ${old_name}/name: ${new_name}/g" ${change_file} >tmp && mv tmp ${change_file} +sed "s/${old_package_name}/${new_package_name}/g" ${change_file} >tmp && mv tmp ${change_file} +sed "s/${old_description}/${new_description}/g" ${change_file} >tmp && mv tmp ${change_file} +sed "s/${old_link}/${new_link}/g" ${change_file} >tmp && mv tmp ${change_file} + + +# ./example/lib/ +change_dir="${PROJECT_ROOT}/example/lib" + +find "$change_dir" -type f | while read -r file; do + sed -i.bak "s/package:${old_name}\//package:${new_name}\//g" "$file" + echo "Replaced in $file" +done + +change_file=${PROJECT_ROOT}/example/pubspec.yaml +sed "s/${old_name}:/${new_name}:/g" ${change_file} >tmp && mv tmp ${change_file} + +find "$change_dir" -name "*.bak" -type f -delete + +echo "All replacements completed successfully, and backup files have been deleted." \ No newline at end of file diff --git a/scripts/code_gen.sh b/scripts/code_gen.sh index b1d4ebdb3..3613b3a74 100644 --- a/scripts/code_gen.sh +++ b/scripts/code_gen.sh @@ -8,9 +8,14 @@ PROJECT_ROOT=$(realpath ${MY_PATH}/..) pushd ${PROJECT_ROOT} +flutter --version + flutter packages get + bash ${PROJECT_ROOT}/tool/terra/build.sh ${RTC_VERSION} + bash ${MY_PATH}/flutter-build-runner.sh + bash ${PROJECT_ROOT}/tool/testcase_gen/build.sh popd \ No newline at end of file diff --git a/scripts/download_unzip_iris_cdn_artifacts.sh b/scripts/download_unzip_iris_cdn_artifacts.sh deleted file mode 100644 index 12e880cf3..000000000 --- a/scripts/download_unzip_iris_cdn_artifacts.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -CDN_URL=$1 -PLATFORM=$2 - -MY_PATH=$(dirname "$0") - -ARTIFACTS_PATH="${MY_PATH}/../artifacts" -mkdir -p ${ARTIFACTS_PATH} - -IRIS_TESTER_PATH=${MY_PATH}/../test_shard/iris_tester - -DOWNLOAD_NAME=${CDN_URL##*/} - -DOWNLOAD_BASE_NAME=${DOWNLOAD_NAME/.zip/""} - -# if not exist, download the artifacts -if [[ ! -f "${ARTIFACTS_PATH}/${DOWNLOAD_NAME}" ]]; then - curl -L --ssl-no-revoke "${CDN_URL}" > ${ARTIFACTS_PATH}/${DOWNLOAD_NAME} -fi - -VERSION="$(cut -d'_' -f2 <<<"${DOWNLOAD_NAME}")" - -pushd ${ARTIFACTS_PATH} - unzip -o ${DOWNLOAD_NAME} -d ${DOWNLOAD_BASE_NAME} -popd - -UNZIP_PATH="${ARTIFACTS_PATH}/${DOWNLOAD_BASE_NAME}/iris_${VERSION}_DCG_${PLATFORM}" - -if [[ ${PLATFORM} == "Android" ]];then - ABIS="arm64-v8a armeabi-v7a x86_64" - for ABI in ${ABIS}; - do - if [[ ! -d "${IRIS_TESTER_PATH}/android/libs/${ABI}" ]]; then - mkdir -p "${IRIS_TESTER_PATH}/android/libs/${ABI}" - fi - - cp -RP "${UNZIP_PATH}/Debugger/ALL_ARCHITECTURE/${ABI}/libIrisDebugger.so" "${IRIS_TESTER_PATH}/android/libs/${ABI}/libIrisDebugger.so" - - ls ${IRIS_TESTER_PATH}/android/libs/${ABI}/ - done; - - -fi - -if [[ ${PLATFORM} == "MAC" ]];then - cp -RP "${UNZIP_PATH}/Debugger/MAC/IrisDebugger.framework" "${IRIS_TESTER_PATH}/macos/" -fi - -if [[ ${PLATFORM} == "iOS" ]];then - cp -RP "${UNZIP_PATH}/Debugger/ALL_ARCHITECTURE/IrisDebugger.xcframework" "${IRIS_TESTER_PATH}/ios/" -fi - -if [[ ${PLATFORM} == "Windows" ]];then - cp -RP "${UNZIP_PATH}/Debugger/x64/IrisDebugger.dll" "${IRIS_TESTER_PATH}/windows/IrisDebugger.dll" - cp -RP "${UNZIP_PATH}/Debugger/x64/IrisDebugger.lib" "${IRIS_TESTER_PATH}/windows/IrisDebugger.lib" -fi - -# pushd ${UNZIP_PATH} - - - - - -# popd \ No newline at end of file diff --git a/tool/terra/terra_config_main.yaml b/tool/terra/terra_config_main.yaml index c10d40e69..9ec3bc311 100644 --- a/tool/terra/terra_config_main.yaml +++ b/tool/terra/terra_config_main.yaml @@ -63,7 +63,6 @@ parsers: package: '@agoraio-extensions/terra_shared_configs' args: configFilePath: configs/merge_node_list.ts - ignoreDefaultConfig: true renderers: - path: renderers/event_handlers_impl_renderer.ts diff --git a/tool/testcase_gen/bin/testcase_gen.dart b/tool/testcase_gen/bin/testcase_gen.dart index 0c00bb3b8..d6624b4ab 100644 --- a/tool/testcase_gen/bin/testcase_gen.dart +++ b/tool/testcase_gen/bin/testcase_gen.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:args/args.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:testcase_gen/generator.dart'; import 'package:testcase_gen/media_recorder_observer_somke_test_generator.dart'; import 'package:testcase_gen/rtc_channel_event_handler_smoke_test_generator.dart'; diff --git a/tool/testcase_gen/build.sh b/tool/testcase_gen/build.sh index 9aa3e9df0..a03f6c1c4 100644 --- a/tool/testcase_gen/build.sh +++ b/tool/testcase_gen/build.sh @@ -9,8 +9,8 @@ pushd ${MY_PATH} dart pub get popd -dart run ${MY_PATH}/bin/testcase_gen.dart \ - --gen-fake-test --output-dir=${PROJECT_ROOT}/test_shard/fake_test_app/integration_test/generated +# dart run ${MY_PATH}/bin/testcase_gen.dart \ +# --gen-fake-test --output-dir=${PROJECT_ROOT}/test_shard/fake_test_app/integration_test/generated dart run ${MY_PATH}/bin/testcase_gen.dart \ --gen-integration-test --output-dir=${PROJECT_ROOT}/test_shard/integration_test_app/integration_test/generated \ No newline at end of file diff --git a/tool/testcase_gen/lib/core/paraphrase.dart b/tool/testcase_gen/lib/core/paraphrase.dart new file mode 100644 index 000000000..2fbdcfb9d --- /dev/null +++ b/tool/testcase_gen/lib/core/paraphrase.dart @@ -0,0 +1,759 @@ +import 'dart:io'; + +import 'package:analyzer/dart/analysis/analysis_context.dart'; +import 'package:analyzer/dart/analysis/analysis_context_collection.dart' + show AnalysisContextCollection; +import 'package:analyzer/dart/analysis/results.dart' show ParsedUnitResult; +import 'package:analyzer/dart/analysis/session.dart' show AnalysisSession; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/ast.dart' as dart_ast; +import 'package:analyzer/dart/ast/visitor.dart' as dart_ast_visitor; +import 'package:analyzer/dart/element/type.dart'; +import 'package:analyzer/error/error.dart' show AnalysisError; +import 'package:analyzer/file_system/file_system.dart'; + +class CallApiInvoke { + late String apiType; + late String params; +} + +class FunctionBody { + late CallApiInvoke callApiInvoke; +} + +class Parameter { + late DartType? dartType; + late Type type; + // List typeArguments = []; + late String name; + late bool isNamed; + late bool isOptional; + String? defaultValue; +} + +extension ParameterExt on Parameter { + bool get isPrimitiveType => + type.type == 'int' || + type.type == 'double' || + type.type == 'bool' || + type.type == 'String' || + type.type == 'List' || + type.type == 'Map' || + type.type == 'Set' || + type.type == 'Uint8List'; + + String primitiveDefualtValue() { + switch (type.type) { + case 'int': + return '10'; + case 'double': + return '10.0'; + case 'String': + return '"hello"'; + case 'bool': + return 'true'; + case 'List': + return '[]'; + case 'Map': + return '{}'; + case 'Uint8List': + return 'Uint8List.fromList([1, 2, 3, 4, 5])'; + case 'Set': + return '{}'; + + default: + throw Exception('not support type $type'); + } + } +} + +class Type { + late String type; + List typeArguments = []; + // The parameters associated with the function type. + List parameters = []; +} + +extension TypeExt on Type { + bool get isPrimitiveType => + type == 'int' || + type == 'double' || + type == 'bool' || + type == 'String' || + type == 'List' || + type == 'Map' || + type == 'Set'; + + String primitiveDefualtValue() { + switch (type) { + case 'int': + return '10'; + case 'double': + return '10.0'; + case 'String': + return '"hello"'; + case 'bool': + return 'true'; + case 'List': + return '[]'; + case 'Map': + return '{}'; + case 'Uint8List': + return 'Uint8List.fromList([])'; + case 'Set': + return '{}'; + default: + throw Exception('not support type $type'); + } + } + + bool isVoid() { + return type == 'void'; + } +} + +class SimpleLiteral { + late String type; + late String value; +} + +class SimpleAnnotation { + late String name; + List arguments = []; +} + +class SimpleComment { + List commentLines = []; + late int offset; + late int end; +} + +class BaseNode { + late SimpleComment comment; + late String source; + late Uri uri; +} + +class Method extends BaseNode { + late String name; + late FunctionBody body; + List parameters = []; + late Type returnType; +} + +class Field extends BaseNode { + late Type type; + late String name; +} + +class Constructor extends BaseNode { + late String name; + List parameters = []; + late bool isFactory; + late bool isConst; +} + +class Clazz extends BaseNode { + late String name; + List constructors = []; + List methods = []; + List fields = []; +} + +class Extensionz extends BaseNode { + late String name; + late String extendedType; + List methods = []; + List fields = []; +} + +class EnumConstant extends BaseNode { + late String name; + List annotations = []; +} + +class Enumz extends BaseNode { + late String name; + List enumConstants = []; +} + +class ParseResult { + late List classes; + late List enums; + late List extensions; + + // TODO(littlegnal): Optimize this later. + // late Map> classFieldsMap; + // late Map fieldsTypeMap; + late Map> genericTypeAliasParametersMap; +} + +extension ParseResultExt on ParseResult { + bool hasEnum(String type) { + return enums.any((e) => e.name == type); + } + + List getEnum(String type, {String? package}) { + List foundEnums = []; + for (final enumz in enums) { + if (package == null) { + if (enumz.name == type) { + foundEnums.add(enumz); + } + } else { + if (enumz.name == type && + enumz.uri.pathSegments.last.replaceAll('.dart', '') == package) { + foundEnums.add(enumz); + } + } + } + + return foundEnums; + } + + bool hasClass(String type) { + return classes.any((e) => e.name == type); + } + + List getClazz(String type, {String? package}) { + List foundClasses = []; + for (final clazz in classes) { + if (package == null) { + if (clazz.name == type) { + foundClasses.add(clazz); + } + } else { + if (clazz.name == type && + clazz.uri.pathSegments.last.replaceAll('.dart', '') == package) { + foundClasses.add(clazz); + } + } + } + + return foundClasses; + } + + bool hasExtension(String type) { + return extensions.any((e) => e.name == type); + } + + List getExtension(String type, {String? package}) { + List foundExtensions = []; + for (final extension in extensions) { + if (package == null) { + if (extension.name == type) { + foundExtensions.add(extension); + } + } else { + if (extension.name == type && + extension.uri.pathSegments.last.replaceAll('.dart', '') == + package) { + foundExtensions.add(extension); + } + } + } + + return foundExtensions; + } +} + +abstract class DefaultVisitor + extends dart_ast_visitor.RecursiveAstVisitor { + /// Called before visiting any node. + void preVisit(Uri uri) {} + + /// Called after visiting nodes completed. + void postVisit(Uri uri) {} +} + +class DefaultVisitorImpl extends DefaultVisitor { + final classFieldsMap = >{}; + final fieldsTypeMap = {}; + final genericTypeAliasParametersMap = >{}; + + final classMap = {}; + final enumMap = {}; + final extensionMap = {}; + + Uri? _currentVisitUri; + + @override + void preVisit(Uri uri) { + _currentVisitUri = uri; + } + + @override + void postVisit(Uri uri) { + _currentVisitUri = null; + } + + @override + Object? visitFieldDeclaration(dart_ast.FieldDeclaration node) { + final clazz = _getClazz(node); + if (clazz == null) return null; + + final dart_ast.TypeAnnotation? type = node.fields.type; + final fieldName = node.fields.variables[0].name.name; + if (type is dart_ast.NamedType) { + Field field = Field() + ..name = fieldName + ..comment = _generateComment(node) + ..source = node.toString() + ..uri = _currentVisitUri!; + + Type t = Type()..type = type.name.name; + field.type = t; + + clazz.fields.add(field); + } else if (type is dart_ast.GenericFunctionType) { + Field field = Field() + ..name = fieldName + ..comment = _generateComment(node) + ..source = node.toString() + ..uri = _currentVisitUri!; + + Type t = Type()..type = type.functionKeyword.stringValue!; + t.parameters = _getParameter(null, type.parameters); + field.type = t; + + clazz.fields.add(field); + } + + return null; + } + + @override + Object? visitConstructorDeclaration(ConstructorDeclaration node) { + final clazz = _getClazz(node); + if (clazz == null) return null; + + Constructor constructor = Constructor() + ..name = node.name?.name ?? '' + ..parameters = _getParameter(node.parent, node.parameters) + ..isFactory = node.factoryKeyword != null + ..isConst = node.constKeyword != null + ..comment = _generateComment(node) + ..source = node.toSource(); + + clazz.constructors.add(constructor); + + return null; + } + + @override + Object? visitEnumDeclaration(EnumDeclaration node) { + final enumz = enumMap.putIfAbsent(node.name.name, () => Enumz()); + enumz.name = node.name.name; + enumz.comment = _generateComment(node); + enumz.uri = _currentVisitUri!; + + for (final constant in node.constants) { + EnumConstant enumConstant = EnumConstant() + ..name = '${node.name.name}.${constant.name.name}' + ..comment = _generateComment(constant) + ..source = constant.toSource(); + enumz.enumConstants.add(enumConstant); + + for (final meta in constant.metadata) { + SimpleAnnotation simpleAnnotation = SimpleAnnotation() + ..name = meta.name.name; + enumConstant.annotations.add(simpleAnnotation); + + for (final a in meta.arguments?.arguments ?? []) { + SimpleLiteral simpleLiteral = SimpleLiteral(); + simpleAnnotation.arguments.add(simpleLiteral); + + late String type; + late String value; + + if (a is IntegerLiteral) { + type = 'int'; + value = a.value.toString(); + } else if (a is PrefixExpression) { + if (a.operand is IntegerLiteral) { + final operand = a.operand as IntegerLiteral; + type = 'int'; + value = '${a.operator.value()}${operand.value.toString()}'; + } + } else if (a is BinaryExpression) { + type = 'int'; + value = a.toSource(); + } else if (a is SimpleStringLiteral) { + type = 'String'; + value = a.toSource(); + } else if (a is ParenthesizedExpression) { + if (a.expression.unParenthesized is BinaryExpression || + a.expression.unParenthesized is IntegerLiteral) { + type = 'int'; + value = a.expression.unParenthesized.toSource(); + } + } else { + stderr.writeln( + 'Not handled enum: ${enumz.name}, annotation type: ${a.runtimeType}'); + } + stderr.writeln( + ' handled enum: ${enumz.name}, annotation type: ${a.runtimeType}'); + simpleLiteral.type = type; + simpleLiteral.value = value; + } + } + } + + return null; + } + + Clazz? _getClazz(AstNode node) { + final classNode = node.parent; + if (_currentVisitUri == null || + classNode == null || + classNode is! dart_ast.ClassDeclaration) { + return null; + } + + Clazz clazz = classMap.putIfAbsent( + '${_currentVisitUri.toString()}#${classNode.name.name}', + () => Clazz() + ..name = classNode.name.name + ..comment = _generateComment(node as AnnotatedNode) + ..uri = _currentVisitUri!, + ); + + return clazz; + } + + List _getParameter( + AstNode? root, FormalParameterList? formalParameterList) { + if (formalParameterList == null) return []; + List parameters = []; + for (final p in formalParameterList.parameters) { + Parameter parameter = Parameter(); + Type type = Type(); + parameter.type = type; + + if (p is SimpleFormalParameter) { + parameter.name = p.identifier?.name ?? ''; + DartType? dartType = p.type?.type; + + parameter.dartType = dartType; + + final namedType = p.type as NamedType; + for (final ta in namedType.typeArguments?.arguments ?? []) { + type.typeArguments.add(ta.name.name); + } + + type.type = namedType.name.name; + parameter.isNamed = p.isNamed; + parameter.isOptional = p.isOptional; + } else if (p is DefaultFormalParameter) { + parameter.name = p.identifier?.name ?? ''; + parameter.defaultValue = p.defaultValue?.toSource(); + + DartType? dartType; + String? typeName; + List typeArguments = []; + + if (p.parameter is SimpleFormalParameter) { + final SimpleFormalParameter simpleFormalParameter = + p.parameter as SimpleFormalParameter; + dartType = simpleFormalParameter.type?.type; + + if (simpleFormalParameter.type is NamedType) { + final namedType = simpleFormalParameter.type as NamedType; + for (final ta in namedType.typeArguments?.arguments ?? []) { + typeArguments.add(ta.name.name); + } + + typeName = (simpleFormalParameter.type as NamedType).name.name; + } else if (simpleFormalParameter.type is GenericFunctionType) { + typeName = (simpleFormalParameter.type as GenericFunctionType) + .functionKeyword + .stringValue; + type.parameters = _getParameter(null, + (simpleFormalParameter.type as GenericFunctionType).parameters); + } + } else if (p.parameter is FieldFormalParameter) { + final FieldFormalParameter fieldFormalParameter = + p.parameter as FieldFormalParameter; + + dartType = fieldFormalParameter.type?.type; + + if (fieldFormalParameter.thisKeyword.stringValue == 'this') { + if (root != null && root is ClassDeclaration) { + for (final classMember in root.members) { + if (classMember is FieldDeclaration) { + final dart_ast.TypeAnnotation? fieldType = + classMember.fields.type; + final fieldName = classMember.fields.variables[0].name.name; + if (fieldType is dart_ast.NamedType) { + if (fieldName == fieldFormalParameter.identifier.name) { + typeName = fieldType.name.name; + for (final ta + in fieldType.typeArguments?.arguments ?? []) { + typeArguments.add(ta.name.name); + } + break; + } + } else if (fieldType is dart_ast.GenericFunctionType) { + if (fieldName == fieldFormalParameter.identifier.name) { + typeName = fieldType.functionKeyword.stringValue; + type.parameters = + _getParameter(null, fieldType.parameters); + + break; + } + } + } + } + } + } else if (fieldFormalParameter is dart_ast.GenericFunctionType) { + typeName = (fieldFormalParameter as GenericFunctionType) + .functionKeyword + .stringValue; + type.parameters = + _getParameter(null, fieldFormalParameter.parameters); + + break; + } + } + + parameter.dartType = dartType; + type.type = typeName!; + type.typeArguments.addAll(typeArguments); + parameter.isNamed = p.isNamed; + parameter.isOptional = p.isOptional; + } else if (p is FieldFormalParameter) { + String typeName = ''; + List typeArguments = []; + if (root != null && root is ClassDeclaration) { + for (final classMember in root.members) { + if (classMember is FieldDeclaration) { + final dart_ast.TypeAnnotation? fieldType = + classMember.fields.type; + final fieldName = classMember.fields.variables[0].name.name; + if (fieldType is dart_ast.NamedType) { + if (fieldName == p.identifier.name) { + typeName = fieldType.name.name; + for (final ta in fieldType.typeArguments?.arguments ?? []) { + typeArguments.add(ta.name.name); + } + break; + } + } else if (fieldType is dart_ast.GenericFunctionType) { + if (fieldName == p.identifier.name) { + typeName = fieldType.functionKeyword.stringValue ?? ''; + type.parameters = _getParameter(root, fieldType.parameters); + + break; + } + } + } + } + } + + parameter.name = p.identifier.name; + parameter.dartType = p.type?.type; + type.type = typeName; + type.typeArguments.addAll(typeArguments); + parameter.isNamed = p.isNamed; + parameter.isOptional = p.isOptional; + } + + parameters.add(parameter); + } + + return parameters; + } + + CallApiInvoke? _getCallApiInvoke(Expression expression) { + if (expression is! MethodInvocation) return null; + + if (expression.target != null) { + return _getCallApiInvoke(expression.target!); + } + + CallApiInvoke callApiInvoke = CallApiInvoke(); + for (final argument in expression.argumentList.arguments) { + if (argument is SimpleStringLiteral) { + } else if (argument is FunctionExpression) { + } else if (argument is SetOrMapLiteral) { + for (final element in argument.elements) { + if (element is MapLiteralEntry) { + final key = (element.key as SimpleStringLiteral).value; + if (key == 'apiType') { + callApiInvoke.apiType = element.value.toSource(); + } else if (key == 'params') { + callApiInvoke.params = element.value.toSource(); + } + } + } + } + } + + return callApiInvoke; + } + + SimpleComment _generateComment(AnnotatedNode node) { + SimpleComment simpleComment = SimpleComment() + ..offset = node.documentationComment?.offset ?? 0 + ..end = node.documentationComment?.end ?? 0; + + for (final token in node.documentationComment?.tokens ?? []) { + simpleComment.commentLines.add(token.stringValue ?? ''); + } + return simpleComment; + } + + @override + Object? visitMethodDeclaration(MethodDeclaration node) { + final clazz = _getClazz(node); + if (clazz == null) return null; + + clazz.methods.add(_createMethod(node)); + + return null; + } + + Method _createMethod(MethodDeclaration node) { + Method method = Method() + ..name = node.name.name + ..source = node.toString() + ..uri = _currentVisitUri!; + + method.comment = _generateComment(node); + + if (node.parameters != null) { + method.parameters.addAll(_getParameter(node.parent, node.parameters)); + } + + if (node.returnType != null && node.returnType is NamedType) { + final returnType = node.returnType as NamedType; + method.returnType = Type() + ..type = returnType.name.name + ..typeArguments = returnType.typeArguments?.arguments + .map((ta) => (ta as NamedType).name.name) + .toList() ?? + []; + } + + if (node.body is BlockFunctionBody) { + final body = node.body as BlockFunctionBody; + + FunctionBody fb = FunctionBody(); + method.body = fb; + CallApiInvoke callApiInvoke = CallApiInvoke(); + method.body.callApiInvoke = callApiInvoke; + + for (final statement in body.block.statements) { + if (statement is ReturnStatement) { + final returns = statement; + + if (returns.expression != null) { + CallApiInvoke? callApiInvoke = + _getCallApiInvoke(returns.expression!); + if (callApiInvoke != null) { + method.body.callApiInvoke = callApiInvoke; + } + } + } + } + } + + return method; + } + + @override + Object? visitGenericTypeAlias(dart_ast.GenericTypeAlias node) { + final parametersList = node.functionType?.parameters.parameters + .map((e) { + if (e is SimpleFormalParameter) { + return '${e.type} ${e.identifier?.name}'; + } + return ''; + }) + .where((e) => e.isNotEmpty) + .toList() ?? + []; + + genericTypeAliasParametersMap[node.name.name] = parametersList; + + return null; + } + + @override + Object? visitExtensionDeclaration(dart_ast.ExtensionDeclaration node) { + extensionMap.putIfAbsent(node.name?.name ?? '', () { + Extensionz extensionz = Extensionz() + ..name = node.name?.name ?? '' + ..uri = _currentVisitUri!; + if (node.extendedType is dart_ast.NamedType) { + extensionz.extendedType = + (node.extendedType as dart_ast.NamedType).name.name; + } + for (final member in node.members) { + if (member is MethodDeclaration) { + extensionz.methods.add(_createMethod(member)); + } + } + + return extensionz; + }); + + return null; + } +} + +class Paraphrase { + const Paraphrase({ + required this.includedPaths, + this.excludedPaths, + this.resourceProvider, + }); + + final List includedPaths; + + final List? excludedPaths; + final ResourceProvider? resourceProvider; + + ParseResult visit() { + final DefaultVisitorImpl rootBuilder = DefaultVisitorImpl(); + + visitWith(visitor: rootBuilder); + + final parseResult = ParseResult() + ..classes = rootBuilder.classMap.values.toList() + ..enums = rootBuilder.enumMap.values.toList() + ..extensions = rootBuilder.extensionMap.values.toList() + ..genericTypeAliasParametersMap = + rootBuilder.genericTypeAliasParametersMap; + + return parseResult; + } + + void visitWith({ + required DefaultVisitor visitor, + }) { + final AnalysisContextCollection collection = AnalysisContextCollection( + includedPaths: includedPaths, + excludedPaths: excludedPaths, + resourceProvider: resourceProvider, + ); + + for (final AnalysisContext context in collection.contexts) { + for (final String path in context.contextRoot.analyzedFiles()) { + final AnalysisSession session = context.currentSession; + final ParsedUnitResult result = + session.getParsedUnit(path) as ParsedUnitResult; + if (result.errors.isEmpty) { + final dart_ast.CompilationUnit unit = result.unit; + visitor.preVisit(result.uri); + unit.accept(visitor); + visitor.postVisit(result.uri); + } else { + for (final AnalysisError error in result.errors) { + stderr.writeln(error.toString()); + } + } + } + } + } +} diff --git a/tool/testcase_gen/lib/default_generator.dart b/tool/testcase_gen/lib/default_generator.dart index 329980908..e12ee18ff 100644 --- a/tool/testcase_gen/lib/default_generator.dart +++ b/tool/testcase_gen/lib/default_generator.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:testcase_gen/generator.dart'; import 'package:meta/meta.dart'; diff --git a/tool/testcase_gen/lib/generator.dart b/tool/testcase_gen/lib/generator.dart index 201e8e0e7..b0b819655 100644 --- a/tool/testcase_gen/lib/generator.dart +++ b/tool/testcase_gen/lib/generator.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; enum GeneratorConfigPlatform { android, diff --git a/tool/testcase_gen/lib/media_recorder_observer_somke_test_generator.dart b/tool/testcase_gen/lib/media_recorder_observer_somke_test_generator.dart index d0487b603..c9c36e9ea 100644 --- a/tool/testcase_gen/lib/media_recorder_observer_somke_test_generator.dart +++ b/tool/testcase_gen/lib/media_recorder_observer_somke_test_generator.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:testcase_gen/default_generator.dart'; import 'package:testcase_gen/generator.dart'; diff --git a/tool/testcase_gen/lib/rtc_channel_event_handler_smoke_test_generator.dart b/tool/testcase_gen/lib/rtc_channel_event_handler_smoke_test_generator.dart index f4fc579b6..fe57c14a0 100644 --- a/tool/testcase_gen/lib/rtc_channel_event_handler_smoke_test_generator.dart +++ b/tool/testcase_gen/lib/rtc_channel_event_handler_smoke_test_generator.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:path/path.dart' as path; import 'package:testcase_gen/generator.dart'; diff --git a/tool/testcase_gen/lib/rtc_device_manager_smoke_test_generator.dart b/tool/testcase_gen/lib/rtc_device_manager_smoke_test_generator.dart index 01001b1ff..bc783d0fd 100644 --- a/tool/testcase_gen/lib/rtc_device_manager_smoke_test_generator.dart +++ b/tool/testcase_gen/lib/rtc_device_manager_smoke_test_generator.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:testcase_gen/default_generator.dart'; import 'package:testcase_gen/generator.dart'; import 'package:path/path.dart' as path; diff --git a/tool/testcase_gen/lib/rtc_engine_event_handler_somke_test_generator.dart b/tool/testcase_gen/lib/rtc_engine_event_handler_somke_test_generator.dart index 845a2208a..f51cbaae9 100644 --- a/tool/testcase_gen/lib/rtc_engine_event_handler_somke_test_generator.dart +++ b/tool/testcase_gen/lib/rtc_engine_event_handler_somke_test_generator.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:path/path.dart' as path; import 'package:testcase_gen/generator.dart'; diff --git a/tool/testcase_gen/lib/rtc_engine_sub_process_smoke_test_generator.dart b/tool/testcase_gen/lib/rtc_engine_sub_process_smoke_test_generator.dart index 0d8c7d209..1580d0cf6 100644 --- a/tool/testcase_gen/lib/rtc_engine_sub_process_smoke_test_generator.dart +++ b/tool/testcase_gen/lib/rtc_engine_sub_process_smoke_test_generator.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'package:path/path.dart' as path; import 'package:testcase_gen/default_generator.dart'; import 'package:testcase_gen/generator.dart'; diff --git a/tool/testcase_gen/lib/templated_generator.dart b/tool/testcase_gen/lib/templated_generator.dart index 639991bd5..c6f8d982b 100644 --- a/tool/testcase_gen/lib/templated_generator.dart +++ b/tool/testcase_gen/lib/templated_generator.dart @@ -1,5 +1,5 @@ import 'package:dart_style/dart_style.dart'; -import 'package:paraphrase/paraphrase.dart'; +import 'package:testcase_gen/core/paraphrase.dart'; import 'dart:io'; import 'package:testcase_gen/default_generator.dart'; diff --git a/tool/testcase_gen/pubspec.yaml b/tool/testcase_gen/pubspec.yaml index 2ba71a855..a78a6e2f2 100644 --- a/tool/testcase_gen/pubspec.yaml +++ b/tool/testcase_gen/pubspec.yaml @@ -9,14 +9,11 @@ environment: publish_to: none dependencies: - paraphrase: - git: - url: https://github.com/littleGnAl/paraphrase.git - ref: 0.1.0 - args: ^2.3.1 - dart_style: ^2.2.1 dev_dependencies: lints: ^1.0.0 + # lock the version of analyzer to avoid non-consistent generated code and errors like: + # lib/core/paraphrase.dart:352:53: Error: The getter 'name' isn't defined for the class 'Token'. + analyzer: 4.7.0