name: "Free Disk Space (Ubuntu)" author: "Jérémie Lumbroso" description: "A configurable GitHub Action to free up disk space on an Ubuntu GitHub Actions runner.(https://github.com/jlumbroso/free-disk-space)" # See: https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#branding branding: icon: "trash-2" color: "green" inputs: android: description: "Remove Android runtime" required: false default: "true" dotnet: description: "Remove .NET runtime" required: false default: "true" haskell: description: "Remove Haskell runtime" required: false default: "true" # option inspired by: # https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh large-packages: description: "Remove large packages" required: false default: "true" docker-images: description: "Remove Docker images" required: false default: "true" # option inspired by: # https://github.com/actions/virtual-environments/issues/2875#issuecomment-1163392159 tool-cache: description: "Remove image tool cache" required: false default: "false" swap-storage: description: "Remove swap storage" required: false default: "true" runs: using: "composite" steps: - shell: bash run: | # ====== # MACROS # ====== # macro to print a line of equals # (silly but works) printSeparationLine() { str=${1:=} num=${2:-80} counter=1 output="" while [ $counter -le $num ] do output="${output}${str}" counter=$((counter+1)) done echo "${output}" } # macro to compute available space # REF: https://unix.stackexchange.com/a/42049/60849 # REF: https://stackoverflow.com/a/450821/408734 getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } # macro to make Kb human readable (assume the input is Kb) # REF: https://unix.stackexchange.com/a/44087/60849 formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } # macro to output saved space printSavedSpace() { saved=${1} title=${2:-} echo "" printSeparationLine '*' 80 if [ ! -z "${title}" ]; then echo "=> ${title}: Saved $(formatByteCount $saved)" else echo "=> Saved $(formatByteCount $saved)" fi printSeparationLine '*' 80 echo "" } # macro to print output of dh with caption printDH() { caption=${1:-} printSeparationLine '=' 80 echo "${caption}" echo "" echo "$ dh -h /" echo "" df -h / echo "$ dh -a /" echo "" df -a / echo "$ dh -a" echo "" df -a printSeparationLine '=' 80 } # ====== # SCRIPT # ====== # Display initial disk space stats AVAILABLE_INITIAL=$(getAvailableSpace) AVAILABLE_ROOT_INITIAL=$(getAvailableSpace '/') printDH "BEFORE CLEAN-UP:" echo "" # Option: Remove Android library if [[ ${{ inputs.android }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo rm -rf /usr/local/lib/android || true AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Android library" fi # Option: Remove .NET runtime if [[ ${{ inputs.dotnet }} == 'true' ]]; then BEFORE=$(getAvailableSpace) # https://github.community/t/bigger-github-hosted-runners-disk-space/17267/11 sudo rm -rf /usr/share/dotnet || true AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED ".NET runtime" fi # Option: Remove Haskell runtime if [[ ${{ inputs.haskell }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo rm -rf /opt/ghc || true sudo rm -rf /usr/local/.ghcup || true AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Haskell runtime" fi # Option: Remove large packages # REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh if [[ ${{ inputs.large-packages }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo apt-get remove -y '^aspnetcore-.*' || echo "::warning::The command [sudo apt-get remove -y '^aspnetcore-.*'] failed to complete successfully. Proceeding..." sudo apt-get remove -y '^dotnet-.*' --fix-missing || echo "::warning::The command [sudo apt-get remove -y '^dotnet-.*' --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y '^llvm-.*' --fix-missing || echo "::warning::The command [sudo apt-get remove -y '^llvm-.*' --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y 'php.*' --fix-missing || echo "::warning::The command [sudo apt-get remove -y 'php.*' --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y '^mongodb-.*' --fix-missing || echo "::warning::The command [sudo apt-get remove -y '^mongodb-.*' --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y '^mysql-.*' --fix-missing || echo "::warning::The command [sudo apt-get remove -y '^mysql-.*' --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y azure-cli google-chrome-stable firefox powershell mono-devel libgl1-mesa-dri --fix-missing || echo "::warning::The command [sudo apt-get remove -y azure-cli google-chrome-stable firefox powershell mono-devel libgl1-mesa-dri --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y google-cloud-sdk --fix-missing || echo "::debug::The command [sudo apt-get remove -y google-cloud-sdk --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get remove -y google-cloud-cli --fix-missing || echo "::debug::The command [sudo apt-get remove -y google-cloud-cli --fix-missing] failed to complete successfully. Proceeding..." sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed to complete successfully. Proceeding..." sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed to complete successfully. Proceeding..." AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Large misc. packages" fi # Option: Remove Docker images if [[ ${{ inputs.docker-images }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo docker image prune --all --force || true AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Docker images" fi # Option: Remove tool cache # REF: https://github.com/actions/virtual-environments/issues/2875#issuecomment-1163392159 if [[ ${{ inputs.tool-cache }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Tool cache" fi # Option: Remove Swap storage if [[ ${{ inputs.swap-storage }} == 'true' ]]; then BEFORE=$(getAvailableSpace) sudo swapoff -a || true sudo rm -f /mnt/swapfile || true free -h AFTER=$(getAvailableSpace) SAVED=$((AFTER-BEFORE)) printSavedSpace $SAVED "Swap storage" fi # Output saved space statistic AVAILABLE_END=$(getAvailableSpace) AVAILABLE_ROOT_END=$(getAvailableSpace '/') echo "" printDH "AFTER CLEAN-UP:" echo "" echo "" echo "/dev/root:" printSavedSpace $((AVAILABLE_ROOT_END - AVAILABLE_ROOT_INITIAL)) echo "overall:" printSavedSpace $((AVAILABLE_END - AVAILABLE_INITIAL))