-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add option to reevaluate key during save #989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@vsvipul - I have updated to resolve the issues. Will you please re-run the workflows so I can see if there's anything else I that needs to be done? Is there anything else you need from me to merge this? Thanks. |
Does your process also require I build and commit the |
Seeing that other PRs have indeed been including the |
Thanks @mattjohnsonpint for contributing. Yes dist/ changes are indeed required for tests to pass.
|
In .NET, lock files are not normally used. The tooling does not create them unless specifically asked to do so. Thus by default, there's no complete list of which packages and versions are required to restore a project - which means no good source of information to create a cache key. One way to get that information is to create a lock file on the fly during the restore phase of a CI build. It's never committed to the repository, so it's never stale. It's not actually used to lock anything, but rather as the basis for the cache key. Since the cache-restore doesn't require an exact match on the key, it can easily restore the last cache that was created regardless of the full key. Then by creating the lock file and using it to compute the cache key, a save only occurs if the key has changed - because the lock file has changed in some way. One important use case is when floating versions are used. For example, I use floating versions in unit test projects for the libraries I develop, such that my library is always being tested against the latest version of any dependencies. Sure, I could instead switch to using lock files and commit them. But then I would have to also have a process to separately update the lock files any time one of my dependencies had an update. On larger projects, this can lead to a disproportionately large number of pull requests that just bump versions of dependencies for no other purpose than testing. Tooling like Dependabot can help automate that, but it still leads to a lot of maintenance overhead. I prefer just using a floating version in my test projects, and having a test workflow fail when a newer version of a dependency breaks something.
Perhaps. I would need two separate actions - one to restore the cache and a separate one to save it. I'd also need to have the ability to get the key that was restored (as an output), such that I could conditionally compare it to the hash of the generated lockfile to decide whether or not to save. Otherwise I'd end up saving every run, overwriting a cache that already exists with the exact same content. I'm not against the idea, but it's a lot simpler with just asking for the key to be re-evaluated. By doing so, the save phase already recognizes it as a cache hit and doesn't attempt to save again (despite it actually being a cache miss in the restore phase). |
If I am not wrong, you would still need to get the restored key as output and compare it - so as to decide whether to set
While it will be simpler in this particular case, there are many asks to add more such knobs to the action e.g. force save cache even if job fails, or save cache even if a cache hit occurred earlier etc etc. Individually each ask is a small one and good to do, but in sum total it becomes one too many knobs bringing down usability and actually making it more opaque and prone to misconfiguration. |
In the I do understand your reasonings with wanting the separate save/restore steps, and I welcome that instead of this if you are heading that direction anyway. Though as I mentioned, I will need the restored key as an output with that approach. Currently the only output is |
Hey @mattjohnsonpint 👋🏽 After considering multiple asks from our customers and this use case, we have published two new actions Also the Hope it solves the use case. :) More details about the new actions here - #1028 Closing this now, feel free to reopen if need be, thanks! |
Description
In
save.ts
there's a comment that describes that because inputs are reevaluated before the post action, the cache key is retrieved from state instead of input:cache/src/save.ts
Lines 29 to 30 in 5c79b3f
In some cases, it is actually quite desirable to have the input re-evaluated and a different cache key used for save than was used during restore.
This PR adds an option
reevaluate-key
which when settrue
will re-evaluate thekey
input in the post action instead of retrieving it from state.The default is
false
, retaining the existing behavior.Motivation and Context
I'm primarily a .NET developer, and I often use this cache action to cache NuGet packages for my build pipelines. When doing so, I have to create a cache key from some reasonable source of the packages in my repository. If I've opted in to using lock files, then I can use the
packages.lock.json
files that are created when the restore phase of my build executes. Indeed, this is what the examples file shows. But there are downsides to using lock files, and thus they are off by default in .NET.Without lock files, one can base the hash on project files (
.csproj
,.props
, etc.), but there are many reasons that project files might change - not just package changes. Also that technique doesn't take into account any floating versions that might be defined in the projects, such as<PackageReference Include="SomePackage" Version="2.*" />
. There could be a new version of the package without any change to the file, and thus the cache would never get updated.Since lock files are still the best source of information about which packages are installed, the easiest thing to do is create them during restore with
dotnet restore --use-lock-file
. The problem is that the cache restore has to run first.So, by having an option to re-evaluate the key, we can save a cache based on the hash of the generated lock files. If anything ever changes, a new cache gets created automatically and used on subsequent runs.
Without the option, there's no way to base the cache key on the generated lock files. Generating them before the cache restore would restore all packages without using the cache, invalidating the reason to have a cache in the first place.
I'm reasonably certain that this unblocks many other similar scenarios. It's not just for .NET developers. Pretty much any time you need to base the cache key on something that depends on the files being cached, you'll need to re-evaluate the key.
How Has This Been Tested?
Screenshots:
First Run (nothing in the cache):
Cache created by first run:
Second Run (has cache hit):
Workflow for above tests is as follows (using my fork):
Types of changes
Checklist: