Repository navigation
Expand file tree
/
Copy pathreusable_workflow_commit-changes.yaml
More file actions
101 lines (90 loc) · 3.88 KB
/
Copy pathreusable_workflow_commit-changes.yaml
File metadata and controls
101 lines (90 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
name: Commit Changes (Reusable Workflow)
# Commits and pushes files generated by an earlier job (uploaded with .github/actions/upload-changes) to a branch.
# A separate job (fresh runner) - the write token is only here, where no build (maven, plugins, ...) has run. In the build
# job it could be leaked via planted git config / env. Only the given files are taken from the artifact, as data.
# Pushes with GITHUB_TOKEN don't trigger workflows, so no loop.
on:
workflow_call:
inputs:
ref:
description: 'The branch to commit to, e.g. master'
type: string
required: true
base:
description: 'The commit (SHA) the files are generated from (base output of .github/actions/upload-changes)'
type: string
required: true
artifact:
description: 'The artifact with the changed files'
type: string
default: 'changes'
files:
description: 'The files to take from the artifact, one per line (paths relative to the repository root)'
type: string
required: true
message:
description: 'The commit message'
type: string
required: true
permissions:
contents: write
jobs:
commit-changes:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.ref }}
- name: Download changes
uses: actions/download-artifact@v8.0.2
with:
name: ${{ inputs.artifact }}
# outside the working tree
path: ${{ runner.temp }}/changes
- name: Commit and push changes
env:
BASE: ${{ inputs.base }}
FILES: ${{ inputs.files }}
MESSAGE: ${{ inputs.message }}
run: |
# fails on a detached HEAD (e.g. a tag or SHA as ref) - there is no branch to push to
BRANCH=$(git symbolic-ref --short HEAD)
mapfile -t FILE_LIST < <(echo "${FILES}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e '/^$/d')
# the base comes from the build job - only a SHA is accepted (e.g. '--upload-pack=...' would run a command)
if [[ ! "${BASE}" =~ ^[0-9a-f]{40}([0-9a-f]{24})?$ ]]; then
echo "Invalid base: ${BASE}"
exit 1
fi
# the branch may have moved since the generation. If the files have changed since the base (e.g. committed by a
# newer run), the generated ones are stale - they would overwrite the newer content, without a rebase conflict
git fetch --depth=1 origin "${BASE}"
if ! git diff --quiet "${BASE}" HEAD -- "${FILE_LIST[@]}"; then
echo "::warning::The files have changed on ${BRANCH} since ${BASE} they are generated from - stale, not committed"
exit 0
fi
for FILE in "${FILE_LIST[@]}"; do
# regular files only (no symlinks)
if [ ! -f "${RUNNER_TEMP}/changes/${FILE}" ] || [ -L "${RUNNER_TEMP}/changes/${FILE}" ]; then
echo "${FILE} is missing in the artifact"
exit 1
fi
mkdir -p "$(dirname "${FILE}")"
cp "${RUNNER_TEMP}/changes/${FILE}" "${FILE}"
done
# git status (not git diff) - lists new (untracked) files as well
CHANGED_FILES=$(git status --porcelain --untracked-files=all -- "${FILE_LIST[@]}")
if [ -z "${CHANGED_FILES}" ]; then
echo "No changes"
exit 0
fi
echo "Changed files:"
echo "${CHANGED_FILES}"
git config --local user.name "github-actions[bot]"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git add -- "${FILE_LIST[@]}"
git commit -m "${MESSAGE}"
# the branch may have moved meanwhile - conflicts (and fails) only if the files have been committed meanwhile too
git pull --rebase
git push