Skip to content

Continuous integration file checks #29

Continuous integration file checks

Continuous integration file checks #29

Workflow file for this run

# Summary: TFQ continuous integration workflow for static code analysis.
#
# This workflow runs linters and code format/style checkers on certain events
# such as pull requests and merge-queue merges. It tries to be as efficient as
# possible by only running jobs when specific types of files were affected by
# a PR, and by caching the Python installation so that it doesn't have to be
# re-installed on every run. It reads the requirements.txt file to find out
# the required versions of some program like pylint and yapf, to adhere to DRY
# principles. It uses GitHub "problem matchers" to write error outputs to the
# workflow summary to make it easier to learn the outcome. Finally, It can be
# invoked manually using the "Run workflow" button on the page at
# https://github.com/tensorflow/quantum/actions/workflows/ci-file-checks.yaml
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
name: CI file checks
run-name: Continuous integration file checks
on:
pull_request:
types: [opened, synchronize]
branches:
- master
merge_group:
types:
- checks_requested
push:
branches:
- master
# Allow manual invocation, with options that can be useful for debugging.
workflow_dispatch:
inputs:
sha:
description: 'SHA of commit to run against:'
type: string
required: true
python_ver:
description: 'Python version:'
type: string
pylint_ver:
description: 'Pylint version:'
type: string
yapf_ver:
description: 'Yapf version:'
type: string
clang_format_ver:
description: 'clang-format version:'
type: string
remake_python_cache:
description: 'Delete & remake the Python cache'
type: boolean
default: false
env:
# Default Python version to use.
python_ver: '3.10'
# Note: as of 2025-01-16, clang-format v. 18 is the latest available on
# GitHub, and you have to use Ubuntu 24 to get it.
clang_format_ver: '18'
concurrency:
# Cancel any previously-started but still active runs on the same branch.
cancel-in-progress: true
group: ${{github.workflow}}-${{github.event.pull_request.number||github.ref}}
jobs:
Changes:
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
python: ${{steps.filter.outputs.python}}
python_files: ${{steps.filter.outputs.python_files}}
cc: ${{steps.filter.outputs.cc}}
cc_files: ${{steps.filter.outputs.cc_files}}
yaml: ${{steps.filter.outputs.yaml}}
yaml_files: ${{steps.filter.outputs.yaml_files}}
steps:
# When invoked manually, use the given SHA to figure out the change list.
- if: github.event_name == 'workflow_dispatch'
name: Use the user-provided SHA as the basis for comparison
env:
GH_TOKEN: ${{github.token}}
run: |
set -x +e
url="repos/${{github.repository}}/commits/${{inputs.sha}}"
full_sha="$(gh api $url -q '.sha')"
exit_code=$?
if [[ "$exit_code" == "0" ]]; then
echo "base=$full_sha" >> "$GITHUB_ENV"
else
{
echo "### :x: Workflow error"
echo "The SHA provided to _Run Workflow_ does not exist:"
echo "<code>${{inputs.sha}}</code>"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- if: github.event_name != 'workflow_dispatch'
name: Use ref ${{github.ref_name}} as the basis for comparison
run: |
echo base=${{github.ref_name}} >> "$GITHUB_ENV"
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
- name: Determine files changed by this ${{github.event_name}} event
uses: dorny/paths-filter@v3
id: filter
with:
base: ${{env.base}}
list-files: 'shell'
# The outputs will be variables named "foo_files" for a filter "foo".
filters: |
python:
- added|modified:
- '**/*.py'
cc:
- added|modified:
- '**/*.cc'
- '**/*.h'
- '**/*.proto'
yaml:
- added|modified:
- '**/*.yaml'
- '**/*.yml'
Setup:
if: needs.Changes.outputs.python == 'true'
needs: Changes
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
cache_key: ${{steps.parameters.outputs.cache_key}}
cache_paths: ${{steps.parameters.outputs.cache_paths}}
steps:
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
# Note: setup-python has a cache facility, but we don't use it here
# because we want to cache more Python things than setup-python does.
- name: Set up Python ${{inputs.python_ver || env.python_ver}}
uses: actions/setup-python@v5
with:
python-version: ${{inputs.python_ver || env.python_ver}}
- name: Set cache keys and other parameters
id: parameters
run: |
key="${{github.workflow_ref}}-${{hashFiles('requirements.txt')}}"
echo "cache_key=$key" >> "$GITHUB_OUTPUT"
# The paths used for actions/cache need to be on separate lines.
# Constructing a multiline value for an output variable is awkward.
# shellcheck disable=SC2005
{
echo "cache_paths<<EOF"
echo "$(pip cache dir)"
echo "${{env.pythonLocation}}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Test if the cache already exists
uses: actions/cache@v4
id: check_cache
with:
lookup-only: true
key: ${{steps.parameters.outputs.cache_key}}
path: ${{steps.parameters.outputs.cache_paths}}
- if: >-
steps.check_cache.outputs.cache-hit == 'true' &&
inputs.remake_python_cache == 'true'
name: Clear the Python cache
continue-on-error: true
env:
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
run: |
key="${{steps.parameters.outputs.cache_key}}"
gh extension install actions/gh-actions-cache
gh actions-cache delete "$key" --confirm
- if: >-
steps.check_cache.outputs.cache-hit != 'true' ||
inputs.remake_python_cache == 'true'
name: Set up the Python cache
uses: actions/cache@v4
id: restore_cache
with:
key: ${{steps.parameters.outputs.cache_key}}
path: ${{steps.parameters.outputs.cache_paths}}
- if: >-
steps.check_cache.outputs.cache-hit != 'true' ||
inputs.remake_python_cache == 'true'
name: Install TFQ dependencies
# Need to install all requirements b/c Pylint needs to load modules.
run: |
pip install -r requirements.txt
- if: ${{inputs.pylint_ver != ''}}
name: Install requested version ${{inputs.pylint_ver}} of Pylint
# Override version of Pylint installed from requirements.txt
run: |
set -x
pip install pylint==${{inputs.pylint_ver}}
- if: ${{inputs.yapf_ver != ''}}
name: Install requested version ${{inputs.yapf_ver}} of Yapf
# Override version of Yapf installed from requirements.txt
run: |
set -x
pip install yapf==${{inputs.yapf_ver}}
Cplusplus-format:
if: needs.Changes.outputs.cc == 'true'
name: Check C++ and Protobuf coding style
needs: Changes
runs-on: ubuntu-24.04
env:
changed_files: ${{needs.Changes.outputs.cc_files}}
steps:
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
- name: Set up clang-format output problem matcher
run: echo '::add-matcher::.github/problem-matchers/clang-format.json'
- name: Run clang-format on C++ and Protobuf files
run: |
set -x +e -o pipefail
version=${{inputs.clang_format_ver || env.clang_format_ver}}
clang-format-$version --verbose -Werror --style google --dry-run \
${{env.changed_files}} > diff.out 2>&1
exit_code=$?
if [[ "$exit_code" != "0" ]]; then
# Write output both here and to the job summary.
bo=$'\e[1m'; bl=$'\e[38;5;117m'; rs=$'\e[0m'; hi='👋🏻'
u="https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
echo "$hi ${bl}Visit $bo$u${rs}$bl for formatted diff output$rs $hi"
echo '::group::clang-format output'
cat diff.out
echo '::endgroup::'
# shellcheck disable=SC2006
{
echo "### Output from <code>clang-format</code> version $version"
echo '```diff'
echo "$(< diff.out)"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
exit $exit_code
Python-lint:
if: needs.Changes.outputs.python == 'true'
name: Check Python lint
needs: [Changes, Setup]
runs-on: ubuntu-22.04
steps:
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{inputs.python_ver || env.python_ver}}
- name: Restore the Python cache
uses: actions/cache@v4
with:
key: ${{needs.Setup.outputs.cache_key}}
path: ${{needs.Setup.outputs.cache_paths}}
fail-on-cache-miss: true
- name: Set up Pylint output problem matcher
run: echo '::add-matcher::.github/problem-matchers/pylint.json'
- name: Lint the changed Python files
run: |
set +e -o pipefail
pylint -v ${{needs.Changes.outputs.python_files}} |& tee ./pylint.out
exit_code=$?
if [[ "$exit_code" != "0" ]]; then
{
echo '### Output from <code>pylint</code>'
echo ''
echo '```'
echo "$(< ./pylint.out)"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
exit $exit_code
Python-format:
if: needs.Changes.outputs.python == 'true'
name: Check Python coding style
needs: [Changes, Setup]
runs-on: ubuntu-22.04
steps:
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{inputs.python_ver || env.python_ver}}
- name: Restore the Python cache
uses: actions/cache@v4
with:
key: ${{needs.Setup.outputs.cache_key}}
path: ${{needs.Setup.outputs.cache_paths}}
fail-on-cache-miss: true
- name: Run Yapf on the Python changed files
run: |
set +e
yapf --parallel --diff --style=google \
${{needs.Changes.outputs.python_files}} > diff.out 2>&1
exit_code=$?
if [[ -s ./diff.out ]]; then
# Write output both here and to the job summary.
bo=$'\e[1m'; bl=$'\e[38;5;117m'; rs=$'\e[0m'; hi='👋🏻'
u="https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
echo "$hi ${bl}Visit $bo$u${rs}$bl for formatted diff output$rs $hi"
echo '::group::Yapf output'
cat diff.out
echo '::endgroup::'
# shellcheck disable=SC2006
{
echo '### Output from <code>yapf</code>'
echo ''
echo '```diff'
echo "$(< diff.out)"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
exit $exit_code
Yaml-lint:
if: needs.Changes.outputs.yaml == 'true'
name: YAML lint
needs: Changes
runs-on: ubuntu-24.04
steps:
- name: Check out a copy of the TFQ git repository
uses: actions/checkout@v4
- name: Set up yamllint output problem matcher
run: echo '::add-matcher::.github/problem-matchers/yamllint.json'
- name: Find out the yamllint version
id: yamllint
run: |
version=$(yamllint --version)
echo "version=${version#yamllint }" >> "$GITHUB_OUTPUT"
- name: Run yamllint ${{steps.yamllint.outputs.version}}
run: |
set -x
# shellcheck disable=SC2086
yamllint --format github ${{needs.Changes.outputs.yaml_files}}