diff --git a/.github/workflows/test-build-docker-image-fat.yml b/.github/workflows/test-build-docker-image-fat.yml new file mode 100644 index 0000000000..b5f9a4a875 --- /dev/null +++ b/.github/workflows/test-build-docker-image-fat.yml @@ -0,0 +1,1337 @@ +name: Test fat, build and push Docker Image + +on: + # This line enables manual triggering of this workflow. + workflow_dispatch: + +jobs: + buildClient: + # If the build has been triggered manually via workflow_dispatch or via a push to protected branches + # then we don't check for the PR approved state + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository) + runs-on: ubuntu-latest + defaults: + run: + working-directory: app/client + shell: bash + + steps: + # Checkout the code + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # Checkout the code + - name: Checkout the merged commit from PR and base branch + if: github.event_name == 'pull_request_review' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: refs/pull/${{ github.event.pull_request.number }}/merge + + - name: Checkout the head commit of the branch + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Figure out the PR number + run: echo ${{ github.event.pull_request.number }} + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(timestamp +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: actions/cache@v2 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}- + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + #- uses: actions/checkout@v2 + # if: steps.run_result.outputs.run_result != 'success' + + # Incase of prior failure run the job + - if: steps.run_result.outputs.run_result != 'success' + run: echo "I'm alive!" && exit 0 + + # Set status = success + - run: echo "::set-output name=run_result::success" > ~/run_result + + - name: Use Node.js 14.15.4 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v1 + with: + node-version: "14.15.4" + + - name: Get yarn cache directory path + if: steps.run_result.outputs.run_result != 'success' + id: yarn-dep-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + # Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again + - name: Cache npm dependencies + if: steps.run_result.outputs.run_result != 'success' + id: yarn-dep-cache + uses: actions/cache@v2 + env: + cache-name: cache-yarn-dependencies + with: + path: | + ${{ steps.yarn-dep-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-dep-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn-dep- + + # Install all the dependencies + - name: Install dependencies + if: steps.run_result.outputs.run_result != 'success' + run: yarn install + + - name: Set the build environment based on the branch + if: steps.run_result.outputs.run_result != 'success' + id: vars + run: | + echo "::set-output name=REACT_APP_ENVIRONMENT::DEVELOPMENT" + if [[ "${{github.ref}}" == "refs/heads/master" ]]; then + echo "::set-output name=REACT_APP_ENVIRONMENT::PRODUCTION" + fi + if [[ "${{github.ref}}" == "refs/heads/release" ]]; then + echo "::set-output name=REACT_APP_ENVIRONMENT::STAGING" + fi + # Since this is an unreleased build, we set the version to incremented version number with + # a `-SNAPSHOT` suffix. + latest_released_version="$(git tag --list 'v*' --sort=-version:refname | head -1)" + echo "latest_released_version = $latest_released_version" + next_version="$(echo "$latest_released_version" | awk -F. -v OFS=. '{ $NF++; print }')" + echo "next_version = $next_version" + echo ::set-output name=version::$next_version-SNAPSHOT + + # We burn React environment & the Segment analytics key into the build itself. + # This is to ensure that we don't need to configure it in each installation + - name: Create the bundle + if: steps.run_result.outputs.run_result != 'success' + run: | + if [[ $GITHUB_REF == "refs/heads/release" ]]; then + REACT_APP_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }} + else + REACT_APP_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} + fi + REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} \ + REACT_APP_FUSIONCHARTS_LICENSE_KEY=${{ secrets.APPSMITH_FUSIONCHARTS_LICENSE_KEY }} \ + REACT_APP_SEGMENT_CE_KEY="$REACT_APP_SEGMENT_CE_KEY" \ + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} \ + REACT_APP_VERSION_ID=${{ steps.vars.outputs.version }} \ + REACT_APP_VERSION_RELEASE_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \ + REACT_APP_GOOGLE_ANALYTICS_ID=${{ secrets.GOOGLE_TAG_MANAGER_ID }} \ + REACT_APP_INTERCOM_APP_ID=${{ secrets.APPSMITH_INTERCOM_ID }} \ + yarn build + ls -l build + + # Restore the previous built bundle if present. If not push the newly built into the cache + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/client/build/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # Upload the build artifact so that it can be used by the test & deploy job in the workflow + - name: Upload react build bundle + uses: actions/upload-artifact@v2 + with: + name: client-build + path: app/client/build/ + + # Set status = success + - run: echo "::set-output name=run_result::success" > ~/run_result + + buildServer: + defaults: + run: + working-directory: app/server + runs-on: ubuntu-latest + # Only run this workflow for internally triggered events + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository) + + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + mongo: + image: mongo + ports: + - 27017:27017 + + steps: + # Checkout the code + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(timestamp +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: actions/cache@v2 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}- + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + # Incase of prior failure run the job + - if: steps.run_result.outputs.run_result != 'success' + run: echo "I'm alive!" && exit 0 + + # Setup Java + - name: Set up JDK 1.11 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-java@v1 + with: + java-version: "11.0.10" + + # Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again + - name: Cache maven dependencies + if: steps.run_result.outputs.run_result != 'success' + uses: actions/cache@v2 + env: + cache-name: cache-maven-dependencies + with: + # maven dependencies are stored in `~/.m2` on Linux/macOS + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + # Here, the GITHUB_REF is of type /refs/head/. We extract branch_name from this by removing the + # first 11 characters. This can be used to build images for several branches + # Since this is an unreleased build, we get the latest released version number, increment the minor number in it, + # append a `-SNAPSHOT` at it's end to prepare the snapshot version number. This is used as the project's version. + - name: Get the version to tag the Docker image + if: steps.run_result.outputs.run_result != 'success' + id: vars + run: | + # Since this is an unreleased build, we set the version to incremented version number with a + # `-SNAPSHOT` suffix. + latest_released_version="$(git tag --list 'v*' --sort=-version:refname | head -1)" + echo "latest_released_version = $latest_released_version" + next_version="$(echo "$latest_released_version" | awk -F. -v OFS=. '{ $NF++; print }')" + echo "next_version = $next_version" + echo ::set-output name=version::$next_version-SNAPSHOT + echo ::set-output name=tag::$(echo ${GITHUB_REF:11}) + + - name: Test and Build package + if: steps.run_result.outputs.run_result != 'success' + env: + APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools" + APPSMITH_REDIS_URL: "redis://127.0.0.1:6379" + APPSMITH_ENCRYPTION_PASSWORD: "password" + APPSMITH_ENCRYPTION_SALT: "salt" + APPSMITH_IS_SELF_HOSTED: false + APPSMITH_GIT_ROOT: "./container-volumes/git-storage" + working-directory: app/server + run: | + mvn --batch-mode versions:set \ + -DnewVersion=${{ steps.vars.outputs.version }} \ + -DgenerateBackupPoms=false \ + -DprocessAllModules=true + ./build.sh -DskipTests + ls -l dist + + # Restore the previous built bundle if present. If not push the newly built into the cache + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/server/dist/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # Upload the build artifact so that it can be used by the test & deploy job in the workflow + - name: Upload server build bundle + uses: actions/upload-artifact@v2 + with: + name: server-build + path: app/server/dist/ + + - run: echo "::set-output name=run_result::success" > ~/run_result + + buildRts: + defaults: + run: + working-directory: app/rts + runs-on: ubuntu-latest + # Only run this workflow for internally triggered events + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository) + + steps: + # Checkout the code + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(timestamp +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: actions/cache@v2 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}- + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + # Incase of prior failure run the job + - if: steps.run_result.outputs.run_result != 'success' + run: echo "I'm alive!" && exit 0 + + - name: Use Node.js 14.15.4 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v1 + with: + node-version: "14.15.4" + + # Here, the GITHUB_REF is of type /refs/head/. We extract branch_name from this by removing the + # first 11 characters. This can be used to build images for several branches + # Since this is an unreleased build, we get the latest released version number, increment the minor number in it, + # append a `-SNAPSHOT` at it's end to prepare the snapshot version number. This is used as the project's version. + - name: Get the version to tag the Docker image + if: steps.run_result.outputs.run_result != 'success' + id: vars + run: | + # Since this is an unreleased build, we set the version to incremented version number with a + # `-SNAPSHOT` suffix. + latest_released_version="$(git tag --list 'v*' --sort=-version:refname | head -1)" + echo "latest_released_version = $latest_released_version" + next_version="$(echo "$latest_released_version" | awk -F. -v OFS=. '{ $NF++; print }')" + echo "next_version = $next_version" + echo ::set-output name=version::$next_version-SNAPSHOT + echo ::set-output name=tag::$(echo ${GITHUB_REF:11}) + + - name: Build + if: steps.run_result.outputs.run_result != 'success' + run: | + echo 'export const VERSION = "${{ steps.vars.outputs.version }}"' > src/version.js + ./build.sh + ls -l dist + + # Restore the previous built bundle if present. If not push the newly built into the cache + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/rts/dist/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # Restore the previous built bundle if present. If not push the newly built into the cache + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/rts/node_modules/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # Upload the build artifact so that it can be used by the test & deploy job in the workflow + - name: Upload server build bundle + uses: actions/upload-artifact@v2 + with: + name: rts-build + path: app/rts/dist/ + + - name: Upload RTS dependencies bundle + uses: actions/upload-artifact@v2 + with: + name: rts-build-deps + path: app/rts/node_modules/ + + fat-conatiner-test: + needs: [buildClient, buildServer, buildRts] + # Only run if the build step is successful + # If the build has been triggered manually via workflow_dispatch or via a push to protected branches + # then we don't check for the PR approved state + if: | + success() && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository)) + runs-on: ubuntu-latest + defaults: + run: + shell: bash + strategy: + fail-fast: false + + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + mongo: + image: mongo + ports: + - 27017:27017 + + steps: + # Checkout the code + - name: Checkout the merged commit from PR and base branch + if: github.event_name == 'pull_request_review' + uses: actions/checkout@v2 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + + - name: Checkout the head commit of the branch + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: actions/checkout@v2 + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(timestamp +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: martijnhols/actions-cache@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + # In case this is second attempt try restoring failed tests + - name: Restore the previous failed combine result + if: steps.run_result.outputs.run_result == 'failedtest' + uses: martijnhols/actions-cache/restore@v3 + with: + path: | + ~/combined_failed_spec + key: ${{ github.run_id }}-"ui-test-result"-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # failed_spec_env will contain list of all failed specs + # We are using evnironment variable instead of regular to support multiline + - name: Get failed_spec + if: steps.run_result.outputs.run_result == 'failedtest' + run: | + failed_spec_env=$(cat ~/combined_failed_spec) + echo "failed_spec_env<> $GITHUB_ENV + echo "$failed_spec_env" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + run: echo "Starting full run" && exit 0 + + - if: steps.run_result.outputs.run_result == 'failedtest' + run: echo "Rerunning failed tests" && exit 0 + + - name: cat run_result + run: echo ${{ steps.run_result.outputs.run_result }} + + # Setup Java + - name: Set up JDK 1.11 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-java@v1 + with: + java-version: "11.0.10" + + - name: Download the react build artifact + uses: actions/download-artifact@v2 + with: + name: client-build + path: app/client/build + + - name: Download the server build artifact + uses: actions/download-artifact@v2 + with: + name: server-build + path: app/server/dist + + - name: Download the rts build artifact + uses: actions/download-artifact@v2 + with: + name: rts-build + path: app/rts/dist + + - name: Download the rts build artifact + uses: actions/download-artifact@v2 + with: + name: rts-build-deps + path: app/rts/node_modules/ + + - name: Build docker image + if: success() && github.ref == 'refs/heads/release' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: "." + run: | + docker build -t fatcontainer . + + - name: Load docker image + if: success() && github.ref == 'refs/heads/release' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: "." + run: | + mkdir fatcontainerlocal + cd fatcontainerlocal + docker run -d --name appsmith -p 80:80 -p 9001:9001 \ + -v "$PWD/stacks:/appsmith-stacks" fatcontainer + + - name: Use Node.js 14.15.4 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v1 + with: + node-version: "14.15.4" + + # Install all the dependencies + - name: Install dependencies + if: steps.run_result.outputs.run_result != 'success' + run: | + cd app/client + yarn install + + - name: Setting up the cypress tests + if: steps.run_result.outputs.run_result != 'success' + shell: bash + env: + APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} + APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} + CYPRESS_URL: ${{ secrets.CYPRESS_URL }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + POSTGRES_PASSWORD: postgres + run: | + cd app/client + chmod a+x ./cypress/setup-test-fat.sh + ./cypress/setup-test-fat.sh + + - name: Run the cypress test + if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + uses: cypress-io/github-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} + with: + browser: chrome + headless: true + record: true + install: false + parallel: true + group: "Electrons on Github Action Fat Container" + spec: "cypress/integration/Smoke_TestSuite_Fat/**/*" + working-directory: app/client + # tag will be either "push" or "pull_request" + tag: ${{ github.event_name }} + env: "NODE_ENV=development" + + # Incase of second attemtp only run failed specs + - name: Run the cypress test with failed tests + if: steps.run_result.outputs.run_result == 'failedtest' + uses: cypress-io/github-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} + with: + browser: chrome + headless: true + record: true + install: false + parallel: true + group: "Electrons on Github Action" + spec: ${{ env.failed_spec_env }} + working-directory: app/client + # tag will be either "push" or "pull_request" + tag: ${{ github.event_name }} + env: "NODE_ENV=development" + + # Set status = failedtest + - name: Set fail if there are test failures + if: failure() + run: echo "::set-output name=run_result::failedtest" > ~/run_result + + # Create a directory ~/failed_spec and add a dummy file + # This will ensure upload and download steps are successfull + - name: Create direcotrs for failed tests + if: always() + run: | + mkdir -p ~/failed_spec + echo "empty" >> ~/failed_spec/dummy-${{ matrix.job }} + + # add list failed tests to a file + - name: Incase of test failures copy them to a file + if: failure() + run: | + cd ${{ github.workspace }}/app/client/cypress/ + find screenshots -type d|grep -i spec |sed 's/screenshots/cypress\/integration/g' > ~/failed_spec/failed_spec-${{ matrix.job }} + + # Upload failed test list using common path for all matrix job + - name: Upload failed test list artifact + if: always() + uses: actions/upload-artifact@v2 + with: + name: failed-spec + path: ~/failed_spec + + # Force store previous run result to cache + - name: Store the previous run result + if: failure() + uses: martijnhols/actions-cache/save@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Force store previous failed test list to cache + - name: Store the previous failed test result + if: failure() + uses: martijnhols/actions-cache/save@v3 + with: + path: | + ~/failed_spec + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Upload the screenshots as artifacts if there's a failure + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: cypress-screenshots-${{ matrix.job }} + path: app/client/cypress/screenshots/ + + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/client/cypress/snapshots/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Upload the snapshots as artifacts for layout validation + - uses: actions/upload-artifact@v1 + with: + name: cypress-snapshots-visualRegression + path: app/client/cypress/snapshots/ + + # Upload the log artifact so that it can be used by the test & deploy job in the workflow + - name: Upload server logs bundle on failure + uses: actions/upload-artifact@v2 + if: failure() + with: + name: server-logs-${{ matrix.job }} + path: app/server/server-logs.log + + # Set status = success + - run: echo "::set-output name=run_result::success" > ~/run_result + + ui-test: + needs: [buildClient, buildServer, buildRts] + # Only run if the build step is successful + # If the build has been triggered manually via workflow_dispatch or via a push to protected branches + # then we don't check for the PR approved state + if: | + success() && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository)) + runs-on: ubuntu-latest + defaults: + run: + working-directory: app/client + shell: bash + strategy: + fail-fast: false + matrix: + job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] + + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + mongo: + image: mongo + ports: + - 27017:27017 + + steps: + # Checkout the code + - name: Checkout the merged commit from PR and base branch + if: github.event_name == 'pull_request_review' + uses: actions/checkout@v2 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + + - name: Checkout the head commit of the branch + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: actions/checkout@v2 + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(timestamp +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: martijnhols/actions-cache@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + # In case this is second attempt try restoring failed tests + - name: Restore the previous failed combine result + if: steps.run_result.outputs.run_result == 'failedtest' + uses: martijnhols/actions-cache/restore@v3 + with: + path: | + ~/combined_failed_spec + key: ${{ github.run_id }}-"ui-test-result"-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # failed_spec_env will contain list of all failed specs + # We are using evnironment variable instead of regular to support multiline + - name: Get failed_spec + if: steps.run_result.outputs.run_result == 'failedtest' + run: | + failed_spec_env=$(cat ~/combined_failed_spec) + echo "failed_spec_env<> $GITHUB_ENV + echo "$failed_spec_env" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + run: echo "Starting full run" && exit 0 + + - if: steps.run_result.outputs.run_result == 'failedtest' + run: echo "Rerunning failed tests" && exit 0 + + - name: cat run_result + run: echo ${{ steps.run_result.outputs.run_result }} + + # Setup Java + - name: Set up JDK 1.11 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-java@v1 + with: + java-version: "11.0.10" + + - name: Download the server build artifact + if: steps.run_result.outputs.run_result != 'success' + uses: actions/download-artifact@v2 + with: + name: server-build + path: app/server/dist + + # Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again + - name: Cache maven dependencies + if: steps.run_result.outputs.run_result != 'success' + uses: actions/cache@v2 + env: + cache-name: cache-maven-dependencies + with: + # maven dependencies are stored in `~/.m2` on Linux/macOS + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + # Here, the GITHUB_REF is of type /refs/head/. We extract branch_name from this by removing the + # first 11 characters. This can be used to build images for several branches + # Since this is an unreleased build, we get the latest released version number, increment the minor number in it, + # append a `-SNAPSHOT` at it's end to prepare the snapshot version number. This is used as the project's version. + - name: Get the version to tag the Docker image + if: steps.run_result.outputs.run_result != 'success' + id: vars + run: | + # Since this is an unreleased build, we set the version to incremented version number with a + # `-SNAPSHOT` suffix. + latest_released_version="$(git tag --list 'v*' --sort=-version:refname | head -1)" + echo "latest_released_version = $latest_released_version" + next_version="$(echo "$latest_released_version" | awk -F. -v OFS=. '{ $NF++; print }')" + echo "next_version = $next_version" + echo ::set-output name=version::$next_version-SNAPSHOT + echo ::set-output name=tag::$(echo ${GITHUB_REF:11}) + + # Start server + - name: Start server + if: steps.run_result.outputs.run_result != 'success' + working-directory: app/server + env: + APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools" + APPSMITH_REDIS_URL: "redis://127.0.0.1:6379" + APPSMITH_ENCRYPTION_PASSWORD: "password" + APPSMITH_ENCRYPTION_SALT: "salt" + APPSMITH_IS_SELF_HOSTED: false + APPSMITH_CLOUD_SERVICES_BASE_URL: "https://release-cs.appsmith.com" + APPSMITH_CLOUD_SERVICES_USERNAME: "" + APPSMITH_CLOUD_SERVICES_PASSWORD: "" + APPSMITH_GIT_ROOT: "./container-volumes/git-storage" + run: | + ls -l + ls -l scripts/ + ls -l dist/ + # Run the server in the background and redirect logs to a log file + ./scripts/start-dev-server.sh &> server-logs.log & + + - name: Wait for 30s and check if server is running + if: steps.run_result.outputs.run_result != 'success' + run: | + sleep 30s + if lsof -i :8080; then + echo "Server Found" + else + echo "Server Not Started. Printing logs from server process" + cat app/server/nohup.out + exit 1 + fi + + - name: Use Node.js 14.15.4 + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v1 + with: + node-version: "14.15.4" + + - name: Get yarn cache directory path + if: steps.run_result.outputs.run_result != 'success' + id: yarn-dep-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + # Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again + - name: Cache npm dependencies + if: steps.run_result.outputs.run_result != 'success' + id: yarn-dep-cache + uses: actions/cache@v2 + env: + cache-name: cache-yarn-dependencies + with: + path: | + ${{ steps.yarn-dep-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-dep-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn-dep- + + # Install all the dependencies + - name: Install dependencies + if: steps.run_result.outputs.run_result != 'success' + run: yarn install + + - name: Download the react build artifact + if: steps.run_result.outputs.run_result != 'success' + uses: actions/download-artifact@v2 + with: + name: client-build + path: app/client/build + + - name: Installing Yarn serve + if: steps.run_result.outputs.run_result != 'success' + run: | + yarn global add serve + echo "$(yarn global bin)" >> $GITHUB_PATH + + - name: Setting up the cypress tests + if: steps.run_result.outputs.run_result != 'success' + shell: bash + env: + APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} + APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} + CYPRESS_URL: ${{ secrets.CYPRESS_URL }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + POSTGRES_PASSWORD: postgres + run: | + ./cypress/setup-test.sh + + - name: Run the cypress test + if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + uses: cypress-io/github-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} + with: + browser: chrome + headless: true + record: true + install: false + parallel: true + group: "Electrons on Github Action" + spec: "cypress/integration/Smoke_TestSuite/**/*" + working-directory: app/client + # tag will be either "push" or "pull_request" + tag: ${{ github.event_name }} + env: "NODE_ENV=development" + + # Incase of second attemtp only run failed specs + - name: Run the cypress test with failed tests + if: steps.run_result.outputs.run_result == 'failedtest' + uses: cypress-io/github-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} + with: + browser: chrome + headless: true + record: true + install: false + parallel: true + group: "Electrons on Github Action" + spec: ${{ env.failed_spec_env }} + working-directory: app/client + # tag will be either "push" or "pull_request" + tag: ${{ github.event_name }} + env: "NODE_ENV=development" + + # Set status = failedtest + - name: Set fail if there are test failures + if: failure() + run: echo "::set-output name=run_result::failedtest" > ~/run_result + + # Create a directory ~/failed_spec and add a dummy file + # This will ensure upload and download steps are successfull + - name: Create direcotrs for failed tests + if: always() + run: | + mkdir -p ~/failed_spec + echo "empty" >> ~/failed_spec/dummy-${{ matrix.job }} + + # add list failed tests to a file + - name: Incase of test failures copy them to a file + if: failure() + run: | + cd ${{ github.workspace }}/app/client/cypress/ + find screenshots -type d|grep -i spec |sed 's/screenshots/cypress\/integration/g' > ~/failed_spec/failed_spec-${{ matrix.job }} + + # Upload failed test list using common path for all matrix job + - name: Upload failed test list artifact + if: always() + uses: actions/upload-artifact@v2 + with: + name: failed-spec + path: ~/failed_spec + + # Force store previous run result to cache + - name: Store the previous run result + if: failure() + uses: martijnhols/actions-cache/save@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Force store previous failed test list to cache + - name: Store the previous failed test result + if: failure() + uses: martijnhols/actions-cache/save@v3 + with: + path: | + ~/failed_spec + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Upload the screenshots as artifacts if there's a failure + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: cypress-screenshots-${{ matrix.job }} + path: app/client/cypress/screenshots/ + + - name: Restore the previous bundle + uses: actions/cache@v2 + with: + path: | + app/client/cypress/snapshots/ + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # Upload the snapshots as artifacts for layout validation + - uses: actions/upload-artifact@v1 + with: + name: cypress-snapshots-visualRegression + path: app/client/cypress/snapshots/ + + # Upload the log artifact so that it can be used by the test & deploy job in the workflow + - name: Upload server logs bundle on failure + uses: actions/upload-artifact@v2 + if: failure() + with: + name: server-logs-${{ matrix.job }} + path: app/server/server-logs.log + + # Set status = success + - run: echo "::set-output name=run_result::success" > ~/run_result + + ui-test-result: + needs: ui-test + if: always() && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository)) + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - run: echo "All ui-test matrices completed" + + # Download failed_spec list for all jobs + - uses: actions/download-artifact@v2 + if: needs.ui-test.result + id: download + with: + name: failed-spec + path: ~/failed_spec + + # Incase for any uti-test job failure, create combined failed spec + - name: "combine all specs" + if: needs.ui-test.result != 'success' + run: cat ~/failed_spec/failed_spec* >> ~/combined_failed_spec + + # Force save the failed spec list into a cache + - name: Store the combined run result + if: needs.ui-test.result + uses: martijnhols/actions-cache/save@v3 + with: + path: | + ~/combined_failed_spec + key: ${{ github.run_id }}-"ui-test-result"-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + # Upload combined failed spec list to a file + # This is done for debugging. + - name: upload combined failed spec + if: needs.ui-test.result + uses: actions/upload-artifact@v2 + with: + name: combined_failed_spec + path: ~/combined_failed_spec + + - name: Return status for ui-matrix + run: | + if [[ "${{ needs.ui-test.result }}" == "success" ]]; then + echo "Integration tests completed successfully!"; + exit 0; + elif [[ "${{ needs.ui-test.result }}" == "skipped" ]]; then + echo "Integration tests were skipped"; + exit 1; + else + echo "Integration tests have failed"; + exit 1; + fi + + package: + needs: [ui-test, fat-conatiner-test] + runs-on: ubuntu-latest + + # Run this job irrespective of tests failing, if this is the release branch; or only if the tests pass, if this is the master branch. + if: (success() && github.ref == 'refs/heads/master') || + ( always() && + ( + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + ( + github.event_name == 'pull_request_review' && + github.event.review.state == 'approved' && + github.event.pull_request.head.repo.full_name == github.repository + ) + ) && + github.ref == 'refs/heads/release' + ) + + steps: + # Checkout the code + - name: Checkout the merged commit from PR and base branch + if: github.event_name == 'pull_request_review' + uses: actions/checkout@v2 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + + - name: Checkout the head commit of the branch + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: actions/checkout@v2 + + - name: Download the react build artifact + uses: actions/download-artifact@v2 + with: + name: client-build + path: app/client/build + + - name: Download the server build artifact + uses: actions/download-artifact@v2 + with: + name: server-build + path: app/server/dist + + - name: Download the rts build artifact + uses: actions/download-artifact@v2 + with: + name: rts-build + path: app/rts/dist + + - name: Download the rts build artifact + uses: actions/download-artifact@v2 + with: + name: rts-build-deps + path: app/rts/node_modules/ + + # Here, the GITHUB_REF is of type /refs/head/. We extract branch_name from this by removing the + # first 11 characters. This can be used to build images for several branches + - name: Get the version to tag the Docker image + id: vars + run: echo ::set-output name=tag::$(echo ${GITHUB_REF:11}) + + - name: Set up QEMU (needed for docker buildx) + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + # Build release Docker image and push to Docker Hub + - name: Push client release image to Docker Hub + if: success() && github.ref == 'refs/heads/release' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: app/client + run: | + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:${{steps.vars.outputs.tag}} . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:${{steps.vars.outputs.tag}} + + # Build master Docker image and push to Docker Hub + - name: Push client master image to Docker Hub with commit tag + if: success() && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: app/client + run: | + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:${GITHUB_SHA} . + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:nightly . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:${GITHUB_SHA} + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-editor:nightly + + - name: Build and push release image to Docker Hub + if: success() && github.ref == 'refs/heads/release' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: "." + run: | + tag_args="--tag ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:${{steps.vars.outputs.tag}}" + docker buildx build \ + --platform linux/arm64,linux/amd64 \ + --push \ + --build-arg APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }} \ + $tag_args \ + . + + - name: Build and push master image to Docker Hub with commit tag + if: success() && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + working-directory: "." + run: | + tag_args="--tag ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:${GITHUB_SHA}" + tag_args="$tag_args --tag ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:nightly" + docker buildx build \ + --platform linux/arm64,linux/amd64 \ + --push \ + --build-arg APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} \ + $tag_args \ + . + + # - name: Check and push fat image to Docker Hub with commit tag + # if: success() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/release') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + # working-directory: "." + # run: | + # if [[ "${{ github.ref }}" == "refs/heads/master" ]]; then + # tag=nightly + # else + # tag="${{ steps.vars.outputs.tag }}" + # fi + # docker run --detach --publish 80:80 --name appsmith \ + # "${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:$tag" + # sleep 180 + # cd deploy/docker + # if bash run-test.sh; then + # echo "Fat container test passed. Pushing image." + # docker push --all-tags ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce + # else + # echo "Fat container test FAILED. Not pushing image." + # # Temporarily pushing even if test fails. + # docker push --all-tags ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-ce + # fi + + # Build release Docker image and push to Docker Hub + - name: Push server release image to Docker Hub + if: success() && github.ref == 'refs/heads/release' + working-directory: app/server + run: | + docker build --build-arg APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }} -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:${{steps.vars.outputs.tag}} . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:${{steps.vars.outputs.tag}} + + # Build master Docker image and push to Docker Hub + - name: Push server master image to Docker Hub with commit tag + if: success() && github.ref == 'refs/heads/master' + working-directory: app/server + run: | + docker build --build-arg APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:${GITHUB_SHA} . + docker build --build-arg APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:nightly . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:${GITHUB_SHA} + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-server:nightly + + # Build release Docker image and push to Docker Hub + - name: Push RTS release image to Docker Hub + if: success() && github.ref == 'refs/heads/release' + working-directory: app/rts + run: | + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${{steps.vars.outputs.tag}} . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${{steps.vars.outputs.tag}} + + # Build master Docker image and push to Docker Hub + - name: Push RTS master image to Docker Hub with commit tag + if: success() && github.ref == 'refs/heads/master' + working-directory: app/rts + run: | + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${GITHUB_SHA} . + docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:nightly . + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${GITHUB_SHA} + # docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:nightly diff --git a/.github/workflows/test-build-docker-image.yml b/.github/workflows/test-build-docker-image.yml index a00314f77a..603104f558 100644 --- a/.github/workflows/test-build-docker-image.yml +++ b/.github/workflows/test-build-docker-image.yml @@ -1025,4 +1025,4 @@ jobs: docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${GITHUB_SHA} . docker build -t ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:nightly . docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:${GITHUB_SHA} - docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:nightly + docker push ${{ secrets.DOCKER_HUB_ORGANIZATION }}/appsmith-rts:nightly \ No newline at end of file diff --git a/app/client/cypress/integration/Smoke_TestSuite_Fat/ClientSideTests/AdminSettings/Admin_settings_spec.js b/app/client/cypress/integration/Smoke_TestSuite_Fat/ClientSideTests/AdminSettings/Admin_settings_spec.js new file mode 100644 index 0000000000..ee29888d91 --- /dev/null +++ b/app/client/cypress/integration/Smoke_TestSuite_Fat/ClientSideTests/AdminSettings/Admin_settings_spec.js @@ -0,0 +1,207 @@ +import adminsSettings from "../../../../locators/AdminsSettings"; + +const { + GITHUB_SIGNUP_SETUP_DOC, + GOOGLE_SIGNUP_SETUP_DOC, +} = require("../../../../../src/constants/ThirdPartyConstants"); + +describe("Admin settings page", function() { + beforeEach(() => { + cy.intercept("GET", "/api/v1/admin/env", { + body: { responseMeta: { status: 200, success: true }, data: {} }, + }).as("getEnvVariables"); + cy.intercept("PUT", "/api/v1/admin/env", { + body: { responseMeta: { status: 200, success: true }, data: {} }, + }).as("postEnvVariables"); + }); + + it("should test that settings page is accessible to super user", () => { + cy.LogOut(); + cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + cy.visit("/applications"); + cy.get(".t--profile-menu-icon").should("be.visible"); + cy.get(".t--profile-menu-icon").click(); + cy.get(".t--admin-settings-menu").should("be.visible"); + cy.get(".t--admin-settings-menu").click(); + cy.url().should("contain", "/settings/general"); + cy.wait("@getEnvVariables"); + cy.LogOut(); + }); + + it("should test that settings page is not accessible to normal users", () => { + cy.wait(2000); + cy.LoginFromAPI(Cypress.env("TESTUSERNAME1"), Cypress.env("TESTPASSWORD1")); + cy.visit("/applications"); + cy.get(".t--profile-menu-icon").should("be.visible"); + cy.get(".t--profile-menu-icon").click(); + cy.get(".t--admin-settings-menu").should("not.exist"); + cy.visit("/settings/general"); + // non super users are redirected to home page + cy.url().should("contain", "/applications"); + cy.LogOut(); + }); + + it("should test that settings page is redirected to default tab", () => { + cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + cy.visit("/applications"); + cy.wait(3000); + cy.visit("/settings"); + cy.url().should("contain", "/settings/general"); + }); + + it("should test that settings page tab redirects", () => { + cy.visit("/applications"); + cy.wait(3000); + cy.get(".t--profile-menu-icon").click(); + cy.get(".t--admin-settings-menu").click(); + cy.get(adminsSettings.generalTab).click(); + cy.url().should("contain", "/settings/general"); + cy.get(adminsSettings.advancedTab).click(); + cy.url().should("contain", "/settings/advanced"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.emailTab).click(); + cy.url().should("contain", "/settings/email"); + cy.get(adminsSettings.googleMapsTab).click(); + cy.url().should("contain", "/settings/google-maps"); + cy.get(adminsSettings.versionTab).click(); + cy.url().should("contain", "/settings/version"); + }); + + it("should test that authentication page redirects", () => { + cy.visit("/settings/general"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.googleButton).click(); + cy.url().should("contain", "/settings/authentication/google-auth"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.githubButton).click(); + cy.url().should("contain", "/settings/authentication/github-auth"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.formloginButton).click(); + cy.url().should("contain", "/settings/authentication/form-login"); + }); + + it("should test that configure link redirects to google signup setup doc", () => { + cy.visit("/settings/general"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.googleButton).click(); + cy.url().should("contain", "/settings/authentication/google-auth"); + cy.get(adminsSettings.readMoreLink).within(() => { + cy.get("a") + .should("have.attr", "target", "_blank") + .invoke("removeAttr", "target") + .click(); + cy.url().should("contain", GOOGLE_SIGNUP_SETUP_DOC); + }); + }); + + it("should test that configure link redirects to github signup setup doc", () => { + cy.visit("/settings/general"); + cy.get(adminsSettings.authenticationTab).click(); + cy.url().should("contain", "/settings/authentication"); + cy.get(adminsSettings.githubButton).click(); + cy.url().should("contain", "/settings/authentication/github-auth"); + cy.get(adminsSettings.readMoreLink).within(() => { + cy.get("a") + .should("have.attr", "target", "_blank") + .invoke("removeAttr", "target") + .click(); + cy.url().should("contain", GITHUB_SIGNUP_SETUP_DOC); + }); + }); + + it("should test save and clear buttons disabled state", () => { + cy.visit("/settings/general"); + const assertVisibilityAndDisabledState = () => { + cy.get(adminsSettings.saveButton).should("be.visible"); + cy.get(adminsSettings.saveButton).should("be.disabled"); + cy.get(adminsSettings.resetButton).should("be.visible"); + cy.get(adminsSettings.resetButton).should("be.disabled"); + }; + assertVisibilityAndDisabledState(); + cy.get(adminsSettings.instanceName).should("be.visible"); + cy.get(adminsSettings.instanceName) + .clear() + .type("AppsmithInstance"); + cy.get(adminsSettings.saveButton).should("be.visible"); + cy.get(adminsSettings.saveButton).should("not.be.disabled"); + cy.get(adminsSettings.resetButton).should("be.visible"); + cy.get(adminsSettings.resetButton).should("not.be.disabled"); + cy.get(adminsSettings.resetButton).click(); + assertVisibilityAndDisabledState(); + }); + + it("should test saving a setting value", () => { + cy.visit("/settings/general"); + cy.get(adminsSettings.restartNotice).should("not.exist"); + cy.get(adminsSettings.instanceName).should("be.visible"); + let instanceName; + cy.generateUUID().then((uuid) => { + instanceName = uuid; + cy.get(adminsSettings.instanceName) + .clear() + .type(uuid); + }); + cy.get(adminsSettings.saveButton).should("be.visible"); + cy.get(adminsSettings.saveButton).should("not.be.disabled"); + cy.intercept("POST", "/api/v1/admin/restart", { + body: { responseMeta: { status: 200, success: true }, data: true }, + }); + cy.get(adminsSettings.saveButton).click(); + cy.wait("@postEnvVariables").then((interception) => { + expect(interception.request.body.APPSMITH_INSTANCE_NAME).to.equal( + instanceName, + ); + }); + cy.get(adminsSettings.restartNotice).should("be.visible"); + cy.wait(3000); + cy.get(adminsSettings.restartNotice).should("not.exist"); + cy.wait(3000); + }); + + it("should test saving settings value from different tabs", () => { + cy.visit("/settings/general"); + cy.get(adminsSettings.restartNotice).should("not.exist"); + cy.get(adminsSettings.instanceName).should("be.visible"); + let instanceName; + cy.generateUUID().then((uuid) => { + instanceName = uuid; + cy.get(adminsSettings.instanceName) + .clear() + .type(uuid); + }); + cy.get(adminsSettings.saveButton).should("be.visible"); + cy.get(adminsSettings.saveButton).should("not.be.disabled"); + cy.get(adminsSettings.emailTab).click(); + cy.get(adminsSettings.saveButton).should("be.visible"); + cy.get(adminsSettings.saveButton).should("not.be.disabled"); + cy.get(adminsSettings.fromAddress).should("be.visible"); + let fromAddress; + cy.generateUUID().then((uuid) => { + fromAddress = uuid; + cy.get(adminsSettings.fromAddress) + .clear() + .type(`${uuid}@appsmith.com`); + }); + cy.intercept("POST", "/api/v1/admin/restart", { + body: { responseMeta: { status: 200, success: true }, data: true }, + }); + cy.get(adminsSettings.saveButton).click(); + cy.wait("@postEnvVariables").then((interception) => { + expect(interception.request.body.APPSMITH_INSTANCE_NAME).to.equal( + instanceName, + ); + expect(interception.request.body.APPSMITH_MAIL_FROM).to.equal( + `${fromAddress}@appsmith.com`, + ); + }); + cy.get(adminsSettings.restartNotice).should("be.visible"); + cy.wait(3000); + cy.get(adminsSettings.restartNotice).should("not.exist"); + cy.wait(3000); + }); +});