From 3c74a573c739f5c59aab40e224a5e458d5367e63 Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 2 May 2022 22:45:24 -0700 Subject: [PATCH 1/5] Bump action dependencies of "Check Go Dependencies" workflow --- .github/workflows/check-go-dependencies-task.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check-go-dependencies-task.yml b/.github/workflows/check-go-dependencies-task.yml index 683d942..62b8b43 100644 --- a/.github/workflows/check-go-dependencies-task.yml +++ b/.github/workflows/check-go-dependencies-task.yml @@ -2,7 +2,7 @@ name: Check Go Dependencies env: - # See: https://github.com/actions/setup-go/tree/v2#readme + # See: https://github.com/actions/setup-go/tree/v3#readme GO_VERSION: "1.13" # See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive @@ -47,7 +47,7 @@ jobs: version: 3.x - name: Install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} @@ -73,7 +73,7 @@ jobs: # Some might find it convenient to have CI generate the cache rather than setting up for it locally - name: Upload cache to workflow artifact if: failure() && steps.diff.outcome == 'failure' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: if-no-files-found: error name: dep-licenses-cache @@ -84,7 +84,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive @@ -95,7 +95,7 @@ jobs: version: 3.x - name: Install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} From bc7e28216a064894cc92a7e300bb4dcb9aabfb9b Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 2 May 2022 22:45:39 -0700 Subject: [PATCH 2/5] Update reference URL in "Check Go Dependencies" workflow - Update redirecting GitHub docs URL to new location - Configure GitHub docs URL to allow localization where available --- .github/workflows/check-go-dependencies-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-go-dependencies-task.yml b/.github/workflows/check-go-dependencies-task.yml index 62b8b43..91d376b 100644 --- a/.github/workflows/check-go-dependencies-task.yml +++ b/.github/workflows/check-go-dependencies-task.yml @@ -5,7 +5,7 @@ env: # See: https://github.com/actions/setup-go/tree/v3#readme GO_VERSION: "1.13" -# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +# See: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows on: push: paths: From fe66ce8350e71b647bc9294d3c22e6352ada4d6d Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 2 May 2022 22:45:57 -0700 Subject: [PATCH 3/5] Detect unused dependency license metadata files The "Check Go Dependencies" GitHub Actions workflow checks for dependencies with incompatible or unapproved license types. The dependency license metadata consumed by the "Licensed" tool is cached in the project repository, in a dedicated file for each dependency. The `check-cache` job of the workflow checks whether that cache is in sync with the project's current dependencies. It does this by using the "Licensed" tool to update the cache and then a `git diff` command to check whether that resulted in any changes (which would indicate it is out of sync). Out of sync states could result from any of three distinct conditions: - Missing metadata file - Incorrect metadata file contents - Superfluous metadata file An incorrectly configured `git diff` command previously caused the last of these to be missed. My first take at this system was simply using `git diff --exit-code` alone. That detects the last two, but misses the first. I added the `git add --intent-to-add .` command to detect added files, but didn't realize that it caused the last to be missed. Superfluous files in the dependency license metadata cache won't actually interfere with its intended functionality, but it is still important to avoid an accumulation of unused files. The new commands will catch all three of the possible out of sync conditions by staging all changes that result from the metadata cache update to the repository and then comparing those against the `HEAD` commit. I considered an alternative approach which works just as well as the chosen one: ``` git add . git diff --exit-code HEAD ``` However, I feel that the `--cached` flag makes the `git diff` command more self-explanatory. --- .github/workflows/check-go-dependencies-task.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-go-dependencies-task.yml b/.github/workflows/check-go-dependencies-task.yml index 91d376b..1af17cb 100644 --- a/.github/workflows/check-go-dependencies-task.yml +++ b/.github/workflows/check-go-dependencies-task.yml @@ -63,8 +63,8 @@ jobs: - name: Check for outdated cache id: diff run: | - git add --intent-to-add . - if ! git diff --color --exit-code; then + git add . + if ! git diff --cached --color --exit-code; then echo echo "::error::Dependency license metadata out of sync. See: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-go-dependencies-task.md#metadata-cache" exit 1 From 599fa85fc610543e62e3675c28308772a1695673 Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 2 May 2022 22:46:11 -0700 Subject: [PATCH 4/5] Add schedule trigger to "Check Go Dependencies" workflow The workflow is configured to run whenever any relevant file in the repository is changed. However, the results of the workflow run are also dependent on the external environment it runs in, which include: - The software running on the GitHub hosted GitHub Actions runner machines - The GitHub Actions actions used by the workflow - The dependencies that are installed by the workflow directly or via the GitHub Actions actions it uses The workflow does not fully pin to a specific version of external tools. This was done in the interest of reducing the maintenance burden of keeping the systems up to date. However, it also means that a new release of one of those tools can cause the workflow runs to start failing (which might happen through an enhancement to that resource resolving a false negative, or a defect causing a false negative). When the repository file path trigger is used by itself, this sort of external breakage is only revealed when an unrelated change triggers the workflow. That can be distracting even to a dedicated member of the project development team, as well as confusing and discouraging to any contributor. This type of change can be caught by adding a `schedule` event trigger that causes the workflow to run periodically in addition to the other on-demand triggers. This allows the problem to be identified and resolved at the maintainer's convenience, separate from the unrelated development work. --- .github/workflows/check-go-dependencies-task.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/check-go-dependencies-task.yml b/.github/workflows/check-go-dependencies-task.yml index 1af17cb..bc2ab4a 100644 --- a/.github/workflows/check-go-dependencies-task.yml +++ b/.github/workflows/check-go-dependencies-task.yml @@ -27,6 +27,9 @@ on: - "**/.gitmodules" - "**/go.mod" - "**/go.sum" + schedule: + # Run periodically to catch breakage caused by external changes. + - cron: "0 8 * * WED" workflow_dispatch: repository_dispatch: From 021a791b4eb0eb367adfccf516afed70c737620f Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 2 May 2022 22:46:23 -0700 Subject: [PATCH 5/5] Run "Check Go Dependencies" workflow on release branch creation The trunk-based development strategy is used by some tooling projects. Their release branches may contain a subset of the history of the default branch. The status of the GitHub Actions workflows should be evaluated before making a release. However, this is not so simple as checking the status of the commit at the tip of the branch in the project using that strategy. The reason is that, for the sake of efficiency, the workflow is configured to run only when the processes are relevant to the trigger event (e.g., no need to run it for a change to the readme). In the case of the default branch, you can simply set the workflow runs filter to that branch and then check the result of the latest run of each workflow of interest. However, that was not possible to do with the release branch since it might be that the workflow was never run in that branch. The status of the latest run of the workflow in the default branch might not match the status for the release branch if the release branch does not contain the full history. For this reason, it will be helpful to trigger the workflow on the creation of a release branch. This will ensure that the workflow will always have at least one run in the release branch. Subsequent commits pushed to the branch can run based on their usual trigger filters and the status of the latest run of the workflow in the branch will provide an accurate indication of the state of that branch. Branches are created for purposes other than releases, most notably feature branches to stage work for a pull request. Because the collection of workflows in a Tooling project are often very comprehensive, it would not be convenient or efficient to run them on the creation of every feature branch. Unfortunately, GitHub Actions does not support filters on the `create` event of branch creation like it does for the `push` and `pull_request` events. There is support for a `branches` filter of the `push` event, but that filter is an AND to the `paths` filter and this application requires an OR. For this reason, the workflows must be triggered by the creation of any branch. The unwanted job runs are prevented by adding a `run-determination` job with the branch filter handled by Bash commands. The other jobs of the workflow use this `run-determination` job as a dependency, only running when it indicates they should via a job output. Because this minimal `run-determination` job runs very quickly, it is roughly equivalent to the workflow having been skipped entirely for non-release branch creations. This approach has been in use for some time already in other workflows. --- .../workflows/check-go-dependencies-task.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/check-go-dependencies-task.yml b/.github/workflows/check-go-dependencies-task.yml index bc2ab4a..be478ab 100644 --- a/.github/workflows/check-go-dependencies-task.yml +++ b/.github/workflows/check-go-dependencies-task.yml @@ -7,6 +7,7 @@ env: # See: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows on: + create: push: paths: - ".github/workflows/check-go-dependencies-task.ya?ml" @@ -34,7 +35,32 @@ on: repository_dispatch: jobs: + run-determination: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.determination.outputs.result }} + steps: + - name: Determine if the rest of the workflow should run + id: determination + run: | + RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x" + # The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead. + if [[ + "${{ github.event_name }}" != "create" || + "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX + ]]; then + # Run the other jobs. + RESULT="true" + else + # There is no need to run the other jobs. + RESULT="false" + fi + + echo "::set-output name=result::$RESULT" + check-cache: + needs: run-determination + if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest steps: @@ -83,6 +109,8 @@ jobs: path: .licenses/ check-deps: + needs: run-determination + if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest steps: