Skip to content

Fix CacheV2 task to ensure cache directory exists for yarn packages #21034

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Tasks/CacheV2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Cache Task

This task improves build performance by caching files between pipeline runs.

## Description
The Cache task can save time by caching files from one run to another. The task helps you deliver faster builds by restoring previously cached files, so you don't have to regenerate or redownload them.

## Common usage scenarios

- **Package dependencies**: Cache your package manager's cache directory to avoid downloading package dependencies for every build.
- **Build outputs**: Cache compiled or processed files that don't change often to speed up builds.

## Example: Caching Yarn packages

```yaml
variables:
YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn

steps:
- task: Cache@2
inputs:
key: 'yarn | "$(Agent.OS)" | yarn.lock'
restoreKeys: |
yarn | "$(Agent.OS)"
path: $(YARN_CACHE_FOLDER)
displayName: Cache Yarn packages
```

## Notes
- The cache directory (specified in the `path` input) will be created automatically if it doesn't exist
- For Yarn, make sure to set the `YARN_CACHE_FOLDER` variable to point to the cache location
- For other package managers, set the appropriate environment variables according to the package manager's documentation

## Inputs

| Input | Description |
| ----- | ----------- |
| key | Key (unique identifier) for the cache. This should be a string that can be segmented using '|'. File paths can be absolute or relative to $(System.DefaultWorkingDirectory). |
| path | Path of the folder to cache. Can be fully-qualified or relative to $(System.DefaultWorkingDirectory). Wildcards are not supported. |
| cacheHitVar | Variable to set to 'true' when the cache is restored (i.e. a cache hit), otherwise set to 'false'. |
| restoreKeys | Additional restore key prefixes that are used if the primary key misses. This can be a newline-delimited list of key prefixes. |
22 changes: 22 additions & 0 deletions Tasks/CacheV2/_buildConfigs/Node20/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "vsts-tasks-cache",
"version": "2.0.0",
"description": "Azure Pipelines Cache Task",
"main": "restoreCache.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/Microsoft/azure-pipelines-tasks.git"
},
"author": "Microsoft Corporation",
"license": "MIT",
"bugs": {
"url": "https://github.com/Microsoft/azure-pipelines-tasks/issues"
},
"homepage": "https://github.com/Microsoft/azure-pipelines-tasks#readme",
"dependencies": {
"azure-pipelines-task-lib": "^4.16.0"
}
}
22 changes: 22 additions & 0 deletions Tasks/CacheV2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "vsts-tasks-cache",
"version": "2.0.0",
"description": "Azure Pipelines Cache Task",
"main": "restoreCache.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/Microsoft/azure-pipelines-tasks.git"
},
"author": "Microsoft Corporation",
"license": "MIT",
"bugs": {
"url": "https://github.com/Microsoft/azure-pipelines-tasks/issues"
},
"homepage": "https://github.com/Microsoft/azure-pipelines-tasks#readme",
"dependencies": {
"azure-pipelines-task-lib": "^4.16.0"
}
}
38 changes: 38 additions & 0 deletions Tasks/CacheV2/restoreCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const tl = require('azure-pipelines-task-lib/task');
const path = require('path');
const fs = require('fs');

/**
* Ensures that the directory exists, creating it if necessary
*/
function ensureDirectoryExists(directoryPath) {
if (!fs.existsSync(directoryPath)) {
console.log(`Directory does not exist, creating: ${directoryPath}`);
try {
fs.mkdirSync(directoryPath, { recursive: true });
console.log(`Successfully created directory: ${directoryPath}`);
} catch (err) {
console.warn(`Failed to create directory: ${directoryPath}. Error: ${err.message}`);
}
} else {
console.log(`Directory already exists: ${directoryPath}`);
}
}

async function run() {
try {
// Get the path from task input
const cachePath = tl.getPathInput('path', true);
console.log(`Ensuring cache directory exists: ${cachePath}`);

ensureDirectoryExists(cachePath);

console.log('Directory preparation completed successfully');
} catch (err) {
console.warn(`Error occurred while ensuring directory exists: ${err.message}`);
// We don't want to fail the task if directory creation fails,
// as this is just a preparation step for the actual cache task
}
}

run();
9 changes: 9 additions & 0 deletions Tasks/CacheV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@
],
"instanceNameFormat": "Cache",
"execution": {
"Node10": {
"target": "restoreCache.js"
},
"Node16": {
"target": "restoreCache.js"
},
"Node20": {
"target": "restoreCache.js"
},
"AgentPlugin": {
"target": "Agent.Plugins.PipelineCache.RestorePipelineCacheV0, Agent.Plugins"
}
Expand Down