Skip to content

t4

t4 #388

Workflow file for this run

name: Build pypylon
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches:
- '**'
tags:
- '*.*.*'
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
TWINE_USERNAME: __token__
# Uncomment the relevant lines to switch between deployment to test.pypi.org or pypi.org
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
# TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/
# TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
is_release_build: ${{ env.RELEASE_BUILD == '1' }}
steps:
- uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ secrets.SDK_URL }}
JF_ACCESS_TOKEN: ${{ secrets.SDK_TOKEN }}
with:
disable-auto-build-publish: true
disable-job-summary: true
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for release build and tag
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG_NAME="${GITHUB_REF#refs/tags/}"
echo "Build release for $TAG_NAME"
echo "RELEASE_BUILD=1" >> $GITHUB_ENV
echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV
# login
- name: Authenticate to Artifactory
run: |
jf c add --url=$JF_URL --access-token=$JF_ACCESS_TOKEN --interactive=false
# download
- name: Download control files from Artifactory
id: get_sdks
run: |
set +x
set -e
build_config=$(cat .github/workflows/build_config.json)
# Get the latest pylon version from Artifactory
pylon_default_version=$(jf rt s "pylon-artifacts-generic-prod/setup/*" | jq '.[] | .path' | awk -F'/' '{print $3}' | sort -V | uniq | tac | head -n 1)
for os in $(echo $build_config | jq -r 'keys[]'); do
# When TAG_NAME is set (release build), use the pylon version from the tag
tag="${TAG_NAME:-$pylon_default_version}"
echo "Downloading control files for $os using pylon $tag"
# Download control files
for path in $(jf rt s "pylon-artifacts-generic-prod/setup/*/report_$os*.json" | jq -r --arg tag "$tag" '.[] | select(.path | test($tag)) | .path'); do
jf rt dl --flat $path ./${os,,}/report_${os,,}.json
done
# Download 3rd party licenses
for path in $(jf rt s "pylon-artifacts-generic-prod/setup/*/oso_$os*.txt" | jq -r --arg tag "$tag" '.[] | select(.path | test($tag)) | .path'); do
jf rt dl --flat $path ./${os,,}/pylon_Third-Party_Licenses.txt
done
done
- name: Upload control files for Linux aarch64
uses: actions/upload-artifact@v4
with:
name: Linux_aarch64_Pylon
path: linux_aarch64
- name: Upload control files for Linux x86_64
uses: actions/upload-artifact@v4
with:
name: Linux_x86_64_Pylon
path: linux_x86_64
- name: Upload control files for Windows
uses: actions/upload-artifact@v4
with:
name: Windows_Pylon
path: windows
- name: Upload control files for macOS
uses: actions/upload-artifact@v4
with:
name: macOS_Pylon
path: macos
download:
needs: prepare
strategy:
fail-fast: false
matrix:
os: [ ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-latest ]
arch: [ x64, arm64 ]
exclude:
# Exclude ARM64 architecture for windows-latest
- os: windows-latest
arch: arm64
# Exclude X64 architecture for macos-14
- os: macos-14
arch: x64
# Exclude ARM64 architecture for ubuntu-24.04
- os: ubuntu-24.04
arch: arm64
# Exclude X64 architecture for ubuntu-24.04-arm
- os: ubuntu-24.04-arm
arch: x64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Detect running os
id: osname
run: |
import re
import os
os_str = "${{ matrix.os }}"
os_name_arch = "${{ matrix.arch }}"
os_name = re.sub(r'-.*', '', os_str)
os_name = os_name.replace('ubuntu', 'linux')
if os_name == 'linux' and os_name_arch == 'arm64':
os_name_arch = 'linux_aarch64'
elif os_name == 'linux' and os_name_arch == 'x64':
os_name_arch = 'linux_x86_64'
elif os_name == 'macos':
os_name_arch = 'macos'
elif os_name == 'windows':
os_name_arch = 'windows'
os_name_camel = os_name.replace('linux', 'Linux').replace('windows', 'Windows').replace('macos', 'macOS')
os_name_arch_camel = os_name_arch.replace('linux', 'Linux').replace('windows', 'Windows').replace('macos', 'macOS')
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f"value={os_name}\n")
f.write(f"value_camel={os_name_camel}\n")
f.write(f"value_arch={os_name_arch}\n")
f.write(f"value_arch_camel={os_name_arch_camel}\n")
shell: python
- name: Install conan v1
run: pip install "conan<2"
- name: Add conan v1 remote and authenticate
env:
JF_URL: ${{ secrets.SDK_URL }}
JF_USER: ${{ secrets.SDK_USER }}
JF_ACCESS_TOKEN: ${{ secrets.SDK_TOKEN }}
run: |
import os
import subprocess
subprocess.run(["conan", "config", "set", "general.revisions_enabled=1"], check=True)
subprocess.run([
"conan", "remote", "add", "pylon-conan-prod",
f"{os.environ['JF_URL']}/artifactory/api/conan/pylon-conan-prod", "--insert", "0"
], check=True)
subprocess.run([
"conan", "user", "-p", os.environ["JF_ACCESS_TOKEN"],
"-r", "pylon-conan-prod", os.environ["JF_USER"]
], check=True)
shell: python
- name: Download ${{ steps.osname.outputs.value_arch_camel }} control artifacts
uses: actions/download-artifact@v5
with:
pattern: ${{ steps.osname.outputs.value_camel }}*Pylon
merge-multiple: true
path: pylon-install-files
- name: Download need pylon modules
run: |
import os
import subprocess
subprocess.run([
"conan", "install", "--update", "--install-folder", "conan",
"-pr", os.path.join(os.environ['GITHUB_WORKSPACE'], ".github", "workflows", "profiles", "${{ steps.osname.outputs.value }}_${{ matrix.arch }}"),
"-o", f"pypylon:build_config={os.path.join(os.environ['GITHUB_WORKSPACE'], '.github', 'workflows', 'build_config.json')}",
"-o", f"pypylon:control_file={os.path.join(os.environ['GITHUB_WORKSPACE'], 'pylon-install-files', 'report_${{ steps.osname.outputs.value_arch }}.json')}",
"-o", f"pypylon:third_party_license_file={os.path.join(os.environ['GITHUB_WORKSPACE'], 'pylon-install-files', 'pylon_Third-Party_Licenses.txt')}",
"-c", "tools.system.package_manager:mode=install",
"-c", "tools.system.package_manager:sudo=True",
os.path.join(os.environ['GITHUB_WORKSPACE'], ".github", "workflows", "conanfile.py")
], check=True)
shell: python
- name: Tar pylon SDK files
if: runner.os == 'Linux' || runner.os == 'macOS'
run: cd conan && tar -czf ../pylon_sdk.tar.gz .
- name: Upload pylon SDK for ${{ steps.osname.outputs.value_arch_camel }}
uses: actions/upload-artifact@v4
with:
name: ${{ steps.osname.outputs.value_arch_camel }}_Pylon_SDK
path: ${{ runner.os == 'Windows' && 'conan' || 'pylon_sdk.tar.gz' }}
build-linux:
needs: download
strategy:
fail-fast: false
matrix:
os: [ ubuntu-24.04, ubuntu-24.04-arm ]
a: [3.9]
p: [manylinux_2_31_x86_64, manylinux_2_31_aarch64]
exclude:
# Exclude manylinux_2_31_aarch64 on ubuntu-24.04
- os: ubuntu-24.04
p: manylinux_2_31_aarch64
# Exclude manylinux_2_31_x86_64 on ubuntu-24.04-arm
- os: ubuntu-24.04-arm
p: manylinux_2_31_x86_64
runs-on: ${{ matrix.os }}
env:
P: ${{ matrix.p }}
A: ${{ matrix.a }}
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Detect docker parameters
id: dockerparams
run: |
import re
import os
# Extract python version and remove dot for pyver_tag
pyver_tag = "${{ matrix.a }}"
pyver_tag_nodot = pyver_tag.replace('.', '')
# Extract ubuntu version and architecture from the os string
os_str = "${{ matrix.os }}"
match = re.match(r'(ubuntu-\d+\.\d+)(?:-(arm))?', os_str)
if match:
base_os = match.group(1)
arch_from_os = match.group(2)
if arch_from_os == "arm":
artifacts_name = "Linux_aarch64_Pylon_SDK"
docker_base_arch = "arm64v8"
docker_platform = "linux/arm64"
qemu_target_arch = "aarch64"
else:
artifacts_name = "Linux_x86_64_Pylon_SDK"
docker_base_arch = "amd64"
docker_platform = "linux/amd64"
qemu_target_arch = "x86_64"
else:
raise ValueError(f"Unexpected OS format: {os_str}")
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f"docker_base_arch={docker_base_arch}\n")
f.write(f"docker_platform={docker_platform}\n")
f.write(f"qemu_target_arch={qemu_target_arch}\n")
f.write(f"artifacts_name={artifacts_name}\n")
f.write(f"pyver_tag=cp{pyver_tag_nodot}\n")
shell: python
# download the pylon sdks
- name: download linux artifacts
uses: actions/download-artifact@v5
with:
pattern: ${{ steps.dockerparams.outputs.artifacts_name }}
path: pylon-sdk
- name: Unpack pylon SDK to pylon-sdk folder
run: |
tar -xzf pylon-sdk/pylon_sdk.tar.gz -C pylon-sdk
- name: Display Structure of downloaded files
run: ls pylon-sdk
- name: Build docker container for pypylon build
run: |
docker build --platform "${{ steps.dockerparams.outputs.docker_platform }}" \
--build-arg "QEMU_TARGET_ARCH=${{ steps.dockerparams.outputs.qemu_target_arch }}" \
--build-arg "DOCKER_BASE_IMAGE=${{ steps.dockerparams.outputs.docker_base_arch }}/python:${{ matrix.a }}-bullseye" \
--build-arg "CMD_WRAPPER=linux64" \
--tag "pypylon-${{ matrix.p }}-${{ steps.dockerparams.outputs.pyver_tag }}-${{ github.run_id }}" - < ${{ github.workspace }}/scripts/build/Dockerfile.debian
- name: Build pypylon wheel
run: |
docker run -v "${{ github.workspace }}:/work" \
-v "${{ github.workspace }}/.github/workflows/scripts:/work/scripts/cibuild" \
-v "${{ github.workspace }}/pylon-sdk/pylon:/opt/pylon" -e PYLON_ROOT="/opt/pylon" \
--user $(id -u) pypylon-${{ matrix.p }}-${{ steps.dockerparams.outputs.pyver_tag }}-${{ github.run_id }} /work/scripts/cibuild/build.sh --update-platform-tag ${{ matrix.p }}
- uses: actions/upload-artifact@v4
with:
name: build-results-${{ matrix.p }}-${{ steps.dockerparams.outputs.pyver_tag }}
path: dist/*
- name: Upload Release Asset
if: needs.setup.outputs.is_release_build == 'true'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: dist/*
- name: Publish package to (Test)PyPI
if: needs.setup.outputs.is_release_build == 'true' && startsWith( matrix.p, 'manylinux' )
run: |
sudo pip3 install "twine==6.0.1"
python3 -m twine upload --non-interactive --skip-existing dist/*
build-windows:
needs: download
runs-on: windows-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.9"
- name: Download pylon SDK
uses: actions/download-artifact@v5
with:
pattern: Windows_Pylon_SDK
path: pylon-sdk
- name: Display Structure of downloaded files
run: dir pylon-sdk
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.3
env:
PYLON_DEV_DIR: ${{ github.workspace }}\pylon-sdk\pylon\Development
- uses: actions/upload-artifact@v4
with:
name: build-results-windows
path: ./wheelhouse/*.whl
- name: Upload Release Asset
if: needs.setup.outputs.is_release_build == 'true'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: ./wheelhouse/*.whl
- name: Publish package to (Test)PyPI
if: needs.setup.outputs.is_release_build == 'true'
run: |
python -m pip install twine
python -m twine upload --non-interactive --skip-existing wheelhouse\\*
shell: cmd
build-macos:
needs: download
runs-on: macos-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.9"
- uses: actions/download-artifact@v5
with:
name: macOS_Pylon_SDK
path: pylon-sdk
- name: Unpack pylon SDK to pylon-sdk folder
run: |
tar -xzf pylon-sdk/pylon_sdk.tar.gz -C pylon-sdk
- name: Display Structure of downloaded files
run: ls pylon-sdk
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.3
env:
PYLON_FRAMEWORK_ARM64: ${{ github.workspace }}/pylon-sdk/pylon/Frameworks
PYLON_FRAMEWORK_X86_64: ${{ github.workspace }}/pylon-sdk/pylon/Frameworks
- uses: actions/upload-artifact@v4
with:
name: build-results-macos
path: ./wheelhouse/*.whl
- name: Upload Release Asset
if: needs.setup.outputs.is_release_build == 'true'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: ./wheelhouse/*.whl
- name: Publish package to (Test)PyPI
if: needs.setup.outputs.is_release_build == 'true'
run: |
sudo pip3 install twine
python3 -m twine upload --non-interactive --skip-existing wheelhouse/*
cleanup:
if: always()
needs: [
prepare,
download,
build-linux,
build-macos,
build-windows
]
runs-on: ubuntu-latest
steps:
- uses: geekyeggo/delete-artifact@v5
continue-on-error: true
with:
name: |
Linux_x86_64_Pylon
Linux_x86_64_Pylon_SDK
Linux_aarch64_Pylon
Linux_aarch64_Pylon_SDK
Windows_Pylon
Windows_Pylon_SDK
macOS_Pylon
macOS_Pylon_SDK
unit-tests:
if: success()
needs: cleanup
strategy:
fail-fast: false
matrix:
os: [ ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-latest ]
python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ]
architecture: [ x64, arm64 ]
exclude:
# Exclude ARM64 architecture for windows-latest
- os: windows-latest
architecture: arm64
# Exclude ARM64 architecture for ubuntu-24.04
- os: ubuntu-24.04
architecture: arm64
# Exclude X64 architecture for ubuntu-24.04-arm
- os: ubuntu-24.04-arm
architecture: x64
# Exclude python 3.9 - 3.10 on macOS x86_64 due too issues with the runner image
# See also GitHub issue: https://github.com/actions/setup-python/issues/825
- os: macos-14
architecture: x64
python-version: 3.9
- os: macos-14
architecture: x64
python-version: 3.10
runs-on: ${{ matrix.os }}
steps:
- name: Check out repository
uses: actions/checkout@v2
- uses: dkershner6/switch-case-action@v1
id: pypylon-wheel-source
with:
default: "build-results-unknown"
conditionals-with-values: |
${{ runner.os == 'Linux' && matrix.architecture == 'arm64' }} => build-results-manylinux_2_31_aarch64-cp39
${{ runner.os == 'Linux' && matrix.architecture == 'x64' }} => build-results-manylinux_2_31_x86_64-cp39
${{ runner.os == 'Windows' }} => build-results-windows
${{ runner.os == 'macOS' }} => build-results-macos
- name: Download pypylon wheels
uses: actions/download-artifact@v4
with:
name: ${{ steps.pypylon-wheel-source.outputs.value }}
path: pypylon-wheels
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }}
- name: Set up needed linux requirements
if: runner.os == 'Linux'
run: |
sudo apt-get update && sudo apt-get install -y locales
sudo sed -i 's/^# *\(fr_FR.UTF-8\)/\1/' /etc/locale.gen
sudo locale-gen
- name: Run pypylon unit tests for Python ${{ matrix.python-version }}
if: runner.os != 'macOS'
run: |
python -m pip install --upgrade pip
pip install pytest numpy
pip install --no-index --find-links pypylon-wheels pypylon
pytest tests/genicam_tests tests/pylon_tests/emulated tests/pylondataprocessing_tests
- uses: dkershner6/switch-case-action@v1
if: runner.os == 'macOS'
id: pypylon-macos-arch
with:
default: "unknown"
conditionals-with-values: |
${{ matrix.architecture == 'arm64' }} => arm64
${{ matrix.architecture == 'x64' }} => x86_64
- name: Run pypylon unit tests for Python ${{ matrix.python-version }} without pylon Data Processing
if: runner.os == 'macOS'
run: |
arch -${{ steps.pypylon-macos-arch.outputs.value }} python -m pip install --upgrade pip
arch -${{ steps.pypylon-macos-arch.outputs.value }} pip install pytest numpy
arch -${{ steps.pypylon-macos-arch.outputs.value }} pip install --no-index --find-links pypylon-wheels pypylon
arch -${{ steps.pypylon-macos-arch.outputs.value }} pytest tests/genicam_tests tests/pylon_tests/emulated