airflow publish
is a composite action repository used to validate artifacts and publish to PyPI from SVN.
This action reads the release configuration file and writes output to GITHUB_OUTPUTS
. The configuration file is a YAML file containing rules to validate and config for the publish process.
- name: "Config parser"
id: config-parser
uses: ./read-config
with:
release-config: ${{ inputs.release-config }}
Example configuration file:
project:
name: airflow
description: "Publish rc provider packages to PyPI"
publisher:
name: airflow
url: https://dist.apache.org/repos/dist/dev/airflow/
path: providers/pypi-rc/
checks:
svn:
- id: extension
description: "Validate svn package extensions"
identifiers:
- type: regex
pattern: ".*(py3-none-any.whl|py3-none-any.whl.asc|py3-none-any.whl.sha512|tar.gz|tar.gz.asc|tar.gz.sha512)$"
- id: package_name
description: "Validate svn package names"
identifiers:
- type: regex
pattern: ".*(apache_airflow_providers.*)$"
checksum:
- id: checksum
description: "Validate check sum with SHA512"
algorithm: "sha512"
signature:
- id: signature
description: "Validate signatures with GPG of packages"
method: gpg
keys: "https://dist.apache.org/repos/dist/release/airflow/KEYS"
artifact:
id: artifact
description: "Find providers artifacts to publish to PyPI"
exclude:
- type: regex
pattern: ".*(.asc|.sha512)$"
This section contains the publisher details like name
, url
, and path
to identify the repository in SVN.
name
: Configure any name for the publisher. A meaningful name is recommended. For example, if you are releasing providers, you can name itproviders
.url
: URL of the SVN repository to checkout.path
: Path to the directory where the artifacts are stored in the SVN repository.
Example:
If you want to release providers, and the SVN repository structure is as follows:
https://dist.apache.org/repos/dist/dev/airflow/providers
https://dist.apache.org/repos/dist/release/airflow/providers
To publish the packages from the dev/providers
folder, set url
and path
in the release-config.yml
as shown below:
url: https://dist.apache.org/repos/dist/dev/airflow
repo-path: providers/
This action is used to checkout the SVN repository to a temporary directory in the runner.
It uses the configuration from the read-config
action to checkout the repository.
Inputs to the action:
temp-dir
: Temporary directory to checkout the repository.repo-url
: URL of the SVN repository to checkout.repo-path
: Path to the directory where the artifacts are stored in the SVN repository.
- name: "Checkout svn ${{ steps.config-parser.outputs.publisher-url }}"
id: "svn-checkout"
uses: ./init
with:
temp-dir: ${{ inputs.temp-dir }}
repo-url: ${{ steps.config-parser.outputs.publisher-url }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
Action to validate the file name patterns and extensions of the artifacts in the SVN repository.
This action uses the svn
section from the release-config.yml
to validate the artifacts. An example configuration is shown below.
checks:
svn:
- id: extension
description: "Validate svn package extensions"
identifiers:
- type: regex
pattern: ".*(py3-none-any.whl|tar.gz.sha512|tar.gz.asc|tar.gz|py3-none-any.whl.asc|py3-none-any.whl.sha512)$"
- id: package_name
description: "Validate svn package names"
identifiers:
- type: regex
pattern: ".*(apache_airflow.*)$"
- type: regex
pattern: ".*(apache-airflow.*)$"
This rule is used to validate the package extension.
It checks whether each package has the required extension or not. Examples include:
.tar.gz
.tar.gz.asc
.tar.gz.sha512
-py3-none-any.whl
-py3-none-any.whl.asc
-py3-none-any.whl.sha512
This rule is used to validate the package name.
It checks whether each package name matches the required pattern or not.
At present, the SVN Action supports only regex type identifiers to validate the package names and extensions.
- name: "Svn check"
id: "svn-check"
uses: ./svn
with:
svn-config: ${{ steps.config-parser.outputs.checks-svn }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
Action to validate the checksum of the artifacts in the SVN repository.
This action uses the checksum
section from the release-config.yml
to validate the artifacts. An example configuration is shown below.
checks:
checksum:
- id: checksum
description: "Validate check sum with SHA512"
algorithm: "sha512"
This rule is used to validate the checksum of the artifacts.
It checks the checksum of the artifacts with the provided checksum type.
Provide the checksum type in the algorithm
field. eg: you may provide sha512
or sha256
as the checksum type. anything that is supported by the hashlib
module in Python.
- name: "Checksum check"
id: "checksum-check"
uses: ./checksum
with:
checksum-config: ${{ steps.config-parser.outputs.checks-checksum }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
Action to validate the signature of the artifacts in the SVN repository.
This action uses the signature
section from the release-config.yml
to validate the artifacts. An example configuration is shown below.
checks:
signature:
- id: signature
description: "Validate signatures with GPG of packages"
method: gpg
keys: "https://dist.apache.org/repos/dist/release/airflow/KEYS"
This rule is used to validate the signature of the artifacts.
It checks the signature of the artifacts with the provided GPG keys file in the keys
field.
At present, the Signature Action supports only GPG type identifiers to validate the signature of the artifacts.
- name: "Signature check"
id: "signature-check"
uses: ./signature
with:
signature-config: ${{ steps.config-parser.outputs.checks-signature }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
Action to publish the artifacts to PyPI.
This action uses the publish
section from the release-config.yml
to publish the artifacts. An example configuration is shown below.
checks:
artifact:
id: artifact
description: "Find providers artifacts to publish to PyPI"
exclude:
- type: regex
pattern: ".*(.asc|.sha512)$"
- name: "Find ${{ steps.config-parser.outputs.publisher-name }} packages"
id: "upload-artifacts"
uses: ./artifacts
with:
artifact-config: ${{ steps.config-parser.outputs.checks-artifact }}
temp-dir: ${{ inputs.temp-dir }}
mode: ${{ inputs.mode }}
publisher-name: ${{ steps.config-parser.outputs.publisher-name }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
if-no-files-found: ${{ inputs.if-no-files-found }}
retention-days: ${{ inputs.retention-days }}
compression-level: ${{ inputs.compression-level }}
overwrite: ${{ inputs.overwrite }}
A sample github workflow file to use the composite actions is shown below:
name: Dry run publish airflow provider packages
description: "Publish or verify svn artifacts"
on:
workflow_dispatch:
inputs:
release-config:
description: "Path to the release config file"
required: true
default: "providers-rc-config.yml"
type: choice
options:
- "providers-rc-config.yml"
- "providers-pypi-config.yml"
temp-dir:
description: >
Temporary directory to checkout the svn repo.
required: false
default: "asf-dist"
mode:
description: >
Mode to run the action, set mode to 'RELEASE' to publish the packages to PyPI.
required: false
default: "VERIFY"
if-no-files-found:
description: >
upload artifacts action behavior if no files are found using the provided path.
default: 'warn'
retention-days:
description: >
Duration after which artifact will expire in days. 0 means using default retention.
default: '5'
compression-level:
description: >
The level of compression for artifact upload.
default: '6'
overwrite:
description: >
Overwrite the existing artifact with the same name.
default: 'false'
artifact-name:
description: >
The name of the artifact to be uploaded.
required: false
default: "pypi-packages"
jobs:
release-checks:
outputs:
publisher-name: ${{ steps.config-parser.outputs.publisher-name }}
runs-on: ubuntu-20.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: "Config parser"
id: config-parser
uses: ./read-config
with:
release-config: ${{ inputs.release-config }}
- name: "Checkout svn ${{ steps.config-parser.outputs.publisher-url }}"
id: "svn-checkout"
uses: ./init
with:
temp-dir: ${{ inputs.temp-dir }}
repo-url: ${{ steps.config-parser.outputs.publisher-url }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
- name: "Svn check"
id: "svn-check"
uses: ./svn
with:
svn-config: ${{ steps.config-parser.outputs.checks-svn }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
- name: "Checksum check"
id: "checksum-check"
uses: ./checksum
with:
checksum-config: ${{ steps.config-parser.outputs.checks-checksum }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
- name: "Signature check"
id: "signature-check"
uses: ./signature
with:
signature-config: ${{ steps.config-parser.outputs.checks-signature }}
temp-dir: ${{ inputs.temp-dir }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
- name: "Find ${{ steps.config-parser.outputs.publisher-name }} packages"
id: "upload-artifacts"
uses: ./artifacts
with:
artifact-config: ${{ steps.config-parser.outputs.checks-artifact }}
temp-dir: ${{ inputs.temp-dir }}
mode: ${{ inputs.mode }}
publisher-name: ${{ steps.config-parser.outputs.publisher-name }}
repo-path: ${{ steps.config-parser.outputs.publisher-path }}
if-no-files-found: ${{ inputs.if-no-files-found }}
retention-days: ${{ inputs.retention-days }}
compression-level: ${{ inputs.compression-level }}
overwrite: ${{ inputs.overwrite }}
artifact-name: ${{ inputs.artifact-name }}
publish-to-pypi:
name: Publish svn packages to PyPI
runs-on: ubuntu-20.04
if: inputs.mode == 'RELEASE' && success()
needs:
- release-checks
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: "Download release distributions for ${{ needs.release-checks.outputs.publisher-name }}"
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact-name }}
merge-multiple: true
path: ./dist
- name: "Publishing ${{ needs.release-checks.outputs.publisher-name }} to PyPI"
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: "./dist"
The mode
input is used to run the action in different modes.
-
VERIFY
:
It will only validate the artifacts and not publish to PyPI. -
RELEASE
:
It will validate the artifacts and publish to PyPI.