├── .github ├── CODEOWNERS └── workflows │ ├── cla.yaml │ ├── lint.yml │ ├── short-tagging.yml │ └── test.yml ├── LICENSE ├── README.md ├── action.yml └── core.sh /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @insightsengineering/idr 2 | -------------------------------------------------------------------------------- /.github/workflows/cla.yaml: -------------------------------------------------------------------------------- 1 | name: CLA 🔏 2 | 3 | on: 4 | issue_comment: 5 | types: 6 | - created 7 | # For PRs that originate from forks 8 | pull_request_target: 9 | types: 10 | - opened 11 | - closed 12 | - synchronize 13 | 14 | jobs: 15 | CLA: 16 | name: CLA 📝 17 | uses: insightsengineering/.github/.github/workflows/cla.yaml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: SuperLinter 🦸🏻‍♀️ 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | jobs: 8 | lint: 9 | name: Lint Code Base 🧶 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout Code 🛎️ 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | - name: Lint Code Base 🧶 17 | uses: github/super-linter/slim@v5 18 | env: 19 | VALIDATE_ALL_CODEBASE: false 20 | DEFAULT_BRANCH: main 21 | VALIDATE_GITHUB_ACTIONS: true 22 | VALIDATE_BASH: true 23 | VALIDATE_BASH_EXEC: true 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/short-tagging.yml: -------------------------------------------------------------------------------- 1 | name: Keep the versions up-to-date ☕️ 2 | on: 3 | release: 4 | types: [published, edited] 5 | jobs: 6 | actions-tagger: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: Actions-R-Us/actions-tagger@latest 10 | with: 11 | publish_latest_tag: true 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test this action 🧪 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | jobs: 7 | test: 8 | name: Test this action 🧪 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repo 🛎️ 12 | uses: actions/checkout@v3 13 | - name: Free Disk Space 🆓 14 | uses: ./ 15 | with: 16 | tools-cache: true 17 | android: true 18 | dotnet: true 19 | haskell: true 20 | large-packages: true 21 | swap-storage: true 22 | docker-images: true 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 F. Hoffmann-La Roche AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Disk Space Reclaimer 2 | 3 | 💡 This is a fork of , only difference is that it's maintained actively. 4 | 5 | A customizable GitHub Action to free disk space on Ubuntu GitHub Action runners. 6 | 7 | On a typical Ubuntu runner, with all options turned on (or not turned off rather), this can clear up to 34 GB of disk space in 4-5 minutes (the longest period is calling `apt` to uninstall packages). This is useful when you need a lot of disk space to run computations. 8 | 9 | ## Example 10 | 11 | ```yaml 12 | name: Free Disk Space (Ubuntu) 13 | on: push 14 | 15 | jobs: 16 | reclaim: 17 | runs-on: ubuntu-latest 18 | steps: 19 | 20 | - name: Free Disk Space (Ubuntu) 21 | uses: insightsengineering/disk-space-reclaimer@v1 22 | with: 23 | # this might remove tools that are actually needed, 24 | # if set to "true" but frees about 6 GB 25 | tools-cache: false 26 | 27 | # all of these default to true, but feel free to set to 28 | # "false" if necessary for your workflow 29 | android: true 30 | dotnet: true 31 | haskell: true 32 | large-packages: true 33 | swap-storage: true 34 | docker-images: true 35 | tools-cache: true 36 | ``` 37 | 38 | ## Options 39 | 40 | Most of the options are self-explanatory. 41 | 42 | The option `tools-cache` removes all the pre-cached tools (Node, Go, Python, Ruby, ...) that are loaded in a runner's environment, [installed in the path specified by the `AGENT_TOOLSDIRECTORY` environment variable](https://github.com/actions/virtual-environments/blob/5a2cb18a48bce5da183486b95f5494e4fd0c0640/images/linux/scripts/installers/configure-environment.sh#L25-L29) (the same environment variable is used across Windows/macOS/Linux runners, see an example of its use on [the `setup-python` GitHub Action](https://github.com/actions/setup-python)). This option was [suggested](https://github.com/actions/virtual-environments/issues/2875#issuecomment-1163392159) by [@miketimofeev](https://github.com/miketimofeev). 43 | 44 | ## Acknowledgement 45 | 46 | This GitHub Actions came around because I kept rewriting the same few lines of `rm -rf` code. 47 | 48 | Here are a few sources of inspiration: 49 | - 50 | - 51 | - 52 | - 53 | - 54 | 55 | ## Typical Output 56 | 57 | The amount of space storage saved by each option on an `ubuntu-22.04` runner is summarized here: 58 | 59 | ```bash 60 | => Android library: Saved 12GiB 61 | => .NET runtime: Saved 1.7GiB 62 | => Haskell runtime: Saved 0B 63 | => Large misc. packages: Saved 4.6GiB 64 | => Docker images: Saved 3.6GiB 65 | => Tool cache: Saved 8.4GiB 66 | => Swap storage: Saved 4.0GiB 67 | => Saved 30GiB 68 | 69 | => Total 34GiB 70 | ``` 71 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Disk Space Reclaimer" 2 | description: "A configurable GitHub Action to reclaim disk space on Ubuntu GitHub Actions runners." 3 | branding: 4 | icon: "save" 5 | color: "blue" 6 | inputs: 7 | android: 8 | description: "Remove Android runtime" 9 | required: false 10 | default: "true" 11 | dotnet: 12 | description: "Remove .NET runtime" 13 | required: false 14 | default: "true" 15 | haskell: 16 | description: "Remove Haskell runtime" 17 | required: false 18 | default: "true" 19 | large-packages: 20 | description: "Remove large packages" 21 | required: false 22 | default: "true" 23 | tools-cache: 24 | description: "Remove image tool cache" 25 | required: false 26 | default: "false" 27 | swap-storage: 28 | description: "Remove swap storage" 29 | required: false 30 | default: "true" 31 | docker-images: 32 | description: "Remove Docker images" 33 | required: false 34 | default: "true" 35 | runs: 36 | using: "composite" 37 | steps: 38 | - name: "Clean up disk space 🗑️" 39 | run: bash ${GITHUB_ACTION_PATH}/core.sh 40 | shell: bash 41 | env: 42 | ANDROID: "${{ inputs.android }}" 43 | DOTNET: "${{ inputs.dotnet }}" 44 | HASKELL: "${{ inputs.haskell }}" 45 | LARGE_PACKAGES: "${{ inputs.large-packages }}" 46 | TOOLS_CACHE: "${{ inputs.tools-cache }}" 47 | SWAP_STORAGE: "${{ inputs.swap-storage }}" 48 | DOCKER_IMAGES: "${{ inputs.docker-images }}" 49 | -------------------------------------------------------------------------------- /core.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # ====== 4 | # MACROS 5 | # ====== 6 | # macro to print a line of equals 7 | # (silly but works) 8 | printSeparationLine() { 9 | str=${1:=} 10 | num=${2:-80} 11 | counter=1 12 | output="" 13 | # shellcheck disable=SC2086 14 | while [ $counter -le $num ]; do 15 | output="${output}${str}" 16 | counter=$((counter + 1)) 17 | done 18 | echo "${output}" 19 | } 20 | 21 | # macro to compute available space 22 | # REF: https://unix.stackexchange.com/a/42049/60849 23 | # REF: https://stackoverflow.com/a/450821/408734 24 | # shellcheck disable=SC2046,SC2005,SC2086 25 | getAvailableSpace() { echo $(df -a $1 | awk 'NR > 1 {avail+=$4} END {print avail}'); } 26 | 27 | # macro to make Kb human readable (assume the input is Kb) 28 | # REF: https://unix.stackexchange.com/a/44087/60849 29 | # shellcheck disable=SC2046,SC2005,SC2086 30 | formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } 31 | 32 | # macro to output saved space 33 | printSavedSpace() { 34 | saved=${1} 35 | title=${2:-} 36 | 37 | echo "" 38 | printSeparationLine '*' 80 39 | if [ -n "${title}" ]; then 40 | echo "=> ${title}: Saved $(formatByteCount "$saved")" 41 | else 42 | echo "=> Saved $(formatByteCount "$saved")" 43 | fi 44 | printSeparationLine '*' 80 45 | echo "" 46 | } 47 | 48 | # macro to print output of dh with caption 49 | printDH() { 50 | caption=${1:-} 51 | 52 | printSeparationLine '=' 80 53 | echo "${caption}" 54 | echo "" 55 | echo "$ dh -h /" 56 | echo "" 57 | df -h / 58 | echo "$ dh -a /" 59 | echo "" 60 | df -a / 61 | echo "$ dh -a" 62 | echo "" 63 | df -a 64 | printSeparationLine '=' 80 65 | } 66 | 67 | # ====== 68 | # SCRIPT 69 | # ====== 70 | # Display initial disk space stats 71 | AVAILABLE_INITIAL=$(getAvailableSpace) 72 | AVAILABLE_ROOT_INITIAL=$(getAvailableSpace '/') 73 | 74 | printDH "BEFORE CLEAN-UP:" 75 | echo "" 76 | 77 | # Option: Remove Android library 78 | 79 | if [[ "$ANDROID" == "true" ]]; then 80 | BEFORE=$(getAvailableSpace) 81 | sudo rm -rf /usr/local/lib/android 82 | AFTER=$(getAvailableSpace) 83 | SAVED=$((AFTER - BEFORE)) 84 | printSavedSpace $SAVED "Android library" 85 | fi 86 | 87 | # Option: Remove .NET runtime 88 | 89 | if [[ "$DOTNET" == "true" ]]; then 90 | BEFORE=$(getAvailableSpace) 91 | 92 | # https://github.community/t/bigger-github-hosted-runners-disk-space/17267/11 93 | sudo rm -rf /usr/share/dotnet 94 | 95 | AFTER=$(getAvailableSpace) 96 | SAVED=$((AFTER - BEFORE)) 97 | printSavedSpace $SAVED ".NET runtime" 98 | fi 99 | 100 | # Option: Remove Haskell runtime 101 | 102 | if [[ "$HASKELL" == "true" ]]; then 103 | BEFORE=$(getAvailableSpace) 104 | 105 | sudo rm -rf /opt/ghc 106 | 107 | AFTER=$(getAvailableSpace) 108 | SAVED=$((AFTER - BEFORE)) 109 | printSavedSpace $SAVED "Haskell runtime" 110 | fi 111 | 112 | # Option: Remove large packages 113 | # REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh 114 | 115 | if [[ "${LARGE_PACKAGES}" == "true" ]]; then 116 | BEFORE=$(getAvailableSpace) 117 | 118 | # Select alternative apt mirror since the original one is unstable 119 | sudo gem install apt-spy2 120 | sudo apt-spy2 fix --commit --launchpad --country=US 121 | sudo apt-get update 122 | 123 | sudo apt-get remove -y '^dotnet-.*' 124 | sudo apt-get remove -y '^llvm-.*' 125 | sudo apt-get remove -y 'php.*' 126 | sudo apt-get remove -y '^mongodb-.*' 127 | sudo apt-get remove -y '^mysql-.*' 128 | sudo apt-get remove -y azure-cli google-cloud-sdk google-chrome-stable firefox powershell mono-devel libgl1-mesa-dri 129 | sudo apt-get autoremove -y 130 | sudo apt-get clean 131 | 132 | AFTER=$(getAvailableSpace) 133 | SAVED=$((AFTER - BEFORE)) 134 | printSavedSpace $SAVED "Large misc. packages" 135 | fi 136 | 137 | # Option: Remove Docker images 138 | if [[ "$DOCKER_IMAGES" == 'true' ]]; then 139 | BEFORE=$(getAvailableSpace) 140 | sudo docker image prune --all --force 141 | AFTER=$(getAvailableSpace) 142 | SAVED=$((AFTER - BEFORE)) 143 | printSavedSpace $SAVED "Docker images" 144 | fi 145 | 146 | # Option: Remove tool cache 147 | # REF: https://github.com/actions/virtual-environments/issues/2875#issuecomment-1163392159 148 | 149 | if [[ "$TOOLS_CACHE" == "true" ]]; then 150 | BEFORE=$(getAvailableSpace) 151 | 152 | sudo rm -rf "$AGENT_TOOLSDIRECTORY" 153 | 154 | AFTER=$(getAvailableSpace) 155 | SAVED=$((AFTER - BEFORE)) 156 | printSavedSpace $SAVED "Tool cache" 157 | fi 158 | 159 | # Option: Remove Swap storage 160 | 161 | if [[ "$SWAP_STORAGE" == "true" ]]; then 162 | BEFORE=$(getAvailableSpace) 163 | 164 | sudo swapoff -a 165 | sudo rm -f /mnt/swapfile 166 | free -h 167 | 168 | AFTER=$(getAvailableSpace) 169 | SAVED=$((AFTER - BEFORE)) 170 | printSavedSpace $SAVED "Swap storage" 171 | fi 172 | 173 | # Output saved space statistic 174 | AVAILABLE_END=$(getAvailableSpace) 175 | AVAILABLE_ROOT_END=$(getAvailableSpace '/') 176 | 177 | echo "" 178 | printDH "AFTER CLEAN-UP:" 179 | 180 | echo "" 181 | echo "" 182 | 183 | echo "/dev/root:" 184 | printSavedSpace $((AVAILABLE_ROOT_END - AVAILABLE_ROOT_INITIAL)) 185 | echo "overall:" 186 | printSavedSpace $((AVAILABLE_END - AVAILABLE_INITIAL)) 187 | --------------------------------------------------------------------------------