version: 2

aliases:
  - &docker
    - image: circleci/openjdk:8-jdk-node-browsers

  - &environment
    TZ: /usr/share/zoneinfo/America/Los_Angeles

  - &restore_yarn_cache
    restore_cache:
      name: Restore yarn cache
      key: v2-node-{{ arch }}-{{ checksum "yarn.lock" }}-yarn

  - &restore_node_modules
    restore_cache:
      name: Restore node_modules cache
      keys:
        - v2-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-modules

  - &TEST_PARALLELISM 20

  - &attach_workspace
    at: build

  - &process_artifacts
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: node ./scripts/rollup/consolidateBundleSizes.js
      - run: ./scripts/circleci/pack_and_store_artifact.sh
      - store_artifacts:
          path: ./node_modules.tgz
      - store_artifacts:
          path: ./build.tgz
      - store_artifacts:
          path: ./build/bundle-sizes.json
      - store_artifacts:
          # TODO: Update release script to use local file instead of pulling
          # from artifacts.
          path: ./scripts/error-codes/codes.json
      - persist_to_workspace:
          root: build
          paths:
            - bundle-sizes.json

jobs:
  setup:
    docker: *docker
    environment: *environment

    steps:
      - checkout
      - run:
          name: Nodejs Version
          command: node --version
      - *restore_yarn_cache
      - run:
          name: Install Packages
          command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn
      - save_cache:
          # Store the yarn cache globally for all lock files with this same
          # checksum. This will speed up the setup job for all PRs where the
          # lockfile is the same.
          name: Save yarn cache for future installs
          key: v2-node-{{ arch }}-{{ checksum "yarn.lock" }}-yarn
          paths:
            - ~/.cache/yarn
      - save_cache:
          # Store node_modules for all jobs in this workflow so that they don't
          # need to each run a yarn install for each job. This will speed up
          # all jobs run on this branch with the same lockfile.
          name: Save node_modules cache
          # This cache key is per branch, a yarn install in setup is required.
          key: v2-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-modules
          paths:
            - node_modules

  yarn_lint:
    docker: *docker
    environment: *environment

    steps:
      - checkout
      - *restore_node_modules
      - run: node ./scripts/prettier/index
      - run: node ./scripts/tasks/eslint
      - run: ./scripts/circleci/check_license.sh
      - run: ./scripts/circleci/check_modules.sh
      - run: ./scripts/circleci/test_print_warnings.sh

  yarn_flow:
    docker: *docker
    environment: *environment

    steps:
      - checkout
      - *restore_node_modules
      - run: node ./scripts/tasks/flow-ci

  RELEASE_CHANNEL_stable_yarn_test:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM

    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=stable --ci

  yarn_test:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --ci

  RELEASE_CHANNEL_stable_yarn_test_www:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-classic --ci

  RELEASE_CHANNEL_stable_yarn_test_www_variant:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-classic --variant --ci

  RELEASE_CHANNEL_stable_yarn_test_prod_www:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-classic --prod --ci

  RELEASE_CHANNEL_stable_yarn_test_prod_www_variant:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-classic --prod --variant --ci

  yarn_test_www:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-modern --ci

  yarn_test_www_variant:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-modern --variant --ci

  yarn_test_prod_www:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-modern --prod --ci

  yarn_test_prod_www_variant:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=www-modern --prod --variant --ci

  RELEASE_CHANNEL_stable_yarn_test_persistent:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM

    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=stable --persistent --ci

  RELEASE_CHANNEL_stable_yarn_test_prod:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM

    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=stable --prod --ci

  yarn_test_prod:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run: yarn test --release-channel=experimental --prod --ci

  RELEASE_CHANNEL_stable_yarn_build:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - *restore_node_modules
      - run:
          environment:
            RELEASE_CHANNEL: stable
          command: |
            ./scripts/circleci/add_build_info_json.sh
            ./scripts/circleci/update_package_versions.sh
            yarn build
      - run: echo "stable" >> build/RELEASE_CHANNEL
      - persist_to_workspace:
          root: build
          paths:
            - RELEASE_CHANNEL
            - facebook-www
            - facebook-react-native
            - node_modules
            - react-native
            - dist
            - sizes/*.json

  yarn_build:
    docker: *docker
    environment: *environment
    parallelism: 20
    steps:
      - checkout
      - *restore_node_modules
      - run:
          environment:
            RELEASE_CHANNEL: experimental
          command: |
            ./scripts/circleci/add_build_info_json.sh
            ./scripts/circleci/update_package_versions.sh
            yarn build
      - run: echo "experimental" >> build/RELEASE_CHANNEL
      - persist_to_workspace:
          root: build
          paths:
            - RELEASE_CHANNEL
            - facebook-www
            - facebook-react-native
            - node_modules
            - react-native
            - dist
            - sizes/*.json

  build_devtools_and_process_artifacts:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_yarn_cache
      - *restore_node_modules
      - run:
          name: Install Packages
          command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn
      - run:
          environment:
            RELEASE_CHANNEL: experimental
          command: ./scripts/circleci/pack_and_store_devtools_artifacts.sh
      - store_artifacts:
          path: ./build/devtools.tgz

  build_devtools_scheduling_profiler:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_yarn_cache
      - *restore_node_modules
      - run:
          name: Install Packages
          command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn
      - run:
          name: Build and archive
          command: |
            mkdir -p build/devtools
            cd packages/react-devtools-scheduling-profiler
            yarn build
            cd dist
            tar -zcvf ../../../build/devtools-scheduling-profiler.tgz .
      - store_artifacts:
          path: ./build/devtools-scheduling-profiler.tgz
      - persist_to_workspace:
          root: packages/react-devtools-scheduling-profiler
          paths:
            - dist
  
  deploy_devtools_scheduling_profiler:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace:
          at: packages/react-devtools-scheduling-profiler
      - *restore_node_modules
      - run:
          name: Deploy
          command: |
            cd packages/react-devtools-scheduling-profiler
            yarn vercel deploy dist --prod --confirm --token $SCHEDULING_PROFILER_DEPLOY_VERCEL_TOKEN

  # These jobs are named differently so we can distinguish the stable and
  # and experimental artifacts
  process_artifacts: *process_artifacts
  process_artifacts_experimental: *process_artifacts

  sizebot_stable:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      # This runs in the process_artifacts job, too, but it's faster to run
      # this step in both jobs instead of running the jobs sequentially
      - run: node ./scripts/rollup/consolidateBundleSizes.js
      - run:
          environment:
            RELEASE_CHANNEL: stable
          command: node ./scripts/tasks/danger

  sizebot_experimental:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      # This runs in the process_artifacts job, too, but it's faster to run
      # this step in both jobs instead of running the jobs sequentially
      - run: node ./scripts/rollup/consolidateBundleSizes.js
      - run:
          environment:
            RELEASE_CHANNEL: experimental
          command: node ./scripts/tasks/danger

  yarn_lint_build:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn lint-build
      - run: scripts/circleci/check_minified_errors.sh

  RELEASE_CHANNEL_stable_yarn_lint_build:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run:
          environment:
            RELEASE_CHANNEL: stable
          command: yarn lint-build
      - run: scripts/circleci/check_minified_errors.sh

  RELEASE_CHANNEL_stable_yarn_test_build:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn test --release-channel=stable --build --ci

  yarn_test_build:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn test --release-channel=experimental --build --ci

  yarn_test_build_devtools:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn test --project=devtools --build --ci

  RELEASE_CHANNEL_stable_yarn_test_dom_fixtures:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run:
          name: Run DOM fixture tests
          environment:
            RELEASE_CHANNEL: stable
          command: |
            cd fixtures/dom
            yarn --frozen-lockfile
            yarn prestart
            yarn test --maxWorkers=2

  test_fuzz:
    docker: *docker
    environment: *environment
    steps:
      - checkout
      - *restore_node_modules
      - run:
          name: Run fuzz tests
          command: |
            FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci
            FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci

  RELEASE_CHANNEL_stable_yarn_test_build_prod:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn test --release-channel=stable --build --prod --ci

  yarn_test_build_prod:
    docker: *docker
    environment: *environment
    parallelism: *TEST_PARALLELISM
    steps:
      - checkout
      - attach_workspace: *attach_workspace
      - *restore_node_modules
      - run: yarn test --release-channel=experimental --build --prod --ci

workflows:
  version: 2
  stable:
    jobs:
      - setup
      - yarn_lint:
          requires:
            - setup
      - yarn_flow:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_prod:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_persistent:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_www:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_www_variant:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_prod_www:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_test_prod_www_variant:
          requires:
            - setup
      - RELEASE_CHANNEL_stable_yarn_build:
          requires:
            - setup
      - process_artifacts:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build
      - sizebot_stable:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build
      - RELEASE_CHANNEL_stable_yarn_lint_build:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build
      - RELEASE_CHANNEL_stable_yarn_test_build:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build
      - RELEASE_CHANNEL_stable_yarn_test_build_prod:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build
      - RELEASE_CHANNEL_stable_yarn_test_dom_fixtures:
          requires:
            - RELEASE_CHANNEL_stable_yarn_build

  experimental:
    jobs:
      - setup
      - yarn_test:
          requires:
            - setup
      - yarn_test_prod:
          requires:
            - setup
      - yarn_test_www:
          requires:
            - setup
      - yarn_test_www_variant:
          requires:
            - setup
      - yarn_test_prod_www:
          requires:
            - setup
      - yarn_test_prod_www_variant:
          requires:
            - setup
      - yarn_build:
          requires:
            - setup
      - process_artifacts_experimental:
          requires:
            - yarn_build
      - sizebot_experimental:
          requires:
            - yarn_build
      - yarn_test_build:
          requires:
            - yarn_build
      - yarn_test_build_prod:
          requires:
            - yarn_build
      - yarn_lint_build:
          requires:
            - yarn_build
      - yarn_test_build_devtools:
          requires:
            - yarn_build
      - build_devtools_and_process_artifacts:
          requires:
            - yarn_build
      - build_devtools_scheduling_profiler:
          requires:
            - yarn_build
      - deploy_devtools_scheduling_profiler:
          requires:
            - build_devtools_scheduling_profiler
          filters:
            branches:
              only:
                - master

  fuzz_tests:
    triggers:
      - schedule:
          # Fuzz tests run hourly
          cron: "0 * * * *"
          filters:
            branches:
              only:
                - master
    jobs:
      - setup
      - test_fuzz:
          requires:
            - setup
