Code Monkey home page Code Monkey logo

Comments (40)

Rarst avatar Rarst commented on June 3, 2024 18

Seems like it would make a lot of sense in some circumstances.

Say I have following steps:

  • install dependencies (success)
  • check code style (fail)
  • post cache (skip)

It would make sense if post cache could happen conditionally on success of dependencies install, code style step is irrelevant to it.

from cache.

pat-s avatar pat-s commented on June 3, 2024 15

Next fork with latest upstream changes (including the new 5GB cache limit): https://github.com/marketplace/actions/always-upload-cache

from cache.

MartijnHols avatar MartijnHols commented on June 3, 2024 15

I made a fork of this repository that gives you full control over when the cache is saved. This allows you to both set your own if: always() (or success or failure or what you want) as well as run the save action where/when you want. Docs here: https://github.com/MartijnHols/actions-cache

For the OP it sounds like you run install and tests in a single job. If you place the save action after the step that generates the things you want to cache, you can achieve this without always. For example:

name: Build app

on: push

jobs:
  install:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Restore "node_modules" from cache
      id: cache
      uses: martijnhols/actions-cache/restore@v3
      with:
        path: node_modules
        key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', 'patches') }}
        restore-keys: ${{ runner.os }}-node_modules

    - name: Install dependencies
      if: steps.cache.outputs.cache-hit != 'true'
      run: yarn install

    - name: Save "node_modules" to cache
      if: steps.cache.outputs.cache-hit != 'true'
      uses: martijnhols/actions-cache/save@v3
      with:
        path: node_modules
        key: ${{ steps.cache.outputs.primary-key }}

    - name: Run flaky tests
      run: yarn test

If you want your cache to be saved regardless of a previous failure you can change the if: steps.cache.outputs.cache-hit != 'true' line into if: always() && steps.cache.outputs.cache-hit != 'true'.

from cache.

kotewar avatar kotewar commented on June 3, 2024 14

Hey everyone 👋🏽

Two new actions actions/cache/restore and actions/cache/save are now available with tag v3 to everyone for use. These can now be used to achieve granular control on the restore and save steps in the cache action.

Do try them and give your feedback. We hope these new actions will take care of your use cases. 🙇🏽

Closing this issue now as we believe the new actions will take care of the same, feel free to reopen it if need be. 😄

from cache.

mcschroeder avatar mcschroeder commented on June 3, 2024 11

I also desperately need this. For my use cases (grading of student assignments), it is expected that at least some of the tests will fail most of the time, so having a completely successful run is rare. This means caching is basically useless, as the cache will never actually be persisted.

@gerbal I've tried your fork, but it also doesn't seem to work. The post-action simply never runs (it stays a grey square in the log UI), same as with the original cache action.

from cache.

DrJume avatar DrJume commented on June 3, 2024 6

I made https://github.com/mxxk/gh-actions-cache-always into a reusable action, which patches the original actions/cache to change the post-if: 'success()' predicate to post-if: 'success() || failure()'.

.github/actions/cache-always/action.yml:

Show file contents

name: 'Cache Always'
description: 'Cache artifacts like dependencies and build outputs to improve workflow execution time'

inputs:
  path:
    description: 'A list of files, directories, and wildcard patterns to cache and restore'
    required: true
  key:
    description: 'An explicit key for restoring and saving the cache'
    required: true
  restore-keys:
    description: 'An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
    required: false
  upload-chunk-size:
    description: 'The chunk size used to split up large files during upload, in bytes'
    required: false

outputs:
  cache-hit:
    description: 'A boolean value to indicate an exact match was found for the primary key'
    value: ${{ steps.cache.outputs.cache-hit }}

runs:
  using: 'composite'
  steps:
    # Instead of running `actions/cache@v3` directly, check it out locally.
    - name: Checkout actions/cache@v3
      uses: actions/checkout@v3
      with:
        repository: actions/cache
        ref: v3
        path: ./.github/.tmp/cache-always/actions/cache

    - name: Patch actions/cache@v3 to make it cache data also when the job fails
      run: |
        sed -i -e 's/post-if:.*$/post-if: "success() || failure()"/' ./.github/.tmp/cache-always/actions/cache/action.yml
      shell: bash

    - name: Cache
      id: cache
      uses: ./.github/.tmp/cache-always/actions/cache
      with:
        path: ${{ inputs.path }}
        key: ${{ inputs.key }}
        restore-keys: ${{ inputs.restore-keys }}
        upload-chunk-size: ${{ inputs.upload-chunk-size }}

You can use it by saving the above action into its recommended location and writing:

uses: ./.github/actions/cache-always

instead of

uses: actions/cache@v3

e.g.

- name: Setup pnpm cache
  uses: ./.github/actions/cache-always
  with:
    path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
    key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-pnpm-store-

Edits:
2022-11-11: run on success() || failure(), to prevent caching on cancelled()

from cache.

mxxk avatar mxxk commented on June 3, 2024 5

An alternative workaround, which does not require maintaining a forked version of actions/cache@v3, is to check out the action repo manually, modify action.yml, and run the modified action from its local path:

- name: Checkout actions/cache@v3
  uses: actions/checkout@v3
  with:
    repository: actions/cache
    ref: v3
    path: .tmp/actions/cache
- name: Make actions/cache@v3 run always, not only when job succeeds
  # Tweak `action.yml` of `actions/cache@v3` to remove its `post-if`
  # condition, making it default to `post-if: always()`.
  run: |
    sed -i -e '/ post-if: /d' .tmp/actions/cache/action.yml
- name: Cache data
  id: cache
  uses: ./.tmp/actions/cache
  with:
    ...

You can see a minimal example of a full workflow in https://github.com/mxxk/gh-actions-cache-always. The modified actions/cache@v3 command still saved the cache even though the job https://github.com/mxxk/gh-actions-cache-always/runs/5847143256 failed.

(Of course, this is only a hack, since the sed command which finds and deletes the post-if: line from action.yml is quite janky.)

from cache.

eyal0 avatar eyal0 commented on June 3, 2024 4

Yeah. If you want, you could use my fork and just change the "success()" to "always()".

#498 (comment)

It lets you control the behavior of the post action with an environment variable. So you could "always" run the post action and then have an environment variable that is set to true or false to control whether or not to update the cache. There are likely dozens of solutions similar to mine.

The authors of actions/cache ought to look at what the common forks of this repo are trying to do and incorporate the features.

from cache.

rhaschke avatar rhaschke commented on June 3, 2024 4

@pat-s, could you please fix deprecation warnings in your fork:

The `save-state` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands
The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

Thanks.

from cache.

kotewar avatar kotewar commented on June 3, 2024 4

Hey all, 👋🏽

We have created a discussion with a proposal that we feel will solve this problem, do let us know your feedback, thanks 😊

from cache.

ktmud avatar ktmud commented on June 3, 2024 3

For anyone interested, you are welcome to try out my advanced cache action built on top of this repo. Simply specify your cache targets in a config file, and finishes restoration, build, and save as many caches as you want in one step:

steps:
- uses: actions/checkout@v2
- uses: ktmud/cached-dependencies@v1
  with:
    run: |
      cache-restore npm
      npm install
      cache-save npm

      cache-restore pip
      pip install -r requirements.txt
      cache-save pip

https://github.com/ktmud/cached-dependencies#speficy-when-to-restore-and-save

from cache.

valfirst avatar valfirst commented on June 3, 2024 3

FYI: such fork already exists: https://github.com/pat-s/always-upload-cache

from cache.

pat-s avatar pat-s commented on June 3, 2024 3

I've just updated my fork to v3.0.1: https://github.com/marketplace/actions/always-upload-cache

from cache.

whfuyn avatar whfuyn commented on June 3, 2024 3

Any progress on this one? I have the same problem as mentioned in #92 (comment).

Would this feature be officially supported?

from cache.

trent-boyd avatar trent-boyd commented on June 3, 2024 2

This would be extremely useful for my team. We use Next.js. The process goes something like this.

  1. Restore the Next build cache
  2. Run the Next build (hopefully with cache)
  3. Run Cypress tests (which can be flakey)
  4. Save the Next build cache.

It would be great to save the Next cache even if the Cypress tests fail. There's a high likelihood that the Cypress tests fail due to flakiness, but sometimes we just need to update the Cypress tests. That change doesn't invalidate the build cache, so it would be nice to have that speedier build on the second run.

from cache.

petetnt avatar petetnt commented on June 3, 2024 2

We have the same use case @trent-boyd for this: failing / flaky end-to-end tests are really hard to debug due to having to re-run build processes: by allowing to cache builds even on failure would speed up this considerably.

from cache.

Trass3r avatar Trass3r commented on June 3, 2024 2

Relevant section: https://github.com/actions/cache/tree/main/save#always-save-cache

from cache.

amolenaar avatar amolenaar commented on June 3, 2024 1

+1

We're running a test suite with Hypothesis, a property based testing tool. The database should be saved (cached) on failed runs, so failed tests are replayed on subsequent runs.

from cache.

kotewar avatar kotewar commented on June 3, 2024 1

Hmm, I understood the requirement. Thanks @LorenzoBettini. I'll take a look at this.

from cache.

stevencpp avatar stevencpp commented on June 3, 2024

Bump. I have some caches that take a long time to rebuild, and sometimes they may need to be rebuilt due to external events right in the middle of other changes that may cause subsequent steps to fail. So it's a big waste of time to have to then disable and reenable all of the following steps to be able to save the cache. A totally configurable 'pass-if' option would be a great solution, but if for some reason that's difficult to implement, maybe we could have a 'save-after' option where you could pass the id of the step that builds the thing that needs to be cached ? Then instead of running the post cache step after all other steps, it could run right after the 'save-after' step, and then that would make it succeed regardless of any subsequent steps that might fail ?

from cache.

ioquatix avatar ioquatix commented on June 3, 2024

@ktmud thanks for the link it seems like a better solution.

from cache.

smolkaj avatar smolkaj commented on June 3, 2024

+1, this would be very good to have, for example for Bazel.

from cache.

ollydev avatar ollydev commented on June 3, 2024

This is very much needed. Even another action which only uploads would be fine.

Something like:

- name: Upload cache because failure
  if: failed()
  uses: actions/upload-cache
  with:
    path: dependencies/
    key: 123

from cache.

glau2 avatar glau2 commented on June 3, 2024

+1, this would be very good to have

from cache.

ben-spiller avatar ben-spiller commented on June 3, 2024

+1 yes please! Seems like a fairly minor addition that would make a bit difference

from cache.

sidey79 avatar sidey79 commented on June 3, 2024

+1
I agree, having this as an option to cache even on a failure. Would be nice, because in docker build workflow this woud allow to get the working layers out of the cache and reduce much build time if the build fails somewhere.

from cache.

eyal0 avatar eyal0 commented on June 3, 2024

@sidey79 @ben-spiller @ollydev @glau2 Is it possible to add post-if to the CI? Like this: post-if: always().

I'm not sure if that is available to users of the action or only available to the developer in action.yml.

from cache.

Rarst avatar Rarst commented on June 3, 2024

@eyal0 that was not possible to override at the time I tried.

from cache.

eyal0 avatar eyal0 commented on June 3, 2024

@Rarst yes, that's what I suspect. post-if is not documented in the user action guide as part of the spec.

You could fork it yourself and change it to always().

from cache.

dhadka avatar dhadka commented on June 3, 2024

You can also reference env vars in the post-if condition:

post-if: success() || env.ALWAYS_SAVE_CACHE == 'true'

(I would love to replace the env var with an input here, but that wasn't supported when I last tested.)

from cache.

eyal0 avatar eyal0 commented on June 3, 2024

@dhadka Inputs and env vars are basically the same thing:

From: https://raw.githubusercontent.com/actions/cache/main/dist/save/index.js

/**
 * Gets the value of an input.  The value is also trimmed.
 *
 * @param     name     name of the input to get
 * @param     options  optional. See InputOptions.
 * @returns   string
 */
function getInput(name, options) {
    const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
    if (options && options.required && !val) {
        throw new Error(`Input required and not supplied: ${name}`);
    }
    return val.trim();
}
exports.getInput = getInput;

Why would you rather use an input instead of an environment variable? The input would be static but an environment variable you can change whenever you want.

from cache.

dhadka avatar dhadka commented on June 3, 2024

@eyal0 👍 true. This is getting off topic 😄 but I prefer inputs because:

  1. This keeps all the inputs to the action defined in one spot instead of split across inputs and env vars, especially when it changes the functionality of the action.

  2. If you need or want to use an env var, you can always pass the env var to the input:

    with:
       always-save: ${{ env.ALWAYS_SAVE_CACHE }}
    
  3. Probably most importantly, inputs are well-defined for an action. You can provide a description, make inputs required or optional, and set default values in action.yml. If you had a typo, for example, an input would show a warning or error whereas an env var would silently ignore the typo. This also lets us auto-generate documentation for each action when using the workflow editor.

But for this issue since we can't use inputs in the post-if condition, this is a moot point.

from cache.

fulldecent avatar fulldecent commented on June 3, 2024

@pat-s please add a v2 tag to your project, matched to the latest v2* release.

This will allow drop-in compatibility with actions/cache@v2

from cache.

pat-s avatar pat-s commented on June 3, 2024

@fulldecent Thanks, done.

from cache.

steven-johnson avatar steven-johnson commented on June 3, 2024

+1, it seems like there is a pretty clear desire for this. It would be really great to get this as a configurable option in the 'official' actions/cache.

from cache.

pat-s avatar pat-s commented on June 3, 2024

I made https://github.com/mxxk/gh-actions-cache-always into a reusable action, which patches the original actions/cache to remove the post-if: 'success()' predicate.

It would be good to know what the difference/advantage over existing forks mentioned in this issue is?

from cache.

steven-johnson avatar steven-johnson commented on June 3, 2024

We have the same use case @trent-boyd for this: failing / flaky end-to-end tests are really hard to debug due to having to re-run build processes: by allowing to cache builds even on failure would speed up this considerably.

Same for Halide, where we may need to build and cache LLVM (!), which takes several hours on some builders

from cache.

DrJume avatar DrJume commented on June 3, 2024

I made https://github.com/mxxk/gh-actions-cache-always into a reusable action, which patches the original actions/cache to remove the post-if: 'success()' predicate.

It would be good to know what the difference/advantage over existing forks mentioned in this issue is?

Basically, it is the original actions/cache, but without the limitation of running only on success. It achieves this by literally deleting only one line in the action manifest file. If actions/cache releases new features, you only need to update the patched action, so that it forwards new input options (if some are added). With this patched version you still use the original logic and have official support.

Other alternatives may rely on unofficial/untrusted code, but may let you customize the caching logic even further.

from cache.

kotewar avatar kotewar commented on June 3, 2024

I was wondering if anybody tried continue-on-error input in their job.

Example workflow and run.

I was able to save cache despite of the induced error as the job exits silently and moves on to the next step, here, saves the cache.

202412956-1404ef1a-f856-4ccc-a338-6860c5ddb50c

from cache.

LorenzoBettini avatar LorenzoBettini commented on June 3, 2024

@kotewar but then is the whole job set as failed? Because of course that would be crucial...

from cache.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.