diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index d1e0c5a..f904a41 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -59,7 +59,7 @@ jobs: env: JULIA_DEPOT_PATH: /tmp/julia-depot steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set cache-name id: cache-name shell: bash @@ -117,7 +117,7 @@ jobs: env: JULIA_DEPOT_PATH: /tmp/julia-depot steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} @@ -161,7 +161,7 @@ jobs: outputs: cache-name: ${{ steps.cache-name.outputs.cache-name }} steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set cache-name id: cache-name run: | @@ -193,7 +193,7 @@ jobs: needs: test-save-nomatrix runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Restore cache id: cache uses: ./ @@ -233,7 +233,7 @@ jobs: outputs: cache-name: ${{ steps.cache-name.outputs.cache-name }} steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set cache-name id: cache-name run: | @@ -259,7 +259,7 @@ jobs: needs: test-save-cloned-registry runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Add General registry clone shell: julia --color=yes {0} run: | diff --git a/README.md b/README.md index 47794e3..c6c9930 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ By default all depot directories called out below are cached. ### Outputs - `cache-hit` - A boolean value to indicate an exact match was found for the primary key. Returns \"\" when the key is new. Forwarded from actions/cache. +- `cache-paths` - A list of paths (as a newline-separated string) that were cached. +- `cache-key` - The cache key that was used for this run. ## How It Works @@ -64,6 +66,9 @@ By default, this action removes caches that were previously made by jobs on the GitHub automatically removes old caches after a certain period or when the repository cache allocation is full. It is, however, more efficient to explicitly remove old caches to improve caching for less frequently run jobs. +For more information about GitHub caching generically, for example how to manually delete caches, see +[this GitHub documentation page](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#managing-caches). + ### Cache keys The cache key that the cache will be saved as is based on: @@ -101,6 +106,35 @@ Which means your caches files will not grow needlessly. GitHub also deletes cach To disable deletion set input `delete-old-caches: 'false'`. +### Caching even if an intermediate job fails + +Just like [the basic actions/cache workflow](https://github.com/actions/cache), this action has a cache restore step, and also a save step which runs after the workflow completes. +By default, if any job in the workflow fails, the entire workflow will be stopped, and the cache will not be saved. + +Due to current limitations in GitHub Actions syntax, there is no built-in option for this action to save the cache even if the job fails. +However, it does output information which you can feed into `actions/cache` yourself to achieve the same effect. +For example, this workflow will ensure that the cache is saved if a step fails (but skipping it if the cache was hit, i.e. there's no need to cache it again). + +```yaml + steps: + - uses: actions/checkout@v4 + + - name: Load Julia packages from cache + id: julia-cache + uses: julia-actions/cache@v2 + + # do whatever you want here (that might fail) + + - name: Save Julia depot cache on cancel or failure + id: julia-cache-save + if: cancelled() || failure() + uses: actions/cache/save@v4 + with: + path: | + ${{ steps.julia-cache.outputs.cache-paths }} + key: ${{ steps.julia-cache.outputs.cache-key }} +``` + ### Cache Garbage Collection Caches are restored and re-saved after every run, retaining the state of the depot throughout runs. diff --git a/action.yml b/action.yml index 4a0852f..f399121 100644 --- a/action.yml +++ b/action.yml @@ -47,12 +47,18 @@ outputs: cache-hit: description: A boolean value to indicate an exact match was found for the primary key. Returns "" when the key is new. Forwarded from actions/cache. value: ${{ steps.hit.outputs.cache-hit }} + cache-paths: + description: The paths that were cached + value: ${{ steps.paths.outputs.cache-paths }} + cache-key: + description: The full cache key used + value: ${{ steps.keys.outputs.key }} runs: using: 'composite' steps: - name: Install jq - uses: dcarbone/install-jq-action@8867ddb4788346d7c22b72ea2e2ffe4d514c7bcb + uses: dcarbone/install-jq-action@b7ef57d46ece78760b4019dbc4080a1ba2a40b45 # v3.2.0 with: force: false # Skip install when an existing `jq` is present @@ -66,6 +72,12 @@ runs: else depot="~/.julia" fi + if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then + depot="${depot/#\~/$USERPROFILE}" # Windows paths + depot="${depot//\\//}" # Replace backslashes with forward slashes + else + depot="${depot/#\~/$HOME}" # Unix-like paths + fi echo "depot=$depot" | tee -a "$GITHUB_OUTPUT" cache_paths=() @@ -75,7 +87,7 @@ runs: [ "${{ inputs.cache-packages }}" = "true" ] && cache_paths+=("$packages_path") registries_path="${depot}/registries" if [ "${{ inputs.cache-registries }}" = "true" ]; then - if [ ! -d "${registries_path/#\~/$HOME}" ]; then + if [ ! -d "${registries_path}" ]; then cache_paths+=("$registries_path") else echo "::warning::Julia depot registries already exist. Skipping restoring of cached registries to avoid potential merge conflicts when updating. Please ensure that \`julia-actions/cache\` precedes any workflow steps which add registries." @@ -115,7 +127,7 @@ runs: env: MATRIX_JSON: ${{ toJSON(matrix) }} - - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache with: path: | @@ -132,6 +144,23 @@ runs: du -shc ${{ steps.paths.outputs.depot }}/* || true shell: bash + # issue https://github.com/julia-actions/cache/issues/110 + # Pkg may not run `Registry.update()` if a manifest exists, which may exist because of a + # `Pkg.dev` call or because one is added to the repo. So be safe and update cached registries here. + # Older (~v1.0) versions of julia that don't have `Pkg.Registry.update()` seem to always update registries in + # Pkg operations. So this is only necessary for newer julia versions. + - name: Update any cached registries + if: ${{ inputs.cache-registries == 'true' }} + continue-on-error: true + run: | + if [ -d "${{ steps.paths.outputs.depot }}/registries" ] && [ -n "$(ls -A "${{ steps.paths.outputs.depot }}/registries")" ]; then + echo "Registries directory exists and is non-empty. Updating any registries" + julia -e "import Pkg; isdefined(Pkg, :Registry) && Pkg.Registry.update();" + else + echo "Registries directory does not exist or is empty. Skipping registry update" + fi + shell: bash + # GitHub actions cache entries are immutable and cannot be updated. In order to have both the Julia # depot cache be up-to-date and avoid storing redundant cache entries we'll manually cleanup old # cache entries before the new cache is saved. However, we need to be careful with our manual @@ -149,7 +178,7 @@ runs: # - https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy # Not windows - - uses: pyTooling/Actions/with-post-step@e9d0dc3dba9fda45f195946858708f60c0240caf # v1.0.5 + - uses: pyTooling/Actions/with-post-step@d6342484cd335d4c9c63d4f52f267c54d5bc3b19 # v5.4.0 if: ${{ inputs.delete-old-caches != 'false' && github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && runner.OS != 'Windows' }} @@ -162,7 +191,7 @@ runs: GH_TOKEN: ${{ inputs.token }} # Windows (because this action uses command prompt on windows) - - uses: pyTooling/Actions/with-post-step@e9d0dc3dba9fda45f195946858708f60c0240caf # v1.0.5 + - uses: pyTooling/Actions/with-post-step@d6342484cd335d4c9c63d4f52f267c54d5bc3b19 # v5.4.0 if: ${{ inputs.delete-old-caches != 'false' && github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && runner.OS == 'Windows' }}