在 GitHub Action 的新作业中使用先前作业的输出
Posted
技术标签:
【中文标题】在 GitHub Action 的新作业中使用先前作业的输出【英文标题】:Using output from a previous job in a new one in a GitHub Action 【发布时间】:2020-03-29 05:10:01 【问题描述】:出于(主要)教学原因,我正在尝试在 GitHub 操作中运行此工作流程:
name: "We ???? Perl"
on:
issues:
types: [opened, edited, milestoned]
jobs:
seasonal_greetings:
runs-on: windows-latest
steps:
- name: Maybe greet
id: maybe-greet
env:
HEY: "Hey you!"
GREETING: "Merry Xmas to you too!"
BODY: $ github.event.issue.body
run: |
$output=(perl -e 'print ($ENVBODY =~ /Merry/)?$ENVGREETING:$ENVHEY;')
Write-Output "::set-output name=GREET::$output"
produce_comment:
name: Respond to issue
runs-on: ubuntu-latest
steps:
- name: Dump job context
env:
JOB_CONTEXT: $ jobs.maybe-greet.steps.id
run: echo "$JOB_CONTEXT"
我需要两个不同的工作,因为它们使用不同的上下文(操作系统),但我需要将第一个工作中的一个步骤的输出传递给第二个工作。我正在尝试使用jobs
找到的here 上下文的几种组合,但似乎没有任何方法可以做到这一点。显然,jobs
只是一个没有真正上下文的 YAML 变量的名称,而上下文 job
只包含成功或失败。有什么想法吗?
【问题讨论】:
【参考方案1】:检查 2020 年 4 月的“GitHub Actions: New workflow features”,这可能对您的情况有所帮助(参考以前工作的步骤输出)
工作产出
您可以指定一组要传递给后续作业的输出,然后从您的需求上下文中访问这些值。
见documentation:
jobs.<jobs_id>.outputs
工作输出地图。
作业输出可用于依赖此作业的所有下游作业。 有关定义作业依赖项的更多信息,请参阅
jobs.<job_id>.needs
。作业输出是字符串,包含表达式的作业输出在每个作业结束时在运行器上进行评估。包含秘密的输出在运行器上被编辑,而不是发送到 GitHub Actions。
要在依赖作业中使用作业输出,您可以使用
needs
上下文。 更多信息见“Context and expression syntax for GitHub Actions.”要在依赖作业中使用作业输出,您可以使用需求上下文。
例子
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: $ steps.step1.outputs.test
output2: $ steps.step2.outputs.test
steps:
- id: step1
run: echo "::set-output name=test::hello"
- id: step2
run: echo "::set-output name=test::world"
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo $needs.job1.outputs.output1 $needs.job1.outputs.output2
Jesse Adelman 加入the comments:
要么将多行文本写入文件(jschmitter's comment) 或对输出进行 base64 编码,然后在下一个作业中对其进行解码(Nate Karasch's comment)这似乎不适用于静态字符串以外的任何内容。 例如,我将如何获取 step 的多行文本输出(例如,我正在运行
pytest
或类似的)并将该输出用于另一个作业?
【讨论】:
谢谢。这似乎不适用于静态字符串以外的任何内容。例如,我将如何获取 step 的多行文本输出(例如,我正在运行pytest
或类似的)并将该输出用于另一个作业?
@JesseAdelman 好问题:我不确定。您应该提出一个单独的问题,并附上指向该答案的链接,以获得更准确的答案。
@Jesse Adelman,在这种情况下,您可能希望将多行文本写入文件。
或者,您可以对输出进行 base64 编码,然后在下一个作业中对其进行解码
对于任何想知道为什么没有生成输出的人;检查您的步骤是否使用id
而不是name
【参考方案2】:
更新:现在可以设置可用于将字符串值传输到下游作业的作业输出。见this answer。
以下是原始答案。这些技术对于某些用例可能仍然有用。
-
将数据写入文件并使用
actions/upload-artifact
和actions/download-artifact
。有点尴尬,但确实有效。
创建存储库调度事件并将数据发送到第二个工作流。我个人更喜欢这种方法,但缺点是它需要repo
作用域PAT。
这是第二种方式如何工作的示例。它使用repository-dispatch 动作。
name: "We ? Perl"
on:
issues:
types: [opened, edited, milestoned]
jobs:
seasonal_greetings:
runs-on: windows-latest
steps:
- name: Maybe greet
id: maybe-greet
env:
HEY: "Hey you!"
GREETING: "Merry Xmas to you too!"
BODY: $ github.event.issue.body
run: |
$output=(perl -e 'print ($ENVBODY =~ /Merry/)?$ENVGREETING:$ENVHEY;')
Write-Output "::set-output name=GREET::$output"
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v1
with:
token: $ secrets.REPO_ACCESS_TOKEN
event-type: my-event
client-payload: '"greet": "$ steps.maybe-greet.outputs.GREET "'
这会触发同一存储库中的存储库调度工作流。
name: Repository Dispatch
on:
repository_dispatch:
types: [my-event]
jobs:
myEvent:
runs-on: ubuntu-latest
steps:
- run: echo $ github.event.client_payload.greet
【讨论】:
此外,第二个工作流不会显示为链接到原始推送或拉取请求。 我相信output
现在已更改为outputs
所以$ steps.maybe-greet.outputs.GREET
@MoltenIce 这是一个错字。我已经纠正了。谢谢。【参考方案3】:
可以在run
步骤中捕获命令的整个输出(和返回代码),我在此写下此步骤,希望能免去其他人的麻烦。 公平警告,它需要大量的 shell 技巧和多行 run
以确保所有事情都发生在单个 shell 实例中。
在我的例子中,我需要调用一个脚本并捕获其标准输出的整个以供后续步骤使用,并保留其结果以供错误检查:
# capture stdout from script
SCRIPT_OUTPUT=$(./do-something.sh)
# capture exit code as well
SCRIPT_RC=$?
# FYI, this would get stdout AND stderr
SCRIPT_ALL_OUTPUT=$(./do-something.sh 2>&1)
由于 Github 的作业输出似乎只能捕获单行文本,我也不得不为输出转义任何换行符:
echo "::set-output name=stdout::$SCRIPT_OUTPUT//$'\n'/\\n"
此外,我最终需要返回脚本的退出代码,以正确指示它是否失败。整个shebang最终看起来像这样:
- name: A run step with stdout as a captured output
id: myscript
run: |
# run in subshell, capturiing stdout to var
SCRIPT_OUTPUT=$(./do-something.sh)
# capture exit code too
SCRIPT_RC=$?
# print a single line output for github
echo "::set-output name=stdout::$SCRIPT_OUTPUT//$'\n'/\\n"
# exit with the script status
exit $SCRIPT_RC
continue-on-error: true
- name: Add above outcome and output as an issue comment
uses: actions/github-script@v5
env:
STEP_OUTPUT: $ steps.myscript.outputs.stdout
with:
github-token: $ secrets.GITHUB_TOKEN
script: |
// indicates whather script succeeded or not
let comment = `Script finished with \`$ steps.myscript.outcome \`\n`;
// adds stdout, unescaping newlines again to make it readable
comment += `<details><summary>Show Output</summary>
\`\`\`
$process.env.STEP_OUTPUT.replace(/\\n/g, '\n')
\`\`\`
</details>`;
// add the whole damn thing as an issue comment
github.rest.issues.createComment(
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
)
编辑:还有an action 可以用更少的引导来完成此任务,我只是发现了这一点。
【讨论】:
有趣的解决方法。赞成。【参考方案4】:就我而言,我想传递整个构建/工件,而不仅仅是一个字符串:
name: Build something on Ubuntu then use it on MacOS
on:
workflow_dispatch:
# Allows for manual build trigger
jobs:
buildUbuntuProject:
name: Builds the project on Ubuntu (Put your stuff here)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: some/compile-action@v99
- uses: actions/upload-artifact@v2
# Upload the artifact so the MacOS runner do something with it
with:
name: CompiledProject
path: pathToCompiledProject
doSomethingOnMacOS:
name: Runs the program on MacOS or something
runs-on: macos-latest
needs: buildUniyProject # Needed so the job waits for the Ubuntu job to finish
steps:
- uses: actions/download-artifact@master
with:
name: CompiledProject
path: somewhereToPutItOnMacOSRunner
- run: ls somewhereToPutItOnMacOSRunner # See the artifact on the MacOS runner
【讨论】:
以上是关于在 GitHub Action 的新作业中使用先前作业的输出的主要内容,如果未能解决你的问题,请参考以下文章
在 CircleCI 工作流或作业之后触发 Github Action
GitHub Actions - 计划的 cron 作业的通知