Files
PhotonVision/.github/workflows/build.yml
Sam Freund 68fc1e7129 Make 2027 build (#2422)
This PR updates everything for 2027. This includes removing GradleRIO, simplifying our wpilib version defintion, updating APIs, updating to Java 21, and more.

Note that photonlibpy is failing because robotpy has not been fully updated yet. Examples are omitted because they need to be updated for our new PhotonPoseEstimator API and still need some changes from WPILIB. photonlib windows build is failing because we're waiting for some upstream changes. Finally, images are failing since they don't have Java 21 yet.
2026-04-11 12:23:14 -05:00

670 lines
24 KiB
YAML

name: Build
on:
# Run on pushes to main and pushed tags, and on pull requests against main, but ignore the docs folder
push:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
env:
IMAGE_VERSION: v2026.1.4
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: gradle/actions/wrapper-validation@v5
# build-examples:
# strategy:
# fail-fast: false
# matrix:
# include:
# - os: windows-2022
# artifact-name: Win64
# - os: macos-14
# artifact-name: macOS
# - os: ubuntu-24.04
# artifact-name: Linux
# name: "Photonlib - Build Examples - ${{ matrix.os }}"
# runs-on: ${{ matrix.os }}
# needs: [build-photonlib-host, build-photonlib-docker]
# steps:
# - name: Checkout code
# uses: actions/checkout@v6
# with:
# fetch-depth: 0
# - name: Fetch tags
# run: git fetch --tags --force
# - uses: actions/setup-java@v5
# with:
# java-version: 21
# distribution: temurin
# - name: Install SystemCore Toolchain
# run: ./gradlew installSystemCoreToolchain
# - name: Delete duplicate toolchains
# run: |
# find ~/.gradle/cache/ -name *bookworm* -exec rm -rf {} +
# du -h . | sort -h
# if: matrix.os == 'ubuntu-24.04'
# # Download prebuilt photonlib artifacts
# - uses: actions/download-artifact@v7
# with:
# name: maven-${{ matrix.artifact-name }}
# - uses: actions/download-artifact@v7
# with:
# name: maven-Athena
# - name: Move to maven local
# run: |
# mkdir -p ~/.m2/repository/
# mv maven/org ~/.m2/repository/
# - name: Copy vendordeps
# shell: bash
# run: |
# for vendordep_folder in photonlib-*-examples/*/; do
# # Remove trailing slash for cross-platform compatibility
# vendordep_folder="${vendordep_folder%/}"
# # Filter for projects only
# if [ -e "$vendordep_folder/build.gradle" ]; then
# mkdir -p "$vendordep_folder/vendordeps/"
# cp vendordeps/photonlib-json-1.0.json "$vendordep_folder/vendordeps/"
# fi
# done
# - name: Build Java examples
# working-directory: photonlib-java-examples
# run: |
# ./gradlew build
# ./gradlew clean
# - name: Build C++ examples
# working-directory: photonlib-cpp-examples
# run: |
# ./gradlew build
# ./gradlew clean
playwright-tests:
name: "Playwright E2E tests"
runs-on: ubuntu-24.04
needs: [validation]
steps:
# Checkout code.
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Fetch tags
run: git fetch --tags --force
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
- name: Setup tests
working-directory: photon-client
run: |
pnpm install
pnpm test-setup
- name: Prebuild Gradle
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
- name: Run Playwright tests
working-directory: photon-client
run: pnpm test
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
archive: false
path: photon-client/playwright-report/
retention-days: 30
build-gradle:
name: "Gradle Build"
runs-on: ubuntu-24.04
needs: [validation]
steps:
# Checkout code.
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Fetch tags
run: git fetch --tags --force
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
- name: Gradle Build
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
- name: Gradle Tests and Coverage
run: ./gradlew test jacocoTestReport --stacktrace
build-offline-docs:
name: "Build Offline Docs"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.14
- name: Install graphviz
run: |
sudo apt-get update
sudo apt-get -y install graphviz
- name: Install dependencies
working-directory: docs
run: |
python -m pip install --upgrade pip
pip install sphinx sphinx_rtd_theme sphinx-tabs sphinxext-opengraph doc8
pip install -r requirements.txt
- name: Build the docs
working-directory: docs
run: |
make html
- uses: actions/upload-artifact@v7
with:
name: built-docs
path: docs/build/html
build-photonlib-vendorjson:
name: "Build Vendor JSON"
runs-on: ubuntu-24.04
needs: [validation]
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
# grab all tags
- run: git fetch --tags --force
# Generate the JSON and give it the ""standard""" name maven gives it
- run: |
./gradlew photon-lib:generateVendorJson
export VERSION=$(git describe --tags --match=v*)
mv photon-lib/build/generated/vendordeps/photonlib.json photon-lib/build/generated/vendordeps/photonlib-$(git describe --tags --match=v*).json
# Upload it here so it shows up in releases
- uses: actions/upload-artifact@v7
with:
archive: false
path: photon-lib/build/generated/vendordeps/photonlib-*.json
build-photonlib-host:
env:
MACOSX_DEPLOYMENT_TARGET: 14
strategy:
fail-fast: false
matrix:
include:
- os: windows-2022
artifact-name: Win64
- os: macos-26
artifact-name: macOS
- os: ubuntu-24.04
artifact-name: Linux
name: "Photonlib - Build Host - ${{ matrix.artifact-name }}"
runs-on: ${{ matrix.os }}
needs: [validation]
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- run: git fetch --tags --force
- run: ./gradlew photon-targeting:build photon-lib:build
name: Build with Gradle
- run: ./gradlew photon-lib:publish photon-targeting:publish
name: Publish
env:
ARTIFACTORY_API_KEY: ${{ secrets.ARTIFACTORY_API_KEY }}
if: github.event_name == 'push' && github.repository_owner == 'photonvision' && github.ref == 'refs/heads/main'
# Copy artifacts to build/outputs/maven
- run: ./gradlew photon-lib:publish photon-targeting:publish -PcopyOfflineArtifacts
- uses: actions/upload-artifact@v7
with:
name: maven-${{ matrix.artifact-name }}
path: build/outputs
build-photonlib-docker:
strategy:
fail-fast: false
matrix:
include:
- container: wpilib/systemcore-cross-ubuntu:2027-24.04
artifact-name: SystemCore
build-options: "-Ponlylinuxsystemcore"
- container: wpilib/raspbian-cross-ubuntu:2027-bookworm-24.04
artifact-name: Raspbian
build-options: "-Ponlylinuxarm32"
- container: wpilib/aarch64-cross-ubuntu:2027-bookworm-24.04
artifact-name: Aarch64
build-options: "-Ponlylinuxarm64"
runs-on: ubuntu-24.04
container: ${{ matrix.container }}
name: "Photonlib - Build Docker - ${{ matrix.artifact-name }}"
needs: [validation]
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Config Git
run: |
git config --global --add safe.directory /__w/photonvision/photonvision
- name: Build PhotonLib
# We don't need to run tests, since we specify only non-native platforms
run: ./gradlew photon-targeting:build photon-lib:build ${{ matrix.build-options }} -x test
- name: Publish
run: ./gradlew photon-lib:publish photon-targeting:publish ${{ matrix.build-options }}
env:
ARTIFACTORY_API_KEY: ${{ secrets.ARTIFACTORY_API_KEY }}
if: github.event_name == 'push' && github.repository_owner == 'photonvision' && github.ref == 'refs/heads/main'
# Copy artifacts to build/outputs/maven
- run: ./gradlew photon-lib:publish photon-targeting:publish -PcopyOfflineArtifacts ${{ matrix.build-options }}
- uses: actions/upload-artifact@v7
with:
name: maven-${{ matrix.artifact-name }}
path: build/outputs
combine:
name: Combine
needs: [build-photonlib-docker, build-photonlib-host]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- run: git fetch --tags --force
# download all maven-* artifacts to outputs/
- uses: actions/download-artifact@v8
with:
merge-multiple: true
path: output
pattern: maven-*
- run: find .
- run: zip -r photonlib-$(git describe --tags --match=v*).zip .
name: ZIP stuff up
working-directory: output
- run: ls output
- uses: actions/upload-artifact@v7
with:
name: photonlib-offline
path: output/*.zip
build-package-linux:
needs: [build-gradle, build-offline-docs]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
artifact-name: Linux
arch-override: linuxx64
- os: ubuntu-24.04
artifact-name: LinuxArm64
arch-override: linuxarm64
runs-on: ${{ matrix.os }}
name: "Build fat JAR - ${{ matrix.artifact-name }}"
steps: &build-package-steps
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
cache-dependency-path: photon-client/pnpm-lock.yaml
- name: Install Arm64 Toolchain
run: ./gradlew installArm64Toolchain
if: ${{ (matrix.artifact-name) == 'LinuxArm64' }}
- uses: actions/download-artifact@v8
with:
name: built-docs
path: photon-server/src/main/resources/web/docs
- run: ./gradlew photon-targeting:jar photon-server:shadowJar -PArchOverride=${{ matrix.arch-override }}
if: ${{ (matrix.arch-override != 'none') }}
- run: ./gradlew photon-server:shadowJar
if: ${{ (matrix.arch-override == 'none') }}
- uses: actions/upload-artifact@v7
with:
archive: false
path: photon-server/build/libs
- uses: actions/upload-artifact@v7
with:
name: photon-targeting_jar-${{ matrix.artifact-name }}
path: photon-targeting/build/libs
build-package-macos:
needs: [build-gradle, build-offline-docs]
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
artifact-name: macOSArm
arch-override: macarm64
- os: macos-latest
artifact-name: macOS
arch-override: macx64
runs-on: ${{ matrix.os }}
name: "Build fat JAR - ${{ matrix.artifact-name }}"
steps: *build-package-steps
build-package-windows:
needs: [build-gradle, build-offline-docs]
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
artifact-name: Win64
arch-override: winx64
runs-on: ${{ matrix.os }}
name: "Build fat JAR - ${{ matrix.artifact-name }}"
steps: *build-package-steps
run-smoketest-native:
needs: [build-package-linux, build-package-macos, build-package-windows]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
artifact-name: photonvision-*-linuxx64.jar
extraOpts: -Djdk.lang.Process.launchMechanism=vfork
- os: windows-latest
artifact-name: photonvision-*-winx64.jar
- os: macos-latest
artifact-name: photonvision-*-macarm64.jar
- os: ubuntu-24.04-arm
artifact-name: photonvision-*-linuxarm64.jar
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- uses: actions/download-artifact@v8
with:
pattern: ${{ matrix.artifact-name }}
# The jar is run twice to exercise different code paths.
- run: |
echo "=== First run ==="
java -jar ${{ matrix.extraOpts }} *.jar --smoketest
echo "=== Checking for files to corrupt ==="
find ~ -type f \( -name "*.so" -o -name "*.dylib" \) | head -20
if [ -d ~/.wpilib ]; then
echo "~/.wpilib directory exists"
echo "Contents of ~/.wpilib:"
find ~/.wpilib -type f \( -name "*.so" -o -name "*.dylib" \) | head -10
RANDOM_FILE=$(find ~/.wpilib -type f \( -name "*.so" -o -name "*.dylib" \) | sort -R | head -n 1)
if [ ! -z "$RANDOM_FILE" ]; then
echo "Corrupting file: $RANDOM_FILE"
echo "corrupted data" > "$RANDOM_FILE"
else
echo "No .so or .dylib files found in ~/.wpilib"
fi
else
echo "~/.wpilib directory does not exist"
fi
echo "=== Second run ==="
java -jar ${{ matrix.extraOpts }} *.jar --smoketest
if: ${{ (matrix.os) != 'windows-latest' }}
- run: |
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break }
if: ${{ (matrix.os) == 'windows-latest' }}
build-image:
needs: [build-package-linux]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04-arm
image_suffix: RaspberryPi
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: limelight2
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: limelight3
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: limelight3G
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3g.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: limelight4
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight4.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: luma_p1
plat_override: LINUX_RASPBIAN64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_luma_p1.img.xz
minimum_free_mb: 100
- os: ubuntu-24.04-arm
image_suffix: orangepi5
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: orangepi5b
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5b.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: orangepi5plus
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5plus.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: orangepi5pro
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5pro.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: orangepi5max
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5max.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: rock5c
plat_override: LINUX_RK3588_64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rock5c.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: orangepi6plus
plat_override: LINUX_AARCH64
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi6plus.img.xz
minimum_free_mb: 1024
- os: ubuntu-24.04-arm
image_suffix: rubikpi3
plat_override: LINUX_QCS6490
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rubikpi3.tar.xz
minimum_free_mb: 1024
root_location: 'offset=569376768'
shrink_image: 'no'
runs-on: ${{ matrix.os }}
name: "Build image - ${{ matrix.image_suffix }}"
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/download-artifact@v8
with:
pattern: photonvision-*-linuxarm64.jar
- uses: photonvision/photon-image-runner@HEAD
name: Generate image
id: generate_image
with:
image_url: ${{ matrix.image_url }}
minimum_free_mb: ${{ matrix.minimum_free_mb }}
root_location: ${{ matrix.root_location || 'partition=2' }}
shrink_image: ${{ matrix.shrink_image || 'yes' }}
commands: ./scripts/armrunner.sh
- name: Compress image
# Compress the standard images
if: ${{ ! startsWith(matrix.image_suffix, 'rubik') }}
run: |
set -ex
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
new_image_name=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
sudo mv ${{ steps.generate_image.outputs.image }} $new_image_name
sudo xz -T 0 -kv $new_image_name
echo "smoketest_image_loc=${new_image_name}" >> $GITHUB_ENV
- name: Tar built image (Rubik)
# Build the RubikPi3-specific tar file
if: ${{ startsWith(matrix.image_suffix, 'rubik') }}
run: |
set -ex
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
tardir=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
imagedir=$(dirname ${{ steps.generate_image.outputs.image }})
sudo mkdir --parents ${tardir}
sudo cp ${imagedir}/* ${tardir}/
sudo tar -I 'xz -T0' -cf ${tardir}.tar.xz ${tardir} --checkpoint=10000 --checkpoint-action=echo='%T'
# Point smoketest to the old image
echo "smoketest_image_loc=${{ steps.generate_image.outputs.image }}" >> $GITHUB_ENV
- uses: actions/upload-artifact@v7
with:
archive: false
path: photonvision*.xz
# This is done after uploading the image to avoid contaminating the image with logs, caches, etc.
- uses: photonvision/photon-image-runner@HEAD
name: Smoketest Image
with:
image_url: file://${{ env.smoketest_image_loc }}
minimum_free_mb: ${{ matrix.minimum_free_mb }}
root_location: ${{ matrix.root_location || 'partition=2' }}
shrink_image: ${{ matrix.shrink_image || 'yes' }}
commands: java -jar *.jar --smoketest --platform=${{ matrix.plat_override }}
matrix-checker:
# This job always runs last to set the overall result based on the matrix jobs. If any matrix job failed, this job will fail.
# This makes it so that we don't need to add each matrix job individually to CI checks.
runs-on: ubuntu-latest
needs: [build-image]
if: always()
steps:
- run: ${{!contains(needs.*.result, 'failure')}}
release:
# Require smoketest-native so that if those fail, we don't release broken artifacts
needs: [build-photonlib-vendorjson, build-image, combine, build-package-linux, build-package-macos, build-package-windows, run-smoketest-native]
if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.repository == 'PhotonVision/photonvision'
runs-on: ubuntu-24.04
steps:
# Download all fat JARs
- uses: actions/download-artifact@v8
with:
merge-multiple: true
pattern: photonvision-*.jar
# Download offline photonlib
- uses: actions/download-artifact@v8
with:
merge-multiple: true
pattern: photonlib-offline
# Download vendor json
- uses: actions/download-artifact@v8
with:
pattern: photonlib-*.json
# Download all images
- uses: actions/download-artifact@v8
with:
merge-multiple: true
pattern: photonvision-*.xz
- run: find
# Push to dev release
- uses: pyTooling/Actions/releaser@r6
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: 'Dev'
rm: true
snapshots: false
files: |
**/*.xz
**/*linux*.jar
**/*win*.jar
**/photonlib*.json
**/photonlib*.zip
if: github.event_name == 'push'
- name: Create Vendor JSON Repo PR
uses: wpilibsuite/vendor-json-repo/.github/actions/add_vendordep@HEAD
with:
repo: PhotonVision/vendor-json-repo
token: ${{ secrets.VENDOR_JSON_REPO_PUSH_TOKEN }}
vendordep_file: ${{ github.workspace }}/photonlib-${{ github.ref_name }}.json
pr_title: Update photonlib to ${{ github.ref_name }}
pr_branch: photonlib-${{ github.ref_name }}
if: github.repository == 'PhotonVision/photonvision' && startsWith(github.ref, 'refs/tags/v')