# Configuration file for https://circleci.com/gh/angular/angular # Note: YAML anchors allow an object to be re-used, reducing duplication. # The ampersand declares an alias for an object, then later the `<<: *name` # syntax dereferences it. # See http://blog.daemonl.com/2016/02/yaml.html # To validate changes, use an online parser, eg. # http://yaml-online-parser.appspot.com/ # Note that the browser docker image comes with Chrome and Firefox preinstalled. This is just # needed for jobs that run tests without Bazel. Bazel runs tests with browsers that will be # fetched by the Webtesting rules. Therefore for jobs that run tests with Bazel, we don't need a # docker image with browsers pre-installed. # **NOTE 1**: If you change the version of the `*-browsers` docker image, make sure the # `CI_CHROMEDRIVER_VERSION_ARG` env var (in `.circleci/env.sh`) points to a ChromeDriver # version that is compatible with the Chrome version in the image. # **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix. var_1: &default_docker_image circleci/node:10.12 var_2: &browsers_docker_image circleci/node:10.12-browsers # We don't want to include the current branch name in the cache key because that would prevent # PRs from being able to restore the cache since the branch names are always different for PRs. # The cache key should only consist of dynamic values that change whenever something in the # cache changes. For example: # 1) yarn lock file changes --> cached "node_modules" are different. # 2) bazel repository definitions change --> cached bazel repositories are different. # **NOTE 1 **: If you change the cache key prefix, also sync the restore_cache fallback to match. # **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks. # See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI. var_3: &cache_key v3-angular-node-10.12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} # Initializes the CI environment by setting up common environment variables. var_4: &init_environment run: name: Initializing environment (setting up variables, overwriting Yarn) # Overwrite the yarn installed in the docker container with our own version. command: | ./.circleci/env.sh ourYarn=$(realpath ./third_party/github.com/yarnpkg/yarn/releases/download/v1.13.0/bin/yarn.js) sudo chmod a+x $ourYarn sudo ln -fs $ourYarn /usr/local/bin/yarn echo "Yarn version: $(yarn --version)" # Add GitHub to known hosts. mkdir -p ~/.ssh echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts # use git+ssh instead of https git config --global url."ssh://git@github.com".insteadOf "https://github.com" || true git config --global gc.auto 0 || true var_5: &setup_bazel_remote_execution run: name: "Setup bazel RBE remote execution" command: | openssl aes-256-cbc -d -in .circleci/gcp_token -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV sudo bash -c "echo 'build --config=remote' >> /etc/bazel.bazelrc" # Settings common to each job var_6: &job_defaults working_directory: ~/ng docker: - image: *default_docker_image # After checkout, rebase on top of master. # Similar to travis behavior, but not quite the same. # See https://discuss.circleci.com/t/1662 var_7: &post_checkout run: name: Post checkout step command: > if [[ -n "${CIRCLE_PR_NUMBER}" ]]; then # Fetch the head and merge commits for this PR. git fetch origin +refs/pull/$CIRCLE_PR_NUMBER/head:pr/$CIRCLE_PR_NUMBER/head git fetch origin +refs/pull/$CIRCLE_PR_NUMBER/merge:pr/$CIRCLE_PR_NUMBER/merge # Checkout the merged PR for testing as CircleCI will just use the PR head otherwise. git checkout -qf pr/$CIRCLE_PR_NUMBER/merge # Reset the merge commit into its PR head. git reset pr/$CIRCLE_PR_NUMBER/head # Commit the merge changes into the head of the PR. # This way we keep the last commit message. git config user.name "angular-ci" git config user.email "angular-ci" git commit . --amend --no-edit fi var_8: &yarn_install run: name: Running Yarn install command: | # Yarn's requests sometimes take more than 10mins to complete. # Print something to stdout, to prevent CircleCI from failing due to not output. while true; do sleep 60; echo "[`date`] Keeping alive..."; done & KEEP_ALIVE_PID=$! yarn install --frozen-lockfile --non-interactive kill $KEEP_ALIVE_PID var_9: &setup_circleci_bazel_config run: name: Setting up CircleCI bazel configuration command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc var_10: &restore_cache restore_cache: keys: - *cache_key # This fallback should be the cache_key without variables. - v3-angular-node-10.12- # Branch filter that can be specified for jobs that should only run on publish branches # (e.g. master or the patch branch) var_12: &publish_branches_filter branches: only: - master # e.g. 7.0.x, 7.1.x, etc. - /\d+\.\d+\.x/ # Workspace initially persisted by the `install` job, and then enhanced by `test_aio` and # `build-npm-packages`. # https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs # https://circleci.com/blog/deep-diving-into-circleci-workspaces/ var_13: &attach_workspace attach_workspace: at: ~/ version: 2 jobs: setup: <<: *job_defaults steps: - checkout - *post_checkout # This cache is saved in the build-npm-packages so that Bazel cache is also included. - *restore_cache - *init_environment - *yarn_install - run: yarn --cwd aio install --frozen-lockfile --non-interactive # Make the bazel directories and add a file to them if they don't exist already so that # persist_to_workspace does not fail. - run: | if [ ! -d ~/bazel_repository_cache ]; then mkdir ~/bazel_repository_cache touch ~/bazel_repository_cache/MARKER fi # Persist any changes at this point to be reused by further jobs. # **NOTE 1 **: Folders persisted here should be kept in sync with `var_13: &attach_workspace`. # **NOTE 2 **: To add new content to the workspace, always persist on the same root. - persist_to_workspace: root: ~/ paths: - ./ng - ./bazel_repository_cache lint: <<: *job_defaults steps: - *attach_workspace - *init_environment - run: 'yarn bazel:format -mode=check || (echo "BUILD files not formatted. Please run ''yarn bazel:format''" ; exit 1)' # Run the skylark linter to check our Bazel rules - run: 'yarn bazel:lint || (echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)' - run: yarn gulp lint test: <<: *job_defaults resource_class: xlarge steps: - *attach_workspace - *init_environment - *setup_circleci_bazel_config # Setup remote execution and run RBE-compatible tests. - *setup_bazel_remote_execution - run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-local # Now run RBE incompatible tests locally. - run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local # Temporary job to test what will happen when we flip the Ivy flag to true test_ivy_aot: <<: *job_defaults resource_class: xlarge steps: - *attach_workspace - *init_environment - *setup_circleci_bazel_config - *setup_bazel_remote_execution # We need to explicitly specify the --symlink_prefix option because otherwise we would # not be able to easily find the output bin directory when uploading artifacts for size # measurements. - run: yarn test-ivy-aot //... --symlink_prefix=dist/ # Publish bundle artifacts which will be used to calculate the size change. **Note**: Make # sure that the size plugin from the Angular robot fetches the artifacts from this CircleCI # job (see .github/angular-robot.yml). Additionally any artifacts need to be stored with the # following path format: "{projectName}/{context}/{fileName}". This format is necessary # because otherwise the bot is not able to pick up the artifacts from CircleCI. See: # https://github.com/angular/github-robot/blob/master/functions/src/plugins/size.ts#L392-L394 - store_artifacts: path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js destination: core/hello_world/bundle - store_artifacts: path: dist/bin/packages/core/test/bundling/todo/bundle.min.js destination: core/todo/bundle - store_artifacts: path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.br destination: core/hello_world/bundle.br - store_artifacts: path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br destination: core/todo/bundle.br test_saucelabs: <<: *job_defaults # In order to avoid the bottleneck of having a slow host machine, we acquire a better # container for this job. This is necessary because we launch a lot of browsers concurrently # and therefore the tunnel and Karma need to process a lot of file requests and tests. resource_class: xlarge steps: - *attach_workspace - *init_environment - run: name: Preparing environment for running tests on Saucelabs. command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev) - run: name: Starting Saucelabs tunnel command: ./scripts/saucelabs/start-tunnel.sh background: true # Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests # too early without Saucelabs not being ready. - run: ./scripts/saucelabs/wait-for-tunnel.sh # All web tests are contained within a single //:test_web_all target for Saucelabs # as running each set of tests as a separate target will attempt to acquire too # many browsers on Saucelabs (7 per target currently) and some tests will always # fail to acquire browsers. For example: # 14 02 2019 19:52:33.170:WARN [launcher]: chrome beta on SauceLabs have not captured in 180000 ms, killing. # //packages/forms/test:web_test_sauce TIMEOUT in 315.0s - run: yarn bazel test --config=saucelabs //:test_web_all - run: ./scripts/saucelabs/stop-tunnel.sh test_aio: <<: *job_defaults docker: # Needed because the AIO tests and the PWA score test depend on Chrome being available. - image: *browsers_docker_image steps: - *attach_workspace - *init_environment # Build aio - run: yarn --cwd aio build --progress=false # Lint the code - run: yarn --cwd aio lint # Run PWA-score tests # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE # Check the bundle sizes. # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio payload-size # Run unit tests - run: yarn --cwd aio test --progress=false --watch=false # Run e2e tests - run: yarn --cwd aio e2e --configuration=ci # Run unit tests for Firebase redirects - run: yarn --cwd aio redirects-test deploy_aio: <<: *job_defaults docker: # Needed because before deploying the deploy-production script runs the PWA score tests. - image: *browsers_docker_image steps: - *attach_workspace - *init_environment # Deploy angular.io to production (if necessary) - run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" - run: yarn --cwd aio deploy-production test_aio_local: <<: *job_defaults docker: # Needed because the AIO tests and the PWA score test depend on Chrome being available. - image: *browsers_docker_image steps: - *attach_workspace - *init_environment # Build aio (with local Angular packages) - run: yarn --cwd aio build-local --progress=false # Run PWA-score tests # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE # Run unit tests - run: yarn --cwd aio test --progress=false --watch=false # Run e2e tests - run: yarn --cwd aio e2e --configuration=ci test_aio_local_ivy: <<: *job_defaults steps: - *attach_workspace - *init_environment # Build aio with Ivy (using local Angular packages) - run: yarn --cwd aio build-with-ivy --progress=false test_aio_tools: <<: *job_defaults steps: - *attach_workspace - *init_environment # Install - run: yarn --cwd aio install --frozen-lockfile --non-interactive - run: yarn --cwd aio extract-cli-command-docs # Run tools tests - run: yarn --cwd aio tools-test - run: ./aio/aio-builds-setup/scripts/test.sh test_docs_examples: <<: *job_defaults docker: # Needed because the example e2e tests depend on Chrome. - image: *browsers_docker_image parallelism: 3 steps: - *attach_workspace - *init_environment # Install aio - run: yarn --cwd aio install --frozen-lockfile --non-interactive # Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. # Since the parallelism is set to "3", there will be three parallel CircleCI containers # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. - run: yarn --cwd aio example-e2e --setup --local --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} test_docs_examples_ivy: <<: *job_defaults docker: # Needed because the example e2e tests depend on Chrome. - image: *browsers_docker_image parallelism: 3 steps: - *attach_workspace - *init_environment # Install aio - run: yarn --cwd aio install --frozen-lockfile --non-interactive # Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. # Since the parallelism is set to "3", there will be three parallel CircleCI containers # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. - run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. aio_preview: <<: *job_defaults environment: AIO_SNAPSHOT_ARTIFACT_PATH: &aio_preview_artifact_path 'aio/tmp/snapshot.tgz' steps: - *attach_workspace - *init_environment - run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT - store_artifacts: path: *aio_preview_artifact_path # The `destination` needs to be kept in synch with the value of # `AIO_ARTIFACT_PATH` in `aio/aio-builds-setup/Dockerfile` destination: aio/dist/aio-snapshot.tgz - run: node ./aio/scripts/create-preview $CIRCLE_BUILD_NUM # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. test_aio_preview: <<: *job_defaults docker: # Needed because the test-preview script runs e2e tests and the PWA score test with Chrome. - image: *browsers_docker_image steps: - *attach_workspace - *init_environment - run: yarn --cwd aio install --frozen-lockfile --non-interactive - run: name: Wait for preview and run tests command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE # The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and # tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh). # Having multiple jobs that independently build in this manner duplicates some work; we build # the bazel packages more than once. Even though we have a remote cache, these jobs will # typically run in parallel so up-to-date outputs will not be available at the time the build # starts. # Build the view engine npm packages. No new jobs should depend on this. build-npm-packages: <<: *job_defaults resource_class: xlarge steps: - *attach_workspace - *init_environment - *setup_circleci_bazel_config - *setup_bazel_remote_execution - run: scripts/build-packages-dist.sh # Save the npm packages from //packages/... for other workflow jobs to read - persist_to_workspace: root: ~/ paths: - ng/dist/packages-dist # Save dependencies and bazel repository cache to use on subsequent runs. - save_cache: key: *cache_key paths: - "node_modules" - "aio/node_modules" - "~/bazel_repository_cache" # Build the ivy npm packages. build-ivy-npm-packages: <<: *job_defaults resource_class: xlarge steps: - *attach_workspace - *init_environment - *setup_circleci_bazel_config - *setup_bazel_remote_execution - run: scripts/build-ivy-npm-packages.sh # Save the npm packages from //packages/... for other workflow jobs to read - persist_to_workspace: root: ~/ paths: - ng/dist/packages-dist-ivy-aot # We run the integration tests outside of Bazel for now. # They are a separate workflow job so that they can be easily re-run. # When the tests are ported to bazel test targets, they should move to the "test" # job above, as part of the bazel test command. That has flaky_test_attempts so the # need to re-run manually should be alleviated. # See comments inside the integration/run_tests.sh script. integration_test: <<: *job_defaults parallelism: 4 docker: # Needed because the integration tests expect Chrome to be installed (e.g cli-hello-world) - image: *browsers_docker_image # Note: we run Bazel in one of the integration tests, and it can consume >2G # of memory. Together with the system under test, this can exhaust the RAM # on a 4G worker so we use a larger machine here too. resource_class: xlarge steps: - *attach_workspace - *init_environment # Runs the integration tests in parallel across multiple CircleCI container instances. The # amount of container nodes for this job is controlled by the "parallelism" option. - run: ./integration/run_tests.sh ${CIRCLE_NODE_INDEX} ${CIRCLE_NODE_TOTAL} # This job updates the content of repos like github.com/angular/core-builds # for every green build on angular/angular. publish_snapshot: <<: *job_defaults steps: - *attach_workspace - *init_environment # See below - ideally this job should not trigger for non-upstream builds. # But since it does, we have to check this condition. - run: name: Skip this job for Pull Requests and Fork builds # Note, `|| true` on the end makes this step always exit 0 command: '[[ "$CI_PULL_REQUEST" != "false" || "$CI_REPO_OWNER" != "angular" || "$CI_REPO_NAME" != "angular" ]] && circleci step halt || true' # CircleCI has a config setting to force SSH for all github connections # This is not compatible with our mechanism of using a Personal Access Token # Clear the global setting - run: git config --global --unset "url.ssh://git@github.com.insteadof" - run: name: Decrypt github credentials command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials' - run: ./scripts/ci/publish-build-artifacts.sh aio_monitoring: <<: *job_defaults docker: # This job needs Chrome to be globally installed because the tests run with Protractor # which does not load the browser through the Bazel webtesting rules. - image: *browsers_docker_image steps: - checkout - *post_checkout - *restore_cache - *init_environment - run: name: Run tests against the deployed apps command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE - run: name: Notify caretaker about failure # `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci. command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL' when: on_fail legacy-unit-tests-saucelabs: <<: *job_defaults # In order to avoid the bottleneck of having a slow host machine, we acquire a better # container for this job. This is necessary because we launch a lot of browsers concurrently # and therefore the tunnel and Karma need to process a lot of file requests and tests. resource_class: xlarge steps: - *attach_workspace - *init_environment - run: name: Preparing environment for running tests on Saucelabs. command: | setPublicVar KARMA_JS_BROWSERS $(node -e 'console.log(require("./browser-providers.conf").sauceAliases.CI_REQUIRED.join(","))') setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev) - run: name: Starting Saucelabs tunnel command: ./scripts/saucelabs/start-tunnel.sh background: true - run: yarn tsc -p packages - run: yarn tsc -p modules # Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests # too early without Saucelabs not being ready. - run: ./scripts/saucelabs/wait-for-tunnel.sh - run: yarn karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} - run: ./scripts/saucelabs/stop-tunnel.sh legacy-misc-tests: <<: *job_defaults steps: - *attach_workspace - *init_environment - run: yarn gulp check-cycle # TODO: disabled because the Bazel packages-dist does not seem to have map files for # the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966 # - run: yarn gulp source-map-test # Job to run unit tests from angular/material2. Needs a browser since all # component unit tests assume they're running in the browser environment. material-unit-tests: <<: *job_defaults resource_class: xlarge docker: - image: *browsers_docker_image steps: - *attach_workspace - *init_environment - run: ./scripts/ci/run_angular_material_unit_tests.sh workflows: version: 2 default_workflow: jobs: - setup - lint: requires: - setup - test: requires: - setup - test_ivy_aot: requires: - setup - build-npm-packages: requires: - setup - build-ivy-npm-packages: requires: - setup - test_aio: requires: - setup - deploy_aio: requires: - test_aio - legacy-misc-tests: requires: - build-npm-packages - test_aio_local: requires: - build-npm-packages - test_aio_local_ivy: requires: - build-npm-packages - test_aio_tools: requires: - build-npm-packages - test_docs_examples: requires: - build-npm-packages - test_docs_examples_ivy: requires: - build-npm-packages - aio_preview: requires: - setup # Only run on PR builds. (There can be no previews for non-PR builds.) filters: branches: only: /pull\/\d+/ - test_aio_preview: requires: - aio_preview - integration_test: requires: - build-npm-packages - publish_snapshot: # Note: no filters on this job because we want it to run for all upstream branches # We'd really like to filter out pull requests here, but not yet available: # https://discuss.circleci.com/t/workflows-pull-request-filter/14396/4 # Instead, the job just exits immediately at the first step. requires: # Only publish if tests and integration tests pass - test - test_ivy_aot - integration_test # Only publish if `aio`/`docs` tests using the locally built Angular packages pass - test_aio_local - test_aio_local_ivy - test_docs_examples - test_docs_examples_ivy # Get the artifacts to publish from the build-packages-dist job # since the publishing script expects the legacy outputs layout. - build-npm-packages - build-ivy-npm-packages - legacy-misc-tests - material-unit-tests: requires: - build-ivy-npm-packages saucelabs_tests: jobs: - setup - test_saucelabs: requires: - setup - legacy-unit-tests-saucelabs: # Don't open up multiple saucelabs tunnels at the same # time to minimize flakes requires: - test_saucelabs triggers: - schedule: # Runs the Saucelabs legacy tests every hour. We still want to run Saucelabs # frequently as the caretaker needs up-to-date results when merging PRs or creating # a new release. Also we primarily moved the Saucelabs job into a cronjob that doesn't # run for PRs, in order to ensure that PRs are not affected by Saucelabs flakiness or # incidents. This is still guaranteed (even if we run the job every hour). cron: "0 * * * *" filters: *publish_branches_filter aio_monitoring: jobs: - aio_monitoring triggers: - schedule: # Runs AIO monitoring job at 00:00AM every day. cron: "0 0 * * *" filters: branches: only: - master # TODO: # - don't build the g3 branch # - verify that we are bootstrapping with the right yarn version coming from the docker image # - check local chrome version pulled from docker image # - remove /tools/ngcontainer