version: 2.1

parameters:
  browserstack-force:
    description: Whether to force browserstack usage. We have limited resources on browserstack so the pipeline might decide to skip browserstack if this parameter isn't set to true.
    type: boolean
    default: false
  react-version:
    description: The version of react to be used
    type: string
    default: stable
  workflow:
    description: The name of the workflow to run
    type: string
    default: pipeline
  with-material-ui-6:
    description: Use material-ui v6 for additional checks and tests
    type: boolean
    default: false
  with-react-version:
    description: The version of react to be used for the additional tests
    type: string
    default: stable
  e2e-base-url:
    description: The base url for running end-to-end test
    type: string
    default: ''

default-job: &default-job
  parameters:
    react-version:
      description: The version of react to be used
      type: string
      default: << pipeline.parameters.react-version >>
    e2e-base-url:
      description: The base url for running end-to-end test
      type: string
      default: << pipeline.parameters.e2e-base-url >>
  environment:
    # expose it globally otherwise we have to thread it from each job to the install command
    BROWSERSTACK_FORCE: << pipeline.parameters.browserstack-force >>
    REACT_VERSION: << parameters.react-version >>
    COREPACK_ENABLE_DOWNLOAD_PROMPT: '0'
  working_directory: /tmp/mui
  docker:
    - image: cimg/node:20.17
# CircleCI has disabled the cache across forks for security reasons.
# Following their official statement, it was a quick solution, they
# are working on providing this feature back with appropriate security measures.
# https://discuss.circleci.com/t/saving-cache-stopped-working-warning-skipping-this-step-disabled-in-configuration/24423/21
#
# restore_repo: &restore_repo
#   restore_cache:
#     key: v1-repo-{{ .Branch }}-{{ .Revision }}

default-context: &default-context
  context:
    - org-global

commands:
  install_js:
    parameters:
      browsers:
        type: boolean
        default: false
        description: 'Set to true if you intend to any browser (for example with playwright).'

    steps:
      - when:
          condition: << parameters.browsers >>
          steps:
            - run:
                name: Install pnpm package manager
                command: corepack enable
      - when:
          condition:
            not: << parameters.browsers >>
          steps:
            - run:
                name: Install pnpm package manager
                # See https://stackoverflow.com/a/73411601
                command: corepack enable --install-directory ~/bin

      - run:
          name: View install environment
          command: |
            node --version
            pnpm --version
      - run:
          name: Install js dependencies
          command: pnpm install

      - run:
          name: Resolve React version
          command: |
            pnpm use-react-version
            # log a patch for maintainers who want to check out this change
            git --no-pager diff HEAD

      - when:
          condition: << pipeline.parameters.with-material-ui-6 >>
          steps:
            - run:
                name: Install @mui/material v6
                command: pnpm use-material-ui-v6

jobs:
  checkout:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: Should not have any git not staged
          command: git add -A && git diff --exit-code --staged
      - run:
          name: '`pnpm dedupe` was run?'
          command: |
            # #default-branch-switch
            if [[ $(git diff --name-status master | grep pnpm-lock) == "" ]];
            then
                echo "No changes to dependencies detected. Skipping..."
            else
                pnpm dedupe --check
            fi
  test_unit:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: Tests fake browser
          command: pnpm test:coverage
      - run:
          name: Check coverage generated
          command: |
            if ! [[ -s coverage/lcov.info ]]
            then
              exit 1
            fi
      - run:
          name: Coverage
          command: |
            curl -Os https://uploader.codecov.io/latest/linux/codecov
            chmod +x codecov
            ./codecov -t ${CODECOV_TOKEN} -Z -F "$REACT_VERSION-jsdom"
  test_lint:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: Eslint
          command: pnpm eslint:ci
      - run:
          name: Lint JSON
          command: pnpm jsonlint
      - run:
          name: Lint Markdown
          command: pnpm markdownlint
  test_static:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: '`pnpm prettier` changes committed?'
          command: |
            # #default-branch-switch
            if [[ $(git diff --name-status master | grep pnpm-lock) == "" ]];
            then
                pnpm prettier --check
            else
                pnpm prettier:check
            fi
      - run:
          name: Generate PropTypes
          command: pnpm proptypes
          environment:
            NODE_OPTIONS: --max-old-space-size=3584
      - run:
          name: '`pnpm proptypes` changes committed?'
          command: git add -A && git diff --exit-code --staged
      - run:
          name: Generate the documentation
          command: pnpm docs:api
          environment:
            NODE_OPTIONS: --max-old-space-size=3584
      - run:
          name: '`pnpm docs:api` changes committed?'
          command: git add -A && git diff --exit-code --staged
      - run:
          name: Sync locale files
          command: pnpm l10n
      - run:
          name: '`pnpm l10n` changes committed?'
          command: git add -A && git diff --exit-code --staged
      - run:
          name: Sync RSC "use client" directives
          command: pnpm rsc:build
      - run:
          name: '`pnpm rsc:build` changes committed?'
          command: git add -A && git diff --exit-code --staged
      - run:
          name: '`pnpm docs:link-check` changes committed?'
          command: |
            pnpm docs:link-check
            git add -A && git diff --exit-code --staged
      - run:
          name: '`pnpm @mui/x-charts-vendor build` was run?'
          command: |
            # #default-branch-switch 
            if [[ $(git diff --name-status master | grep pnpm-lock) == "" ]]; 
            then
              echo "No changes to dependencies detected. Skipping..."
            else
              pnpm --filter @mui/x-charts-vendor build
              git add -A && git diff --exit-code --staged
            fi
      - run:
          name: 'No dynamic date library import in the Pickers built types?'
          command: |
            pnpm --filter @mui/x-date-pickers* prebuild
            pnpm --filter @mui/x-date-pickers* build:types
            if grep -nr 'import("luxon")\|import("dayjs")\|import("moment")' --exclude Adapter*.d.ts packages/{x-date-pickers,x-date-pickers-pro}/build
            then
                exit 1
            else
                exit 0
            fi

  test_browser:
    <<: *default-job
    docker:
      - image: mcr.microsoft.com/playwright:v1.44.1-focal
    steps:
      - checkout
      - install_js:
          browsers: true
      - run:
          name: Tests real browsers
          command: pnpm test:karma
      - store_artifacts:
          # hardcoded in karma-webpack
          path: /tmp/_karma_webpack_
          destination: artifact-file
  test_types:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: Transpile TypeScript demos
          command: pnpm docs:typescript:formatted --disable-cache
      - run:
          name: '`pnpm docs:typescript:formatted` changes committed?'
          command: git add -A && git diff --exit-code --staged docs/src docs/data
      - run:
          name: Tests TypeScript definitions
          command: pnpm typescript:ci
          environment:
            NODE_OPTIONS: --max-old-space-size=3584
  test_e2e:
    <<: *default-job
    docker:
      - image: mcr.microsoft.com/playwright:v1.44.1-focal
    steps:
      - checkout
      - install_js:
          browsers: true
      - run:
          name: Run e2e tests
          command: pnpm test:e2e
  test_e2e_website:
    <<: *default-job
    docker:
      - image: mcr.microsoft.com/playwright:v1.44.1-focal
    steps:
      - checkout
      - install_js:
          browsers: true
      - run:
          name: pnpm test:e2e-website
          command: pnpm test:e2e-website
          environment:
            PLAYWRIGHT_TEST_BASE_URL: << parameters.e2e-base-url >>
  test_regressions:
    <<: *default-job
    docker:
      - image: mcr.microsoft.com/playwright:v1.44.1-focal
    steps:
      - checkout
      - install_js:
          browsers: true
      - run:
          name: Run visual regression tests
          command: xvfb-run pnpm test:regressions
      - run:
          name: Upload screenshots to Argos CI
          command: pnpm test:argos
  run_danger:
    <<: *default-job
    steps:
      - checkout
      - install_js
      - run:
          name: Run danger on PRs
          command: pnpm danger ci --fail-on-errors
workflows:
  version: 2
  pipeline:
    when:
      equal: [pipeline, << pipeline.parameters.workflow >>]
    jobs:
      - checkout:
          <<: *default-context
      - test_unit:
          <<: *default-context
          requires:
            - checkout
      - test_lint:
          <<: *default-context
          requires:
            - checkout
      - test_static:
          <<: *default-context
          requires:
            - checkout
      - test_browser:
          <<: *default-context
          requires:
            - checkout
      - test_types:
          <<: *default-context
          requires:
            - checkout
      - test_e2e:
          <<: *default-context
          requires:
            - checkout
      - test_regressions:
          <<: *default-context
          requires:
            - checkout
      - run_danger:
          <<: *default-context
          requires:
            - checkout
  e2e-website:
    when:
      equal: [e2e-website, << pipeline.parameters.workflow >>]
    jobs:
      - checkout:
          <<: *default-context
      - test_e2e_website:
          requires:
            - checkout

  additional-tests:
    when:
      and:
        - equal: [additional, << pipeline.parameters.workflow >>]
        - or:
            - equal: [true, << pipeline.parameters.with-material-ui-6 >>]
            - not:
                equal: ['stable', << pipeline.parameters.with-react-version >>]
    jobs:
      - test_unit:
          <<: *default-context
          name: test_unit_additional
          react-version: << pipeline.parameters.with-react-version >>
      - test_browser:
          <<: *default-context
          name: test_browser_additional
          react-version: << pipeline.parameters.with-react-version >>
      - test_regressions:
          <<: *default-context
          name: test_regressions_additional
          react-version: << pipeline.parameters.with-react-version >>
      - test_e2e:
          <<: *default-context
          name: test_e2e_additional
          react-version: << pipeline.parameters.with-react-version >>

  additional-checks:
    when:
      and:
        - equal: [additional, << pipeline.parameters.workflow >>]
        - equal: [true, << pipeline.parameters.with-material-ui-6 >>]
    jobs:
      - test_types:
          <<: *default-context
          name: test_types_additional
