diff --git a/pages/developers/gha_basic.md b/pages/developers/gha_basic.md new file mode 100644 index 0000000..b7c54bf --- /dev/null +++ b/pages/developers/gha_basic.md @@ -0,0 +1,166 @@ +--- +layout: page +title: GitHub Actions +permalink: /developer/gha_basic +nav_order: 7 +parent: Developer information +--- + +# GitHub Actions + +The recommended CI for Scikit-HEP is GitHub Actions (GHA), although it's +predecessor (Azure) is also in heavy usage, and other popular services (Travis, +Appveyor, and Circle CI) may be found in a few packages. GHA is preferred due +to the flexible, extensible design and the tight integration with the GitHub +permissions model (and UI). Here is a guide in setting up a new package with GHA. + +GHA is made up of workflows which consist of actions. Here are some of the +workflows you will probably want in your package. These should be in a file +named `.github/workflows/main.yml` or similar. + +## Header + +Your main CI workflow file should begin something like this: + +```yaml +name: CI + +on: + pull_request: + push: + branches: master + tags: + - 'v*' + +jobs: +``` + +This gives the workflow a nice name, and defines the conditions under which it +runs. This will run on pull requests or pushes to master, and on version tags. If +you use a develop branch, you probably will want to include that. + +## Pre-commit + +If you use [pre-commit](https://pre-commit.com) (and you should), this is a job that will check pre-commit for you: + +```yaml + pre-commit: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - name: set PY + run: echo "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')" + - uses: actions/cache@v1 + with: + path: ~/.cache/pre-commit + key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }} + - uses: pre-commit/action@v1.1.0 +``` + +## Unit tests + +Implementing unit tests is also easy. Since you should be following best +practices listed in the previous sections, this becomes an almost directly +copy-and-paste formula, regardless of the package details. You might need +to adjust the Python versions to suit your taste. + +```yaml + checks: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - 2.7 + - 3.6 + - 3.8 + name: Check Python ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + run: python -m pip install -e .[test] + + - name: Test package + run: python -m pytest +``` + +A few things to note from above: + +The matrix should contain the versions you are interested in. You can also test +on other OS's if you are building any extensions or are worried about your +package on macOS or Windows. Fail-fast is optional. + +You need to use version 1 of the checkout, since version 2 strips too much +from the repository for `setuptools_scm` to work. + +The formula here for installing should be identical for all users; and using +[PEP 517](https://www.python.org/dev/peps/pep-0517/)/[518](https://www.python.org/dev/peps/pep-0518/) +builds, you are even guaranteed a consistent wheel will be produced just as if +you were building a final package. + +## Distribution: Pure Python wheels + +We will cover binary wheels later, but for a simple universal (pure Python) +package, the procedure is simple. + +```yaml + dist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: 3.8 + + - name: Install wheel and SDist requirements + run: python -m pip install "setuptools>=42.0" "setuptools_scm[toml]>=3.4" "wheel" + + - name: Build SDist + run: python setup.py sdist + + - name: Build wheel + run: > + python -m pip wheel . -w wheels && + ls -lh wheels && + mkdir -p dist && + cp wheels/*any.whl dist/ + + - uses: actions/upload-artifact@v1 + with: + name: DistPackage + path: dist + + - uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') +``` + +A few things to note that are new to this job: + +We install SDist requirements by hand since `python setup.py sdist` does not +get the benefits of having pip install things. If you have any special +requirements in your `pyproject.toml`, you'll need to list them here. This is +special just for the SDist, not for making wheels (which should be done by the +PEP 517/518 process for you). + +You need to put your base package name in for `` in the copy +command; pip will put all wheels needed in the directory you specify, and you +need to just pick out your wheels for upload. You don't want to upload numpy or +some other wheel it had to build (not common anymore, but can happen). + +We upload the artifact just to make it available via the GitHub PR/Checks API. +You can download a file to test locally if you want without making a release. + +Finally, only on release tags, we publish to PyPI. You'll need to go to PyPI, +generate a token for your project, and put it into `pypi_password` on your +repo's secrets page. + +