name: Build And Test

on:
  pull_request:
    branches:
      - develop
      - "feat/*"
      - "feat-*"
  merge_group:
    types: [ checks_requested ]
    branches:
      - develop
      - "feat/*"
      - "feat-*"

# to automatically cancel the running workflow for same PR.
concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true

jobs:
  run-workflow:
    name: PR Workflow
    # If any dependent jobs fails, this WF skips which won't block merging PRs
    # calling always() is required for this WF to run all the time
    if: github.repository_owner == 'aws' && always()
    runs-on: ubuntu-latest
    needs:
      - make-pr
      - validate-schema
      - integration-tests
      - smoke-and-functional-tests
      - docker-disabled
    steps:
      - name: report-failure
        if : |
          needs.make-pr.result != 'success' ||
          needs.validate-schema.result != 'success' ||
          needs.integration-tests.result != 'success' ||
          needs.smoke-and-functional-tests.result != 'success' ||
          needs.docker-disabled.result != 'success'
        run: exit 1
      - name: report-success
        run: exit 0

  make-pr:
    name: make pr / ${{ matrix.os }} / ${{ matrix.python }}
    if: github.repository_owner == 'aws'
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - macos-latest
          - ubuntu-latest
          - windows-latest
        python:
          - "3.8"
          - "3.9"
          - "3.11"
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python }}
    - run: test -f "./.github/ISSUE_TEMPLATE/Bug_report.md"  # prevent Bug_report.md from being renamed or deleted
    - run: make init
    - run: make pr

  validate-schema:
    name: Validate JSON schema
    if: github.repository_owner == 'aws'
    permissions:
      pull-requests: write
      contents: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        name: Install Python 3.11
        with:
          python-version: 3.11
      - run: make init
      - run: |
          diff <( cat schema/samcli.json ) <( python -m schema.make_schema && cat schema/samcli.json ) && \
            echo "No changes found." && \
            exit 0 # exit if schema is unchanged
          echo "The generated schema differs from that in the PR. Please run 'make schema'."
          exit 1
        name: Generate and compare the schema
        shell: bash

  integration-tests:
    name: Integ / ${{ matrix.os }} / ${{ matrix.python }} / ${{ matrix.tests_config }}
    if: github.repository_owner == 'aws'
    runs-on: ${{ matrix.os }}
    env:
      AWS_DEFAULT_REGION: us-east-1
      SAM_CLI_DEV: "1"
      CARGO_LAMBDA_VERSION: 0.17.1
      CARGO_INCREMENTAL: 0 # disable incremental compilation
      CARGO_TERM_COLOR: always # enable colors in Cargo output
      CI: true
    defaults:
      run:
        shell: bash
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
        python:
          - "3.8"
          - "3.9"
        # folders that is commented below requires credentials, no need to spare time to run them
        tests_config:
          - "-n 2 --reruns 3 tests/integration/buildcmd"
          #- "delete"
          #- "deploy"
          - "tests/integration/init"
          #- "list"
          - "tests/integration/local"
          #- "logs"
          #- "package"
          - "tests/integration/pipeline"
          #- "publish"
          - "tests/integration/root"
          - "tests/integration/scripts"
          #- "sync"
          - "tests/integration/telemetry"
          #- "traces"
          #- "validate"
          - "tests/integration/docs"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          # set last version as the one in matrix to make it default
          python-version: |
            3.7
            3.8
            3.9
            3.10
            3.11
            3.12
            ${{ matrix.python }}
      - uses: actions/setup-go@v5
        with:
          go-version: '1.19'
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: |
            8
            11
            17
            21
       # Install and configure Rust & Cargo Lambda
      - name: Install and configure Rust & Cargo Lambda
        if: ${{ matrix.os == 'ubuntu-latest' }}
        run: |
          : install rustup if needed
          if ! command -v rustup &> /dev/null ; then
            curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --default-toolchain none -y
            echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
          fi
          rustup toolchain install stable --profile minimal --no-self-update
          rustup default stable
          pip install cargo-lambda==$CARGO_LAMBDA_VERSION
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Upgrade pip in Python3.12 (Linux)
        run: |
          python3.12 -m pip install pip --upgrade 
          python3.12 -m pip install setuptools --upgrade
        if: ${{ matrix.os == 'ubuntu-latest' }}

      - name: Upgrade pip in Python3.12 (Windows)
        run: |
          py -3.12 -m pip install pip --upgrade 
          py -3.12 -m pip install setuptools --upgrade
        if: ${{ matrix.os == 'windows-latest' }}


      - name: Init samdev
        run: make init
      - name: Run integration tests for ${{ matrix.tests_config }}
        run: pytest -vv ${{ matrix.tests_config }}

  smoke-and-functional-tests:
    name: Functional & Smoke Tests / ${{ matrix.os }} / ${{ matrix.python }}
    if: github.repository_owner == 'aws'
    runs-on: ${{ matrix.os }}
    env:
      AWS_DEFAULT_REGION: us-east-1
      SAM_CLI_DEV: "1"
      CARGO_LAMBDA_VERSION: 0.17.1
    defaults:
      run:
        shell: bash
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
        python:
          - "3.8"
          - "3.9"
          - "3.11"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Init samdev
        run: make init
      - name: Run functional & smoke tests
        run: pytest -vv -n 4 tests/functional tests/smoke

  docker-disabled:
    name: Docker-disabled Tests / ${{ matrix.os }}
    if: github.repository_owner == 'aws'
    runs-on: ${{ matrix.os }}
    env:
      SAM_CLI_DEV: "1"
      CI: true
    strategy:
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          # These are the versions of Python that correspond to the supported Lambda runtimes
          python-version: |
            3.7
            3.8
            3.9
            3.10
            3.11
            3.12
      - name: Stop Docker Linux
        if: ${{ matrix.os == 'ubuntu-latest' }}
        run: |
          : sudo systemctl stop docker
          sudo systemctl stop docker.service
          sudo systemctl stop docker.socket
      - name: Stop Docker Windows
        if: ${{ matrix.os == 'windows-latest' }}
        shell: pwsh
        run: stop-service docker
      - name: Upgrade pip in Python3.12 (Linux)
        run: |
          python3.12 -m pip install pip --upgrade 
          python3.12 -m pip install setuptools --upgrade
        if: ${{ matrix.os == 'ubuntu-latest' }}
      - name: Upgrade pip in Python3.12 (Windows)
        run: |
          py -3.12 -m pip install pip --upgrade 
          py -3.12 -m pip install setuptools --upgrade
        if: ${{ matrix.os == 'windows-latest' }}
      - name: Check Docker not Running
        run: docker info
        id: run-docker-info
        continue-on-error: true
      - name: Report failure
        if: steps.run-docker-info.outcome == 'success'
        run: exit 1
      - name: Init samdev
        run: make init
      - name: Run tests without Docker
        run: pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_PythonFunctions_WithoutDocker