1+ # Modified version of https://github.com/easimon/maximize-build-space
2+ name : ' Maximize build disk space'
3+ description : ' Maximize the available disk space for your build job'
4+ branding :
5+ icon : ' crop'
6+ color : ' orange'
7+ inputs :
8+ root-reserve-mb :
9+ description : ' Space to be left free on the root filesystem, in Megabytes.'
10+ required : false
11+ default : ' 1024'
12+ temp-reserve-mb :
13+ description : ' Space to be left free on the temp filesystem (/mnt), in Megabytes.'
14+ required : false
15+ default : ' 100'
16+
17+ swap-size-mb :
18+ description : ' Swap space to create, in Megabytes.'
19+ required : false
20+ default : ' 4096'
21+ overprovision-lvm :
22+ description : |
23+ Create the LVM disk images as sparse files, making the space required for the LVM image files *appear* unused on the
24+ hosting volumes until actually allocated. Use with care, this can lead to surprising out-of-disk-space situations.
25+ You should prefer adjusting root-reserve-mb/temp-reserve-mb over using this option.
26+ required : false
27+ default : ' false'
28+ build-mount-path :
29+ description : ' Absolute path to the mount point where the build space will be available, defaults to $GITHUB_WORKSPACE if unset.'
30+ required : false
31+ build-mount-path-ownership :
32+ description : ' Ownership of the mount point path, defaults to standard "runner" user and group.'
33+ required : false
34+ default : ' runner:runner'
35+ pv-loop-path :
36+ description : ' Absolute file path for the LVM image created on the root filesystem, the default is usually fine.'
37+ required : false
38+ default : ' /pv.img'
39+ tmp-pv-loop-path :
40+ description : ' Absolute file path for the LVM image created on the temp filesystem, the default is usually fine. Must reside on /mnt'
41+ required : false
42+ default : ' /mnt/tmp-pv.img'
43+
44+ remove-dotnet :
45+ description : ' Removes .NET runtime and libraries. (frees ~17 GB)'
46+ required : false
47+ default : ' false'
48+ remove-android :
49+ description : ' Removes Android SDKs and Tools. (frees ~11 GB)'
50+ required : false
51+ default : ' false'
52+ remove-haskell :
53+ description : ' Removes GHC (Haskell) artifacts. (frees ~2.7 GB)'
54+ required : false
55+ default : ' false'
56+ remove-codeql :
57+ description : ' Removes CodeQL Action Bundles. (frees ~5.4 GB)'
58+ required : false
59+ default : ' false'
60+ remove-docker-images :
61+ description : ' Removes cached Docker images. (frees ~3 GB)'
62+ required : false
63+ default : ' false'
64+ runs :
65+ using : " composite"
66+ steps :
67+ - name : Disk space report before modification
68+ shell : bash
69+ run : |
70+ echo "Memory and swap:"
71+ sudo free -h
72+ echo
73+ sudo swapon --show
74+ echo
75+
76+ echo "Available storage:"
77+ sudo df -h
78+ echo
79+
80+ - name : Maximize build disk space
81+ shell : bash
82+ run : |
83+ set -euo pipefail
84+
85+ BUILD_MOUNT_PATH="${{ inputs.build-mount-path }}"
86+ if [[ -z "${BUILD_MOUNT_PATH}" ]]; then
87+ BUILD_MOUNT_PATH="${GITHUB_WORKSPACE}"
88+ fi
89+
90+ echo "Arguments:"
91+ echo
92+ echo " Root reserve: ${{ inputs.root-reserve-mb }} MiB"
93+ echo " Temp reserve: ${{ inputs.temp-reserve-mb }} MiB"
94+ echo " Swap space: ${{ inputs.swap-size-mb }} MiB"
95+ echo " Overprovision LVM: ${{ inputs.overprovision-lvm }}"
96+ echo " Mount path: ${BUILD_MOUNT_PATH}"
97+ echo " Root PV loop path: ${{ inputs.pv-loop-path }}"
98+ echo " Temp PV loop path: ${{ inputs.tmp-pv-loop-path }}"
99+
100+ echo -n " Removing: "
101+ if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then
102+ echo -n "dotnet "
103+ fi
104+ if [[ ${{ inputs.remove-android }} == 'true' ]]; then
105+ echo -n "android "
106+ fi
107+ if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then
108+ echo -n "haskell "
109+ fi
110+ if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then
111+ echo -n "codeql "
112+ fi
113+ if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then
114+ echo -n "docker "
115+ fi
116+ echo
117+
118+ # store owner of $GITHUB_WORKSPACE in case the action deletes it
119+ WORKSPACE_OWNER="$(stat -c '%U:%G' "${GITHUB_WORKSPACE}")"
120+
121+ # ensure mount path exists before the action
122+ sudo mkdir -p "${BUILD_MOUNT_PATH}"
123+ sudo find "${BUILD_MOUNT_PATH}" -maxdepth 0 ! -empty -exec echo 'WARNING: directory [{}] is not empty, data loss might occur. Content:' \; -exec ls -al "{}" \;
124+
125+ echo "Removing unwanted software... "
126+ if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then
127+ sudo rm -rf /usr/share/dotnet
128+ fi
129+ if [[ ${{ inputs.remove-android }} == 'true' ]]; then
130+ sudo rm -rf /usr/local/lib/android
131+ fi
132+ if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then
133+ sudo rm -rf /opt/ghc
134+ fi
135+ if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then
136+ sudo rm -rf /opt/hostedtoolcache/CodeQL
137+ fi
138+ if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then
139+ sudo docker image prune --all --force
140+ fi
141+ echo "... done"
142+
143+ VG_NAME=buildvg
144+
145+ # github runners have an active swap file in /mnt/swapfile
146+ # we want to reuse the temp disk, so first unmount swap and clean the temp disk
147+ echo "Unmounting and removing swap file."
148+ sudo swapoff -a
149+ sudo rm -f /mnt/swapfile
150+
151+ echo "Creating LVM Volume."
152+ echo " Creating LVM PV on root fs."
153+ # create loop pv image on root fs
154+ ROOT_RESERVE_KB=$(expr ${{ inputs.root-reserve-mb }} \* 1024)
155+ ROOT_FREE_KB=$(df --block-size=1024 --output=avail / | tail -1)
156+ ROOT_LVM_SIZE_KB=$(expr $ROOT_FREE_KB - $ROOT_RESERVE_KB)
157+ ROOT_LVM_SIZE_BYTES=$(expr $ROOT_LVM_SIZE_KB \* 1024)
158+ sudo touch "${{ inputs.pv-loop-path }}" && sudo fallocate -z -l "${ROOT_LVM_SIZE_BYTES}" "${{ inputs.pv-loop-path }}"
159+ export ROOT_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.pv-loop-path }}")
160+ sudo pvcreate -f "${ROOT_LOOP_DEV}"
161+
162+
163+
164+ # create volume group from these pvs
165+ # create pv on temp disk if it is on a different filesystem than root
166+ TMP_LOOP_DEV=""
167+ ROOT_FS=$(df --output=source / | tail -1)
168+ TEMP_FS=$(df --output=source /mnt 2>/dev/null || echo "")
169+
170+ if [[ -n "${TEMP_FS}" && "${ROOT_FS}" != "${TEMP_FS}" ]]; then
171+ echo " Creating LVM PV on temp fs."
172+ TMP_RESERVE_KB=$(expr ${{ inputs.temp-reserve-mb }} \* 1024)
173+ TMP_FREE_KB=$(df --block-size=1024 --output=avail /mnt | tail -1)
174+ TMP_LVM_SIZE_KB=$(expr $TMP_FREE_KB - $TMP_RESERVE_KB)
175+ TMP_LVM_SIZE_BYTES=$(expr $TMP_LVM_SIZE_KB \* 1024)
176+ sudo touch "${{ inputs.tmp-pv-loop-path }}" && sudo fallocate -z -l "${TMP_LVM_SIZE_BYTES}" "${{ inputs.tmp-pv-loop-path }}"
177+ export TMP_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.tmp-pv-loop-path }}")
178+ sudo pvcreate -f "${TMP_LOOP_DEV}"
179+ else
180+ echo " Skipping LVM PV on temp fs (same as root or not available)."
181+ fi
182+
183+ # create volume group from these pvs
184+ if [[ -n "${TMP_LOOP_DEV}" ]]; then
185+ sudo vgcreate "${VG_NAME}" "${TMP_LOOP_DEV}" "${ROOT_LOOP_DEV}"
186+ else
187+ sudo vgcreate "${VG_NAME}" "${ROOT_LOOP_DEV}"
188+ fi
189+
190+ echo "Recreating swap"
191+ # create and activate swap
192+ sudo lvcreate -L "${{ inputs.swap-size-mb }}M" -n swap "${VG_NAME}"
193+ sudo mkswap "/dev/mapper/${VG_NAME}-swap"
194+ sudo swapon "/dev/mapper/${VG_NAME}-swap"
195+
196+ echo "Creating build volume"
197+ # create and mount build volume
198+ sudo lvcreate -l 100%FREE -n buildlv "${VG_NAME}"
199+ if [[ ${{ inputs.overprovision-lvm }} == 'true' ]]; then
200+ sudo mkfs.ext4 -m0 "/dev/mapper/${VG_NAME}-buildlv"
201+ else
202+ sudo mkfs.ext4 -Enodiscard -m0 "/dev/mapper/${VG_NAME}-buildlv"
203+ fi
204+ sudo mount "/dev/mapper/${VG_NAME}-buildlv" "${BUILD_MOUNT_PATH}"
205+ sudo chown -R "${{ inputs.build-mount-path-ownership }}" "${BUILD_MOUNT_PATH}"
206+
207+ # if build mount path is a parent of $GITHUB_WORKSPACE, and has been deleted, recreate it
208+ if [[ ! -d "${GITHUB_WORKSPACE}" ]]; then
209+ sudo mkdir -p "${GITHUB_WORKSPACE}"
210+ sudo chown -R "${WORKSPACE_OWNER}" "${GITHUB_WORKSPACE}"
211+ fi
212+
213+ - name : Disk space report after modification
214+ shell : bash
215+ run : |
216+ echo "Memory and swap:"
217+ sudo free -h
218+ echo
219+ sudo swapon --show
220+ echo
221+
222+ echo "Available storage:"
223+ sudo df -h
0 commit comments