Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/workflows/release-drafter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,26 @@ jobs:
update_release_draft:
name: 'Update Release Draft'
permissions:
# write permission is required to create releases
contents: write
contents: write # Create and update draft releases
runs-on: 'ubuntu-latest'
timeout-minutes: 3
steps:
# Harden the runner used by this workflow
# Load the egress allow-list out-of-band from the
# organisation's .github repository and publish it as
# $CONNECTION_ALLOW_LIST for the harden-runner step below.
# yamllint disable-line rule:line-length
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
- uses: lfreleng-actions/harden-runner-block-action@6db537b3e6d060c3287c5a3ce2c28b55b0af330d # v0.2.1
with:
egress-policy: 'audit'
config: '@18d9c4446bea555d0783e850f6d295f844fe8f67' # v0.1.1

# Harden the runner with the just-loaded allow-list.
- name: 'Harden runner (block)'
# yamllint disable-line rule:line-length
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: 'block'
allowed-endpoints: >
${{ env.CONNECTION_ALLOW_LIST }}

# yamllint disable-line rule:line-length
- uses: release-drafter/release-drafter@ed4bc48ec97379be2258e7b7ac2624a3e26ab809 # v7.4.0
- uses: release-drafter/release-drafter@4d75298e00d9e34c483e5ff8c68d0ea1c1940c1e # v7.5.1
43 changes: 36 additions & 7 deletions .github/workflows/tag-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ on:

permissions: {}

# Serialise repeated runs for the same tag; never cancel an in-flight
# release promotion. Distinct tags use distinct groups and proceed
# independently.
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
cancel-in-progress: false

jobs:
validate_tag:
name: 'Validate Tag'
Expand All @@ -25,11 +32,22 @@ jobs:
outputs:
tag: "${{ steps.tag_validate.outputs.tag_name }}"
steps:
# Harden the runner used by this workflow
# Load the egress allow-list out-of-band from the
# organisation's .github repository and publish it as
# $CONNECTION_ALLOW_LIST for the harden-runner step below.
# yamllint disable-line rule:line-length
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
- uses: lfreleng-actions/harden-runner-block-action@6db537b3e6d060c3287c5a3ce2c28b55b0af330d # v0.2.1
with:
config: '@18d9c4446bea555d0783e850f6d295f844fe8f67' # v0.1.1

# Harden the runner with the just-loaded allow-list.
- name: 'Harden runner (block)'
# yamllint disable-line rule:line-length
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
egress-policy: 'block'
allowed-endpoints: >
${{ env.CONNECTION_ALLOW_LIST }}

# yamllint disable-line rule:line-length
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand All @@ -53,14 +71,25 @@ jobs:
needs: validate_tag
runs-on: 'ubuntu-latest'
permissions:
contents: write
contents: write # Promote (publish) the draft release for the tag
timeout-minutes: 5
steps:
# Harden the runner used by this workflow
# Load the egress allow-list out-of-band from the
# organisation's .github repository and publish it as
# $CONNECTION_ALLOW_LIST for the harden-runner step below.
# yamllint disable-line rule:line-length
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
- uses: lfreleng-actions/harden-runner-block-action@6db537b3e6d060c3287c5a3ce2c28b55b0af330d # v0.2.1
with:
config: '@18d9c4446bea555d0783e850f6d295f844fe8f67' # v0.1.1

# Harden the runner with the just-loaded allow-list.
- name: 'Harden runner (block)'
# yamllint disable-line rule:line-length
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
egress-policy: 'block'
allowed-endpoints: >
${{ env.CONNECTION_ALLOW_LIST }}

# yamllint disable-line rule:line-length
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ on:

permissions: {}

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

env:
python_version: "3.12"

Expand All @@ -34,11 +38,14 @@ jobs:
steps:
- name: "Checkout repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

# Perform setup prior to running test(s)
- name: "Checkout sample project repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
repository: "lfreleng-actions/test-python-project"
path: "test-python-project"

Expand Down
118 changes: 76 additions & 42 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,31 +49,43 @@ runs:
using: 'composite'
steps:
- name: 'Setup action/environment'
id: setup
shell: bash
env:
PYTHON_VERSION: "${{ inputs.python_version }}"
PATH_PREFIX: "${{ inputs.path_prefix }}"
PERMIT_FAIL: "${{ inputs.permit_fail }}"
run: |
# Setup action/environment
if [ -z "${{ inputs.python_version }}" ]; then
if [ -z "$PYTHON_VERSION" ]; then
echo 'Error: Python version was not provided ❌'; exit 1
else
echo "Using Python: ${{ inputs.python_version }} 🐍"
echo "Using Python: $PYTHON_VERSION 🐍"
fi

# Handle path_prefix input consistently and when absent
path_prefix="${{ inputs.PATH_PREFIX }}"
path_prefix="$PATH_PREFIX"
if [ -z "$path_prefix" ]; then
# Set current directory as path prefix
path_prefix="."
else
# Strip any trailing slash in provided path
# Strip any trailing slash in provided path
path_prefix="${path_prefix%/}"
fi
# Verify is a valid directory path
if [ ! -d "$path_prefix" ]; then
echo 'Error: invalid path/prefix to project directory ❌'; exit 1
fi
echo "path_prefix=$path_prefix" >> "$GITHUB_ENV"
# Use the heredoc output form with a unique delimiter to
# guard against output injection via crafted input values
delimiter="ghadelim_$$_${RANDOM}${RANDOM}${RANDOM}"
{
echo "path_prefix<<${delimiter}"
echo "$path_prefix"
echo "${delimiter}"
} >> "$GITHUB_OUTPUT"

if [ "f${{ inputs.PERMIT_FAIL }}" = "ftrue" ]; then
if [ "f$PERMIT_FAIL" = "ftrue" ]; then
echo 'Warning: test failures will be permitted ⚠️'
fi

Expand All @@ -84,7 +96,7 @@ runs:
python-version: ${{ inputs.python_version }}

- name: 'Cache Python dependencies'
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4.0.2
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cache/pip
Expand All @@ -102,7 +114,12 @@ runs:
# yamllint enable rule:line-length

- name: 'Install notebook/test dependencies'
id: flags
shell: bash
env:
PATH_PREFIX: "${{ steps.setup.outputs.path_prefix }}"
NBMAKE_KERNEL: "${{ inputs.nbmake_kernel }}"
PARALLEL_TESTS: "${{ inputs.parallel_tests }}"
run: |
# Install notebook/test dependencies
echo 'Installing: pytest, pytest-cov, nbmake ⬇️'
Expand All @@ -111,26 +128,32 @@ runs:
pytest pytest-cov nbmake

echo 'Install project and dependencies'
if [ -f ${{ env.path_prefix }}/pyproject.toml ]; then
echo "Source: ${{ env.path_prefix }}/pyproject.toml ⬇️"
pip install -q "${{ env.path_prefix }}/"
elif [ -f ${{ env.path_prefix }}/requirements.txt ]; then
echo "Source: ${{ env.path_prefix }}/requirements.txt ⬇️"
pip install -q -r "${{ env.path_prefix }}/requirements.txt"
if [ -f "$PATH_PREFIX/pyproject.toml" ]; then
echo "Source: $PATH_PREFIX/pyproject.toml ⬇️"
pip install -q "$PATH_PREFIX/"
elif [ -f "$PATH_PREFIX/requirements.txt" ]; then
echo "Source: $PATH_PREFIX/requirements.txt ⬇️"
pip install -q -r "$PATH_PREFIX/requirements.txt"
else
# Jupyter Notebooks are not necessarily Python projects
# Jupyter Notebooks are not necessarily Python projects
echo 'No Python dependencies to install ⚠️'
fi

# Set appropriate flags to nbmake
if [ -n "${{ inputs.nbmake_kernel }}" ]; then
echo "Forcing use of a custom kernel: ${{ inputs.nbmake_kernel }} 💬"
echo "kernel_flags=--nbmake-kernel=${{ inputs.nbmake_kernel }}" \
>> "$GITHUB_ENV"
# Set appropriate flags to nbmake
if [ -n "$NBMAKE_KERNEL" ]; then
echo "Forcing use of a custom kernel: $NBMAKE_KERNEL 💬"
# Use the heredoc output form with a unique delimiter to
# guard against output injection via crafted input values
delimiter="ghadelim_$$_${RANDOM}${RANDOM}${RANDOM}"
{
echo "kernel_flags<<${delimiter}"
echo "--nbmake-kernel=$NBMAKE_KERNEL"
echo "${delimiter}"
} >> "$GITHUB_OUTPUT"
fi
# Set flags for parallel testing
if [ "${{ inputs.parallel_tests }}" = 'true' ]; then
echo "flags=-n=auto" >> "$GITHUB_ENV"
# Set flags for parallel testing
if [ "$PARALLEL_TESTS" = 'true' ]; then
echo "flags=-n=auto" >> "$GITHUB_OUTPUT"
fi

- name: 'Install Pytest parallel test tool'
Expand All @@ -152,32 +175,43 @@ runs:
- name: 'Install nbmake custom kernel'
if: inputs.install_kernel == 'true'
shell: bash
env:
NBMAKE_KERNEL: "${{ inputs.nbmake_kernel }}"
run: |
# Install parallel test tool
echo "Installing custom nbmake kernel: ${{ inputs.nbmake_kernel }} ⬇️"
python -m ipykernel install --user --name "${{ inputs.nbmake_kernel }}"
# Install nbmake custom kernel
echo "Installing custom nbmake kernel: $NBMAKE_KERNEL ⬇️"
python -m ipykernel install --user --name "$NBMAKE_KERNEL"

- name: 'Build/test Jupyter Notebooks'
shell: bash
env:
PATH_PREFIX: "${{ steps.setup.outputs.path_prefix }}"
PERMIT_FAIL: "${{ inputs.permit_fail }}"
PYTEST_FLAGS: "${{ inputs.pytest_flags }}"
KERNEL_FLAGS: "${{ steps.flags.outputs.kernel_flags }}"
FLAGS: "${{ steps.flags.outputs.flags }}"
run: |
# Build/Test Jupyter Notebooks
echo 'Searching repository for Jupyter Notebooks'
find "${{ env.path_prefix }}/" -name '*.ipynb'
if [ $? -eq 0 ]; then
if [ "f${{ inputs.permit_fail }}" = 'ftrue' ]; then
echo 'Warning: flag set to permit test failures ⚠️'
pytest --nbmake \
${{ inputs.pytest_flags }} \
${{ env.kernel_flags }} \
${{ env.flags }} \
${{ env.path_prefix }}/**/*ipynb || true
else
pytest --nbmake \
${{ inputs.pytest_flags }} \
${{ env.kernel_flags }} \
${{ env.flags }} \
${{ env.path_prefix }}/**/*ipynb
fi
else
mapfile -t notebooks < <(find "$PATH_PREFIX/" -name '*.ipynb')
if [ "${#notebooks[@]}" -eq 0 ]; then
echo 'Error: no Jupyter Notebooks were found ❌'; exit 1
fi
printf '%s\n' "${notebooks[@]}"
# Word splitting of the flag variables below is intentional
if [ "f$PERMIT_FAIL" = 'ftrue' ]; then
echo 'Warning: flag set to permit test failures ⚠️'
# shellcheck disable=SC2086
pytest --nbmake \
$PYTEST_FLAGS \
$KERNEL_FLAGS \
$FLAGS \
"${notebooks[@]}" || true
else
# shellcheck disable=SC2086
pytest --nbmake \
$PYTEST_FLAGS \
$KERNEL_FLAGS \
$FLAGS \
"${notebooks[@]}"
fi
Loading