From 0c91fb7d3d437933ff6dc2419276c639594eff54 Mon Sep 17 00:00:00 2001 From: Nick Volynkin Date: Thu, 10 Nov 2022 16:26:30 +0600 Subject: [PATCH] prepare-workspace: make actions/checkout more reliable Make an empty detached commit for actions/checkout to properly clean the project's workspace before checking out new code revision. It makes the actions/checkout resilient to various problems related to git submodules. Part of #28 Related to tarantool/tarantool-qa#145 --- prepare-checkout/README.md | 56 +++++++++++++++++++++++++++++++++++++ prepare-checkout/action.yml | 14 ++++++++++ 2 files changed, 70 insertions(+) create mode 100644 prepare-checkout/README.md create mode 100644 prepare-checkout/action.yml diff --git a/prepare-checkout/README.md b/prepare-checkout/README.md new file mode 100644 index 0000000..5fa5916 --- /dev/null +++ b/prepare-checkout/README.md @@ -0,0 +1,56 @@ +# Prepare workspace for checkout action + +This action creates and checks out an empty detached commit. +It helps subsequent [actions/checkout](https://github.com/actions/checkout) action +correctly clean the workspace. + +## Usage + +Add the following line to your workflow before the `actions/checkout` action: + +```diff ++ - uses: tarantool/actions/prepare-checkout@master + - uses: actions/checkout@v3 + ... +``` + +## Explanation and rationale + +This actions is solution to +[tarantool/tarantool-qa#145](https://github.com/tarantool/tarantool-qa/issues/145). +First attempt to solve this was the tarantool/actions/cleanup action. +The tarantool/actions/prepare-checkout action is a softer alternative to it. + +When submodules change, actions/checkout can fail with git errors. +It's a well-known problem and the related issues are still open: +actions/checkout#354, +actions/checkout#385, +actions/checkout#418, and +actions/checkout#590. + +Before checking out a new revision, actions/checkout runs the following code: + +```bash +# removes ignored and non-versioned files +git clean -ffdx +# resets workspace to the commit, on which it was left +# after the last job run +git reset --hard +``` + +The problem is that when a workflow fails because of a particular commit, +the repository still stays on that commit. On the next job run, +actions/checkout will run the above code, restore that particular commit, +and fail to make a proper code checkout. + +By creating a detached empty commit, this actions forces actions/checkout +to clean up the project's workspace entirely, removing any files that could +break checkout. Meanwhile, the `.git` directory stays intact, so full checkout +isn't required and the workflow does not waste much time. + +If this is a first job run on a particular runner and there's no repository yet, +the command in this action will silently fail, thanks to `|| :`, +but the action itself will succeed. + +This action uses a solution proposed in a +[comment](https://github.com/actions/checkout/issues/590#issuecomment-970586842) at actions/checkout#590. diff --git a/prepare-checkout/action.yml b/prepare-checkout/action.yml new file mode 100644 index 0000000..57d2409 --- /dev/null +++ b/prepare-checkout/action.yml @@ -0,0 +1,14 @@ +--- +name: 'Prepare workspace for checkout' +description: 'Prepare workspace for the actions/checkout action' +runs: + using: 'composite' + steps: + - run: | + set -e + shopt -s dotglob + git checkout -f \ + $(git -c user.name=TarantoolBot -c user.email=bot@tarantool.io commit-tree \ + $(git hash-object -t tree /dev/null) -m 'empty commit' \ + < /dev/null) || : + shell: bash