Skip to content

Conversation

@chrisd8088
Copy link
Member

We upgrade our CI and release GitHub Actions workflows to use the latest Ubuntu runners, which run Ubuntu LTS 22.04 at present, and the latest available versions of all Actions steps.

As testing the release.yml workflow is not convenient without generating a release, it has instead been run successfully on a separate, private repository cloned from this one.

Ubuntu Runners

In commit d6b34fa of PR #4437 we switched our CI and release GitHub Actions workflows to explicitly use the then-latest Ubuntu LTS version 20.04 in order to support ARM64 builds, as these required a version of Go (specifically 1.16) which was not available on the ubuntu-latest Actions runners at the time because they still ran Ubuntu LTS version 18.04.

However, ubuntu-latest Actions runners now use an even newer LTS version of Ubuntu, 22.04, than the one we have explicitly identified, so we can return to specifying ubuntu-latest for our CI and release builds.

Actions and Checkouts

In PR #5236 we upgraded our CI and release workflows to use the latest recommended ruby/setup-ruby@v1 GitHub Actions step to install Ruby and its dependencies.

We now update our other Actions steps to their respective latest versions as well:

  actions/checkout:           v1 -> v3
  actions/download-artifact:  v1 -> v3
  actions/setup-go:           v2 -> v3
  actions/upload-artifact:    v1 -> v3
  docker/setup-qemu-action:   v1 -> v2

Artifact Download Paths

As of v2 of the actions/download-artifact Action, downloaded assets are not placed in a new subdirectory created with the name from the step's name argument, but in the current working directory instead. We want to retain the previous behaviour so we add a path argument with the same name as each of the macos-assets and windows-assets download steps.

Fetching Full Clones

By default, the actions/checkout Action (as of v2) performs a Git fetch with a --depth=1 option, so a shallow clone is made. As a result, when our Makefile calls git describe HEAD to set its VERSION variable, no tags are available and Git responds with an error message.

Many of our workflow jobs succeed despite logging that error, including the build-docker and build-docker-cross jobs in both our CI and Release workflows. (The Docker builds create upload artifacts with the valid filenames despite the lack of any tags because they rely on the Git LFS version strings in our debian/changelog file and in our binary; the rpm/build_rpms.bsh script builds a binary just to run git-lfs version and determine the version string from its output.)

However, our workflow jobs which run the make release command fail outright in the absence of any Git tags, as they search for build artifacts using filenames constructed with the empty VERSION variable, such as git-lfs-windows-amd64-.zip. When no files are found, the tar command fails, halting the job. This affects both the build-default job in our CI workflow (for Linux and macOS), and all of build-main, build-macos, and build-windows jobs in our Release workflow.

To resolve this in the case of a PR or other push to a branch, we set a fetch-depth value of 0 for our actions/checkout@v3 steps, which downloads the full Git history and all tags. This is somewhat more expensive than a shallow clone, but our project's history is not excessively large.

Temporary Workaround for Incorrect Tag Fetches

Due to the GitHub Actions bug documented in actions/checkout#882, though, this resolution is insufficient in the case of a push to a tag. At present, when fetch-depth is 0, the actions/checkout@v3 incorrectly determines the SHA of an annotated tag to be the SHA of its associated commit, and then proceeds as if the tag had been updated on the server since the Action was started, and so rewrites the tag locally to refer to the commit SHA. This has the effect of making the local tag into a lightweight tag, which git describe then ignores (since we don't pass the --tags option to it).

As a temporary fix for this problem, we add a step after the actions/checkout@v3 step which updates the local tag again to match the remote one. We only run this step when the pushed reference was a tag, because on a branch push it would fail as Git would refuse to update the currently checked-out branch. In our Release workflow, since it only runs on pushes to tags, we can run this step unconditionally. (We could also continue to use the default fetch-depth of 1 for the actions/checkout@v3 step, since we always subsequently fetch the relevant tag, but to be consistent and to avoid future issues once actions/checkout#882 is fixed upstream, we do not do so.)

/cc actions/checkout#882
/cc #5228

In commit d6b34fa of PR git-lfs#4437 we
switched our CI and release GitHub Actions workflows to explicitly
use the then-latest Ubuntu LTS version 20.04 in order to support ARM64
builds, as these required a version of Go (specifically 1.16) which was
not available on the ubuntu-latest Actions runners at the time because
they still ran Ubuntu LTS version 18.04.

However, ubuntu-latest Actions runners now use an even newer LTS version
of Ubuntu, 22.04, than the one we have explicitly identified, so we can
return to specifying ubuntu-latest for our CI and release builds.
We can simplify our calls to the "xargs" command by removing the
redundant -L1 option, as this is implied by the -I option when
running on Linux with the GNU version of xargs(1).
In commit b7fa3a5 of PR git-lfs#5236 we
replaced the deprecated actions/setup-ruby@v1 GitHub Action in our
CI and release workflows with the current ruby/setup-ruby@v1 Action.

We now update our other Actions to their respective latest versions
as well:

  actions/checkout:           v1 -> v3
  actions/download-artifact:  v1 -> v3
  actions/setup-go:           v2 -> v3
  actions/upload-artifact:    v1 -> v3
  docker/setup-qemu-action:   v1 -> v2

As of v2 of the actions/download-artifact Action, downloaded assets are
not placed in a new subdirectory created with the name from the step's
"name" argument, but in the current working directory instead.  We want
to retain the previous behaviour so we add a "path" argument with the
same name as each of the macos-assets and windows-assets download steps.

By default, the actions/checkout Action (as of v2) performs a Git fetch
with a --depth=1 option, so a shallow clone is made.  As a result, when
our Makefile calls "git describe HEAD" to set its VERSION variable, no
tags are available and Git responds with an error message.

Many of our workflow jobs succeed despite logging that error, including
the build-docker and build-docker-cross jobs in both our CI and Release
workflows.  (The Docker builds create upload artifacts with the correct
filenames despite the lack of any tags because they rely on the Git LFS
version strings in our debian/changelog file and in our binary; the
rpm/build_rpms.bsh script builds a binary just to run "git-lfs version"
and determine the version string from its output.)

However, our workflow jobs which run the "make release" command fail
outright in the absence of any Git tags, as they search for build
artifacts using filenames constructed with the empty VERSION variable,
such as "git-lfs-windows-amd64-.zip".  When no files are found, the
tar command fails, halting the job.  This affects both the build-default
job in our CI workflow (for Linux and macOS), and all of build-main,
build-macos, and build-windows jobs in our Release workflow.

To resolve this in the case of a PR or other push to a branch, we set
a fetch-depth value of 0 for our actions/checkout@v3 steps, which
downloads the full Git history and all tags.  This is somewhat more
expensive than a shallow clone, but our project's history is not
excessively large.

Due to the GitHub Actions bug documented in actions/checkout#882,
though, this resolution is insufficient in the case of a push to a
tag.  At present, the actions/checkout@v3 incorrectly determines the
SHA of an annotated tag to be the SHA of its associated commit, and
then proceeds as if the tag had been updated on the server since the
Action was started, and so rewrites the tag locally to refer to the
commit SHA.  This has the effect of making the local tag into a
lightweight tag, which "git describe" then ignores (since we don't
pass the --tags option to it).

As a temporary fix for this problem, we add a step after the
actions/checkout@v3 step which updates the local tag again to match
the remote one.  We only run this step when the pushed reference
was a tag, because on a branch push it would fail as Git would refuse
to update the currently checked-out branch.  In our Release workflow,
since it only runs on pushes to tags, we can run this step
unconditionally.  (We could also continue to use the default fetch-depth
of 1 for the actions/checkout@v3 step, since we always subsequently
fetch the relevant tag, but to be consistent and to avoid future
issues once actions/checkout#882 is fixed upstream, we do not do so.)
@chrisd8088 chrisd8088 force-pushed the actions-update-steps-ubuntu branch from 5fcbc7e to df6e49c Compare January 4, 2023 06:59
@chrisd8088 chrisd8088 marked this pull request as ready for review January 4, 2023 08:16
@chrisd8088 chrisd8088 requested a review from a team as a code owner January 4, 2023 08:16
@chrisd8088 chrisd8088 merged commit 9d7b7eb into git-lfs:main Jan 4, 2023
@chrisd8088 chrisd8088 deleted the actions-update-steps-ubuntu branch January 4, 2023 17:33
chrisd8088 added a commit to chrisd8088/git-lfs that referenced this pull request Jan 24, 2025
In commit df6e49c of PR git-lfs#5243 we added
a step to all of the jobs in our CI and release GitHub Actions workflows
to work around the problem described in actions/checkout#290 and
actions/checkout#882.  This step, which only executes if the job is
running due to the push of a new tag, performs a "git fetch" command
of the tag's reference to ensure that the local copy is identical to
the remote one and has not been converted from an annotated tag into
a lightweight one.  Starting with v2 of the actions/checkout action,
annotated tags are by default replaced with lightweight ones, which then
causes any subsequent "git describe" commands to return an incorrect
value.  Since we depend on the output of "git describe" in several
places in our workflows to generate the appropriate version name for our
release artifacts, we need to ensure we have the full annotated tag
for the current reference rather than a lightweight one.

Recently, in commit 9c3fab1 of PR git-lfs#5930,
we strengthened the security of our GitHub Action workflows by setting
the "persist-credentials" option of the actions/checkout action to "false",
so that any cached Git credentials are removed at the end of that step.
While this causes no problems when our CI workflow runs after a branch
is pushed, as is the case for new PRs, when we push a new tag the
"git fetch" step now fails as it depends on the cached Git credentials
from the actions/checkout step.

We could use the GITHUB_TOKEN Action secret to temporarily set an
appropriate HTTP Authorization header to make the "git fetch" command
succeed.  However, a more straightforward solution exists whereby we
specify explicitly the reference we want to check out using the "ref"
option of the actions/checkout action.  This causes the action to
fetch the reference such that if the reference is an annotated tag,
it remains one and is not converted into a lightweight one.  For
reference, see:

  actions/checkout#882 (comment)
  actions/runner-images#1717 (comment)

h/t classabbyamp and xenoterracide for documenting this workaround
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants