当前位置: 首页 > 知识库问答 >
问题:

如何安排GitHub每晚的操作构建,但仅在最近的代码发生更改时运行它?

瞿宏儒
2023-03-14

我希望通过GitHub操作实现夜间自动构建(来自开发分支的每日快照)。

为了降低计费成本,我希望GitHub操作工作流仅在自上次GitHub操作夜间构建工作流运行以来出现新提交时触发(或执行任务)。

如何安排GitHub操作的夜间构建,但仅在自上次夜间运行后代码发生更改时运行它?

请注意,还有其他GitHub Actions工作流不会干扰此夜间构建。

共有2个答案

郁鸿博
2023-03-14

我有一个可行的解决方案,与您的情况略有不同,但应该不难调整。主要目标完全相同-如果不需要,不要将CI时间浪费在每日跑步上。

虽然不可能(AFAIK)将计划限制为完全不运行,但您可以通过第一步运行一个小的shell脚本来降低工作流执行时间,甚至在签出存储库之前也是如此。第二部分是在存储库没有新的提交/没有要运行的内容时禁用所有其他步骤。

完整示例,稍后逐段讨论,以及如何将其应用于您的用例。

TL;DR-<代码>bash,<代码>curl,<代码>jq。

  - name:  Activity check
    run:   |
           :
           curl -sL https://api.github.com/repos/$GITHUB_REPOSITORY/commits | jq -r '[.[] | select(.author.login != "${{ secrets.ANTALASKAYA_LOGIN }}")][0]' > $HOME/commit.json
           date="$(jq -r '.commit.author.date' $HOME/commit.json)"
           timestamp=$(date --utc -d "$date" +%s)
           author="$(jq -r '.commit.author.name' $HOME/commit.json)"
           url="$(jq -r '.html_url' $HOME/commit.json)"
           days=$(( ( $(date --utc +%s) - $timestamp ) / 86400 ))
           rm -f $HOME/commit.json
           echo "Repository activity : $timestamp $author $url"
           alive=0
           if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
              echo "[WARNING] Ignoring activity limits : workflow triggered manually"
              alive=1
           else
              if [ $days -gt 2 ]; then
                 echo "[WARNING] Repository activity : $days days ago"
              fi
              if [ $days -lt 8 ]; then
                 echo Repository active : $days days
                 alive=1
              else
                 echo "[WARNING] Repository not updated : event<${{ github.event_name }}> not allowed to modify stale repository"
              fi
           fi
           if [ $alive -eq 1 ]; then
              echo ::set-env name=GHA_REPO_ALIVE::true
           fi
    shell: bash

首先,我使用GitHub API获取最后一次非自动提交(并将结果保存到.json)。在我的例子中,所有“夜间”构建都通过专用的bot帐户将结果提交回存储库,所以很容易过滤掉。

curl -sL https://api.github.com/repos/$GITHUB_REPOSITORY/commits | jq -r '[.[] | select(.author.login != "${{ secrets.ANTALASKAYA_LOGIN }}")][0]' > $HOME/commit.json

接下来,我将提取最后一次提交的时间戳(以及其他一些内容),并将其转换为经过的天数。在您的情况下,您很可能希望在此处使用小时。

date="$(jq -r '.commit.author.date' $HOME/commit.json)"
timestamp=$(date --utc -d "$date" +%s)
author="$(jq -r '.commit.author.name' $HOME/commit.json)"
url="$(jq -r '.html_url' $HOME/commit.json)"
days=$(( ( $(date --utc +%s) - $timestamp ) / 86400 ))
rm -f $HOME/commit.json
echo "Repository activity : $timestamp $author $url"

工作流可以运行时有几个不同的场景(推送,工作流文件更改,存储库调度,计划),所以我将最终活动检查结果保留为本地var,稍后检查。假定默认情况下存储库不需要更新。

alive=0

接下来是“repository\u dispatch”处理,允许手动触发计划;这将强制工作流忽略任何限制运行。

if [ "${{ github.event_name }}" == "repository_dispatch" ]; then
   echo "[WARNING] Ignoring activity limits : workflow triggered manually"
   alive=1
else

在没有自动提交的第三天,我在日志中添加条目,只是为了好玩。

if [ $days -gt 2 ]; then
   echo "[WARNING] Repository activity : $days days ago"
fi

如果最后一次提交是在上周,将存储库标记为活动,否则什么也不做。

if [ $days -lt 8 ]; then
   echo Repository active : $days days
   alive=1
else
    echo "[WARNING] Repository not updated : event<${{ github.event_name }}> not allowed to modify stale repository"
fi

最后,如果有工作要做,将局部变量保存为全局变量。在此处使用::set env(或::set output)非常重要,这样可以在执行步骤之前检查变量。

if [ $alive -eq 1 ]; then
   echo ::set-env name=GHA_REPO_ALIVE::true
fi

活动检查后的所有步骤都应在执行任何操作之前检查此全局变量以节省时间和/或金钱。

- name: Clone
  if:   env.GHA_REPO_ALIVE == 'true'
  uses: actions/checkout@v2

在野外:

  • 完整工作流(警告:dragons)
  • 每日运行,活动存储库(平均约10m)
  • 每日运行,非活动存储库(平均约6秒)

现在,关于在您的案例中采用这种解决方案:

如果您没有提交返回结果,您可以通过从API获取最后一次提交(尽管有作者)并检查经过的时间来简化第一部分。如果在过去24小时内有任何提交,则应将存储库标记为活动。

如果您只想运行构建,可以忽略部件检查、存储库调度或推送场景。然而,我发现有一些非调度触发器非常有用,可以在不等待的情况下运行构建;我强烈建议在以后的调整中保留这一点。

通过跳过作者/url提取和禁用日志记录可以节省几个ms;)

可能有一些操作提供了相同的功能,但我觉得shell脚本API总是会更快。他们也有可能会做完全相同的事情,只是“浪费”下载和执行操作所需的额外时间。

鱼渝
2023-03-14

您可以这样做:

  1. 首先添加此作业:
  check_date:
    runs-on: ubuntu-latest
    name: Check latest commit
    outputs:
      should_run: ${{ steps.should_run.outputs.should_run }}
    steps:
      - uses: actions/checkout@v2
      - name: print latest_commit
        run: echo ${{ github.sha }}

      - id: should_run
        continue-on-error: true
        name: check latest commit is less than a day
        if: ${{ github.event_name == 'schedule' }}
        run: test -z $(git rev-list  --after="24 hours"  ${{ github.sha }}) && echo "::set-output name=should_run::false"
    needs: check_date
    if: ${{ needs.check_date.outputs.should_run != 'false' }}

例如:

  do_something:
    needs: check_date
    if: ${{ needs.check_date.outputs.should_run != 'false' }}
    runs-on: windows-latest
    name: do something.
    steps:
      - uses: actions/checkout@v2

来源

 类似资料:
  • 问题内容: 在Dockerfile中,我有一个要安装的层: 当我构建Docker映像时, 无论 对该文件进行任何更改,它都会运行整个过程。 如何确保仅在文件发生更改的情况下运行Docker ? 问题答案: 我假设在构建过程中的某个时候,您正在使用或将整个应用程序复制到Docker映像中: 问题在于,每次将整个应用程序复制到映像时,您都会使Docker构建缓存无效。这还将使所有后续构建步骤的缓存无效

  • 我正在构建一个python项目--。我想使用Github操作来自动化一些linting 为此,我使用了Github推荐的python actions starter工作流——python应用程序的一个轻微修改。 在作业中的“安装依赖项”步骤中,我遇到了一个错误。这是因为pip试图安装我的本地软件包,但失败了。 如果[-f requirements.txt], 相应的错误是: 很可能,该作业无法安装

  • 当我通过命令行运行此代码时,我得到了一个异常。当我通过Eclipse IDE运行它时,它运行得很好,没有异常。我不知道发生了什么,但它肯定在会话语句中得到了异常。 我得到的错误仅当它在命令行运行时: 你知道这是什么原因吗?

  • 我使用jsonschema生成器基于我的POJO生成JSON模式文件。目前,我正在通过一个在<code>gradle构建</code>步骤中运行的测试来完成这项工作。这工作正常,但感觉不对,因为我所做的并不是测试任何东西。 我还找到了这个答案,其中详细说明了如何在上运行它,但这也不理想,因为它会在每次应用程序出现时毫无意义地执行它,但在我构建时不会。 因此,有没有一种方法可以告诉gradle(在中

  • 我是新来的Laravel我想做的只是如下: 我的表单中有一些字段,如标题、描述。 标题字段在数据库中是唯一的。 这就是我所做的来更新我的价值观。 但这将导致错误(该值已经存在),因为我的标题字段是唯一的。 我只想在标题值更改时更新标题,否则更新相同的值,但更新其他字段。谢谢

  • 问题内容: 如何告诉Jenkins / Hudson仅针对Git树中特定项目的更改触发构建? 问题答案: Git插件有一个选项(排除的区域),可使用正则表达式根据提交中的文件是否与排除的区域正则表达式匹配来确定是否跳过构建。 不幸的是,当前的Git插件目前没有“包含区域”功能(1.15)。但是,有人在GitHub上发布了可在Jenkins和Hudson上运行的补丁,这些补丁实现了所需的功能。 构建