Skip to content

Build and Test

Build and Test #6259

name: Build and Test
on:
pull_request: # Trigger for pull requests.
types: [opened, synchronize, reopened, ready_for_review]
branches:
- main
- v[0-9]*
workflow_dispatch: # Allows for manual triggering.
inputs:
ref:
description: "The ref to build and test."
required: false
schedule:
# Run every night at midnight PST / 8am UTC, testing against the main branch.
- cron: '0 8 * * *'
# If another instance of this workflow is started for the same PR, cancel the
# old one. If a PR is updated and a new test run is started, the old test run
# will be cancelled automatically to conserve resources.
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || inputs.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Lint
run: python build/check.py
build_and_test:
# Don't waste time doing a full matrix of test runs when there was an
# obvious linter error.
needs: lint
strategy:
matrix:
include:
# Run Linux browsers with xvfb, so they're in a headless X session.
# Additionally, generate a code coverage report from Linux Chrome.
# It should be the uncompiled build, or else we won't execute any
# coverage instrumentation on full-stack player integration tests.
- os: ubuntu-latest
browser: Chrome
extra_flags: "--use-xvfb"
- os: ubuntu-latest
browser: Firefox
extra_flags: "--use-xvfb"
- os: ubuntu-latest
browser: Edge
extra_flags: "--use-xvfb"
- os: ubuntu-latest
browser: Opera
extra_flags: "--use-xvfb"
- os: macos-latest
browser: Chrome
- os: macos-latest
browser: Edge
- os: macos-latest
browser: Opera
- os: macos-latest
browser: Firefox
- os: macos-latest
browser: Safari
- os: macos-latest
browser: Safari-old
- os: windows-latest
browser: Chrome
- os: windows-latest
browser: Firefox
- os: windows-latest
browser: Edge
extra_flags: "--html-coverage-report --uncompiled"
# Disabled until working properly
# - os: windows-latest
# browser: Opera
# Disable fail-fast so that one matrix-job failing doesn't make the other
# ones end early.
fail-fast: false
name: ${{ matrix.os }} ${{ matrix.browser }}
runs-on: ${{ matrix.os }}
steps:
# Firefox on Ubuntu appears to not have the right things installed in
# the environment used by GitHub actions, so make sure that ffmpeg is
# installed. Otherwise, the browser might not support some codecs that the
# tests assume will be supported.
- name: Install FFmpeg
timeout-minutes: 5
if: matrix.os == 'ubuntu-latest' && matrix.browser == 'Firefox'
run: sudo apt -y update && sudo apt -y install ffmpeg
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
# Older versions of Safari can be installed, but not to the root, and it
# can't replace the standard version, at least not on GitHub's VMs. If
# you try to install directly to the root with sudo, it will appear to
# succeed, but will have no effect. If you try to script it explicitly
# with rm -rf and cp, this will fail. Safari may be on a read-only
# filesystem.
- name: Install old Safari to home directory
timeout-minutes: 5
if: matrix.os == 'macos-latest' && matrix.browser == 'Safari-old'
run: |
# Download Safari 15
# This URL discovered through the seed files listed at
# https://github.com/zhangyoufu/swscan.apple.com/blob/master/url.txt
curl -Lv http://swcdn.apple.com/content/downloads/42/33/012-57329-A_41P2VU6UHN/5fw5vna27fdw4mqfak5adj3pjpxvo9hgh7/Safari15.6.1CatalinaAuto.pkg > Safari.pkg
# Install older Safari to homedir specifically.
installer -pkg Safari.pkg -target CurrentUserHomeDirectory
# Install a launcher that can execute a shell script to launch this
npm install karma-script-launcher --save-dev
# When "Chrome for Testing" is installed on Mac or Windows, it gets
# invoked instead of simply "Chrome". This other copy of Chrome,
# however, doesn't seem to have basic codecs like AAC and H264 available,
# causing many of our test scenarios to fail. Deleting "Chrome for
# Testing" fixes this.
- name: 'Delete "Chrome for Testing" on Mac'
timeout-minutes: 5
if: matrix.os == 'macos-latest' && matrix.browser == 'Chrome'
run: sudo rm -rf /Applications/Google\ Chrome\ for\ Testing.app
- name: 'Overwrite "Chrome for Testing" on Windows'
timeout-minutes: 5
if: matrix.os == 'windows-latest' && matrix.browser == 'Chrome'
shell: bash
run: choco install -y googlechrome --ignore-checksums
- name: 'Install Opera on Ubuntu'
timeout-minutes: 5
if: matrix.os == 'ubuntu-latest' && matrix.browser == 'Opera'
run: sudo apt -y update && sudo apt -y install snapd && sudo snap install opera
- name: 'Install Opera on Windows'
timeout-minutes: 5
if: matrix.os == 'windows-latest' && matrix.browser == 'Opera'
run: choco install -y opera --ignore-checksums --params '"/NoAutostart /NoDesktopShortcut /NoTaskbarShortcut"'
# Firefox, Edge and Opera might be missing on Mac CI images.
- name: 'Install Firefox on Mac'
timeout-minutes: 5
if: matrix.os == 'macos-latest' && matrix.browser == 'Firefox'
run: brew install --cask firefox
- name: 'Install Edge on Mac'
timeout-minutes: 5
if: matrix.os == 'macos-latest' && matrix.browser == 'Edge'
run: brew install --cask microsoft-edge
- name: 'Install Opera on Mac'
timeout-minutes: 5
if: matrix.os == 'macos-latest' && matrix.browser == 'Opera'
run: brew install --cask opera
# Some CI images (self-hosted or otherwise) don't have the minimum Java
# version necessary for the compiler (Java 11).
- uses: actions/setup-java@v4
with:
distribution: zulu
java-version: 11
- name: Build Player
timeout-minutes: 10
run: python build/all.py
- name: Test Player
timeout-minutes: 15
shell: bash
run: |
browser=${{ matrix.browser }}
if [[ "$browser" == "Safari-old" ]]; then
# Replace the browser name with a script that can launch this
# browser from the command line.
browser="$PWD/.github/workflows/safari-homedir-launcher.sh"
fi
python build/test.py \
--browsers "$browser" \
--reporters spec --spec-hide-passed \
${{ matrix.extra_flags }}
- name: Find coverage reports
id: coverage
if: always() # Even on failure of an earlier step.
shell: bash
run: |
# If the "coverage" directory exists...
if [ -d coverage ]; then
# Find the path to the coverage output folder. It includes the
# exact browser version in the path, so it will vary.
coverage_folder="$( (ls -d coverage/* || true) | head -1 )"
# Build a folder to stage all the coverage artifacts with
# predictable paths. The resulting zip file will not have any
# internal directories.
mkdir coverage/staging/
cp "$coverage_folder"/coverage.json coverage/staging/
cp "$coverage_folder"/coverage-details.json coverage/staging/
echo "${{ github.event.number }}" > coverage/staging/pr-number.json
echo "coverage_found=true" >> $GITHUB_OUTPUT
echo "Coverage report staged."
else
echo "No coverage report generated."
fi
- name: Upload coverage reports
uses: actions/upload-artifact@v4
if: ${{ always() && steps.coverage.outputs.coverage_found }}
with:
name: coverage
# This will create a download called coverage.zip containing all of
# these files, with no internal folders.
path: |
coverage/staging/coverage.json
coverage/staging/coverage-details.json
coverage/staging/pr-number.json
# Since we've already filtered this step for instances where there is
# an environment variable set, the file should definitely be there.
if-no-files-found: error
# Upload new screenshots and diffs on failure; ignore if missing
- name: Upload screenshots
uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: screenshots-${{ matrix.browser }}
path: |
test/test/assets/screenshots/*/*.png-new
test/test/assets/screenshots/*/*.png-diff
if-no-files-found: ignore
retention-days: 5
build_in_docker:
# Don't waste time doing a full matrix of test runs when there was an
# obvious linter error.
needs: lint
name: Docker
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Docker
run: |
docker build -t shaka-player-build build/docker
docker run -v $(pwd):/usr/src --user $(id -u):$(id -g) shaka-player-build