Skip to content

CI

CI #1539

Workflow file for this run

name: CI
on:
push:
branches:
- master
tags:
# Version tags.
#
# Tags matching this pattern will cause the "release" job below to run,
# so edit it carefully! It should not match arbitrary tags.
- "[0-9]+.[0-9]+.[0-9]+*"
pull_request:
workflow_dispatch:
# Routinely check that we continue to work in the face of external changes.
schedule:
# Every day at 17:42 UTC / 9:42 Seattle (winter) / 10:42 Seattle (summer)
- cron: "42 17 * * *"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nextstrain/.github/actions/shellcheck@master
test-source:
name: test-source (python=${{ matrix.python }} os=${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
python:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install Nextstrain CLI
run: python3 -m pip install --upgrade '.[dev]'
- run: ./devel/pytest -v
build-dist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
# Install up-to-date packaging toolchain.
- run: python3 -m pip install --upgrade pip setuptools wheel
- run: python3 -m pip install --upgrade build
# Update version to include local git rev if we're not building a release tag.
- if: github.ref_type != 'tag'
run: |
version="$(./devel/read-version)"
git_rev="$(git rev-parse --short @)"
./devel/update-version "${version%%+*}+git.${git_rev}"
# Build dists.
- run: python3 -m build
# Upload dists as workflow artifacts.
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
build-standalone:
needs: build-dist
strategy:
fail-fast: false
matrix:
# Generally we want to build on the oldest supported OS to maximize the
# final binary's compatibility. See pyoxidizer's docs for more
# considerations affecting the choice of build machine OS¹ and future
# plans for robust, turnkey build environments².
#
# On Linux, we build inside a container to avoid portability issues, so
# the container's host OS version here doesn't have an impact (other
# than CI stability).
#
# ¹ https://pyoxidizer.readthedocs.io/en/stable/pyoxidizer_distributing_binary_portability.html
# ² https://pyoxidizer.readthedocs.io/en/stable/pyoxidizer_status.html#an-official-build-environment
include:
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
exe: nextstrain
- os: macos-12
target: x86_64-apple-darwin
exe: nextstrain
- os: macos-14
target: aarch64-apple-darwin
exe: nextstrain
- os: windows-2019
target: x86_64-pc-windows-msvc
exe: nextstrain.exe
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
# Note that this Python version doesn't impact the actual build.
- uses: actions/setup-python@v5
with:
python-version: "3.10"
# Build the executable + necessary external files from the dists.
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Set DIST, DIST_VERSION, and INSTALLATION_ARCHIVE_STEM
run: |
# shellcheck disable=SC2034
DISTS=(dist/nextstrain_cli-*-py3-none-any.whl)
DIST="${DISTS[0]}"
DIST_VERSION="$DIST"
DIST_VERSION="${DIST_VERSION#dist/nextstrain_cli-}"
DIST_VERSION="${DIST_VERSION%-py3-none-any.whl}"
INSTALLATION_ARCHIVE_STEM="nextstrain-cli-${DIST_VERSION}-standalone-${{ matrix.target }}"
for var in DIST DIST_VERSION INSTALLATION_ARCHIVE_STEM; do
echo "${var}=${!var}" | tee -a "$GITHUB_ENV"
done
- run: |
./devel/pyoxidizer build \
--release \
--target-triple ${{ matrix.target }} \
--var NEXTSTRAIN_CLI_DIST "$DIST"
# Analyze the executable for potential portability issues.
#
# This is for informational purposes only in build logs, so we don't care
# if it fails. Currently it only works on Linux, though it's supposed to
# eventually work on all platforms supported by pyoxidizer.
- if: runner.os == 'Linux'
run: ./devel/pyoxidizer analyze build/${{ matrix.target }}/release/installation/${{ matrix.exe }}
continue-on-error: true
# XXX TODO: Review and report on licensing of all the stuff built into
# the binary, as bundling things statically can trigger different license
# terms than "normal" installs (e.g. via pip). See also pyoxidizer's
# docs about this and the tooling it includes to support license review.¹
# -trs, 1 June 2022
#
# ¹ https://pyoxidizer.readthedocs.io/en/stable/pyoxidizer_packaging_licensing.html#licensing-considerations
# Create installation archive.
#
# Use tar on Unix to preserve file modes (e.g. the executable bit), thus
# avoiding having to restore them manually after archive extraction. Use
# zip on Windows because it's a native format which requires no extra
# tooling.
- if: runner.os != 'Windows'
run: tar czvpf "$INSTALLATION_ARCHIVE_STEM.tar.gz" -C build/${{ matrix.target }}/release/installation/ .
- if: runner.os == 'Windows'
run: Compress-Archive -DestinationPath "$Env:INSTALLATION_ARCHIVE_STEM.zip" -Path build/${{ matrix.target }}/release/installation/*
shell: pwsh
# Upload installation archive as a workflow artifact.
#
# At least one path needs to match, or this errors.
- uses: actions/upload-artifact@v4
with:
name: standalone-${{ matrix.target }}
path: |
${{ env.INSTALLATION_ARCHIVE_STEM }}.tar.gz
${{ env.INSTALLATION_ARCHIVE_STEM }}.zip
if-no-files-found: error
# Quick smoke test that the executable at least runs! Useful before
# launching the more extensive tests below.
- run: ./build/${{ matrix.target }}/release/installation/${{ matrix.exe }} --help
write-install-commands:
needs: build-standalone
runs-on: ubuntu-latest
steps:
- name: Write installation commands to job summary
run: |
cat >"$GITHUB_STEP_SUMMARY" <<'~~'
Build complete. Commands to install locally:
Linux:
```bash
curl -fsSL --proto '=https' https://nextstrain.org/cli/installer/linux | bash -s ci-build/${{ github.run_id }}
```
macOS:
```bash
curl -fsSL --proto '=https' https://nextstrain.org/cli/installer/mac | bash -s ci-build/${{ github.run_id }}
```
Windows:
```powershell
Invoke-Expression "& { $(Invoke-RestMethod https://nextstrain.org/cli/installer/windows) } ci-build/${{ github.run_id }}"
```
~~
test-dist:
needs: build-dist
name: test-dist (python=${{ matrix.python }} os=${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
python:
- '3.8'
- '3.9'
- '3.10'
# XXX TODO: Add 3.11 here once supported by bioconda: https://github.com/nextstrain/augur/issues/1334
# XXX TODO: Add 3.12 here once supported by bioconda: https://github.com/nextstrain/augur/issues/1334
runs-on: ${{ matrix.os }}
defaults:
run:
# Add -l for setup-integration-tests → setup-miniconda → automatic
# activation of "test" environment.
shell: bash -l -eo pipefail {0}
steps:
- uses: actions/checkout@v4
with:
path: src/
- uses: ./src/.github/actions/setup-integration-tests
with:
python-version: ${{ matrix.python }}
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Install Nextstrain CLI
run: python3 -m pip install --upgrade dist/nextstrain_cli-*-py3-none-any.whl
- uses: ./src/.github/actions/run-integration-tests
test-standalone:
needs: build-standalone
name: test-standalone (os=${{ matrix.os}}, target=${{ matrix.target }})
strategy:
fail-fast: false
matrix:
# Test on all the platforms available via GitHub Actions.
#
# Ideally we'd test on machines with ~fresh OS installs. The kitchen
# sink of development/build software pre-installed into GitHub Action's
# virtual-environments has a decent risk of making this CI blind to
# end-user runtime issues with our binaries (e.g. missing DLLs). Such
# fresh CI machines are not readily available, however, since
# pre-installation is convenient for builds.
include:
- { os: ubuntu-20.04, target: x86_64-unknown-linux-gnu }
- { os: ubuntu-22.04, target: x86_64-unknown-linux-gnu }
- { os: macos-12, target: x86_64-apple-darwin }
- { os: macos-14, target: aarch64-apple-darwin }
- { os: windows-2019, target: x86_64-pc-windows-msvc }
- { os: windows-2022, target: x86_64-pc-windows-msvc }
runs-on: ${{matrix.os}}
defaults:
run:
# Add -l for setup-integration-tests → setup-miniconda → automatic
# activation of "test" environment.
shell: bash -l -eo pipefail {0}
steps:
- uses: actions/checkout@v4
with:
path: src/
- uses: ./src/.github/actions/setup-integration-tests
with:
python-version: '3.9'
# Download and extract the installation archive.
- uses: actions/download-artifact@v4
with:
name: standalone-${{ matrix.target }}
- if: runner.os != 'Windows'
run: tar xzvpf nextstrain-cli-*-standalone-${{ matrix.target }}.tar.gz
- if: runner.os == 'Windows'
run: Expand-Archive -Path nextstrain-cli-*-standalone-${{ matrix.target }}.zip -DestinationPath .
shell: pwsh
- run: echo "$PWD" >> "$GITHUB_PATH"
- uses: ./src/.github/actions/run-integration-tests
doc:
uses: nextstrain/.github/.github/workflows/docs-ci.yaml@master
with:
docs-directory: doc/
pip-install-target: .[dev]
make-target: dirhtml
release:
# Restricted to version tags by the "on: push: tags: …" config at the top.
if: |2
github.event_name == 'push'
&& github.ref_type == 'tag'
needs:
- build-dist
- build-standalone
- test-source
- test-dist
- test-standalone
- lint
- doc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# In actions/checkout@v4 above, annotated tags are intentionally
# **overwritten** and converted to a lightweight tag. Forcibly restore
# the annotated tag object from the remote so we can verify/use it later.
- run: git fetch --force origin tag "$GITHUB_REF_NAME"
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- run: python3 -m pip install --upgrade twine
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: actions/download-artifact@v4
with:
name: standalone-x86_64-unknown-linux-gnu
- uses: actions/download-artifact@v4
with:
name: standalone-x86_64-apple-darwin
- uses: actions/download-artifact@v4
with:
name: standalone-aarch64-apple-darwin
- uses: actions/download-artifact@v4
with:
name: standalone-x86_64-pc-windows-msvc
- run: twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
TWINE_REPOSITORY_URL: https://upload.pypi.org/legacy/
- run: ./devel/create-github-release "${{github.ref_name}}" dist/* nextstrain-cli-*-standalone-*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}