如何生成动态包含 nox 会话列表的 github 动作构建矩阵?
How to generate a github actions build matrix that dynamically includes a list of nox sessions?
我最近开始迁移我的一些 open source python libraries from Travis to Github Actions. To be more independent from the CI/CD platform, I decided to first describe all test environments and configurations using nox
。
让我们考虑以下原型noxfile.py
:
import nox
@nox.session(python=["3.7", "3.8"])
def tests(session):
print("Interesting stuff going on here")
@nox.session(python=["3.7", "3.8"])
@nox.parametrize("a", [-1, 1])
@nox.parametrize("b", [False, True])
def tests_with_params(session, a, b):
print("Interesting stuff going on here")
@nox.session(python="3.7")
def other(session):
print("another session")
导致以下 nox --list
输出:
* tests-3.7
* tests-3.8
* tests_with_params-3.7(b=False, a=-1)
* tests_with_params-3.7(b=True, a=-1)
* tests_with_params-3.7(b=False, a=1)
* tests_with_params-3.7(b=True, a=1)
* tests_with_params-3.8(b=False, a=-1)
* tests_with_params-3.8(b=True, a=-1)
* tests_with_params-3.8(b=False, a=1)
* tests_with_params-3.8(b=True, a=1)
* other
我希望 github 操作工作流程 运行 tests
或 tests_with_params
的所有会话。在我的工作流 yaml 定义文件中使用硬编码的 build matrix 它可以工作,例如在这里我列出了 tests
:
的两个会话
# (in .github/workflows/base.yml)
jobs:
run_all_tests:
strategy:
fail-fast: false
matrix:
# Here we manually list two nox sessions
nox_session: ["tests-3.7", "tests-3.8"]
name: Run nox session ${{ matrix.nox_session }}
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python and nox...)
- run: nox -s "${{ matrix.nox_session }}"
但是如上所示,必须在矩阵中手动复制会话列表。因此,如果我决定更改我的 nox 会话的参数化,则必须对其进行更新。
因此,让 github 操作工作流“询问 nox”以动态获取此列表会容易得多。我们该怎么做?
(回答我自己的问题,因为我找不到关于 SO 的条目)
感谢 this great post,我找到了一种方法来做到这一点。该解决方案基于两个步骤:
- 首先创建一个 nox 任务
gha_list
,它将打印给定基本会话名称的所有会话名称列表
- 然后将作业添加到 github 操作工作流,它将利用此任务动态获取列表,并将此列表注入后续作业的构建矩阵。
1。创建一个 nox 任务以打印所需的会话列表
让我们将此任务添加到我们的 noxfile.py
:
import itertools
import json
@nox.session(python=False)
def gha_list(session):
"""(mandatory arg: <base_session_name>) Prints all sessions available for <base_session_name>, for GithubActions."""
# get the desired base session to generate the list for
if len(session.posargs) != 1:
raise ValueError("This session has a mandatory argument: <base_session_name>")
session_func = globals()[session.posargs[0]]
# list all sessions for this base session
try:
session_func.parametrize
except AttributeError:
sessions_list = ["%s-%s" % (session_func.__name__, py) for py in session_func.python]
else:
sessions_list = ["%s-%s(%s)" % (session_func.__name__, py, param)
for py, param in itertools.product(session_func.python, session_func.parametrize)]
# print the list so that it can be caught by GHA.
# Note that json.dumps is optional since this is a list of string.
# However it is to remind us that GHA expects a well-formatted json list of strings.
print(json.dumps(sessions_list))
我们可以在终端测试它是否有效:
>>> nox -s gha_list -- tests
nox > Running session gha_list
["tests-3.7", "tests-3.8"]
nox > Session gha_list was successful.
>>> nox -s gha_list -- tests_with_params
nox > Running session gha_list
["tests_with_params-3.7(b=False, a=-1)", "tests_with_params-3.7(b=True, a=-1)", "tests_with_params-3.7(b=False, a=1)", "tests_with_params-3.7(b=True, a=1)", "tests_with_params-3.8(b=False, a=-1)", "tests_with_para
ms-3.8(b=True, a=-1)", "tests_with_params-3.8(b=False, a=1)", "tests_with_params-3.8(b=True, a=1)"]
nox > Session gha_list was successful.
2。编辑 github 操作工作流程以动态地将此列表注入构建矩阵
现在我们能够打印所需的列表,我们修改 github 操作工作流程以添加一个调用它的作业 before 作业 运行测试。
# (in .github/workflows/base.yml)
jobs:
list_nox_test_sessions:
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python and nox...)
- name: list all test sessions
id: set-matrix
run: echo "::set-output name=matrix::$(nox -s gha_list -- tests)"
# save the list into the outputs
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
run_all_tests:
needs: list_nox_test_sessions
strategy:
fail-fast: false
matrix:
nox_session: ${{ fromJson(needs.list_nox_test_sessions.outputs.matrix) }}
name: Run nox session ${{ matrix.nox_session }}
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python)
- run: nox -s "${{ matrix.nox_session }}"
例子
可在 this repo 找到示例,工作流程如下:
其他可行的选择
我还考虑过在 nox --list
输出上使用 grep
,这可能也有效。但是,对于那些对 python 感到放心但对 grep
.
感到不安的开发人员来说,调试起来可能会更加困难。
我最近开始迁移我的一些 open source python libraries from Travis to Github Actions. To be more independent from the CI/CD platform, I decided to first describe all test environments and configurations using nox
。
让我们考虑以下原型noxfile.py
:
import nox
@nox.session(python=["3.7", "3.8"])
def tests(session):
print("Interesting stuff going on here")
@nox.session(python=["3.7", "3.8"])
@nox.parametrize("a", [-1, 1])
@nox.parametrize("b", [False, True])
def tests_with_params(session, a, b):
print("Interesting stuff going on here")
@nox.session(python="3.7")
def other(session):
print("another session")
导致以下 nox --list
输出:
* tests-3.7
* tests-3.8
* tests_with_params-3.7(b=False, a=-1)
* tests_with_params-3.7(b=True, a=-1)
* tests_with_params-3.7(b=False, a=1)
* tests_with_params-3.7(b=True, a=1)
* tests_with_params-3.8(b=False, a=-1)
* tests_with_params-3.8(b=True, a=-1)
* tests_with_params-3.8(b=False, a=1)
* tests_with_params-3.8(b=True, a=1)
* other
我希望 github 操作工作流程 运行 tests
或 tests_with_params
的所有会话。在我的工作流 yaml 定义文件中使用硬编码的 build matrix 它可以工作,例如在这里我列出了 tests
:
# (in .github/workflows/base.yml)
jobs:
run_all_tests:
strategy:
fail-fast: false
matrix:
# Here we manually list two nox sessions
nox_session: ["tests-3.7", "tests-3.8"]
name: Run nox session ${{ matrix.nox_session }}
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python and nox...)
- run: nox -s "${{ matrix.nox_session }}"
但是如上所示,必须在矩阵中手动复制会话列表。因此,如果我决定更改我的 nox 会话的参数化,则必须对其进行更新。
因此,让 github 操作工作流“询问 nox”以动态获取此列表会容易得多。我们该怎么做?
(回答我自己的问题,因为我找不到关于 SO 的条目)
感谢 this great post,我找到了一种方法来做到这一点。该解决方案基于两个步骤:
- 首先创建一个 nox 任务
gha_list
,它将打印给定基本会话名称的所有会话名称列表 - 然后将作业添加到 github 操作工作流,它将利用此任务动态获取列表,并将此列表注入后续作业的构建矩阵。
1。创建一个 nox 任务以打印所需的会话列表
让我们将此任务添加到我们的 noxfile.py
:
import itertools
import json
@nox.session(python=False)
def gha_list(session):
"""(mandatory arg: <base_session_name>) Prints all sessions available for <base_session_name>, for GithubActions."""
# get the desired base session to generate the list for
if len(session.posargs) != 1:
raise ValueError("This session has a mandatory argument: <base_session_name>")
session_func = globals()[session.posargs[0]]
# list all sessions for this base session
try:
session_func.parametrize
except AttributeError:
sessions_list = ["%s-%s" % (session_func.__name__, py) for py in session_func.python]
else:
sessions_list = ["%s-%s(%s)" % (session_func.__name__, py, param)
for py, param in itertools.product(session_func.python, session_func.parametrize)]
# print the list so that it can be caught by GHA.
# Note that json.dumps is optional since this is a list of string.
# However it is to remind us that GHA expects a well-formatted json list of strings.
print(json.dumps(sessions_list))
我们可以在终端测试它是否有效:
>>> nox -s gha_list -- tests
nox > Running session gha_list
["tests-3.7", "tests-3.8"]
nox > Session gha_list was successful.
>>> nox -s gha_list -- tests_with_params
nox > Running session gha_list
["tests_with_params-3.7(b=False, a=-1)", "tests_with_params-3.7(b=True, a=-1)", "tests_with_params-3.7(b=False, a=1)", "tests_with_params-3.7(b=True, a=1)", "tests_with_params-3.8(b=False, a=-1)", "tests_with_para
ms-3.8(b=True, a=-1)", "tests_with_params-3.8(b=False, a=1)", "tests_with_params-3.8(b=True, a=1)"]
nox > Session gha_list was successful.
2。编辑 github 操作工作流程以动态地将此列表注入构建矩阵
现在我们能够打印所需的列表,我们修改 github 操作工作流程以添加一个调用它的作业 before 作业 运行测试。
# (in .github/workflows/base.yml)
jobs:
list_nox_test_sessions:
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python and nox...)
- name: list all test sessions
id: set-matrix
run: echo "::set-output name=matrix::$(nox -s gha_list -- tests)"
# save the list into the outputs
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
run_all_tests:
needs: list_nox_test_sessions
strategy:
fail-fast: false
matrix:
nox_session: ${{ fromJson(needs.list_nox_test_sessions.outputs.matrix) }}
name: Run nox session ${{ matrix.nox_session }}
runs-on: ubuntu-latest
steps:
# (other steps before this: checkout code, install python)
- run: nox -s "${{ matrix.nox_session }}"
例子
可在 this repo 找到示例,工作流程如下:
其他可行的选择
我还考虑过在 nox --list
输出上使用 grep
,这可能也有效。但是,对于那些对 python 感到放心但对 grep
.