Build documentation

name: Build documentation

# Documentation is deployed in the following ways
# 1. Each time a commit is pushed to main branch
# 2. Nightly (so that docs are updated even when there is no commit to main branch on the day)
# 3. Manual trigger for release
#    Because release requires changing the version number, which is used as a directory name,
#    automating release doc deployment is tricky.
#    There is no reliable way to know if there should have been a minor version bump.
#
on:
  pull_request:
  push:
    branches:
      - main
  workflow_dispatch:
  schedule:
    - cron: '0 0 * * *'

jobs:
  build:
    # Do not use matrix here to parameterize Python/CUDA versions.
    # This job is required to pass for each PR.
    # The name of the required job is sensitive to matrix parameter.
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      job-name: Build doc
      runner: linux.g5.4xlarge.nvidia.gpu
      repository: pytorch/audio
      gpu-arch-type: cuda
      gpu-arch-version: "11.8"
      timeout: 120
      upload-artifact: docs

      script: |
        set -ex
        # Set up Environment Variables
        export PYTHON_VERSION="3.10"
        export CU_VERSION="11.8"
        export CUDATOOLKIT="pytorch-cuda=${CU_VERSION}"

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export CHANNEL=test
          export BUILD_VERSION="$( cut -f 1 -d a version.txt )"
        else
          export CHANNEL=nightly
          export BUILD_VERSION="$( cut -f 1 -d a version.txt )".dev"$(date "+%Y%m%d")"
        fi

        echo "::group::Create conda env"
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio
        conda create --quiet -y --prefix ci_env python="${PYTHON_VERSION}"
        conda activate ./ci_env

        echo "::endgroup::"
        echo "::group::Install PyTorch"
        conda install \
          --yes \
          --quiet \
          -c "pytorch-${CHANNEL}" \
          -c nvidia "pytorch-${CHANNEL}"::pytorch[build="*${CU_VERSION}*"] \
          "${CUDATOOLKIT}"

        echo "::endgroup::"
        echo "::group::Install TorchAudio"
        conda install --quiet --yes cmake>=3.18.0 ninja
        pip3 install --progress-bar off -v -e . --no-use-pep517

        echo "::endgroup::"
        echo "::group::Build FFmpeg"
        .github/scripts/ffmpeg/build_gpu.sh

        echo "::endgroup::"
        echo "::group::Install other dependencies"
        conda install \
          --quiet --yes \
          -c conda-forge \
          sox libvorbis pandoc doxygen pysoundfile
        pip install --progress-bar off \
            git+https://github.com/kpu/kenlm/ flashlight-text \
            -r docs/requirements.txt -r docs/requirements-tutorials.txt

        echo "::endgroup::"
        echo "::group::Build documentation"
        export BUILD_GALLERY=true
        (cd docs && make html)

        echo "::endgroup::"
        echo "::group::Copy artifact"
        cp -rf docs/build/html/* "${RUNNER_DOCS_DIR}"
        mv docs/build/html /artifacts/

  commit-main:
    if: github.ref_name == 'main'
    permissions:
      # Required for `git push`
      # Note:
      #   This is not effective from fork.
      #   When you debug this, make sure to make a branch on pytorch and
      #   make PR from there.
      contents: write
    runs-on: ubuntu-latest
    needs: build
    steps:
    - uses: actions/checkout@v3
      with:
        ref: gh-pages
        fetch-depth: 5
    - uses: actions/download-artifact@v3
      with:
        name: docs
    - name: Update main doc
      run: |
        set -x

        git config user.name "pytorchbot"
        git config user.email "soumith+bot@pytorch.org"
        # When `git clone`, `gh-pages` branch is fetched by default.
        # The size of gh-pages grows significantly, so we use ammend and force push
        # We add a new commit once a week
        if [ "$(date +%d)" = "1" ]; then
           git commit --allow-empty -m "placeholder"
        fi

        # TODO: add tag-based process (need to handle the main directory name)
        # Update the main doc
        rm -rf main
        mv html main
        git add --all main || true

        git commit --amend -m "auto-generating sphinx docs" || true
        git push -f

  # Push for release
  # Make sure that version.txt is updated first (alpha suffix is removed)
  commit-release:
    if: startsWith(github.ref_name, 'release/') && ( github.event_name == 'workflow_dispatch' )
    permissions:
      # Required for `git push`
      # Note:
      #   This is not effective from fork.
      #   When you debug this, make sure to make a branch on pytorch and
      #   make PR from there.
      contents: write
    runs-on: ubuntu-latest
    needs: build
    steps:
    - uses: actions/checkout@v3
      with:
        ref: gh-pages
        fetch-depth: 5
    - uses: actions/checkout@v4
      with:
        path: _src
    - uses: actions/download-artifact@v3
      with:
        name: docs
    - name: Update doc
      run: |
        set -x

        git config user.name "pytorchbot"
        git config user.email "soumith+bot@pytorch.org"
        # When `git clone`, `gh-pages` branch is fetched by default.
        # The size of gh-pages grows significantly, so we use ammend and force push
        # We add a new commit once a week
        if [ "$(date +%d)" = "1" ]; then
           git commit --allow-empty -m "placeholder"
        fi

        dirname="$(cat _src/version.txt)"
        rm -rf "${dirname}"
        mv html "${dirname}"
        git add --all "${dirname}" || true

        git commit --amend -m "auto-generating sphinx docs" || true
        git push -f


Build Aarch64 Linux Wheels

name: Build Aarch64 Linux Wheels

on:
    pull_request:
    push:
      branches:
        - nightly
        - main
        - release/*
      tags:
          # NOTE: Binary build pipelines should only get triggered on release candidate builds
          # Release candidate tags look like: v1.11.0-rc1
          - v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+
    workflow_dispatch:

concurrency:
    group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref_name }}-${{ github.ref_type == 'branch' && github.sha }}-${{ github.event_name == 'workflow_dispatch' }}
    cancel-in-progress: true

permissions:
  id-token: write
  contents: read

jobs:
  generate-matrix:
    uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main
    with:
      package-type: wheel
      os: linux-aarch64
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
      with-cuda: disable
  build:
    needs: generate-matrix
    strategy:
      fail-fast: false
      matrix:
        include:
          - repository: pytorch/audio
            smoke-test-script: test/smoke_test/smoke_test.py
            package-name: torchaudio
    name: ${{ matrix.repository }}
    uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@main
    with:
      repository: ${{ matrix.repository }}
      ref: ""
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
      build-matrix: ${{ needs.generate-matrix.outputs.matrix }}
      pre-script: ${{ matrix.pre-script }}
      post-script: ${{ matrix.post-script }}
      package-name: ${{ matrix.package-name }}
      smoke-test-script: ${{ matrix.smoke-test-script }}
      trigger-event: ${{ github.event_name }}
      architecture: aarch64
      setup-miniconda: false


Build Linux Wheels

name: Build Linux Wheels

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
    tags:
        # NOTE: Binary build pipelines should only get triggered on release candidate builds
        # Release candidate tags look like: v1.11.0-rc1
        - v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref_name }}-${{ github.ref_type == 'branch' && github.sha }}-${{ github.event_name == 'workflow_dispatch' }}
  cancel-in-progress: true

permissions:
  id-token: write
  contents: read

jobs:
  generate-matrix:
    uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main
    with:
      package-type: wheel
      os: linux
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
  build:
    needs: generate-matrix
    strategy:
      fail-fast: false
      matrix:
        include:
          - repository: pytorch/audio
            smoke-test-script: test/smoke_test/smoke_test_no_ffmpeg.py
            package-name: torchaudio
    name: ${{ matrix.repository }}
    uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@main
    with:
      repository: ${{ matrix.repository }}
      ref: ""
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
      build-matrix: ${{ needs.generate-matrix.outputs.matrix }}
      smoke-test-script: ${{ matrix.smoke-test-script }}
      package-name: ${{ matrix.package-name }}
      trigger-event: ${{ github.event_name }}


Build Windows Wheels

name: Build Windows Wheels

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
    tags:
        # NOTE: Binary build pipelines should only get triggered on release candidate builds
        # Release candidate tags look like: v1.11.0-rc1
        - v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  generate-matrix:
    uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main
    with:
      package-type: wheel
      os: windows
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
  build:
    needs: generate-matrix
    strategy:
      fail-fast: false
      matrix:
        include:
          - repository: pytorch/audio
            env-script: packaging/vc_env_helper.bat
            wheel-build-params: "--plat-name win_amd64"
            smoke-test-script: test/smoke_test/smoke_test_no_ffmpeg.py
            package-name: torchaudio
    name: ${{ matrix.repository }}
    uses: pytorch/test-infra/.github/workflows/build_wheels_windows.yml@main
    with:
      repository: ${{ matrix.repository }}
      ref: ""
      test-infra-repository: pytorch/test-infra
      test-infra-ref: main
      build-matrix: ${{ needs.generate-matrix.outputs.matrix }}
      env-script: ${{ matrix.env-script }}
      package-name: ${{ matrix.package-name }}
      smoke-test-script: ${{ matrix.smoke-test-script }}
      trigger-event: ${{ github.event_name }}


FFmpeg Binaries

# This job is not directly related to regular CI pipeline.
# It is intended to create FFmpeg binaries that we upload on S3,
# which then will be used during all the build process in CI or local.
#
# This job does not include uploading part.
# Upload needs to be done manually, and it should be done only once
# par new major release of FFmepg.
name: FFmpeg Binaries

on:
  workflow_dispatch:
  schedule:
    - cron: '0 0 * * 0'  # on sunday

jobs:
  LGPL-Linux-x86_64:
    strategy:
      fail-fast: false
      matrix:
        ffmpeg_version: ["4.4.4", "5.1.4", "6.1.1", "master"]
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      job-name: Build
      upload-artifact: ffmpeg-lgpl
      repository: pytorch/audio
      script: |
        export FFMPEG_VERSION="${{ matrix.ffmpeg_version }}"
        export FFMPEG_ROOT="${PWD}/ffmpeg"
        .github/scripts/ffmpeg/build.sh

        tar -cf ffmpeg.tar.gz ffmpeg/include ffmpeg/lib

        artifact_dir="${RUNNER_ARTIFACT_DIR}/$(date +%Y-%m-%d)/linux_x86_64/"
        mkdir -p "${artifact_dir}"
        mv ffmpeg.tar.gz "${artifact_dir}/${FFMPEG_VERSION}.tar.gz"

  LGPL-Linux-aarch64:
    strategy:
      fail-fast: false
      matrix:
        ffmpeg_version: ["4.4.4", "5.1.4", "6.1.1", "master"]
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      job-name: Build
      upload-artifact: ffmpeg-lgpl
      repository: pytorch/audio
      runner: linux.arm64.2xlarge
      docker-image: pytorch/manylinuxaarch64-builder:cpu-aarch64
      script: |
        export FFMPEG_VERSION="${{ matrix.ffmpeg_version }}"
        export FFMPEG_ROOT="${PWD}/ffmpeg"
        .github/scripts/ffmpeg/build.sh

        tar -cf ffmpeg.tar.gz ffmpeg/include ffmpeg/lib

        artifact_dir="${RUNNER_ARTIFACT_DIR}/$(date +%Y-%m-%d)/linux_aarch64/"
        mkdir -p "${artifact_dir}"
        mv ffmpeg.tar.gz "${artifact_dir}/${FFMPEG_VERSION}.tar.gz"

  LGPL-macOS:
    strategy:
      fail-fast: false
      matrix:
        ffmpeg_version: ["4.4.4", "5.1.4", "6.1.1", "master"]
        runner: ["macos-m1-stable", "macos-12"]
    uses: pytorch/test-infra/.github/workflows/macos_job.yml@main
    with:
      job-name: Build
      upload-artifact: ffmpeg-lgpl
      repository: pytorch/audio
      runner: "${{ matrix.runner }}"
      script: |
        export FFMPEG_VERSION="${{ matrix.ffmpeg_version }}"
        export FFMPEG_ROOT="${PWD}/ffmpeg"
        .github/scripts/ffmpeg/build.sh

        tar -cf ffmpeg.tar.gz ffmpeg/include ffmpeg/lib

        artifact_dir="${RUNNER_ARTIFACT_DIR}/$(date +%Y-%m-%d)/macos_$(uname -m)"
        mkdir -p "${artifact_dir}"
        mv ffmpeg.tar.gz "${artifact_dir}/${FFMPEG_VERSION}.tar.gz"

  LGPL-Windows:
    strategy:
      fail-fast: false
      matrix:
        ffmpeg_version: ["4.4.4", "5.1.4", "6.1.1", "master"]
    uses: pytorch/test-infra/.github/workflows/windows_job.yml@main
    with:
      job-name: Build
      upload-artifact: ffmpeg-lgpl
      repository: pytorch/audio
      script: |
        export FFMPEG_VERSION="${{ matrix.ffmpeg_version }}"
        export FFMPEG_ROOT="${PWD}/ffmpeg"
        .github/scripts/ffmpeg/build.bat

        tar -cf ffmpeg.tar.gz ffmpeg/include ffmpeg/bin

        artifact_dir="${RUNNER_ARTIFACT_DIR}/$(date +%Y-%m-%d)/windows"
        mkdir -p "${artifact_dir}"
        mv ffmpeg.tar.gz "${artifact_dir}/${FFMPEG_VERSION}.tar.gz"


Integration Test

name: Integration Test

on:
  pull_request:
    branches: [ main ]

  workflow_dispatch:

jobs:
  build:

    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix:
        python-version: [ 3.8 ]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        sudo apt install -y -qq libavfilter-dev libavdevice-dev
    - name: Install packages
      run: |
        python -m pip install --quiet --upgrade pip
        python -m pip install --quiet --pre torch -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html
        python -m pip install --quiet pytest requests cmake ninja deep-phonemizer sentencepiece flashlight-text git+https://github.com/kpu/kenlm
        python setup.py install
    - name: Run integration test
      run: |
        cd test && pytest integration_tests -v --use-tmp-hub-dir


Lint

name: Lint

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

jobs:
  python-source-and-configs:
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      repository: pytorch/audio
      script: |
        set -euo pipefail

        echo '::group::Setup environment'
        eval "$("$(which conda)" shell.bash hook)"
        # libcst does not have 3.11 pre-built binaries yet. Use python 3.10
        conda create -y --name env python=3.10
        conda activate env
        pip3 install --progress-bar=off pre-commit
        echo '::endgroup::'

        set +e
        pre-commit run --all-files --show-diff-on-failure
        status=$?

        echo '::group::Add Summry'
        if [ $status -ne 0 ]; then
          echo '### Lint failure'  >> $GITHUB_STEP_SUMMARY
          echo '```diff'           >> $GITHUB_STEP_SUMMARY
          git --no-pager diff      >> $GITHUB_STEP_SUMMARY
          echo '```'               >> $GITHUB_STEP_SUMMARY
        fi
        echo '::endgroup::'
        exit $status


pr-labels

name: pr-labels

on:
  push:
    branches:
      - main

jobs:
  is-properly-labeled:
    runs-on: ubuntu-latest

    steps:
      - name: Set up python
        uses: actions/setup-python@v2

      - name: Install requests
        run: pip install requests

      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Process commit and find merger responsible for labeling
        id: commit
        env:
          SHA1: ${{ github.sha }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: python .github/process_commit.py "${SHA1}"

concurrency:
  group: pr-labels-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}
  cancel-in-progress: true


Unit-tests on Linux CPU

name: Unit-tests on Linux CPU

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

jobs:
  tests:
    strategy:
      matrix:
        python_version: ["3.8", "3.9", "3.10"]
      fail-fast: false
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      runner: linux.12xlarge
      repository: pytorch/audio
      timeout: 120
      script: |
        echo '::group::Setup Environment Variables'
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio

        # Set up Environment Variables
        export PYTHON_VERSION="${{ matrix.python_version }}"
        export CUDA_TESTS_ONLY="0"
        unset CUDA_VERSION

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export UPLOAD_CHANNEL=test
        else
          export UPLOAD_CHANNEL=nightly
        fi

        export PATH="${PWD}/third_party/install/bin/:${PATH}"
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_APPLY_CMVN_SLIDING=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_FBANK_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_KALDI_PITCH_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_MFCC_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_SPECTROGRAM_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_KALDI=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CUDA=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_HW_ACCEL=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MACOS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_TEMPORARY_DISABLED=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_DECODER=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_ENCODER=true
        echo '::endgroup::'

        set -euxo pipefail

        echo '::group::Install PyTorch and Torchaudio'
        ./.github/scripts/unittest-linux/install.sh
        echo '::endgroup::'

        echo '::group::Run Tests'
        ./.github/scripts/unittest-linux/run_test.sh
        echo '::endgroup::'


Unit-tests on Linux GPU

name: Unit-tests on Linux GPU

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

jobs:
  tests:
    strategy:
      matrix:
        python_version: ["3.8", "3.9", "3.10"]
        cuda_arch_version: ["11.8"]
      fail-fast: false
    uses: pytorch/test-infra/.github/workflows/linux_job.yml@main
    with:
      runner: linux.g5.4xlarge.nvidia.gpu
      repository: pytorch/audio
      gpu-arch-type: cuda
      gpu-arch-version: ${{ matrix.cuda_arch_version }}
      timeout: 120

      script: |
        set -ex
        # Set up Environment Variables
        export PYTHON_VERSION="${{ matrix.python_version }}"
        export CU_VERSION="${{ matrix.cuda_arch_version }}"
        export CUDATOOLKIT="pytorch-cuda=${CU_VERSION}"
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_APPLY_CMVN_SLIDING=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_FBANK_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_KALDI_PITCH_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_MFCC_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_SPECTROGRAM_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_CUDA_SMALL_MEMORY=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_TEMPORARY_DISABLED=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_DECODER=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_ENCODER=true

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export CHANNEL=test
        else
          export CHANNEL=nightly
        fi

        echo "::group::Create conda env"
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio
        conda create --quiet -y --prefix ci_env python="${PYTHON_VERSION}"
        conda activate ./ci_env

        echo "::endgroup::"
        echo "::group::Install PyTorch"
        conda install \
          --yes \
          --quiet \
          -c "pytorch-${CHANNEL}" \
          -c nvidia "pytorch-${CHANNEL}"::pytorch[build="*${CU_VERSION}*"] \
          "${CUDATOOLKIT}"

        echo "::endgroup::"
        echo "::group::Install TorchAudio"
        conda install --quiet --yes 'cmake>=3.18.0' ninja
        pip3 install --progress-bar off -v -e . --no-use-pep517

        echo "::endgroup::"
        echo "::group::Build FFmpeg"
        .github/scripts/ffmpeg/build_gpu.sh

        echo "::endgroup::"
        echo "::group::Install other Dependencies"
        conda install \
          --quiet --yes \
          -c conda-forge \
          -c numba/label/dev \
          sox libvorbis 'librosa==0.10.0' parameterized 'requests>=2.20'
        pip3 install --progress-bar off \
          kaldi-io \
          SoundFile \
          coverage \
          pytest \
          pytest-cov \
          'scipy==1.7.3' \
          transformers \
          expecttest \
          unidecode \
          inflect \
          Pillow \
          sentencepiece \
          pytorch-lightning \
          'protobuf<4.21.0' \
          demucs \
          tinytag \
          flashlight-text \
          git+https://github.com/kpu/kenlm/ \
          git+https://github.com/pytorch/fairseq.git@e47a4c8

        echo "::endgroup::"
        echo "::group::Run tests"
        export PATH="${PWD}/third_party/install/bin/:${PATH}"

        declare -a args=(
            '-v'
            '--cov=torchaudio'
            "--junitxml=${RUNNER_TEST_RESULTS_DIR}/junit.xml"
            '--durations' '100'
            '-k' 'cuda or gpu'
        )

        cd test
        python3 -m torch.utils.collect_env
        env | grep TORCHAUDIO || true
        pytest "${args[@]}" torchaudio_unittest
        coverage html


Unit-tests on Macos CPU

name: Unit-tests on Macos CPU

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

env:
  CHANNEL: "nightly"

jobs:
  tests:
    uses: pytorch/test-infra/.github/workflows/macos_job.yml@main
    with:
      runner: macos-12
      repository: pytorch/audio
      timeout: 180
      script: |
        echo '::group::Setup Environment Variables'
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio

        # Set up Environment Variables
        export PYTHON_VERSION="3.8"
        export CU_VERSION=""
        export CUDATOOLKIT=""
        export USE_OPENMP="0"

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export UPLOAD_CHANNEL=test
        else
          export UPLOAD_CHANNEL=nightly
        fi

        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_APPLY_CMVN_SLIDING=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_FBANK_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_KALDI_PITCH_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_MFCC_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_SPECTROGRAM_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CUDA=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_HW_ACCEL=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_QUANTIZATION=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MOD_sentencepiece=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_TEMPORARY_DISABLED=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_DECODER=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_ENCODER=true
        echo '::endgroup::'

        set -euxo pipefail

        echo '::group::Install PyTorch and Torchaudio'
        ./.github/scripts/unittest-linux/install.sh
        echo '::endgroup::'

        echo '::group::Run Tests'
        ./.github/scripts/unittest-linux/run_test.sh
        echo '::endgroup::'


Unittests on Windows CPU

name: Unittests on Windows CPU

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

jobs:
  unittests-windows-cpu:
    uses: pytorch/test-infra/.github/workflows/windows_job.yml@main
    with:
      repository: pytorch/audio
      runner: windows.4xlarge
      timeout: 180
      script: |
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio

        # Set up Environment Variables
        export PYTHON_VERSION="3.8"
        unset CUDA_VERSION

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export UPLOAD_CHANNEL=test
        else
          export UPLOAD_CHANNEL=nightly
        fi

        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_APPLY_CMVN_SLIDING=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_FBANK_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_KALDI_PITCH_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_MFCC_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_SPECTROGRAM_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_SOX=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CUDA=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_HW_ACCEL=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_KALDI=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MOD_sentencepiece=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MACOS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_TEMPORARY_DISABLED=true

        .github/scripts/unittest-windows/setup_env.sh
        .github/scripts/unittest-windows/install.sh
        .github/scripts/unittest-windows/run_test.sh


Unittests on Windows GPU

name: Unittests on Windows GPU

on:
  pull_request:
  push:
    branches:
      - nightly
      - main
      - release/*
  workflow_dispatch:

jobs:
  unittests-windows-gpu:
    uses: pytorch/test-infra/.github/workflows/windows_job.yml@main
    with:
      repository: pytorch/audio
      runner: windows.g5.4xlarge.nvidia.gpu
      timeout: 360
      script: |
        # Mark Build Directory Safe
        git config --global --add safe.directory /__w/audio/audio

        # Set up Environment Variables
        export PYTHON_VERSION="3.8"
        export CUDA_VERSION=11.8

        # Set CHANNEL
        if [[(${GITHUB_EVENT_NAME} = 'pull_request' && (${GITHUB_BASE_REF} = 'release'*)) || (${GITHUB_REF} = 'refs/heads/release'*) ]]; then
          export UPLOAD_CHANNEL=test
        else
          export UPLOAD_CHANNEL=nightly
        fi

        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_APPLY_CMVN_SLIDING=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_FBANK_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_KALDI_PITCH_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_MFCC_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_COMPUTE_SPECTROGRAM_FEATS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_CMD_SOX=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_KALDI=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MOD_sentencepiece=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MACOS=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_CUDA_SMALL_MEMORY=true
        export TORCHAUDIO_TEST_ALLOW_SKIP_IF_TEMPORARY_DISABLED=true

        .github/scripts/unittest-windows/setup_env.sh
        ./packaging/windows/internal/cuda_install.bat
        ./packaging/windows/internal/driver_update.bat

        .github/scripts/unittest-windows/install.sh
        .github/scripts/unittest-windows/run_test.sh


Kodi Addon-Check

name: Kodi Addon-Check
on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master
jobs:
  kodi-addon-checker:
    runs-on: ubuntu-latest
    name: Kodi addon checker
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Kodi addon checker validation
      id: kodi-addon-checker
      uses: xbmc/action-kodi-addon-checker@master
      with:
        kodi-version: matrix
        addon-id: ${{ github.event.repository.name }}


CI

name: CI
on: [push, pull_request]
jobs:
  tests:
    name: Add-on testing
    runs-on: ubuntu-latest
    env:
      PYTHONIOENCODING: utf-8
      PYTHONPATH: ${{ github.workspace }}/resources/lib:${{ github.workspace }}/tests
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.7', '3.8', '3.9', '3.10']
    steps:
    - name: Check out ${{ github.sha }} from repository ${{ github.repository }}
      uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v1
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Run tox
      run: python -m tox -q -e flake8,py
      if: always()
    - name: Run pylint
      run: python -m pylint resources/lib/ tests/
      if: always()
    - name: Analyze with SonarCloud
      uses: SonarSource/sonarcloud-github-action@v1.4
      with:
        args: >
          -Dsonar.organization=add-ons
          -Dsonar.projectKey=add-ons_plugin.video.netflix
          -Dsonar.python.version=3.7,3.8,3.9,3.10
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
      continue-on-error: true


Release

name: Release
on:
  push:
    tags:
    - 'v*'
jobs:
  build:
    if: github.event.base_ref == 'refs/heads/master'
    name: Publish release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Build zip files
        run: |
          sudo apt-get update
          sudo apt-get install libxml2-utils
          make build release=1
      - name: Get zip filename
        id: get-zip-filename
        run: |
          echo ::set-output name=zip-filename::$(cd ..;ls plugin.video.netflix*.zip | head -1)
      - name: Get body
        id: get-body
        run: |
          description=$(sed '/v[0-9\.]*\s([0-9-]*)/d;/^$/,$d' changelog.txt)
          echo $description
          description="${description//'%'/'%25'}"
          description="${description//$'\n'/'%0A'}"
          description="${description//$'\r'/'%0D'}"
          echo ::set-output name=body::$description
      - name: Create GitHub Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
          body: ${{ steps.get-body.outputs.body }}
          draft: false
          prerelease: false
      - name: Upload zip file
        id: upload-zip
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_name: ${{ steps.get-zip-filename.outputs.zip-filename }}
          asset_path: ../${{ steps.get-zip-filename.outputs.zip-filename }}
          asset_content_type: application/zip


Translations

name: Translations
on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master
jobs:
  tests:
    name: Check translations
    runs-on: ubuntu-latest
    env:
      PYTHONIOENCODING: utf-8
    strategy:
      fail-fast: false
      matrix:
        kodi-branch: [matrix]
    steps:
    - uses: actions/checkout@v2
      with:
        path: ${{ github.repository }}
    - name: Set up Python 3.8
      uses: actions/setup-python@v1
      with:
        python-version: 3.8
    - name: Install dependencies
      run: |
        sudo apt-get install gettext
    - name: Checking language translations
      run: make check-translations
      working-directory: ${{ github.repository }}


CI

name: CI

on:
  workflow_dispatch:
  push:
    branches:
      - dev
      - master

# only run the latest commit to avoid cache overwrites
concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true

env:
  PYTHON_VERSION: 3.9

jobs:
  amd64_build:
    runs-on: ubuntu-latest
    name: AMD64 Build
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - name: Set up QEMU and Buildx
        id: setup
        uses: ./.github/actions/setup
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push amd64 standard build
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/main/Dockerfile
          push: true
          platforms: linux/amd64
          target: frigate
          tags: ${{ steps.setup.outputs.image-name }}-amd64
          cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
  arm64_build:
    runs-on: ubuntu-latest
    name: ARM Build
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - name: Set up QEMU and Buildx
        id: setup
        uses: ./.github/actions/setup
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push arm64 standard build
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/main/Dockerfile
          push: true
          platforms: linux/arm64
          target: frigate
          tags: |
            ${{ steps.setup.outputs.image-name }}-standard-arm64
          cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
      - name: Build and push RPi build
        uses: docker/bake-action@v4
        with:
          push: true
          targets: rpi
          files: docker/rpi/rpi.hcl
          set: |
            rpi.tags=${{ steps.setup.outputs.image-name }}-rpi
            *.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
            *.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64,mode=max
      - name: Build and push Rockchip build
        uses: docker/bake-action@v3
        with:
          push: true
          targets: rk
          files: docker/rockchip/rk.hcl
          set: |
            rk.tags=${{ steps.setup.outputs.image-name }}-rk
            *.cache-from=type=gha
  jetson_jp4_build:
    runs-on: ubuntu-latest
    name: Jetson Jetpack 4
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - name: Set up QEMU and Buildx
        id: setup
        uses: ./.github/actions/setup
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push TensorRT (Jetson, Jetpack 4)
        env:
          ARCH: arm64
          BASE_IMAGE: timongentzsch/l4t-ubuntu20-opencv:latest
          SLIM_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
          TRT_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
        uses: docker/bake-action@v4
        with:
          push: true
          targets: tensorrt
          files: docker/tensorrt/trt.hcl
          set: |
            tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt-jp4
            *.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4
            *.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4,mode=max
  jetson_jp5_build:
    runs-on: ubuntu-latest
    name: Jetson Jetpack 5
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - name: Set up QEMU and Buildx
        id: setup
        uses: ./.github/actions/setup
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push TensorRT (Jetson, Jetpack 5)
        env:
          ARCH: arm64
          BASE_IMAGE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
          SLIM_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
          TRT_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
        uses: docker/bake-action@v4
        with:
          push: true
          targets: tensorrt
          files: docker/tensorrt/trt.hcl
          set: |
            tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt-jp5
            *.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5
            *.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5,mode=max
  amd64_extra_builds:
    runs-on: ubuntu-latest
    name: AMD64 Extra Build
    needs:
      - amd64_build
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - name: Set up QEMU and Buildx
        id: setup
        uses: ./.github/actions/setup
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push TensorRT (x86 GPU)
        env:
          COMPUTE_LEVEL: "50 60 70 80 90"
        uses: docker/bake-action@v4
        with:
          push: true
          targets: tensorrt
          files: docker/tensorrt/trt.hcl
          set: |
            tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt
            *.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
            *.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64,mode=max
      #- name: AMD/ROCm general build
      #  env:
      #    AMDGPU: gfx
      #    HSA_OVERRIDE: 0
      #  uses: docker/bake-action@v3
      #  with:
      #    push: true
      #    targets: rocm
      #    files: docker/rocm/rocm.hcl
      #    set: |
      #      rocm.tags=${{ steps.setup.outputs.image-name }}-rocm
      #      *.cache-from=type=gha
      #- name: AMD/ROCm gfx900
      #  env:
      #    AMDGPU: gfx900
      #    HSA_OVERRIDE: 1
      #    HSA_OVERRIDE_GFX_VERSION: 9.0.0
      #  uses: docker/bake-action@v3
      #  with:
      #    push: true
      #    targets: rocm
      #    files: docker/rocm/rocm.hcl
      #    set: |
      #      rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx900
      #      *.cache-from=type=gha
      #- name: AMD/ROCm gfx1030
      #  env:
      #    AMDGPU: gfx1030
      #    HSA_OVERRIDE: 1
      #    HSA_OVERRIDE_GFX_VERSION: 10.3.0
      #  uses: docker/bake-action@v3
      #  with:
      #    push: true
      #    targets: rocm
      #    files: docker/rocm/rocm.hcl
      #    set: |
      #      rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx1030
      #      *.cache-from=type=gha
      #- name: AMD/ROCm gfx1100
      #  env:
      #    AMDGPU: gfx1100
      #    HSA_OVERRIDE: 1
      #    HSA_OVERRIDE_GFX_VERSION: 11.0.0
      #  uses: docker/bake-action@v3
      #  with:
      #    push: true
      #    targets: rocm
      #    files: docker/rocm/rocm.hcl
      #    set: |
      #      rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx1100
      #      *.cache-from=type=gha
  # The majority of users running arm64 are rpi users, so the rpi
  # build should be the primary arm64 image
  assemble_default_build:
    runs-on: ubuntu-latest
    name: Assemble and push default build
    needs:
      - amd64_build
      - arm64_build
    steps:
      - id: lowercaseRepo
        uses: ASzc/change-string-case-action@v6
        with:
          string: ${{ github.repository }}
      - name: Log in to the Container registry
        uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Create short sha
        run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
      - uses: int128/docker-manifest-create-action@v2
        with:
          tags: ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}
          sources: |
            ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}-amd64
            ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}-rpi


dependabot-auto-merge

name: dependabot-auto-merge
on: pull_request

permissions:
  contents: write

jobs:
  dependabot-auto-merge:
    runs-on: ubuntu-latest
    if: github.actor == 'dependabot[bot]'
    steps:
      - name: Get Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Enable auto-merge for Dependabot PRs
        if: steps.metadata.outputs.dependency-type == 'direct:development' && (steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch')
        run: |
          gh pr review --approve "$PR_URL"
          gh pr merge --auto --squash "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


On pull request

name: On pull request

on: pull_request

env:
  DEFAULT_PYTHON: 3.9

jobs:
  build_devcontainer:
    runs-on: ubuntu-latest
    name: Build Devcontainer
    # The Dockerfile contains features that requires buildkit, and since the
    # devcontainer cli uses docker-compose to build the image, the only way to
    # ensure docker-compose uses buildkit is to explicitly enable it.
    env:
      DOCKER_BUILDKIT: "1"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@master
        with:
          node-version: 16.x
      - name: Install devcontainer cli
        run: npm install --global @devcontainers/cli
      - name: Build devcontainer
        run: devcontainer build --workspace-folder .
      # It would be nice to also test the following commands, but for some
      # reason they don't work even though in VS Code devcontainer works.
      # - name: Start devcontainer
      #   run: devcontainer up --workspace-folder .
      # - name: Run devcontainer scripts
      #   run: devcontainer run-user-commands --workspace-folder .

  web_lint:
    name: Web - Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@master
        with:
          node-version: 16.x
      - run: npm install
        working-directory: ./web
      - name: Lint
        run: npm run lint
        working-directory: ./web

  web_test:
    name: Web - Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@master
        with:
          node-version: 20.x
      - run: npm install
        working-directory: ./web
      # - name: Test
      #   run: npm run test
      #   working-directory: ./web

  python_checks:
    runs-on: ubuntu-latest
    name: Python Checks
    steps:
      - name: Check out the repository
        uses: actions/checkout@v4
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        uses: actions/setup-python@v5.1.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
      - name: Install requirements
        run: |
          python3 -m pip install -U pip
          python3 -m pip install -r docker/main/requirements-dev.txt
      - name: Check formatting
        run: |
          ruff format --check --diff frigate migrations docker *.py
      - name: Check lint
        run: |
          ruff check frigate migrations docker *.py

  python_tests:
    runs-on: ubuntu-latest
    name: Python Tests
    steps:
      - name: Check out code
        uses: actions/checkout@v4
      - uses: actions/setup-node@master
        with:
          node-version: 16.x
      - run: npm install
        working-directory: ./web
      - name: Build web
        run: npm run build
        working-directory: ./web
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Build
        run: make
      - name: Run mypy
        run: docker run --rm --entrypoint=python3 frigate:latest -u -m mypy --config-file frigate/mypy.ini frigate
      - name: Run tests
        run: docker run --rm --entrypoint=python3 frigate:latest -u -m unittest


On release

name: On release

on:
  workflow_dispatch:
  release:
    types: [published]

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - id: lowercaseRepo
        uses: ASzc/change-string-case-action@v6
        with:
          string: ${{ github.repository }}
      - name: Log in to the Container registry
        uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Create tag variables
        run: |
          BRANCH=$([[ "${{ github.ref_name }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && echo "master" || echo "dev")
          echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
          echo "BASE=ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}" >> $GITHUB_ENV
          echo "BUILD_TAG=${BRANCH}-${GITHUB_SHA::7}" >> $GITHUB_ENV
          echo "CLEAN_VERSION=$(echo ${GITHUB_REF##*/} | tr '[:upper:]' '[:lower:]' | sed 's/^[v]//')" >> $GITHUB_ENV
      - name: Tag and push the main image
        run: |
          VERSION_TAG=${BASE}:${CLEAN_VERSION}
          STABLE_TAG=${BASE}:stable
          PULL_TAG=${BASE}:${BUILD_TAG}
          docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG} docker://${VERSION_TAG}
          for variant in standard-arm64 tensorrt tensorrt-jp4 tensorrt-jp5 rk; do
            docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG}-${variant} docker://${VERSION_TAG}-${variant}
          done

          # stable tag
          if [[ "${BRANCH}" == "master" ]]; then
            docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG} docker://${STABLE_TAG}
            for variant in standard-arm64 tensorrt tensorrt-jp4 tensorrt-jp5 rk; do
              docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG}-${variant} docker://${STABLE_TAG}-${variant}
            done
          fi


Stalebot

# Close Stale Issues
# Warns and then closes issues and PRs that have had no activity for a specified amount of time.
# https://github.com/actions/stale

name: "Stalebot"
on:
  schedule:
    - cron: "0 0 * * *" # run stalebot once a day

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@main
        id: stale
        with:
          stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
          close-issue-message: ""
          days-before-stale: 30
          days-before-close: 3
          exempt-draft-pr: true
          exempt-issue-labels: "pinned,security"
          exempt-pr-labels: "pinned,security,dependencies"
          operations-per-run: 120
      - name: Print outputs
        run: echo ${{ join(steps.stale.outputs.*, ',') }}

  clean_ghcr:
    name: Delete outdated dev container images
    runs-on: ubuntu-latest
    steps:
      - name: Delete old images
        uses: snok/container-retention-policy@v2
        with:
          image-names: dev-*
          cut-off: 60 days ago UTC
          keep-at-least: 5
          account-type: personal
          token: ${{ secrets.GITHUB_TOKEN }}
          token-type: github-token


Build

name: Build
on:
  push:
    branches-ignore:
      - data
      - gh-pages
    tags:
      - '**'
  pull_request:
    branches-ignore:
      - data
      - gh-pages
  workflow_dispatch:

jobs:

  # Build job. Builds source distribution (sdist) and binary wheels distribution (bdist_wheel)
  build:
    name: Build ${{ matrix.dist }} [${{ matrix.python-version }} | ${{ matrix.os }} ${{ matrix.architecture }}]
    strategy:
      fail-fast: false
      matrix:
        # os: [ubuntu-latest, macos-latest, windows-latest] # Build wheels on different systems
        # python-version: [3.6, 3.7]
        # architecture: [x64]
        # dist: [bdist_wheel]
        include:
          - os: ubuntu-latest # Modify one element to build source distribution
            python-version: '3.10'
            architecture: x64
            dist: sdist bdist_wheel
    runs-on: ${{ matrix.os }}
    env:
      PYTHONUNBUFFERED: 1

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
        architecture: ${{ matrix.architecture }}

    - name: Build
      run: |
        python -m pip install --upgrade pip
        python -m pip install --upgrade setuptools wheel
        python setup.py ${{ matrix.dist }}

    - name: Upload artifacts
      uses: actions/upload-artifact@v2
      with:
        name: dist
        path: dist

  # Deploy job. Uploads distribution to PyPI (only on tags)
  deploy:
    name: Publish to PyPI
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
    env:
      PYTHONUNBUFFERED: 1

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Download artifacts
      uses: actions/download-artifact@v2
      with:
        name: dist
        path: dist

    - name: Publish to PyPI
      uses: pypa/gh-action-pypi-publish@v1.5.0
      with:
        user: __token__
        password: ${{ secrets.PYPI_TOKEN }}
        packages_dir: dist/


Lint

name: Lint
on:
  push:
    branches-ignore:
      - data
      - gh-pages
    tags:
      - '**'
  pull_request:
    branches-ignore:
      - data
      - gh-pages
  workflow_dispatch:

jobs:

  # Lint job. Runs pre-commit, fails if there are changed files
  lint:
    name: Check pre-commit [${{ matrix.python-version }} | ${{ matrix.os }} ${{ matrix.architecture }}]
    strategy:
      fail-fast: true
      matrix:
        os: [ubuntu-latest]
        python-version: ['3.10']
        architecture: [x64]
    runs-on: ${{ matrix.os }}
    env:
      PYTHONUNBUFFERED: 1

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
        architecture: ${{ matrix.architecture }}

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install --upgrade setuptools wheel
        python -m pip install --upgrade pre-commit

    - name: Check pre-commit
      run: pre-commit run --all-files


Release

name: Release
on:
  push:
    branches-ignore:
      - data
      - gh-pages
    tags:
      - '**'
  pull_request:
    branches-ignore:
      - data
      - gh-pages
  workflow_dispatch:
    inputs:
      version:
        description: New version in format n.n.n (1.111.11)
        required: true
      next_version:
        description: Next development version in format n.n.n.devn (1.111.11.dev0). USE ONLY FOR MAJOR DEVELOPMENT VERSIONS (2.0.0.dev0). DON'T WRITE ANYTHING HERE
        required: false

jobs:

  # Release job. Runs make_release.py tool. Pushes changes only on dispatch_event
  release:
    name: Release
    runs-on: ubuntu-latest
    env:
      PYTHONUNBUFFERED: 1

    steps:
    - name: Checkout
      uses: actions/checkout@v2
      with:
        fetch-depth: 0
        persist-credentials: ${{ github.event_name != 'workflow_dispatch' }}  # Allow using PAT when making release

    - name: Set up Python 3.10
      uses: actions/setup-python@v2
      with:
        python-version: '3.10'
        architecture: x64

    - name: Set up environment
      run: |
        git config user.name "KivyMD Bot"
        git config user.email 69076719+KivyMD-Bot@users.noreply.github.com
        pip install -e .
        pip install pre-commit

    - name: Release
      if: github.event_name == 'workflow_dispatch'
      run: |
        # Use personal token to push (when using GITHUB_TOKEN, it will not run workflows)
        git remote set-url origin https://KivyMD-Bot:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}
        python kivymd/tools/release/make_release.py release "${{ github.event.inputs.version }}" "${{ github.event.inputs.next_version }}" --yes --push

    - name: Release preparation
      if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.event_name != 'workflow_dispatch'
      run: |
        # Use personal token to push
        git remote set-url origin https://KivyMD-Bot:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}
        python kivymd/tools/release/make_release.py prepare --yes --push
        git format-patch origin/master... --stdout

    - name: Release test
      if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/master' && github.event_name != 'workflow_dispatch')
      run: |
        python kivymd/tools/release/make_release.py test --yes
        git format-patch origin/master... --stdout
        git format-patch origin/master... --stdout > release_test.patch


Test

name: Test
on:
  push:
    branches-ignore:
      - data
      - gh-pages
    tags:
      - '**'
  pull_request:
    branches-ignore:
      - data
      - gh-pages
  workflow_dispatch:

jobs:

  # Test job. Runs pytest on Ubuntu, MacOS and Windows, uploads coverage report
  test:
    name: Test [${{ matrix.python-version }} | Kivy ${{ matrix.kivy-version }} | ${{ matrix.os }} ${{ matrix.architecture }}]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ['3.10']
        architecture: [x64]
        kivy-version: [2.1.0]
        include:
          - os: windows-latest
            python-version: '3.10'
            architecture: x86
            kivy-version: 2.1.0
    runs-on: ${{ matrix.os }}
    env:
      PYTHONUNBUFFERED: 1

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
        architecture: ${{ matrix.architecture }}

    - name: Cache MacOS deps
      uses: actions/cache@v2
      if: startswith(matrix.os, 'macos')
      with:
        path: macos-cache
        key: ${{ runner.OS }}-deps-${{ hashFiles('.ci/macos_versions.sh') }}

    - name: Cache MacOS gst-devel deps
      uses: actions/cache@v2
      if: startswith(matrix.os, 'macos')
      with:
        path: macos-cache-gst-devel
        key: gst-devel-${{ runner.OS }}-deps-gst-devel-${{ hashFiles('.ci/macos_versions.sh') }}

    - name: Install dependencies for Ubuntu
      if: startswith(matrix.os, 'ubuntu')
      env:
        KIVY_VERSION: ${{ matrix.kivy-version }}
      run: .ci/ubuntu_dependencies.sh

    - name: Install dependencies for MacOS
      if: startswith(matrix.os, 'macos')
      env:
        KIVY_VERSION: ${{ matrix.kivy-version }}
      run: .ci/macos_dependencies.sh

    - name: Install dependencies for Windows
      if: startswith(matrix.os, 'windows')
      env:
        KIVY_VERSION: ${{ matrix.kivy-version }}
      run: .ci\windows_dependencies.ps1

    - name: Install KivyMD
      run: python -m pip install -e .

    - name: Test
      run: python -m pytest kivymd/tests --timeout=300 --cov=kivymd --cov-report=term

    - name: Test packaging with PyInstaller
      run: python -m PyInstaller.utils.run_tests --include_only kivymd.

    # Only from Ubuntu
    - name: Upload coverage report
      if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'kivymd/KivyMD' && startswith(matrix.os, 'ubuntu')
      continue-on-error: true
      env:
        COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
      run: python -m coveralls


Build supervisor

name: Build supervisor

on:
  workflow_dispatch:
    inputs:
      channel:
        description: "Channel"
        required: true
        default: "dev"
      version:
        description: "Version"
        required: true
      publish:
        description: "Publish"
        required: true
        default: "false"
      stable:
        description: "Stable"
        required: true
        default: "false"
  pull_request:
    branches: ["main"]
  release:
    types: ["published"]
  push:
    branches: ["main"]
    paths:
      - "rootfs/**"
      - "supervisor/**"
      - build.yaml
      - Dockerfile
      - requirements.txt
      - setup.py

env:
  DEFAULT_PYTHON: "3.12"
  BUILD_NAME: supervisor
  BUILD_TYPE: supervisor

concurrency:
  group: "${{ github.workflow }}-${{ github.ref }}"
  cancel-in-progress: true

jobs:
  init:
    name: Initialize build
    runs-on: ubuntu-latest
    outputs:
      architectures: ${{ steps.info.outputs.architectures }}
      version: ${{ steps.version.outputs.version }}
      channel: ${{ steps.version.outputs.channel }}
      publish: ${{ steps.version.outputs.publish }}
      requirements: ${{ steps.requirements.outputs.changed }}
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v4.1.7
        with:
          fetch-depth: 0

      - name: Get information
        id: info
        uses: home-assistant/actions/helpers/info@master

      - name: Get version
        id: version
        uses: home-assistant/actions/helpers/version@master
        with:
          type: ${{ env.BUILD_TYPE }}

      - name: Get changed files
        id: changed_files
        if: steps.version.outputs.publish == 'false'
        uses: masesgroup/retrieve-changed-files@v3.0.0

      - name: Check if requirements files changed
        id: requirements
        run: |
          if [[ "${{ steps.changed_files.outputs.all }}" =~ (requirements.txt|build.yaml) ]]; then
            echo "changed=true" >> "$GITHUB_OUTPUT"
          fi

  build:
    name: Build ${{ matrix.arch }} supervisor
    needs: init
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
      packages: write
    strategy:
      matrix:
        arch: ${{ fromJson(needs.init.outputs.architectures) }}
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v4.1.7
        with:
          fetch-depth: 0

      - name: Write env-file
        if: needs.init.outputs.requirements == 'true'
        run: |
          (
            # Fix out of memory issues with rust
            echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
          ) > .env_file

      - name: Build wheels
        if: needs.init.outputs.requirements == 'true'
        uses: home-assistant/wheels@2024.01.0
        with:
          abi: cp312
          tag: musllinux_1_2
          arch: ${{ matrix.arch }}
          wheels-key: ${{ secrets.WHEELS_KEY }}
          apk: "libffi-dev;openssl-dev;yaml-dev"
          skip-binary: aiohttp
          env-file: true
          requirements: "requirements.txt"

      - name: Set version
        if: needs.init.outputs.publish == 'true'
        uses: home-assistant/actions/helpers/version@master
        with:
          type: ${{ env.BUILD_TYPE }}

      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        if: needs.init.outputs.publish == 'true'
        uses: actions/setup-python@v5.1.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}

      - name: Install Cosign
        if: needs.init.outputs.publish == 'true'
        uses: sigstore/cosign-installer@v3.5.0
        with:
          cosign-release: "v2.2.3"

      - name: Install dirhash and calc hash
        if: needs.init.outputs.publish == 'true'
        run: |
          pip3 install setuptools dirhash
          dir_hash="$(dirhash "${{ github.workspace }}/supervisor" -a sha256 --match "*.py")"
          echo "${dir_hash}" > rootfs/supervisor.sha256

      - name: Sign supervisor SHA256
        if: needs.init.outputs.publish == 'true'
        run: |
          cosign sign-blob --yes rootfs/supervisor.sha256 --bundle rootfs/supervisor.sha256.sig

      - name: Login to GitHub Container Registry
        if: needs.init.outputs.publish == 'true'
        uses: docker/login-action@v3.2.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set build arguments
        if: needs.init.outputs.publish == 'false'
        run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV

      - name: Build supervisor
        uses: home-assistant/builder@2024.03.5
        with:
          args: |
            $BUILD_ARGS \
            --${{ matrix.arch }} \
            --target /data \
            --cosign \
            --generic ${{ needs.init.outputs.version }}
        env:
          CAS_API_KEY: ${{ secrets.CAS_TOKEN }}

  version:
    name: Update version
    needs: ["init", "run_supervisor"]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        if: needs.init.outputs.publish == 'true'
        uses: actions/checkout@v4.1.7

      - name: Initialize git
        if: needs.init.outputs.publish == 'true'
        uses: home-assistant/actions/helpers/git-init@master
        with:
          name: ${{ secrets.GIT_NAME }}
          email: ${{ secrets.GIT_EMAIL }}
          token: ${{ secrets.GIT_TOKEN }}

      - name: Update version file
        if: needs.init.outputs.publish == 'true'
        uses: home-assistant/actions/helpers/version-push@master
        with:
          key: ${{ env.BUILD_NAME }}
          version: ${{ needs.init.outputs.version }}
          channel: ${{ needs.init.outputs.channel }}

  run_supervisor:
    runs-on: ubuntu-latest
    name: Run the Supervisor
    needs: ["build", "init"]
    timeout-minutes: 60
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v4.1.7

      - name: Build the Supervisor
        if: needs.init.outputs.publish != 'true'
        uses: home-assistant/builder@2024.03.5
        with:
          args: |
            --test \
            --amd64 \
            --target /data \
            --generic runner

      - name: Pull Supervisor
        if: needs.init.outputs.publish == 'true'
        run: |
          docker pull ghcr.io/home-assistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }}
          docker tag ghcr.io/home-assistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }} ghcr.io/home-assistant/amd64-hassio-supervisor:runner

      - name: Create the Supervisor
        run: |
          mkdir -p /tmp/supervisor/data
          docker create --name hassio_supervisor \
            --privileged \
            --security-opt seccomp=unconfined \
            --security-opt apparmor=unconfined \
            -v /run/docker.sock:/run/docker.sock \
            -v /run/dbus:/run/dbus \
            -v /tmp/supervisor/data:/data \
            -v /etc/machine-id:/etc/machine-id:ro \
            -e SUPERVISOR_SHARE="/tmp/supervisor/data" \
            -e SUPERVISOR_NAME=hassio_supervisor \
            -e SUPERVISOR_DEV=1 \
            -e SUPERVISOR_MACHINE="qemux86-64" \
          ghcr.io/home-assistant/amd64-hassio-supervisor:runner

      - name: Start the Supervisor
        run: docker start hassio_supervisor

      - name: Wait for Supervisor to come up
        run: |
          SUPERVISOR=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor)
          ping="error"
          while [ "$ping" != "ok" ]; do
            ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r '.result')
            sleep 5
          done

      - name: Check the Supervisor
        run: |
          echo "Checking supervisor info"
          test=$(docker exec hassio_cli ha supervisor info --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          echo "Checking supervisor network info"
          test=$(docker exec hassio_cli ha network info --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

      - name: Check the Store / Addon
        run: |
          echo "Install Core SSH Add-on"
          test=$(docker exec hassio_cli ha addons install core_ssh --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          # Make sure it actually installed
          test=$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.version')
          if [[ "$test" == "null" ]]; then
            exit 1
          fi

          echo "Start Core SSH Add-on"
          test=$(docker exec hassio_cli ha addons start core_ssh --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          # Make sure its state is started
          test="$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.state')"
          if [ "$test" != "started" ]; then
            exit 1
          fi

      - name: Check the Supervisor code sign
        if: needs.init.outputs.publish == 'true'
        run: |
          echo "Enable Content-Trust"
          test=$(docker exec hassio_cli ha security options --content-trust=true --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          echo "Run supervisor health check"
          test=$(docker exec hassio_cli ha resolution healthcheck --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          echo "Check supervisor unhealthy"
          test=$(docker exec hassio_cli ha resolution info --no-progress --raw-json | jq -r '.data.unhealthy[]')
          if [ "$test" != "" ]; then
            exit 1
          fi

          echo "Check supervisor supported"
          test=$(docker exec hassio_cli ha resolution info --no-progress --raw-json | jq -r '.data.unsupported[]')
          if [[ "$test" =~ source_mods ]]; then
            exit 1
          fi

      - name: Create full backup
        id: backup
        run: |
          test=$(docker exec hassio_cli ha backups new --no-progress --raw-json)
          if [ "$(echo $test | jq -r '.result')" != "ok" ]; then
            exit 1
          fi
          echo "slug=$(echo $test | jq -r '.data.slug')" >> "$GITHUB_OUTPUT"

      - name: Uninstall SSH add-on
        run: |
          test=$(docker exec hassio_cli ha addons uninstall core_ssh --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

      - name: Restart supervisor
        run: |
          test=$(docker exec hassio_cli ha supervisor restart --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

      - name: Wait for Supervisor to come up
        run: |
          SUPERVISOR=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor)
          ping="error"
          while [ "$ping" != "ok" ]; do
            ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r '.result')
            sleep 5
          done

      - name: Restore SSH add-on from backup
        run: |
          test=$(docker exec hassio_cli ha backups restore ${{ steps.backup.outputs.slug }} --addons core_ssh --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

          # Make sure it actually installed
          test=$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.version')
          if [[ "$test" == "null" ]]; then
            exit 1
          fi

          # Make sure its state is started
          test="$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.state')"
          if [ "$test" != "started" ]; then
            exit 1
          fi

      - name: Restore SSL directory from backup
        run: |
          test=$(docker exec hassio_cli ha backups restore ${{ steps.backup.outputs.slug }} --folders ssl --no-progress --raw-json | jq -r '.result')
          if [ "$test" != "ok" ]; then
            exit 1
          fi

      - name: Get supervisor logs on failiure
        if: ${{ cancelled() || failure() }}
        run: docker logs hassio_supervisor


Check PR

name: Check PR

on:
  pull_request:
    branches: ["main"]
    types: [labeled, unlabeled, synchronize]

jobs:
  init:
    name: Check labels
    runs-on: ubuntu-latest
    steps:
      - name: Check labels
        run: |
          labels=$(jq -r '.pull_request.labels[] | .name' ${{github.event_path }})
          echo "$labels"
          if [ "$labels" == "cla-signed" ]; then
            exit 1
          fi


CI

name: CI

# yamllint disable-line rule:truthy
on:
  push:
    branches:
      - main
  pull_request: ~

env:
  DEFAULT_PYTHON: "3.12"
  PRE_COMMIT_CACHE: ~/.cache/pre-commit

concurrency:
  group: "${{ github.workflow }}-${{ github.ref }}"
  cancel-in-progress: true

jobs:
  # Separate job to pre-populate the base dependency cache
  # This prevent upcoming jobs to do the same individually
  prepare:
    runs-on: ubuntu-latest
    outputs:
      python-version: ${{ steps.python.outputs.python-version }}
    name: Prepare Python dependencies
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python
        id: python
        uses: actions/setup-python@v5.1.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Create Python virtual environment
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          python -m venv venv
          . venv/bin/activate
          pip install -U pip setuptools
          pip install -r requirements.txt -r requirements_tests.txt
      - name: Restore pre-commit environment from cache
        id: cache-precommit
        uses: actions/cache@v4.0.2
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          lookup-only: true
          key: |
            ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pre-commit-
      - name: Install pre-commit dependencies
        if: steps.cache-precommit.outputs.cache-hit != 'true'
        run: |
          . venv/bin/activate
          pre-commit install-hooks

  lint-ruff-format:
    name: Check ruff-format
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Restore pre-commit environment from cache
        id: cache-precommit
        uses: actions/cache@v4.0.2
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          key: |
            ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
      - name: Fail job if cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Run ruff-format
        run: |
          . venv/bin/activate
          pre-commit run --hook-stage manual ruff-format --all-files --show-diff-on-failure
        env:
          RUFF_OUTPUT_FORMAT: github

  lint-ruff:
    name: Check ruff
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Restore pre-commit environment from cache
        id: cache-precommit
        uses: actions/cache@v4.0.2
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          key: |
            ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
      - name: Fail job if cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Run ruff
        run: |
          . venv/bin/activate
          pre-commit run --hook-stage manual ruff --all-files --show-diff-on-failure
        env:
          RUFF_OUTPUT_FORMAT: github

  lint-dockerfile:
    name: Check Dockerfile
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Register hadolint problem matcher
        run: |
          echo "::add-matcher::.github/workflows/matchers/hadolint.json"
      - name: Check Dockerfile
        uses: docker://hadolint/hadolint:v1.18.0
        with:
          args: hadolint Dockerfile

  lint-executable-shebangs:
    name: Check executables
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Restore pre-commit environment from cache
        id: cache-precommit
        uses: actions/cache@v4.0.2
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          key: |
            ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
      - name: Fail job if cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Register check executables problem matcher
        run: |
          echo "::add-matcher::.github/workflows/matchers/check-executables-have-shebangs.json"
      - name: Run executables check
        run: |
          . venv/bin/activate
          pre-commit run --hook-stage manual check-executables-have-shebangs --all-files

  lint-json:
    name: Check JSON
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Restore pre-commit environment from cache
        id: cache-precommit
        uses: actions/cache@v4.0.2
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          key: |
            ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
      - name: Fail job if cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Register check-json problem matcher
        run: |
          echo "::add-matcher::.github/workflows/matchers/check-json.json"
      - name: Run check-json
        run: |
          . venv/bin/activate
          pre-commit run --hook-stage manual check-json --all-files

  lint-pylint:
    name: Check pylint
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Register pylint problem matcher
        run: |
          echo "::add-matcher::.github/workflows/matchers/pylint.json"
      - name: Run pylint
        run: |
          . venv/bin/activate
          pylint supervisor tests

  pytest:
    runs-on: ubuntu-latest
    needs: prepare
    name: Run tests Python ${{ needs.prepare.outputs.python-version }}
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Install Cosign
        uses: sigstore/cosign-installer@v3.5.0
        with:
          cosign-release: "v2.2.3"
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Install additional system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends libpulse0 libudev1 dbus dbus-x11
      - name: Register Python problem matcher
        run: |
          echo "::add-matcher::.github/workflows/matchers/python.json"
      - name: Install Pytest Annotation plugin
        run: |
          . venv/bin/activate
          # Ideally this should be part of our dependencies
          # However this plugin is fairly new and doesn't run correctly
          # on a non-GitHub environment.
          pip install pytest-github-actions-annotate-failures
      - name: Run pytest
        run: |
          . venv/bin/activate
          pytest \
            -qq \
            --timeout=10 \
            --durations=10 \
            --cov supervisor \
            -o console_output_style=count \
            tests
      - name: Upload coverage artifact
        uses: actions/upload-artifact@v4.3.3
        with:
          name: coverage-${{ matrix.python-version }}
          path: .coverage

  coverage:
    name: Process test coverage
    runs-on: ubuntu-latest
    needs: ["pytest", "prepare"]
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ needs.prepare.outputs.python-version }}
        uses: actions/setup-python@v5.1.0
        id: python
        with:
          python-version: ${{ needs.prepare.outputs.python-version }}
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.0.2
        with:
          path: venv
          key: |
            ${{ runner.os }}-venv-${{ needs.prepare.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_tests.txt') }}
      - name: Fail job if Python cache restore failed
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          echo "Failed to restore Python virtual environment from cache"
          exit 1
      - name: Download all coverage artifacts
        uses: actions/download-artifact@v4.1.7
      - name: Combine coverage results
        run: |
          . venv/bin/activate
          coverage combine coverage*/.coverage*
          coverage report
          coverage xml
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4.5.0


Lock

name: Lock

# yamllint disable-line rule:truthy
on:
  schedule:
    - cron: "0 0 * * *"

jobs:
  lock:
    runs-on: ubuntu-latest
    steps:
      - uses: dessant/lock-threads@v5.0.1
        with:
          github-token: ${{ github.token }}
          issue-inactive-days: "30"
          exclude-issue-created-before: "2020-10-01T00:00:00Z"
          issue-lock-reason: ""
          pr-inactive-days: "1"
          exclude-pr-created-before: "2020-11-01T00:00:00Z"
          pr-lock-reason: ""


Release Drafter

name: Release Drafter

on:
  push:
    branches:
      - main

jobs:
  update_release_draft:
    runs-on: ubuntu-latest
    name: Release Drafter
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v4.1.7
        with:
          fetch-depth: 0

      - name: Find Next Version
        id: version
        run: |
          declare -i newpost
          latest=$(git describe --tags $(git rev-list --tags --max-count=1))
          latestpre=$(echo "$latest" | awk '{split($0,a,"."); print a[1] "." a[2]}')
          datepre=$(date --utc '+%Y.%m')

          if [[ "$latestpre" == "$datepre" ]]; then
              latestpost=$(echo "$latest" | awk '{split($0,a,"."); print a[3]}')
              newpost=$latestpost+1
          else
              newpost=0
          fi

          echo Current version:    $latest
          echo New target version: $datepre.$newpost
          echo "version=$datepre.$newpost" >> "$GITHUB_OUTPUT"

      - name: Run Release Drafter
        uses: release-drafter/release-drafter@v6.0.0
        with:
          tag: ${{ steps.version.outputs.version }}
          name: ${{ steps.version.outputs.version }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


Sentry Release

name: Sentry Release

# yamllint disable-line rule:truthy
on:
  release:
    types: [published, prereleased]

jobs:
  createSentryRelease:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Sentry Release
        uses: getsentry/action-release@v1.7.0
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
          SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
        with:
          environment: production


Stale

name: Stale

# yamllint disable-line rule:truthy
on:
  schedule:
    - cron: "0 * * * *"

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v9.0.0
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          days-before-stale: 30
          days-before-close: 7
          stale-issue-label: "stale"
          exempt-issue-labels: "no-stale,Help%20wanted,help-wanted,pinned,rfc,security"
          stale-issue-message: >
            There hasn't been any activity on this issue recently. Due to the
            high number of incoming GitHub notifications, we have to clean some
            of the old issues, as many of them have already been resolved with
            the latest updates.

            Please make sure to update to the latest version and check if that
            solves the issue. Let us know if that works for you by
            adding a comment 👍

            This issue has now been marked as stale and will be closed if no
            further activity occurs. Thank you for your contributions.

          stale-pr-label: "stale"
          exempt-pr-labels: "no-stale,pinned,rfc,security"
          stale-pr-message: >
            There hasn't been any activity on this pull request recently. This
            pull request has been automatically marked as stale because of that
            and will be closed if no further activity occurs within 7 days.

            Thank you for your contributions.


Elyra Tests

#
# Copyright 2018-2023 Elyra Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: Elyra Tests
on:
  push: # all branches
  pull_request: # all branches
  schedule:
    # once a day at 3 am (PST) (10 am (UTC))
    - cron:  '0 10 * * *'

env:
  FORCE_COLOR: true

jobs:
  prepare-yarn-cache:
    name: Prepare Cache
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "*"
      - uses: actions/cache@v3
        with:
          path: |
            node_modules
            */*/node_modules
            /home/runner/.cache/Cypress
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
      - name: Install
        run: yarn install --frozen-lockfile && tsc -v

  lint-server:
    name: Lint Server
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Lint
        run: make lint-server

  lint-ui:
    name: Lint UI
    needs: prepare-yarn-cache
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "*"
      - uses: actions/cache@v3
        with:
          path: |
            node_modules
            */*/node_modules
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
      - name: Install
        run: make yarn-install
      - name: Lint
        run: make eslint-check-ui
      - name: Check format
        run: make prettier-check-ui

  test-server:
    name: Test Server
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.8, 3.9, "3.10"]
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install
        # Note: Tests fail if we don't install `wheel` for some reason.
        run: |
          make install-server
          make test-dependencies
      - name: Version Snapshot
        run: pip freeze
      - name: Test
        id: Test
        run: make pytest
      - name: Fetch packages metadata (if Test step failed)
        # Note: checking for general failure() first is needed according to docs
        if: ${{ failure() && steps.Test.conclusion == 'failure' }}
        env:
          days: 7 # check for newer package versions in past X days
        run: |
          python3 ./.github/workflows/scripts/fetch_packages_metadata.py $days

  test-ui:
    name: Test UI
    needs: prepare-yarn-cache
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "*"
      - uses: actions/setup-python@v4
        with:
          python-version: "3.10"
      - uses: actions/cache@v3
        with:
          path: |
            node_modules
            */*/node_modules
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
      - name: Build
        run: |
          make build-dependencies
          make yarn-install
          make build-ui
      - name: Install
        run: make install-server
      - name: Test
        run: make test-ui-unit

  test-integration:
    name: Run Integration Tests
    needs: prepare-yarn-cache
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "*"
      - uses: actions/setup-python@v4
        with:
          python-version: "3.10"
      - uses: actions/cache@v3
        with:
          path: |
            node_modules
            */*/node_modules
            /home/runner/.cache/Cypress
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
      - name: Build
        run: |
          make build-dependencies
          make yarn-install
          make build-ui
      - name: Install
        run: |
          make install-server
          make install-examples
      - name: Cypress
        run: make test-integration
      - name: Collect logs
        uses: actions/upload-artifact@v3
        if: failure()
        with:
          path: |
            ${{ github.workspace }}/build/cypress-tests/*.log
            ${{ github.workspace }}/build/cypress-tests/screenshots//**/*
            ${{ github.workspace }}/build/cypress-tests/videos//**/*
            /home/runner/.npm/_logs/*.log

  test-documentation-build:
    name: Test documentation build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build
        run: make docs

  validate-image-env:
    name: Validate Image Environment
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.8, 3.9, "3.10"]
    steps:
      - uses: actions/checkout@v3
      - name: Validate image environment
        run: make PYTHON_VERSION=${{ matrix.python-version }} elyra-image-env

  validate-images:
    name: Validate Images
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Validate runtime images
        run: make REMOVE_RUNTIME_IMAGE=1 validate-runtime-images


CodeQL

# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
  push:
    branches: [main]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [main]
  schedule:
    # Run every Wednesday at 8 am
    - cron: '0 8 * * 3'

permissions:
  security-events:
    write

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-20.04

    strategy:
      fail-fast: false
      matrix:
        # Override automatic language detection by changing the below list
        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
        language: ['javascript', 'python']
        # Learn more...
        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3
      with:
        # We must fetch at least the immediate parents so that if this is
        # a pull request then we can checkout the head.
        fetch-depth: 2

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v2
      with:
        languages: ${{ matrix.language }}
        config-file: ./.github/codeql/codeql-config.yml

        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v2

    # ℹ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2


style

name: style

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  code_style:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout viv
      uses: actions/checkout@v2
    - name: Set up Python 3.8
      uses: actions/setup-python@v2
      with:
        python-version: 3.8
    - name: Install dependencies
      run: pip install 'isort==5.*' black
    - name: Lint with isort
      run: isort --profile black --length-sort --line-width 120 -c .
    - name: Lint with black
      run: black -l 120 --check .


ci

name: ci

on:
  push:
    branches:
      - master
      - ci

  pull_request:
    branches:
      - master

jobs:
  doctest-and-lint:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: 3.6.15

    - name: Install pinned dependencies
      run: |
        python -m pip install --upgrade pip
        pip install astropy==3.0.1 docutils==0.17.1 matplotlib==3.3.0 numpy==1.15.4 pandas==1.0.0 pyflakes scipy==1.2.2 sphinx==1.7.2 spktype21

    - name: Install Skyfield
      run: |
        python setup.py sdist
        pip install -e .

    - name: Doctest
      run: |
        ./test-docs.sh

    - name: Lint
      run: |
        pyflakes $(find skyfield/ -name '*.py')

  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        python: [python2, python3]

    steps:
    - uses: actions/checkout@v2

    - name: Install
      run: |
        sudo apt install -q -q python3-virtualenv virtualenv
        virtualenv -p ${{matrix.python}} V

    - name: Build scripts
      run: |
        cat <<'EOF' > GITHUB_INSTALL.sh
        source ./V/bin/activate
        echo PATH is $PATH
        which python
        python --version
        python -m pip install --upgrade pip
        python setup.py sdist
        python -m pip install dist/*
        python -m pip install mock pandas
        python -m pip install https://github.com/brandon-rhodes/assay/archive/master.zip
        EOF
        cat <<'EOF' > GITHUB_TEST.sh
        source ./V/bin/activate
        cd ci && ../test-code.sh
        EOF

    - name: Install
      run: |
        bash -e -x GITHUB_INSTALL.sh

    - name: Test
      run: |
        bash -e -x GITHUB_TEST.sh