diff --git a/Tasks/CopyFilesV2/copyfiles.ts b/Tasks/CopyFilesV2/copyfiles.ts index a310d23a76e2..46a733c0b5f4 100644 --- a/Tasks/CopyFilesV2/copyfiles.ts +++ b/Tasks/CopyFilesV2/copyfiles.ts @@ -2,6 +2,7 @@ import fs = require('fs'); import path = require('path'); import tl = require('azure-pipelines-task-lib/task'); import { RetryOptions, RetryHelper } from './retrylogichelper'; +import fastGlob from 'fast-glob'; /** * Shows timestamp change operation results @@ -105,12 +106,43 @@ async function main(): Promise { // normalize the source folder path. this is important for later in order to accurately // determine the relative path of each found file (substring using sourceFolder.length). sourceFolder = path.normalize(sourceFolder); - let allPaths: string[] = tl.find(sourceFolder, findOptions); - let sourceFolderPattern = sourceFolder.replace('[', '[[]'); // directories can have [] in them, and they have special meanings as a pattern, so escape them - let matchedPaths: string[] = tl.match(allPaths, contents, sourceFolderPattern); // default match options - let matchedFiles: string[] = filterOutDirectories(matchedPaths); + // Normalize patterns: if patterns were given as absolute rooted under sourceFolder, make them relative. + const globPatterns = contents.map(p => { + let pattern = p.trim(); + if (!pattern) return pattern; + // If absolute and starts with sourceFolder, strip the prefix + if (path.isAbsolute(pattern) && pattern.startsWith(sourceFolder)) { + pattern = pattern.substring(sourceFolder.length).replace(/^[/\\]/, ''); + } + // fast-glob handles forward slashes best + return pattern.split(path.sep).join('/'); + }).filter(p => !!p); + + // If no patterns, default to all files + if (globPatterns.length === 0) { + globPatterns.push('**/*'); + } + + tl.debug(`Using fast-glob with patterns: ${globPatterns.join(', ')}`); - // copy the files to the target folder + const fgOptions: fastGlob.Options = { + cwd: sourceFolder, + dot: true, + onlyFiles: true, + followSymbolicLinks: findOptions.followSymbolicLinks, + unique: true, + suppressErrors: true, + markDirectories: false, + }; + + let matchedFiles: string[] = []; + try { + const relFiles: string[] = await fastGlob(globPatterns, fgOptions); + matchedFiles = relFiles.map(r => path.join(sourceFolder, r)); + } catch (e) { + tl.setResult(tl.TaskResult.Failed, `fast-glob failed: ${e}`); + return; + } console.log(tl.loc('FoundNFiles', matchedFiles.length)); if (matchedFiles.length > 0) { diff --git a/Tasks/CopyFilesV2/package-lock.json b/Tasks/CopyFilesV2/package-lock.json index 170e05a1ca21..2bd836237d4c 100644 --- a/Tasks/CopyFilesV2/package-lock.json +++ b/Tasks/CopyFilesV2/package-lock.json @@ -12,12 +12,48 @@ "@types/mocha": "^5.2.7", "@types/node": "^20.11.0", "@types/uuid": "^8.3.0", - "azure-pipelines-task-lib": "^5.2.0" + "azure-pipelines-task-lib": "^5.2.0", + "fast-glob": "^3.3.2" }, "devDependencies": { "typescript": "5.1.6" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U=", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha1-W9Jir5Tp0lvR5xsF3u1Eh2oiLos=", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha1-6Vc36LtnRt3t9pxVaVNJTxlv5po=", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@types/mocha": { "version": "5.2.7", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@types/mocha/-/mocha-5.2.7.tgz", @@ -86,6 +122,18 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/braces/-/braces-3.0.3.tgz", + "integrity": "sha1-SQMy9AkZRSJy1VqEgK3AxEE1h4k=", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/concat-map/-/concat-map-0.0.1.tgz", @@ -108,6 +156,43 @@ } } }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha1-0G1YXOjbqQoWsFBcVDw8z7OuuBg=", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha1-1Q6rqAPIhGqIPBZJKCHrzSzaVfU=", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha1-RCZdPKwH4+p9wkdRY4BkN1SgUpI=", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -157,6 +242,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/minimatch/-/minimatch-3.1.2.tgz", @@ -225,6 +322,58 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ=", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha1-1m+hjzpHB2eJMgubGvMr2G2fogI=", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/mime-db/-/mime-db-1.52.0.tgz", @@ -296,6 +445,18 @@ "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/q/-/q-1.5.1.tgz", @@ -305,6 +466,26 @@ "teleport": ">=0.2.0" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha1-SSkii7xyTfrEPg77BYyve2z7YkM=", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/rechoir/-/rechoir-0.6.2.tgz", @@ -332,6 +513,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha1-D+E7lSLhRz9RtVjueW4I8R+bSJ8=", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4=", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/sanitize-filename": { "version": "1.6.3", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/sanitize-filename/-/sanitize-filename-1.6.3.tgz", @@ -376,6 +590,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", diff --git a/Tasks/CopyFilesV2/package.json b/Tasks/CopyFilesV2/package.json index ee4c85c02eeb..9b8dd977d631 100644 --- a/Tasks/CopyFilesV2/package.json +++ b/Tasks/CopyFilesV2/package.json @@ -17,7 +17,8 @@ "@types/node": "^20.11.0", "@types/mocha": "^5.2.7", "@types/uuid": "^8.3.0", - "azure-pipelines-task-lib": "^5.2.0" + "azure-pipelines-task-lib": "^5.2.0", + "fast-glob": "^3.3.2" }, "devDependencies": { "typescript": "5.1.6" diff --git a/Tasks/CopyFilesV2/task.json b/Tasks/CopyFilesV2/task.json index d1becaea458e..1ead7db60715 100644 --- a/Tasks/CopyFilesV2/task.json +++ b/Tasks/CopyFilesV2/task.json @@ -16,7 +16,7 @@ "author": "Microsoft Corporation", "version": { "Major": 2, - "Minor": 256, + "Minor": 257, "Patch": 0 }, "releaseNotes": "Match pattern consistency.",