From b8143bd5978237d1bcdad189e06eea786afc6d50 Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 07:58:55 +0200 Subject: [PATCH 01/10] add v7 with node 24 --- CHANGELOG.md | 5 + README.md | 56 +- package-lock.json | 14 +- package.json | 11 +- scripts/package.js | 2 +- tasks/ReplaceTokensV5/package-lock.json | 37 +- tasks/ReplaceTokensV5/package.json | 2 +- tasks/ReplaceTokensV6/package-lock.json | 41 +- tasks/ReplaceTokensV6/package.json | 2 +- tasks/ReplaceTokensV7/CHANGELOG.md | 4 + tasks/ReplaceTokensV7/README.md | 328 +++ tasks/ReplaceTokensV7/index.ts | 315 +++ tasks/ReplaceTokensV7/package-lock.json | 2144 +++++++++++++++++ tasks/ReplaceTokensV7/package.json | 24 + tasks/ReplaceTokensV7/task.json | 324 +++ tasks/ReplaceTokensV7/telemetry.ts | 118 + tasks/ReplaceTokensV7/tests/.gitignore | 1 + tasks/ReplaceTokensV7/tests/L0.ts | 1154 +++++++++ .../tests/L0_IfNoFilesFound.ts | 36 + tasks/ReplaceTokensV7/tests/L0_LogLevel.ts | 43 + tasks/ReplaceTokensV7/tests/L0_NoMock.ts | 44 + tasks/ReplaceTokensV7/tests/L0_Run.ts | 62 + .../tests/_data/empty.expected.txt | 2 + tasks/ReplaceTokensV7/tests/_data/empty.txt | 2 + .../tests/_data/file.expected.txt | 10 + ...ile.only_additional_variables.expected.txt | 10 + tasks/ReplaceTokensV7/tests/_data/file.txt | 10 + tasks/ReplaceTokensV7/tests/_data/vars.jsonc | 3 + tasks/ReplaceTokensV7/tests/_data/vars.xml | 3 + tasks/ReplaceTokensV7/tests/_data/vars.yaml | 3 + tasks/ReplaceTokensV7/tests/_data/vars.yml | 3 + tasks/ReplaceTokensV7/tsconfig.json | 8 + vss-extension.json | 2 +- 33 files changed, 4738 insertions(+), 85 deletions(-) create mode 100644 tasks/ReplaceTokensV7/CHANGELOG.md create mode 100644 tasks/ReplaceTokensV7/README.md create mode 100644 tasks/ReplaceTokensV7/index.ts create mode 100644 tasks/ReplaceTokensV7/package-lock.json create mode 100644 tasks/ReplaceTokensV7/package.json create mode 100644 tasks/ReplaceTokensV7/task.json create mode 100644 tasks/ReplaceTokensV7/telemetry.ts create mode 100644 tasks/ReplaceTokensV7/tests/.gitignore create mode 100644 tasks/ReplaceTokensV7/tests/L0.ts create mode 100644 tasks/ReplaceTokensV7/tests/L0_IfNoFilesFound.ts create mode 100644 tasks/ReplaceTokensV7/tests/L0_LogLevel.ts create mode 100644 tasks/ReplaceTokensV7/tests/L0_NoMock.ts create mode 100644 tasks/ReplaceTokensV7/tests/L0_Run.ts create mode 100644 tasks/ReplaceTokensV7/tests/_data/empty.expected.txt create mode 100644 tasks/ReplaceTokensV7/tests/_data/empty.txt create mode 100644 tasks/ReplaceTokensV7/tests/_data/file.expected.txt create mode 100644 tasks/ReplaceTokensV7/tests/_data/file.only_additional_variables.expected.txt create mode 100644 tasks/ReplaceTokensV7/tests/_data/file.txt create mode 100644 tasks/ReplaceTokensV7/tests/_data/vars.jsonc create mode 100644 tasks/ReplaceTokensV7/tests/_data/vars.xml create mode 100644 tasks/ReplaceTokensV7/tests/_data/vars.yaml create mode 100644 tasks/ReplaceTokensV7/tests/_data/vars.yml create mode 100644 tasks/ReplaceTokensV7/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f949e..bb8969d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## 6.0.0 +Task 7.0.0 +- **Breaking changes**: Remove Node 16 support. +- Add Node 24 support ([#90](https://github.com/qetza/replacetokens-task/issues/90)). + ## 5.3.0 Task 6.3.1 - Fix "name not supplied" on empty token ([#88](https://github.com/qetza/replacetokens-task/issues/88)). diff --git a/README.md b/README.md index 01892cb..21dbe1d 100644 --- a/README.md +++ b/README.md @@ -6,57 +6,13 @@ This Azure Pipelines task replaces tokens in text based files with variable valu ## What's new Please refer to the [release page](https://github.com/qetza/replacetokens-task/releases/latest) for the latest release notes. -## Breaking changes in v6 -The task was completely rewritten to use the npm package [@qetza/replacetokens](https://www.npmjs.com/package/@qetza/replacetokens) and be more similar with the new [ReplaceTokens GitHub Actions](https://github.com/marketplace/actions/replacetokens): - - support only node 16 (mininum agent version 2.206.1) - - renamed input _targetFiles_ to _sources_ - - migrated to [fast-glob](https://github.com/mrmlnc/fast-glob) for glob patterns causing syntax changes (must use forward slash (`/`) for directory separator whatever the OS) - - removed support for comma-separated paths in _targetFiles_ - - renamed _encoding_ value `win1252` to `windows1252` - - renamed _escapeType_ to _escape_ - - renamed _escapeType_ value `none` to `off` - - merged inputs _variableFiles_ and _inlineVariables_ in _additionalVariables_ - - renamed input _variableSeparator_ to _separator_ - - renamed input _enableRecursion_ to _recursive_ - - renamed input _rootDirectory_ to _root_ - - renamed _tokenPattern_ value `rm` to `doubleunderscores` - - renamed input _writeBOM_ to _addBOM_ - - changed _writeBOM_ default value to `false` - - renamed input _verbosity_ to _logLevel_ - - renamed _verbosity_ value `detailed` to `debug` - - renamed _verbosity_ value `normal` to `info` - - removed _verbosity_ value `off` (see new supported values for replacement) - - renamed input _actionOnMissing_ to _missingVarLog_ - - renamed _actionOnMissing_ value `continue` to `off` - - renamed _actionOnMissing_ value `fail` to `error` - - replaced _keepToken_ with _missingVarAction_ with value `keep` - - renamed input _actionOnNoFiles_ to _ifNoFilesFound_ - - renamed _actionOnNoFiles_ value `continue` to `ignore` - - renamed _actionOnNoFiles_ value `fail` to `error` - - renamed input _enableTransforms_ to _transforms_ - - renamed transform `noescape` to `raw` - - renamed input _transformPrefix_ to _transformsPrefix_ - - renamed input _transformSuffix_ to _transformsSuffix_ - - removed input _useLegacyPattern_ - - removed input _useLegacyEmptyFeature_ - - replaced input _useDefaultValue_ with _missingVarAction_ with value `replace` - - removed input _emptyValue_ - - renamed input _defaultValue_ to _missingVarDefault_ - - removed input _enableTelemetry_ to _telemetryOptout_ and inverse meaning - - renamed output _tokenReplacedCount_ to _replaced_ - - renamed output _tokenFoundCount_ to _tokens_ - - renamed output _fileProcessedCount_ to _files_ - - renamed output _transformExecutedCount_ to _transforms_ - - renamed output _defaultValueCount_ to _defaults_ - -You can find some documentation to help migrate here: [Migrate from v5 to v6](https://github.com/qetza/replacetokens-task/discussions/34) - -If you are migrating from **v3 to v6** make sure to read this documentation first: [Migrate from v3 to v5](https://github.com/qetza/replacetokens-task/discussions/33) +## Breaking changes in v7 +Remove Node 16 support. ## Usage ### Inputs ```yaml -- task: qetza.replacetokens.replacetokens-task.replacetokens@6 +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 inputs: # A multiline list of files to replace tokens in. # Each line supports: @@ -297,7 +253,7 @@ If you are migrating from **v3 to v6** make sure to read this documentation firs ## Examples ### Multiple target files and opt out of sending telemetry data ```yaml -- task: qetza.replacetokens.replacetokens-task.replacetokens@6 +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 inputs: telemetryOptout: true sources: | @@ -307,7 +263,7 @@ If you are migrating from **v3 to v6** make sure to read this documentation firs ### Additional variables ```yaml -- task: qetza.replacetokens.replacetokens-task.replacetokens@6 +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 inputs: sources: '**/*.json' additionalVariables: | @@ -320,7 +276,7 @@ If you are migrating from **v3 to v6** make sure to read this documentation firs ### Access outputs ```yaml steps: -- task: qetza.replacetokens.replacetokens-task.replacetokens@6 +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 name: replaceTokens inputs: sources: '**/*.json' diff --git a/package-lock.json b/package-lock.json index f2f6e9c..edc525b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "semver": "^7.6.0", "shelljs": "^0.8.5", "tfx-cli": "^0.21.0", - "typescript": "^5.1.6" + "typescript": "5.7.2" } }, "node_modules/@babel/code-frame": { @@ -3124,9 +3124,9 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5687,9 +5687,9 @@ } }, "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true }, "unbox-primitive": { diff --git a/package.json b/package.json index 615932d..402fc8a 100644 --- a/package.json +++ b/package.json @@ -22,23 +22,26 @@ "url": "git+https://github.com/qetza/replacetokens-task.git" }, "scripts": { - "build": "npm run build:v3 && npm run build:v4 && npm run build:v5 && npm run build:v6", + "build": "npm run build:v3 && npm run build:v4 && npm run build:v5 && npm run build:v6 && npm run build:v7", "build:v3": "tsc --project tasks/ReplaceTokensV3/tsconfig.json", "build:v4": "tsc --project tasks/ReplaceTokensV4/tsconfig.json", "build:v5": "tsc --project tasks/ReplaceTokensV5/tsconfig.json", "build:v6": "tsc --project tasks/ReplaceTokensV6/tsconfig.json", - "test": "npm run build && mocha tasks/**/tests/L0.js", + "build:v7": "tsc --project tasks/ReplaceTokensV7/tsconfig.json", + "test": "npm run test:v3 && npm run test:v4 && npm run test:v5 && npm run test:v6 && npm run test:v7", "test:v3": "npm run build:v3 && mocha tasks/ReplaceTokensV3/dist/tests/L0.js", "test:v4": "npm run build:v4 && mocha tasks/ReplaceTokensV4/dist/tests/L0.js", "test:v5": "npm run build:v5 && mocha tasks/ReplaceTokensV5/dist/tests/L0.js", "test:v6": "npm run build:v6 && mocha tasks/ReplaceTokensV6/dist/tests/L0.js", + "test:v7": "npm run build:v7 && mocha tasks/ReplaceTokensV7/dist/tests/L0.js", "package": "node scripts/package.js", "package:public": "node scripts/package.js --public", - "format": "npm run format:v3 && npm run format:v4 && npm run format:v5 && npm run format:v6", + "format": "npm run format:v3 && npm run format:v4 && npm run format:v5 && npm run format:v6 && npm run format:v7", "format:v3": "prettier --write tasks/ReplaceTokensV3/**/*.ts", "format:v4": "prettier --write tasks/ReplaceTokensV4/**/*.ts", "format:v5": "prettier --write tasks/ReplaceTokensV5/**/*.ts", "format:v6": "prettier --write tasks/ReplaceTokensV6/**/*.ts", + "format:v7": "prettier --write tasks/ReplaceTokensV7/**/*.ts", "format:check": "prettier --check **/*.ts" }, "devDependencies": { @@ -49,6 +52,6 @@ "semver": "^7.6.0", "shelljs": "^0.8.5", "tfx-cli": "^0.21.0", - "typescript": "^5.1.6" + "typescript": "5.7.2" } } diff --git a/scripts/package.js b/scripts/package.js index ae301bb..44b5d73 100644 --- a/scripts/package.js +++ b/scripts/package.js @@ -92,7 +92,7 @@ var generateVersion = function (major) { } // globals -var versions = ['3','4','5','6']; +var versions = ['3','4','5','6', '7']; // ensure clean output console.log('clean:'); diff --git a/tasks/ReplaceTokensV5/package-lock.json b/tasks/ReplaceTokensV5/package-lock.json index 29eb00c..cfc5810 100644 --- a/tasks/ReplaceTokensV5/package-lock.json +++ b/tasks/ReplaceTokensV5/package-lock.json @@ -16,7 +16,7 @@ "@types/chai": "^4.3.12", "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.6", - "@types/node": "^20.3.1", + "@types/node": "24.10.0", "chai": "^4.4.1" } }, @@ -39,11 +39,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/adm-zip": { "version": "0.5.10", @@ -525,6 +528,13 @@ "node": ">=4" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -565,10 +575,13 @@ "dev": true }, "@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", - "dev": true + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "dev": true, + "requires": { + "undici-types": "~7.16.0" + } }, "adm-zip": { "version": "0.5.10", @@ -924,6 +937,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", diff --git a/tasks/ReplaceTokensV5/package.json b/tasks/ReplaceTokensV5/package.json index 154f5c2..05a3ae5 100644 --- a/tasks/ReplaceTokensV5/package.json +++ b/tasks/ReplaceTokensV5/package.json @@ -11,7 +11,7 @@ "@types/chai": "^4.3.12", "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.6", - "@types/node": "^20.3.1", + "@types/node": "24.10.0", "chai": "^4.4.1" } } diff --git a/tasks/ReplaceTokensV6/package-lock.json b/tasks/ReplaceTokensV6/package-lock.json index 52143d6..220c2a6 100644 --- a/tasks/ReplaceTokensV6/package-lock.json +++ b/tasks/ReplaceTokensV6/package-lock.json @@ -19,7 +19,7 @@ "@types/chai": "^4.3.12", "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.6", - "@types/node": "^20.3.1", + "@types/node": "24.10.0", "chai": "^4.4.1" } }, @@ -34,7 +34,7 @@ "semver": "^7.6.0", "shelljs": "^0.8.5", "tfx-cli": "^0.21.0", - "typescript": "^5.1.6" + "typescript": "5.7.2" } }, "node_modules/@nodelib/fs.scandir": { @@ -169,11 +169,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/adm-zip": { "version": "0.5.10", @@ -993,6 +996,13 @@ "node": ">=4" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -1154,10 +1164,13 @@ "dev": true }, "@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", - "dev": true + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "dev": true, + "requires": { + "undici-types": "~7.16.0" + } }, "adm-zip": { "version": "0.5.10", @@ -1646,7 +1659,7 @@ "semver": "^7.6.0", "shelljs": "^0.8.5", "tfx-cli": "^0.21.0", - "typescript": "^5.1.6" + "typescript": "5.7.2" } }, "require-directory": { @@ -1750,6 +1763,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", diff --git a/tasks/ReplaceTokensV6/package.json b/tasks/ReplaceTokensV6/package.json index b4f1289..cebf943 100644 --- a/tasks/ReplaceTokensV6/package.json +++ b/tasks/ReplaceTokensV6/package.json @@ -18,7 +18,7 @@ "@types/chai": "^4.3.12", "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.6", - "@types/node": "^20.3.1", + "@types/node": "24.10.0", "chai": "^4.4.1" } } diff --git a/tasks/ReplaceTokensV7/CHANGELOG.md b/tasks/ReplaceTokensV7/CHANGELOG.md new file mode 100644 index 0000000..2029746 --- /dev/null +++ b/tasks/ReplaceTokensV7/CHANGELOG.md @@ -0,0 +1,4 @@ +# Changelog +## 7.0.0 +- **Breaking changes**: Remove Node 16 support. +- Add Node 24 support. \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/README.md b/tasks/ReplaceTokensV7/README.md new file mode 100644 index 0000000..15ba93c --- /dev/null +++ b/tasks/ReplaceTokensV7/README.md @@ -0,0 +1,328 @@ +# ReplaceTokens v7 +[![mit license](https://img.shields.io/badge/license-MIT-green)](https://github.com/qetza/replacetokens-task/blob/main/LICENSE) [![donate](https://img.shields.io/badge/donate-paypal-blue)](https://www.paypal.com/donate/?hosted_button_id=CCEAVYA8DUFD8) + +This Azure Pipelines task replaces tokens in text based files with variable values. + +## What's new +Please refer to the [release page](https://github.com/qetza/replacetokens-task/releases/latest) for the latest release notes. + +## Breaking changes in v7 +Remove Node 16 support. + +## Usage +### Inputs +```yaml +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 + inputs: + # A multiline list of files to replace tokens in. + # Each line supports: + # - multiple glob patterns separated by a semi-colon ';' using fast-glob syntax + # (you must always use forward slash '/' as a directory separator, on win32 will + # automatically replace backslash with forward slash) + # - outputing the result in another file adding the output path after an arrow '=>' + # (if the output path is a relative path, it will be relative to the input file) + # - wildcard replacement in the output file name using an asterix '*' in the input + # and output file names + # + # Example: '**/*.json; !**/local/* => out/*.json' will match all files ending with + # '.json' in all directories and sub directories except in `local` directory and the + # output will be in a sub directory `out` relative to the input file keeping the file + # name. + # + # Required. + sources: '' + + # Add BOM when writing files. + # + # Optional. Default: false + addBOM: '' + + # A YAML formatted string containing additional variable values (keys are case-insensitive). + # Value can be: + # - an object: properties will be parsed as key/value pairs + # - a string starting with '@': value is parsed as multiple glob patterns separated + # by a semi-colon ';' using fast-glob syntax to JSON or YAML files + # - a string starting with '$': value is parsed as an environment variable name + # containing JSON encoded key/value pairs + # - an array: each item must be an object or a string and will be parsed as + # specified previously + # + # Multiple entries are merge into a single list of key/value pairs. + # + # Example: + # - '@**/*.json;**/*.yml;!**/local/*' + # - '$COMPUTER_VARS' + # - var1: '${{ parameters.var1 }}' + # + # will add all variables from: + # - '.json' and '.yml' files except under 'local' directory, + # - the environment variable 'COMPUTER_VARS' + # - the inline variable 'var1' + # + # Optional. + additionalVariables: '' + + # Enable case-insensitive file path matching in glob patterns for sources and additionalVariables. + # + # Optional. Default: true + caseInsensitivePaths: '' + + # The characters to escape when using 'custom' escape. + # + # Optional. + charsToEscape: '' + + # The encoding to read and write all files. + # + # Accepted values: + # - auto: detect encoding using js-chardet + # - any value supported by iconv-lite + # + # Optional. Default: auto + encoding: '' + + # The character escape type to apply on each value. + # + # Accepted values: + # - auto: automatically apply JSON or XML escape based on file extension + # - off: don't escape values + # - json: JSON escape + # - xml: XML escape + # - custom: apply custom escape using escape-char and chars-to-escape + # + # Optional. Default: auto + escape: '' + + # The escape character to use when using 'custom' escape. + # + # Optional. + escapeChar: '' + + # The behavior if no files are found. + # + # Accepted values: + # - ignore: do not output any message, the action do not fail + # - warn: output a warning but do not fail the action + # - error: fail the action with an error message + # + # Optional. Default: ignore + ifNoFilesFound: '' + + # Include directories and files starting with a dot ('.') in glob matching results for sources and additionalVariables. + # + # Optional. Default: true + includeDotPaths: '' + + # The log level. + # + # Accepted values: + # - debug + # - info + # - warn + # - error + # + # Debug messages will always be sent to the internal debug system. + # Error messages will always fail the action. + # + # Optional. Default: info + logLevel: '' + + # The behavior if variable is not found. + # + # Accepted values: + # - none: replace the token with an empty string and log a message + # - keep: leave the token and log a message + # - replace: replace with the value from missing-var-default and do not + # log a message + # + # Optional. Default: none + missingVarAction: '' + + # The default value to use when a key is not found. + # + # Optional. Default: empty string + missingVarDefault: '' + + # The level to log key not found messages. + # + # Accepted values: + # - off + # - info + # - warn + # - error + # + # Optional. Default: warn + missingVarLog: '' + + # Enable token replacements in values recusively. + # + # Example: '#{message}#' with variables '{"message":"hello #{name}#!","name":"world"}' + # will result in 'hello world!' + # + # Optional. Default: false + recursive: '' + + # The root path to use when reading files with a relative path. + # + # Optional. Default: $(System.DefaultWorkingDirectory) + root: '' + + # The separtor to use when flattening keys in variables. + # + # Example: '{ "key": { "array": ["a1", "a2"], "sub": "s1" } }' will be flatten as + # '{ "key.array.0": "a1", "key.array.1": "a2", "key.sub": "s1" }' + # + # Optional. Default: . + separator: '' + + # Opt out of the anonymous telemetry feature. + # You can also set the REPLACETOKENS_TELEMETRY_OPTOUT environment variable to '1' or + # 'true'. + # + # Optional. Default: false + telemetryOptout: '' + + # The token pattern to use. + # Use 'custom' to provide your own prefix and suffix. + # + # Accepted values: + # - default: #{ ... }# + # - azpipelines: $( ... ) + # - custom: token-prefix ... token-suffix + # - doublebraces: {{ ... }} + # - doubleunderscores: __ ... __ + # - githubactions: ${{ ... }} + # - octopus: #{ ... } + # + # Optional. Default: default + tokenPattern: '' + + # The token prefix when using 'custom' token pattern. + # + # Optional. + tokenPrefix: '' + + # The token suffix when using 'custom' token pattern. + # + # Optional. + tokenSuffix: '' + + # Enable transforms on values. + # The syntax to apply transform on a value is '#{([,])}#'. + # + # Supported transforms: + # - base64(name): base64 encode the value + # - indent(name[, size, firstline]): indent lines in the value where size is the + # indent size (default is '2') and firstline specifies if the first line must be + # indented also (default is 'false') + # - lower(name): lowercase the value + # - raw(name): raw value (disable escaping) + # - upper(name): uppercase the value + # + # Example: 'key=#{upper(KEY1)}#' with '{ "KEY1": "value1" }' will result in + # 'key=VALUE1' + # + # Optional. Default: false + transforms: '' + + # The tranforms prefix when using transforms. + # + # Optional. Default: ( + transformsPrefix: '' + + # The tranforms prefix when using transforms. + # + # Optional. Default: ) + transformsSuffix: '' + + # Use only variables declared in 'additionalVariables'. + # + # Optional: Default: false + useAdditionalVariablesOnly: '' +``` + +### Output +| Name | Description | Example | +| - | - | - | +| defaults | The number of tokens replaced with the default value if one was specified. | `1` | +| files | The number of source files parsed. | `2` | +| replaced | The number of values replaced by a value different than the default value. | `7` | +| tokens | The number of tokens found in all files. | `8` | +| transforms | The number of transforms applied. | `2` | + +## Examples +### Multiple target files +```yaml +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 + inputs: + sources: | + **/*.json;!**/*.dev.json;!**/vars.json => _tmp/*.json + **/*.yml +``` + +### Additional variables +```yaml +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 + inputs: + sources: '**/*.json' + additionalVariables: | + - '@**/vars.(json|yml|yaml)' # read from files + - '$ENV_VARS', # read from env + - var1: '${{ parameters.var1 }}' # inline key/value pairs + var2: '${{ parameters.var2 }}' +``` + +### Access outputs +```yaml +steps: +- task: qetza.replacetokens.replacetokens-task.replacetokens@7 + name: replaceTokens + inputs: + sources: '**/*.json' +- script: | + echo "defaults : $(replaceTokens.defaults)" + echo "files : $(replaceTokens.files)" + echo "replaced : $(replaceTokens.replaced)" + echo "tokens : $(replaceTokens.tokens)" + echo "transforms: $(replaceTokens.transforms)" +``` + +## Data/Telemetry +The Replace Tokens task for Azure Pipelines collects **anonymous** usage data and sends them by default to its author to help improve the product. If you don't wish to send usage data, you can change your telemetry settings through the _telemetryOptout_ parameter or by setting the `REPLACETOKENS_TELEMETRY_OPTOUT` environment variable to `1` or `true`. + +The following **anonymous** data is send: +- the **hash** of your collection id +- the **hash** of your project id and pipeline definition id +- the hosting (`server` or `cloud`) +- the agent OS (`Windows`, `macOS` or `Linux`) +- the inputs values for + - _addBOM_ + - _caseInsensitivePaths_ + - _charsToEscape_ + - _encoding_ + - _escape_ + - _escapeChar_ + - _ifNoFilesFound_ + - _includeDotPaths_ + - _logLevel_ + - _missingVarAction_ + - _missingVarDefault_ + - _missingVarLog_ + - _recursive_ + - _separator_ + - _tokenPattern_ + - _tokenPrefix_ + - _tokenSuffix_ + - _transforms_ + - _transformsPrefix_ + - _transformsSuffix_ + - _useAdditionalVariablesOnly_ +- the **number of** _sources_ entries +- the **number of** _additionalVariables_ entries referencing file +- the **number of** _additionalVariables_ entries referencing environment variables +- the **number of** _additionalVariables_ inline entries +- the task result (`succeed` or `failed`) +- the task execution duration +- the outputs (defaults, files, replaced, tokens and transforms) + +You can see the JSON serialized telemetry data sent in debug logs. \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/index.ts b/tasks/ReplaceTokensV7/index.ts new file mode 100644 index 0000000..7b3f23c --- /dev/null +++ b/tasks/ReplaceTokensV7/index.ts @@ -0,0 +1,315 @@ +import * as tl from 'azure-pipelines-task-lib'; +import * as yaml from 'js-yaml'; +import * as rt from '@qetza/replacetokens'; +import * as telemetry from './telemetry'; +import { SpanStatusCode } from '@opentelemetry/api'; +import * as os from 'os'; + +async function run() { + const _debug = console.debug; + const _info = console.info; + const _warn = console.warn; + const _error = console.error; + const _group = console.group; + const _groupEnd = console.groupEnd; + + if ( + !tl.getBoolInput('telemetryOptout') && + !['true', '1'].includes(process.env['REPLACETOKENS_TELEMETRY_OPTOUT'] || process.env['REPLACETOKENS_DISABLE_TELEMETRY']) + ) { + telemetry.enableTelemetry(tl.getHttpProxyConfiguration()?.proxyUrl); + } + + const serverType = tl.getVariable('System.ServerType'); + const telemetryEvent = telemetry.startSpan( + 'run', + tl.getVariable('system.collectionid'), + `${tl.getVariable('system.teamprojectid')}${tl.getVariable('system.definitionid')}`, + !serverType || serverType.toLowerCase() !== 'hosted' ? 'server' : 'cloud', + (() => { + const os = tl.getVariable('Agent.OS'); + switch (os) { + case 'Windows_NT': + return 'Windows'; + case 'Darwin': + return 'macOS'; + case 'Linux': + return 'Linux'; + default: + return os || 'unknown'; + } + })() + ); + + try { + // read and validate inputs + const sources = getSources(); + const options: rt.Options = { + addBOM: tl.getBoolInput('writeBOM'), + encoding: tl.getInput('encoding') || rt.Encodings.Auto, + escape: { + chars: tl.getInput('charsToEscape'), + escapeChar: tl.getInput('escapeChar'), + type: getChoiceInput('escapeType', [rt.Escapes.Auto, rt.Escapes.Custom, rt.Escapes.Json, rt.Escapes.Off, rt.Escapes.Xml], 'escape') || rt.Escapes.Auto + }, + missing: { + action: + getChoiceInput('missingVarAction', [rt.MissingVariables.Action.Keep, rt.MissingVariables.Action.None, rt.MissingVariables.Action.Replace]) || + rt.MissingVariables.Action.None, + default: tl.getInput('defaultValue') || '', + log: + getChoiceInput( + 'actionOnMissing', + [rt.MissingVariables.Log.Error, rt.MissingVariables.Log.Off, rt.MissingVariables.Log.Info, rt.MissingVariables.Log.Warn], + 'missingVarLog' + ) || rt.MissingVariables.Log.Warn + }, + recursive: tl.getBoolInput('enableRecursion'), + root: tl.getPathInput('rootDirectory', false, true), + sources: { + caseInsensitive: tl.getBoolInput('caseInsensitivePaths'), + dot: tl.getBoolInput('includeDotPaths') + }, + token: { + pattern: + getChoiceInput('tokenPattern', [ + rt.TokenPatterns.AzurePipelines, + rt.TokenPatterns.Custom, + rt.TokenPatterns.Default, + rt.TokenPatterns.DoubleBraces, + rt.TokenPatterns.DoubleUnderscores, + rt.TokenPatterns.GithubActions, + rt.TokenPatterns.Octopus + ]) || rt.TokenPatterns.Default, + prefix: tl.getInput('tokenPrefix'), + suffix: tl.getInput('tokenSuffix') + }, + transforms: { + enabled: tl.getBoolInput('enableTransforms'), + prefix: tl.getInput('transformPrefix') || rt.Defaults.TransformPrefix, + suffix: tl.getInput('transformSuffix') || rt.Defaults.TransformSuffix + } + }; + + const ifNoFilesFound = tl.getInput('actionOnNoFiles') || 'ignore'; + const logLevelStr = tl.getInput('verbosity') || 'info'; + + // override console logs + const logLevel = parseLogLevel(logLevelStr); + console.debug = function (...args: any[]) { + tl.debug(args.join(' ')); // always debug to core + + if (logLevel === LogLevel.Debug) console.log(args.join(' ')); // log as info to be independant of core switch + }; + console.info = function (...args: any[]) { + if (logLevel < LogLevel.Warn) console.log(args.join(' ')); + }; + console.warn = function (...args: any[]) { + if (logLevel < LogLevel.Error) tl.warning(args.join(' ')); + }; + console.error = function (...args: any[]) { + tl.setResult(tl.TaskResult.Failed, args.join(' ')); // always set failure on error + }; + console.group = function (...args: any[]) { + console.info('##[group] ' + args.join(' ')); + }; + console.groupEnd = function () { + console.info('##[endgroup]'); + }; + + // load additional variables + const separator = tl.getInput('variableSeparator') || rt.Defaults.Separator; + const additionalVariables = await getAdditionalVariables(options.root, separator, options.sources.caseInsensitive, options.sources.dot); + const useAdditionalVariablesOnly = tl.getBoolInput('useAdditionalVariablesOnly'); + + // set telemetry attributes + telemetryEvent.setAttributes({ + sources: sources.length, + 'add-bom': options.addBOM, + 'case-insenstive-paths': options.sources.caseInsensitive, + 'chars-to-escape': options.escape.chars, + encoding: options.encoding, + escape: options.escape.type, + 'escape-char': options.escape.escapeChar, + 'if-no-files-found': ifNoFilesFound, + 'include-dot-paths': options.sources.dot, + 'log-level': logLevelStr, + 'missing-var-action': options.missing.action, + 'missing-var-default': options.missing.default, + 'missing-var-log': options.missing.log, + recursive: options.recursive, + separator: separator, + 'token-pattern': options.token.pattern, + 'token-prefix': options.token.prefix, + 'token-suffix': options.token.suffix, + transforms: options.transforms.enabled, + 'transforms-prefix': options.transforms.prefix, + 'transforms-suffix': options.transforms.suffix, + 'use-additional-variables-only': useAdditionalVariablesOnly, + 'variable-files': variableFilesCount, + 'variable-envs': variablesEnvCount, + 'inline-variables': inlineVariablesCount + }); + + // replace tokens + const result = await rt.replaceTokens( + sources, + (name: string) => (name in additionalVariables || useAdditionalVariablesOnly ? additionalVariables[name] : name ? tl.getVariable(name) : undefined), + options + ); + + if (result.files === 0) { + (msg => { + switch (ifNoFilesFound) { + case 'warn': + console.warn(msg); + break; + case 'error': + console.error(msg); + break; + default: + console.info(msg); + break; + } + })('No files were found with provided sources.'); + } + + // set outputs + tl.setVariable('defaults', `${result.defaults}`); + tl.setVariable('files', `${result.files}`); + tl.setVariable('replaced', `${result.replaced}`); + tl.setVariable('tokens', `${result.tokens}`); + tl.setVariable('transforms', `${result.transforms}`); + + telemetryEvent.setAttributes({ + 'output-defaults': result.defaults, + 'output-files': result.files, + 'output-replaced': result.replaced, + 'output-tokens': result.tokens, + 'output-transforms': result.transforms + }); + + telemetryEvent.setStatus({ code: SpanStatusCode.OK }); + } catch (error) { + telemetryEvent.setStatus({ code: SpanStatusCode.ERROR }); + + tl.setResult(tl.TaskResult.Failed, error); + } finally { + telemetryEvent.end(); + + // restore console logs + console.debug = _debug; + console.info = _info; + console.warn = _warn; + console.error = _error; + console.group = _group; + console.groupEnd = _groupEnd; + } +} + +var getSources = function (): string[] { + const sources = tl.getDelimitedInput('targetFiles', /\r?\n/); + if (sources.length === 0) throw new Error('Input required: sources'); + + // make sources compatible with fast-glob on win32 + if (os.platform() === 'win32') { + for (var i in sources) { + sources[i] = sources[i].replace(/\\/g, '/').replace(/\/\/+/g, '/'); + } + } + + return sources; +}; + +var getChoiceInput = function (name: string, choices: string[], alias?: string): string { + alias = alias || name; + const input = tl.getInput(name)?.trim(); + if (!input || choices.includes(input)) return input; + + throw new Error(`Unsupported value for input: ${alias}. Support input list: '${choices.join(' | ')}'`); +}; + +var variableFilesCount = 0; +var variablesEnvCount = 0; +var inlineVariablesCount = 0; +var getAdditionalVariables = async function (root?: string, separator?: string, caseInsensitive?: boolean, dot?: boolean): Promise<{ [key: string]: string }> { + const input = tl.getInput('additionalVariables') || ''; + if (!input) return {}; + + return await rt.loadVariables( + (() => { + switch (input[0]) { + case '@': // single string referencing a file + ++variableFilesCount; + return [input]; + + case '$': // single string referencing environment variable + ++variablesEnvCount; + return [input]; + + default: // yaml format + return getAdditionalVariablesFromYaml(input); + } + })(), + { caseInsensitive: caseInsensitive, dot: dot, normalizeWin32: true, root: root, separator: separator } + ); +}; + +var getAdditionalVariablesFromYaml = function (input: string): string[] { + const variables = yaml.load(input); + const load = (v: any): string => { + if (typeof v === 'string') { + switch (v[0]) { + case '@': + ++variableFilesCount; + return v; + + case '$': + ++variablesEnvCount; + return v; + + default: + throw new Error("Unsupported value for: additionalVariables. String values must starts with '@' (file path) or '$' (environment variable)"); + } + } + + inlineVariablesCount += Object.keys(v).length; + + return JSON.stringify(v); + }; + + if (Array.isArray(variables)) { + // merge items + const vars: string[] = []; + for (let v of variables) { + vars.push(load(v)); + } + + return vars; + } + + return [load(variables)]; +}; + +enum LogLevel { + Debug, + Info, + Warn, + Error +} +var parseLogLevel = function (level: string): LogLevel { + switch (level) { + case 'debug': + return LogLevel.Debug; + case 'info': + return LogLevel.Info; + case 'warn': + return LogLevel.Warn; + case 'error': + return LogLevel.Error; + default: + return LogLevel.Info; + } +}; + +run(); diff --git a/tasks/ReplaceTokensV7/package-lock.json b/tasks/ReplaceTokensV7/package-lock.json new file mode 100644 index 0000000..b8d0bac --- /dev/null +++ b/tasks/ReplaceTokensV7/package-lock.json @@ -0,0 +1,2144 @@ +{ + "name": "replacetokens-v7", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "replacetokens-v7", + "dependencies": { + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/sdk-trace-base": "^1.22.0", + "@opentelemetry/semantic-conventions": "^1.22.0", + "@qetza/replacetokens": "^1.9.0", + "axios": "1.14.0", + "azure-pipelines-task-lib": "5.2.8", + "js-yaml": "4.1.1", + "replacetokens-task": "file:../.." + }, + "devDependencies": { + "@types/chai": "^4.3.12", + "@types/js-yaml": "^4.0.9", + "@types/mocha": "^10.0.6", + "@types/node": "24.10.0", + "chai": "^4.4.1" + } + }, + "../..": { + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^10.17.0", + "@vercel/ncc": "^0.38.1", + "mocha": "^10.3.0", + "prettier": "^3.2.5", + "semver": "^7.6.0", + "shelljs": "^0.8.5", + "tfx-cli": "^0.21.0", + "typescript": "5.7.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "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://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@qetza/replacetokens": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@qetza/replacetokens/-/replacetokens-1.9.0.tgz", + "integrity": "sha512-GSTf4ZnweFNXcKoK/XeNzIklAjiBJ9Cf/K7YtCwYnw0UQbK0wlczKJKUsHygmW7eDBpexU2ue5b4ZS9fRJeXzA==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.2", + "iconv-lite": "^0.6.3", + "js-yaml": "^4.1.0", + "jschardet": "^3.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "replacetokens": "dist/bin/index.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.com/donate/?hosted_button_id=CCEAVYA8DUFD8" + } + }, + "node_modules/@types/chai": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.12.tgz", + "integrity": "sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==", + "dev": true + }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/azure-pipelines-task-lib": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-5.2.8.tgz", + "integrity": "sha512-JrPLrurMxxhCEFP9LXls2AkuM8468kW5j44vyUE46DOUIBFnmIficj5dmgFA9Bc/nUtH4GcdcDSr23BzrJr1gw==", + "license": "MIT", + "dependencies": { + "adm-zip": "^0.5.10", + "minimatch": "^3.1.5", + "nodejs-file-downloader": "^4.11.1", + "q": "^1.5.1", + "semver": "^5.7.2", + "shelljs": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "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.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jschardet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz", + "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "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://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodejs-file-downloader": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/nodejs-file-downloader/-/nodejs-file-downloader-4.12.1.tgz", + "integrity": "sha512-LpfCTNhh805AlLnJnzt1PuEj+RmbrccbAQZ6hBRw2e6QPVR0Qntuo6qqyvPHG5s77/0w0IEKgRAD4nbSnr/X4w==", + "dependencies": { + "follow-redirects": "^1.15.1", + "https-proxy-agent": "^5.0.0", + "mime-types": "^2.1.27", + "sanitize-filename": "^1.6.3" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/replacetokens-task": { + "resolved": "../..", + "link": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz", + "integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==", + "license": "BSD-3-Clause", + "dependencies": { + "execa": "^5.1.1", + "fast-glob": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==" + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@opentelemetry/api": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==" + }, + "@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "requires": { + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==" + }, + "@qetza/replacetokens": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@qetza/replacetokens/-/replacetokens-1.9.0.tgz", + "integrity": "sha512-GSTf4ZnweFNXcKoK/XeNzIklAjiBJ9Cf/K7YtCwYnw0UQbK0wlczKJKUsHygmW7eDBpexU2ue5b4ZS9fRJeXzA==", + "requires": { + "fast-glob": "^3.3.2", + "iconv-lite": "^0.6.3", + "js-yaml": "^4.1.0", + "jschardet": "^3.0.0", + "yargs": "^17.7.2" + } + }, + "@types/chai": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.12.tgz", + "integrity": "sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==", + "dev": true + }, + "@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true + }, + "@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true + }, + "@types/node": { + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "dev": true, + "requires": { + "undici-types": "~7.16.0" + } + }, + "adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "requires": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "azure-pipelines-task-lib": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-5.2.8.tgz", + "integrity": "sha512-JrPLrurMxxhCEFP9LXls2AkuM8468kW5j44vyUE46DOUIBFnmIficj5dmgFA9Bc/nUtH4GcdcDSr23BzrJr1gw==", + "requires": { + "adm-zip": "^0.5.10", + "minimatch": "^3.1.5", + "nodejs-file-downloader": "^4.11.1", + "q": "^1.5.1", + "semver": "^5.7.2", + "shelljs": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + } + }, + "check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, + "escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" + }, + "form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true + }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jschardet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz", + "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==" + }, + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.1" + } + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "nodejs-file-downloader": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/nodejs-file-downloader/-/nodejs-file-downloader-4.12.1.tgz", + "integrity": "sha512-LpfCTNhh805AlLnJnzt1PuEj+RmbrccbAQZ6hBRw2e6QPVR0Qntuo6qqyvPHG5s77/0w0IEKgRAD4nbSnr/X4w==", + "requires": { + "follow-redirects": "^1.15.1", + "https-proxy-agent": "^5.0.0", + "mime-types": "^2.1.27", + "sanitize-filename": "^1.6.3" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==" + }, + "proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "replacetokens-task": { + "version": "file:../..", + "requires": { + "@types/node": "^10.17.0", + "@vercel/ncc": "^0.38.1", + "mocha": "^10.3.0", + "prettier": "^3.2.5", + "semver": "^7.6.0", + "shelljs": "^0.8.5", + "tfx-cli": "^0.21.0", + "typescript": "5.7.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "requires": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shelljs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz", + "integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==", + "requires": { + "execa": "^5.1.1", + "fast-glob": "^3.3.2" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "requires": { + "utf8-byte-length": "^1.0.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + }, + "utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } +} diff --git a/tasks/ReplaceTokensV7/package.json b/tasks/ReplaceTokensV7/package.json new file mode 100644 index 0000000..4b45492 --- /dev/null +++ b/tasks/ReplaceTokensV7/package.json @@ -0,0 +1,24 @@ +{ + "name": "replacetokens-v7", + "author": "Guillaume ROUCHON", + "scripts": { + "test": "jest" + }, + "dependencies": { + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/sdk-trace-base": "^1.22.0", + "@opentelemetry/semantic-conventions": "^1.22.0", + "@qetza/replacetokens": "^1.9.0", + "axios": "1.14.0", + "azure-pipelines-task-lib": "5.2.8", + "js-yaml": "4.1.1", + "replacetokens-task": "file:../.." + }, + "devDependencies": { + "@types/chai": "^4.3.12", + "@types/js-yaml": "^4.0.9", + "@types/mocha": "^10.0.6", + "@types/node": "24.10.0", + "chai": "^4.4.1" + } +} diff --git a/tasks/ReplaceTokensV7/task.json b/tasks/ReplaceTokensV7/task.json new file mode 100644 index 0000000..699df63 --- /dev/null +++ b/tasks/ReplaceTokensV7/task.json @@ -0,0 +1,324 @@ +{ + "id": "A8515EC8-7254-4FFD-912C-86772E2B5962", + "name": "replacetokens", + "friendlyName": "Replace Tokens", + "description": "Replace tokens in text based files", + "helpMarkDown": "[Learn more about this task](https://github.com/qetza/replacetokens-task/blob/master/tasks/ReplaceTokensV7/README.md)", + "category": "Utility", + "visibility": [ + "Build", + "Release" + ], + "author": "Guillaume ROUCHON", + "version": { + "Major": 7, + "Minor": 0, + "Patch": 0 + }, + "releaseNotes": "breaking changes, see [changelog](https://github.com/qetza/replacetokens-task/blob/master/tasks/ReplaceTokensV7/CHANGELOG.md)", + "instanceNameFormat": "Replace tokens", + "minimumAgentVersion": "4.248.0", + "groups": [], + "inputs": [ + { + "name": "rootDirectory", + "aliases": ["root"], + "type": "filePath", + "required": false, + "defaultValue": "", + "label": "Root", + "helpMarkDown": "The root path to use when reading files with a relative path. Default: $(System.DefaultWorkingDirectory)" + }, + { + "name": "targetFiles", + "aliases": ["sources"], + "type": "multiLine", + "required": true, + "defaultValue": "", + "label": "Source files", + "helpMarkDown": "A multiline list of files to replace tokens in." + }, + { + "name": "tokenPattern", + "type": "pickList", + "required": false, + "defaultValue": "default", + "options": { + "default": "#{ ... }#", + "azpipelines": "$( ... )", + "doublebraces": "{{ ... }}", + "doubleunderscores": "__ ... __", + "githubactions": "${{ ... }}", + "octopus": "#{ ... }", + "custom": "custom" + }, + "label": "Token pattern", + "helpMarkDown": "The token pattern to use, use custom to specify your own prefix and suffix. Default: default" + }, + { + "name": "tokenPrefix", + "type": "string", + "required": false, + "visibleRule": "tokenPattern == custom", + "label": "Token prefix", + "helpMarkDown": "The token prefix when using 'custom' token pattern." + }, + { + "name": "tokenSuffix", + "type": "string", + "required": false, + "visibleRule": "tokenPattern == custom", + "label": "Token suffix", + "helpMarkDown": "The token suffix when using 'custom' token pattern." + }, + { + "name": "caseInsensitivePaths", + "type": "boolean", + "required": false, + "defaultValue": true, + "label": "Case insensitive paths", + "helpMarkDown": "Enable case-insensitive file path matching in glob patterns (sources and additionalVariables). Default: true" + }, + { + "name": "includeDotPaths", + "type": "boolean", + "required": false, + "defaultValue": true, + "label": "Include dot paths", + "helpMarkDown": "Include directories and files starting with a dot ('.') in glob matching results (sources and additionalVariables). Default: true" + }, + { + "name": "encoding", + "type": "pickList", + "required": false, + "defaultValue": "auto", + "options": { + "auto": "auto", + "ascii": "ascii", + "utf-7": "utf-7", + "utf-8": "utf-8", + "utf-16le": "utf-16", + "utf-16be": "utf-16 (big endian)", + "windows1252": "windows 1252", + "iso88591": "iso 8859-1" + }, + "label": "Files encoding", + "helpMarkDown": "The encoding to read and write all files. Default: auto" + }, + { + "name": "writeBOM", + "aliases": ["addBOM"], + "type": "boolean", + "required": false, + "defaultValue": false, + "visibleRule": "encoding != ascii && encoding != windows1252 && encoding != iso88591", + "label": "Add BOM", + "helpMarkDown": "Add BOM when writing files. Default: false" + }, + { + "name": "additionalVariables", + "type": "multiLine", + "required": false, + "defaultValue": "", + "label": "Additional variables (YAML)", + "helpMarkDown": "A YAML formatted string containing additional variables or file or environment variable references." + }, + { + "name": "variableSeparator", + "aliases": ["separator"], + "type": "string", + "defaultValue": ".", + "required": false, + "visibleRule": "additionalVariables != \"\"", + "label": "Separator", + "helpMarkDown": "The separtor to use when flattening keys in variables." + }, + { + "name": "useAdditionalVariablesOnly", + "type": "boolean", + "required": false, + "defaultValue": false, + "visibleRule": "additionalVariables != \"\"", + "label": "Use only additional variables", + "helpMarkDown": "Use only variables declared in additional variables. Default: false" + }, + { + "name": "escapeType", + "aliases": ["escape"], + "type": "pickList", + "required": false, + "defaultValue": "auto", + "options": { + "auto": "auto", + "off": "no escaping", + "json": "json", + "xml": "xml", + "custom": "custom" + }, + "label": "Escape values", + "helpMarkDown": "The character escape type to apply on each value. Default: auto" + }, + { + "name": "escapeChar", + "type": "string", + "required": false, + "visibleRule": "escapeType == custom", + "label": "Escape character", + "helpMarkDown": "The escape character to use when using 'custom' escape." + }, + { + "name": "charsToEscape", + "type": "string", + "required": false, + "visibleRule": "escapeType == custom", + "label": "Characters to escape", + "helpMarkDown": "The characters to escape when using 'custom' escape." + }, + { + "name": "verbosity", + "aliases": ["logLevel"], + "type": "pickList", + "required": false, + "defaultValue": "info", + "options": { + "debug": "debug", + "info": "info", + "warn": "warn", + "error": "error" + }, + "label": "Log level", + "helpMarkDown": "The log level. Default: info" + }, + { + "name": "missingVarAction", + "type": "pickList", + "required": false, + "defaultValue": "none", + "options": { + "none": "replace with empty and log", + "keep": "keep token and log", + "replace": "replace with default" + }, + "label": "Behavior on missing variable", + "helpMarkDown": "The behavior if variable is not found. Default: none" + }, + { + "name": "defaultValue", + "aliases": ["missingVarDefault"], + "type": "string", + "required": false, + "defaultValue": "", + "visibleRule": "missingVarAction == replace", + "label": "Default value", + "helpMarkDown": "The default value to use when a key is not found. Default: empty string" + }, + { + "name": "actionOnMissing", + "aliases": ["missingVarLog"], + "type": "pickList", + "required": false, + "defaultValue": "warn", + "options": { + "off": "no log", + "info": "information", + "warn": "warning", + "error": "error and fail task" + }, + "visibleRule": "missingVarAction != replace", + "label": "Missing variable log level", + "helpMarkDown": "The level to log key not found messages. Default: warn" + }, + { + "name": "actionOnNoFiles", + "aliases": ["ifNoFilesFound"], + "type": "pickList", + "required": false, + "defaultValue": "ignore", + "options": { + "ignore": "silently continue", + "warn": "log warning", + "error": "fail task" + }, + "label": "Behavior on no file", + "helpMarkDown": "The behavior if no files are found. Default: ignore" + }, + { + "name": "enableRecursion", + "aliases": ["recursive"], + "type": "boolean", + "required": false, + "defaultValue": false, + "label": "Enable recursion in values", + "helpMarkDown": "Enable token replacements in values recusively. Default: false" + }, + { + "name": "enableTransforms", + "aliases": ["transforms"], + "type": "boolean", + "required": false, + "defaultValue": false, + "label": "Enable transforms", + "helpMarkDown": "Enable transforms on values. Default: false" + }, + { + "name": "transformPrefix", + "aliases": ["transformsPrefix"], + "type": "string", + "required": false, + "defaultValue": "(", + "visibleRule": "enableTransforms == true", + "label": "Transforms prefix", + "helpMarkDown": "The tranforms prefix when using transforms. Default: (" + }, + { + "name": "transformSuffix", + "aliases": ["transformsSuffix"], + "type": "string", + "required": false, + "defaultValue": ")", + "visibleRule": "enableTransforms == true", + "label": "Transforms suffix", + "helpMarkDown": "The tranforms suffix when using transforms. Default: )" + }, + { + "name": "telemetryOptout", + "type": "boolean", + "required": false, + "defaultValue": false, + "label": "Opt out of anonymous telemetry", + "helpMarkDown": "Opt out of the anonymous telemetry feature. Default: false" + } + ], + "outputVariables": [ + { + "name": "defaults", + "description": "The number of tokens replaced with the default value if one was specified." + }, + { + "name": "files", + "description": "The number of source files parsed." + }, + { + "name": "replaced", + "description": "The number of values replaced by a value different than the default value." + }, + { + "name": "tokens", + "description": "The number of tokens found in all files." + }, + { + "name": "transforms", + "description": "The number of transforms applied." + } + ], + "execution": { + "Node20_1": { + "target": "index.js", + "argumentFormat": "" + }, + "Node24": { + "target": "index.js", + "argumentFormat": "" + } + } +} \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/telemetry.ts b/tasks/ReplaceTokensV7/telemetry.ts new file mode 100644 index 0000000..27d16d4 --- /dev/null +++ b/tasks/ReplaceTokensV7/telemetry.ts @@ -0,0 +1,118 @@ +import { ExportResult, ExportResultCode, hrTimeToMilliseconds } from '@opentelemetry/core'; +import { trace, SpanStatusCode } from '@opentelemetry/api'; +import { BasicTracerProvider, SimpleSpanProcessor, SpanExporter, ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import * as axios from 'axios'; +import * as crypto from 'crypto'; + +const application = 'replacetokens-task'; +const version = '6.0.0'; +const endpoint = 'https://insights-collector.eu01.nr-data.net/v1/accounts/4392697/events'; +const key = 'eu01xxc28887c2d47d9719ed24a74df5FFFFNRAL'; +const timeout = 3000; + +class NewRelicExporter implements SpanExporter { + private readonly _proxy?: string; + + private _isShutdown = false; + + constructor(options: { proxy?: string }) { + this._proxy = options.proxy; + this._isShutdown = false; + } + + async export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): Promise { + if (this._isShutdown) { + setTimeout(() => resultCallback({ code: ExportResultCode.FAILED }), 0); + + return; + } + + if (spans.length > 0) { + const events = spans.map(s => this._spanToEvent(s)); + console.debug(`telemetry: ${JSON.stringify(events)}`); + + resultCallback(await this._send(events)); + } + + resultCallback({ code: ExportResultCode.SUCCESS }); + } + + shutdown(): Promise { + this._isShutdown = true; + + return Promise.resolve(); + } + + private _spanToEvent(span: ReadableSpan): { [key: string]: any } { + return { + eventType: 'TokensReplaced', + application: application, + version: version, + ...span.attributes, + result: (() => { + switch (span.status.code) { + case SpanStatusCode.ERROR: + return 'failed'; + case SpanStatusCode.OK: + return 'success'; + default: + return ''; + } + })(), + duration: hrTimeToMilliseconds(span.duration) + }; + } + + private async _send(data: any[]): Promise { + try { + const options: axios.AxiosRequestConfig = { + headers: { + 'Api-Key': key, + 'Content-Type': 'application/json' + }, + timeout: timeout + }; + if (this._proxy) { + const proxyUrl = new URL(this._proxy); + + let proxy: any = { host: proxyUrl.host }; + if (proxyUrl.port) proxy = { ...proxy, port: parseInt(proxyUrl.port) }; + if (proxyUrl.username) proxy = { ...proxy, auth: { username: proxyUrl.username } }; + if (proxyUrl.password) proxy = { ...proxy, auth: { ...proxy.auth, password: proxyUrl.password } }; + + options.proxy = proxy; + } + + await axios.default.post(endpoint, data, options); + + return { code: ExportResultCode.SUCCESS }; + } catch (e) { + return { code: ExportResultCode.FAILED }; + } + } +} + +const tracer = trace.getTracer(application, version); +const provider = new BasicTracerProvider({ forceFlushTimeoutMillis: timeout }); +trace.setGlobalTracerProvider(provider); + +export function enableTelemetry(proxy?: string) { + provider.addSpanProcessor(new SimpleSpanProcessor(new NewRelicExporter({ proxy: proxy }))); +} + +export function startSpan(name: string, account: string, pipeline: string, host: string, os: string) { + return tracer.startSpan(name, { + attributes: { + account: crypto + .createHash('sha256') + .update(account || '') + .digest('hex'), + pipeline: crypto + .createHash('sha256') + .update(pipeline || '') + .digest('hex'), + host: host, + os: os + } + }); +} diff --git a/tasks/ReplaceTokensV7/tests/.gitignore b/tasks/ReplaceTokensV7/tests/.gitignore new file mode 100644 index 0000000..bda32ed --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/.gitignore @@ -0,0 +1 @@ +_tmp/ \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/L0.ts b/tasks/ReplaceTokensV7/tests/L0.ts new file mode 100644 index 0000000..7677791 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/L0.ts @@ -0,0 +1,1154 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as ttm from 'azure-pipelines-task-lib/mock-test'; +import * as os from 'os'; + +require('chai').should(); + +const data = path.join(__dirname, '..', '..', 'tests', '_data'); +const tmp = path.join(__dirname, '..', '..', 'tests', '_tmp'); + +describe('ReplaceTokens v7 L0 suite', function () { + this.timeout(10000); + + beforeEach(() => { + fs.mkdirSync(tmp, { recursive: true }); + + process.env['__caseInsensitivePaths__'] = 'true'; + process.env['__includeDotPaths__'] = 'true'; + }); + + afterEach(() => { + delete process.env['__sources__']; + delete process.env['__addBOM__']; + delete process.env['__additionalVariables__']; + delete process.env['__caseInsensitivePaths__']; + delete process.env['__charsToEscape__']; + delete process.env['__encoding__']; + delete process.env['__escape__']; + delete process.env['__escapeChar__']; + delete process.env['__ifNoFilesFound__']; + delete process.env['__includeDotPaths__']; + delete process.env['__logLevel__']; + delete process.env['__missingVarAction__']; + delete process.env['__missingVarDefault__']; + delete process.env['__missingVarLog__']; + delete process.env['__recursive__']; + delete process.env['__root__']; + delete process.env['__separator__']; + delete process.env['__telemetryOptout__']; + delete process.env['__tokenPattern__']; + delete process.env['__tokenPrefix__']; + delete process.env['__tokenSuffix__']; + delete process.env['__transforms__']; + delete process.env['__transformsPrefix__']; + delete process.env['__transformsSuffix__']; + delete process.env['__VARS__']; + + if (process.env['VSTS_PUBLIC_VARIABLES']) { + for (const name in JSON.parse(process.env['VSTS_PUBLIC_VARIABLES'])) { + delete process.env[name.replace(/[ \.]/g, '_').toUpperCase()]; + } + delete process.env['VSTS_PUBLIC_VARIABLES']; + } + + if (process.env['VSTS_SECRET_VARIABLES']) { + for (const name in JSON.parse(process.env['VSTS_SECRET_VARIABLES'])) { + delete process.env[`SECRET_${name.replace(/[ \.]/g, '_').toUpperCase()}`]; + } + delete process.env['VSTS_SECRET_VARIABLES']; + } + + fs.rmSync(tmp, { force: true, recursive: true }); + }); + + function runValidations(validator: () => void, tr: ttm.MockTestRunner) { + try { + validator(); + } catch (error) { + console.log('STDERR', tr.stderr); + console.log('STDOUT', tr.stdout); + + throw error; + } + } + + function addVariables(variables: { [key: string]: string }) { + process.env['VSTS_PUBLIC_VARIABLES'] = JSON.stringify(Object.keys(variables)); + + for (const [name, value] of Object.entries(variables)) { + process.env[name.replace(/[ \.]/g, '_').toUpperCase()] = value; + } + } + + function addSecrets(secrets: { [key: string]: string }) { + process.env['VSTS_SECRET_VARIABLES'] = JSON.stringify(Object.keys(secrets)); + + for (const [name, value] of Object.entries(secrets)) { + process.env[`SECRET_${name.replace(/[ \.]/g, '_').toUpperCase()}`] = value; + } + } + + it('validate: sources', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include('##vso[task.complete result=Failed;]Error: Input required: sources'); + }, tr); + }); + + it('validate: escape', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__escape__'] = 'unsupported'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include( + "##vso[task.complete result=Failed;]Error: Unsupported value for input: escape. Support input list: 'auto | custom | json | off | xml'" + ); + }, tr); + }); + + it('validate: missingVarAction', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__missingVarAction__'] = 'unsupported'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include( + "##vso[task.complete result=Failed;]Error: Unsupported value for input: missingVarAction. Support input list: 'keep | none | replace'" + ); + }, tr); + }); + + it('validate: missingVarLog', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__missingVarLog__'] = 'unsupported'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include( + "##vso[task.complete result=Failed;]Error: Unsupported value for input: missingVarLog. Support input list: 'error | off | info | warn'" + ); + }, tr); + }); + + it('validate: tokenPattern', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__tokenPattern__'] = 'unsupported'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include( + "##vso[task.complete result=Failed;]Error: Unsupported value for input: tokenPattern. Support input list: 'azpipelines | custom | default | doublebraces | doubleunderscores | githubactions | octopus'" + ); + }, tr); + }); + + it('default', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json\r\n**/*.xml\r\n**/*.yml'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.not.contain('loadVariables_variables'); + tr.stdout.should.include('sources: ["**/*.json","**/*.xml","**/*.yml"]'); + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('telemetry: success', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json\r\n**/*.xml\r\n**/*.yml'; + process.env['SYSTEM_SERVERTYPE'] = 'hosted'; + process.env['SYSTEM_COLLECTIONID'] = 'col01'; + process.env['SYSTEM_TEAMPROJECTID'] = 'project01'; + process.env['SYSTEM_DEFINITIONID'] = 'def01'; + process.env['AGENT_OS'] = 'Windows_NT'; + + try { + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('telemetry sent'); + tr.stdout.should.match( + /\[\{"eventType":"TokensReplaced","application":"replacetokens-task","version":"6.0.0","account":"494d0aad9d06c4ddb51d5300620122ce55366a9382b3cc2835ed5f0e2e67b4d0","pipeline":"b98ed03d3eec376dcc015365c1a944e3ebbcc33d30e3261af3f4e4abb107aa82","host":"cloud","os":"Windows","sources":3,"add-bom":false,"case-insenstive-paths":true,"encoding":"auto","escape":"auto","if-no-files-found":"ignore","include-dot-paths":true,"log-level":"info","missing-var-action":"none","missing-var-default":"","missing-var-log":"warn","recursive":false,"separator":".","token-pattern":"default","transforms":false,"transforms-prefix":"\(","transforms-suffix":"\)","use-additional-variables-only":false,"variable-files":0,"variable-envs":0,"inline-variables":0,"output-defaults":1,"output-files":2,"output-replaced":3,"output-tokens":4,"output-transforms":5,"result":"success","duration":\d+(?:\.\d+)?}]/ + ); + }, tr); + } finally { + delete process.env['SYSTEM_SERVERTYPE']; + delete process.env['SYSTEM_COLLECTIONID']; + delete process.env['SYSTEM_TEAMPROJECTID']; + delete process.env['SYSTEM_DEFINITIONID']; + delete process.env['AGENT_OS']; + } + }); + + it('telemetry: failed', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['SYSTEM_SERVERTYPE'] = 'hosted'; + process.env['SYSTEM_COLLECTIONID'] = 'col01'; + process.env['SYSTEM_TEAMPROJECTID'] = 'project01'; + process.env['SYSTEM_DEFINITIONID'] = 'def01'; + process.env['AGENT_OS'] = 'Windows_NT'; + + try { + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include('telemetry sent'); + tr.stdout.should.match( + /\[\{"eventType":"TokensReplaced","application":"replacetokens-task","version":"6.0.0","account":"494d0aad9d06c4ddb51d5300620122ce55366a9382b3cc2835ed5f0e2e67b4d0","pipeline":"b98ed03d3eec376dcc015365c1a944e3ebbcc33d30e3261af3f4e4abb107aa82","host":"cloud","os":"Windows","result":"failed","duration":\d+(?:\.\d+)?}]/ + ); + }, tr); + } finally { + delete process.env['SYSTEM_SERVERTYPE']; + delete process.env['SYSTEM_COLLECTIONID']; + delete process.env['SYSTEM_TEAMPROJECTID']; + delete process.env['SYSTEM_DEFINITIONID']; + delete process.env['AGENT_OS']; + } + }); + + it('sources: normalize', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = 'D:\\a\\1\\s/test.json'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + if (os.platform() === 'win32') { + tr.stdout.should.include('sources: ["D:/a/1/s/test.json"]'); + } else { + tr.stdout.should.include('sources: ["D:\\\\a\\\\1\\\\s/test.json"]'); + } + }, tr); + }); + + it('addBOM', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__addBOM__'] = 'true'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":true,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('additionalVariables: file', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__root__'] = path.join(data, '..'); + process.env['__additionalVariables__'] = '@**/_data/vars.(json|jsonc|yml|yaml)'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('loadVariables_variables: ["@**/_data/vars.(json|jsonc|yml|yaml)"]'); + tr.stdout.should.include( + `loadVariables_options: {"caseInsensitive":true,"dot":true,"normalizeWin32":true,"root":"${process.env['__root__'].replace(/\\/g, '\\\\')}","separator":"."}` + ); + }, tr); + }); + + it('additionalVariables: env', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__VARS__'] = '{ "var1": "value1", "var2": "value2" }'; + process.env['__additionalVariables__'] = '$__VARS__'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('loadVariables_variables: ["$__VARS__"]'); + tr.stdout.should.include(`loadVariables_options: {"caseInsensitive":true,"dot":true,"normalizeWin32":true,"separator":"."}`); + }, tr); + }); + + it('additionalVariables: object', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__additionalVariables__'] = ` + var1: value1 + var2: value2 + `; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('loadVariables_variables: ["{\\"var1\\":\\"value1\\",\\"var2\\":\\"value2\\"}"]'); + tr.stdout.should.include(`loadVariables_options: {"caseInsensitive":true,"dot":true,"normalizeWin32":true,"separator":"."}`); + }, tr); + }); + + it('additionalVariables: merge', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__telemetryOptout__'] = 'true'; + process.env['__sources__'] = '**/*.json'; + process.env['__root__'] = path.join(data, '..'); + process.env['__VARS__'] = '{ "var1": "env", "var2": "env" }'; + process.env['__additionalVariables__'] = ` +- '@**/_data/vars.*;!**/*.xml' +- '$__VARS__' +- var2: inline + var_yml2: inline +`; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('loadVariables_variables: ["@**/_data/vars.*;!**/*.xml","$__VARS__","{\\"var2\\":\\"inline\\",\\"var_yml2\\":\\"inline\\"}"]'); + tr.stdout.should.include( + `loadVariables_options: {"caseInsensitive":true,"dot":true,"normalizeWin32":true,"root":"${process.env['__root__'].replace(/\\/g, '\\\\')}","separator":"."}` + ); + }, tr); + }); + + it('caseInsensitivePaths', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__additionalVariables__'] = 'var1: value1'; + process.env['__caseInsensitivePaths__'] = 'false'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('loadVariables_options: {"caseInsensitive":false,"dot":true,"normalizeWin32":true,"separator":"."}'); + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":false,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('charsToEscape', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__charsToEscape__'] = 'abcd'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"chars":"abcd","type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('encoding', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__encoding__'] = 'abcd'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"abcd","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('escape', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__escape__'] = 'json'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"json"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('ifNoFilesFound: ignore', async () => { + // arrange + const tp = path.join(__dirname, 'L0_IfNoFilesFound.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__ifNoFilesFound__'] = 'ignore'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('No files were found with provided sources.'); + }, tr); + }); + + it('ifNoFilesFound: warn', async () => { + // arrange + const tp = path.join(__dirname, 'L0_IfNoFilesFound.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__ifNoFilesFound__'] = 'warn'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('##vso[task.issue type=warning;source=TaskInternal;]No files were found with provided sources.'); + }, tr); + }); + + it('ifNoFilesFound: error', async () => { + // arrange + const tp = path.join(__dirname, 'L0_IfNoFilesFound.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__ifNoFilesFound__'] = 'error'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.failed.should.be.true; + + tr.stdout.should.include('##vso[task.issue type=error;source=TaskInternal;]No files were found with provided sources.'); + tr.stdout.should.include('##vso[task.complete result=Failed;]No files were found with provided sources.'); + }, tr); + }); + + it('includeDotPaths', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__additionalVariables__'] = 'var1: value1'; + process.env['__includeDotPaths__'] = 'false'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('loadVariables_options: {"caseInsensitive":true,"dot":false,"normalizeWin32":true,"separator":"."}'); + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":false},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('logLevel: debug', async () => { + // arrange + const tp = path.join(__dirname, 'L0_LogLevel.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__logLevel__'] = 'debug'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('##vso[task.debug]debug'); + tr.stdout.should.include('\ndebug\n'); + tr.stdout.should.include('info'); + tr.stdout.should.include('##vso[task.issue type=warning;source=TaskInternal;]warn'); + tr.stdout.should.include('##vso[task.issue type=error;source=TaskInternal;]error'); + tr.stdout.should.include('##vso[task.complete result=Failed;]error'); + tr.stdout.should.include('##[group] group'); + tr.stdout.should.include('##[endgroup]'); + }, tr); + }); + + it('logLevel: info', async () => { + // arrange + const tp = path.join(__dirname, 'L0_LogLevel.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__logLevel__'] = 'info'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('##vso[task.debug]debug'); + tr.stdout.should.not.include('\ndebug\n'); + tr.stdout.should.include('\ninfo\n'); + tr.stdout.should.include('##vso[task.issue type=warning;source=TaskInternal;]warn'); + tr.stdout.should.include('##vso[task.issue type=error;source=TaskInternal;]error'); + tr.stdout.should.include('##vso[task.complete result=Failed;]error'); + tr.stdout.should.include('##[group] group'); + tr.stdout.should.include('##[endgroup]'); + }, tr); + }); + + it('logLevel: warn', async () => { + // arrange + const tp = path.join(__dirname, 'L0_LogLevel.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__logLevel__'] = 'warn'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('##vso[task.debug]debug'); + tr.stdout.should.not.include('\ndebug\n'); + tr.stdout.should.not.include('\ninfo\n'); + tr.stdout.should.include('##vso[task.issue type=warning;source=TaskInternal;]warn'); + tr.stdout.should.include('##vso[task.issue type=error;source=TaskInternal;]error'); + tr.stdout.should.include('##vso[task.complete result=Failed;]error'); + tr.stdout.should.not.include('##[group] group'); + tr.stdout.should.not.include('##[endgroup]'); + }, tr); + }); + + it('logLevel: error', async () => { + // arrange + const tp = path.join(__dirname, 'L0_LogLevel.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__logLevel__'] = 'error'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.stdout.should.include('##vso[task.debug]debug'); + tr.stdout.should.not.include('\ndebug\n'); + tr.stdout.should.not.include('\ninfo\n'); + tr.stdout.should.not.include('##vso[task.issue type=warning;source=TaskInternal;]warn'); + tr.stdout.should.include('##vso[task.issue type=error;source=TaskInternal;]error'); + tr.stdout.should.include('##vso[task.complete result=Failed;]error'); + tr.stdout.should.not.include('##[group] group'); + tr.stdout.should.not.include('##[endgroup]'); + }, tr); + }); + + it('missingVarAction', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__missingVarAction__'] = 'keep'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"keep","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('missingVarDefault', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__missingVarDefault__'] = 'abcd'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"abcd","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('missingVarLog', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__missingVarLog__'] = 'off'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"off"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('recursive', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__recursive__'] = 'true'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":true,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('root', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__root__'] = __dirname; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + `options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"root":"${__dirname.replace(/\\/g, '\\\\')}","sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}` + ); + }, tr); + }); + + it('separator', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__additionalVariables__'] = 'var1: value1'; + process.env['__separator__'] = ':'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include('loadVariables_options: {"caseInsensitive":true,"dot":true,"normalizeWin32":true,"separator":":"}'); + }, tr); + }); + + it('telemetryOptout: input', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__telemetryOptout__'] = 'true'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + tr.stdout.should.not.include('telemetry sent'); + tr.stdout.should.not.include('##vso[task.debug]telemetry: ['); + }, tr); + }); + + it('telemetryOptout: REPLACETOKENS_TELEMETRY_OPTOUT=1', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['REPLACETOKENS_TELEMETRY_OPTOUT'] = '1'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + tr.stdout.should.not.include('telemetry sent'); + tr.stdout.should.not.include('##vso[task.debug]telemetry: ['); + }, tr); + }); + + it('telemetryOptout: REPLACETOKENS_TELEMETRY_OPTOUT=true', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['REPLACETOKENS_TELEMETRY_OPTOUT'] = '1'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + tr.stdout.should.not.include('telemetry sent'); + tr.stdout.should.not.include('##vso[task.debug]telemetry: ['); + }, tr); + }); + + it('telemetryOptout: REPLACETOKENS_DISABLE_TELEMETRY=1', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['REPLACETOKENS_TELEMETRY_OPTOUT'] = '1'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + tr.stdout.should.not.include('telemetry sent'); + tr.stdout.should.not.include('##vso[task.debug]telemetry: ['); + }, tr); + }); + + it('telemetryOptout: REPLACETOKENS_DISABLE_TELEMETRY=true', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['REPLACETOKENS_TELEMETRY_OPTOUT'] = '1'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + tr.stdout.should.not.include('telemetry sent'); + tr.stdout.should.not.include('##vso[task.debug]telemetry: ['); + }, tr); + }); + + it('tokenPattern', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__tokenPattern__'] = 'azpipelines'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"azpipelines"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('tokenPrefix', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__tokenPrefix__'] = '[['; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default","prefix":"[["},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('tokenSuffix', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__tokenSuffix__'] = ']]'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default","suffix":"]]"},"transforms":{"enabled":false,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('transforms', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__transforms__'] = 'true'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":true,"prefix":"(","suffix":")"}}' + ); + }, tr); + }); + + it('transformsPrefix', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__transformsPrefix__'] = '['; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"[","suffix":")"}}' + ); + }, tr); + }); + + it('transformsSuffix', async () => { + // arrange + const tp = path.join(__dirname, 'L0_Run.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + process.env['__sources__'] = '**/*.json'; + process.env['__transformsSuffix__'] = ']'; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + tr.stdout.should.include( + 'options: {"addBOM":false,"encoding":"auto","escape":{"type":"auto"},"missing":{"action":"none","default":"","log":"warn"},"recursive":false,"sources":{"caseInsensitive":true,"dot":true},"token":{"pattern":"default"},"transforms":{"enabled":false,"prefix":"(","suffix":"]"}}' + ); + }, tr); + }); + + it('replace tokens', async () => { + // arrange + const tp = path.join(__dirname, 'L0_NoMock.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + addVariables({ 'var.var': 'var', var_yaml2: 'var' }); + addSecrets({ 'var.secret': 'secret', 'var.yml2': 'secret' }); + + let input = path.join(tmp, 'file.txt'); + await fs.promises.copyFile(path.join(data, 'file.txt'), input); + input = path.resolve(input); + + process.env['__telemetryOptout__'] = 'true'; + process.env['__sources__'] = input; + process.env['__missingVarAction__'] = 'replace'; + process.env['__missingVarDefault__'] = 'DEFAULT'; + process.env['__root__'] = path.join(data, '..'); + process.env['__VARS__'] = '{ "var1": "env", "var2": "env" }'; + process.env['__additionalVariables__'] = ` +- '@**/_data/vars.*;!**/*.xml' +- '$__VARS__' +- var2: inline + var.yml2: inline +`; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + const actual = fs.readFileSync(input, 'utf8'); + const expected = fs.readFileSync(path.join(data, 'file.expected.txt'), 'utf8'); + + actual.should.equal(expected); + }, tr); + }); + + it('empty token', async () => { + // arrange + const tp = path.join(__dirname, 'L0_NoMock.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + addVariables({ 'var.var': 'var', var_yaml2: 'var' }); + + let input = path.join(tmp, 'empty.txt'); + await fs.promises.copyFile(path.join(data, 'empty.txt'), input); + input = path.resolve(input); + + process.env['__telemetryOptout__'] = 'false'; + process.env['__sources__'] = input; + process.env['__missingVarAction__'] = 'keep'; + process.env['__missingVarDefault__'] = 'DEFAULT'; + process.env['__root__'] = path.join(data, '..'); + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + const actual = fs.readFileSync(input, 'utf8'); + const expected = fs.readFileSync(path.join(data, 'empty.expected.txt'), 'utf8'); + + actual.should.equal(expected); + + tr.stdout.should.include("##vso[task.issue type=warning;source=TaskInternal;]variable '' not found"); + tr.stdout.should.include('##vso[task.debug]: #{}#'); + }, tr); + }); + + it('useAdditionalVariablesOnly', async () => { + // arrange + const tp = path.join(__dirname, 'L0_NoMock.js'); + const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + addVariables({ 'var.var': 'var', var_yaml2: 'var' }); + addSecrets({ 'var.secret': 'secret', 'var.yml2': 'secret' }); + + let input = path.join(tmp, 'file.txt'); + await fs.promises.copyFile(path.join(data, 'file.txt'), input); + input = path.resolve(input); + + process.env['__telemetryOptout__'] = 'true'; + process.env['__sources__'] = input; + process.env['__missingVarAction__'] = 'replace'; + process.env['__missingVarDefault__'] = 'DEFAULT'; + process.env['__root__'] = path.join(data, '..'); + process.env['__VARS__'] = '{ "var1": "env", "var2": "env" }'; + process.env['__useAdditionalVariablesOnly__'] = 'true'; + process.env['__additionalVariables__'] = ` +- '@**/_data/vars.*;!**/*.xml' +- '$__VARS__' +- var2: inline + var.yml2: inline +`; + + // act + await tr.runAsync(); + + // assert + runValidations(() => { + tr.succeeded.should.be.true; + + const actual = fs.readFileSync(input, 'utf8'); + const expected = fs.readFileSync(path.join(data, 'file.only_additional_variables.expected.txt'), 'utf8'); + + actual.should.equal(expected); + }, tr); + }); +}); diff --git a/tasks/ReplaceTokensV7/tests/L0_IfNoFilesFound.ts b/tasks/ReplaceTokensV7/tests/L0_IfNoFilesFound.ts new file mode 100644 index 0000000..54368a8 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/L0_IfNoFilesFound.ts @@ -0,0 +1,36 @@ +import * as tmrm from 'azure-pipelines-task-lib/mock-run'; +import * as path from 'path'; + +const taskPath = path.join(__dirname, '..', 'index.js'); +const tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +// inputs +tmr.setInput('targetFiles', process.env['__sources__']); +tmr.setInput('actionOnNoFiles', process.env['__ifNoFilesFound__']); + +// mocks +const rtClone = Object.assign({}, require('@qetza/replacetokens')); +rtClone.loadVariables = function (variables, options) { + console.log(`loadVariables_variables: ${JSON.stringify(variables)}`); + console.log(`loadVariables_options: ${JSON.stringify(options)}`); + + return Promise.resolve({}); +}; +rtClone.replaceTokens = function (sources, variables, options) { + return Promise.resolve({ defaults: 1, files: 0, replaced: 3, tokens: 4, transforms: 5 }); +}; + +tmr.registerMock('@qetza/replacetokens', rtClone); + +const axiosClone = Object.assign({}, require('axios')); +axiosClone.default = Object.assign({}, axiosClone.default); +axiosClone.default.post = function () { + console.log('telemetry sent'); + + return Promise.resolve(); +}; + +tmr.registerMock('axios', axiosClone); + +// act +tmr.run(); diff --git a/tasks/ReplaceTokensV7/tests/L0_LogLevel.ts b/tasks/ReplaceTokensV7/tests/L0_LogLevel.ts new file mode 100644 index 0000000..81bdad5 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/L0_LogLevel.ts @@ -0,0 +1,43 @@ +import * as tmrm from 'azure-pipelines-task-lib/mock-run'; +import * as path from 'path'; + +const taskPath = path.join(__dirname, '..', 'index.js'); +const tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +// inputs +tmr.setInput('targetFiles', process.env['__sources__']); +tmr.setInput('verbosity', process.env['__logLevel__']); + +// mocks +const rtClone = Object.assign({}, require('@qetza/replacetokens')); +rtClone.loadVariables = function (variables, options) { + console.log(`loadVariables_variables: ${JSON.stringify(variables)}`); + console.log(`loadVariables_options: ${JSON.stringify(options)}`); + + return Promise.resolve({}); +}; +rtClone.replaceTokens = function (sources, variables, options) { + console.debug('debug'); + console.info('info'); + console.warn('warn'); + console.error('error'); + console.group('group'); + console.groupEnd(); + + return Promise.resolve({ defaults: 1, files: 2, replaced: 3, tokens: 4, transforms: 5 }); +}; + +tmr.registerMock('@qetza/replacetokens', rtClone); + +const axiosClone = Object.assign({}, require('axios')); +axiosClone.default = Object.assign({}, axiosClone.default); +axiosClone.default.post = function () { + console.log('telemetry sent'); + + return Promise.resolve(); +}; + +tmr.registerMock('axios', axiosClone); + +// act +tmr.run(); diff --git a/tasks/ReplaceTokensV7/tests/L0_NoMock.ts b/tasks/ReplaceTokensV7/tests/L0_NoMock.ts new file mode 100644 index 0000000..dad91ff --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/L0_NoMock.ts @@ -0,0 +1,44 @@ +import * as tmrm from 'azure-pipelines-task-lib/mock-run'; +import * as path from 'path'; + +const taskPath = path.join(__dirname, '..', 'index.js'); +const tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +// inputs +if (process.env['__sources__']) tmr.setInput('targetFiles', process.env['__sources__']); +if (process.env['__addBOM__']) tmr.setInput('writeBOM', process.env['__addBOM__']); +if (process.env['__additionalVariables__']) tmr.setInput('additionalVariables', process.env['__additionalVariables__']); +if (process.env['__charsToEscape__']) tmr.setInput('charsToEscape', process.env['__charsToEscape__']); +if (process.env['__encoding__']) tmr.setInput('encoding', process.env['__encoding__']); +if (process.env['__escape__']) tmr.setInput('escapeType', process.env['__escape__']); +if (process.env['__escapeChar__']) tmr.setInput('escapeChar', process.env['__escapeChar__']); +if (process.env['__ifNoFilesFound__']) tmr.setInput('actionOnNoFiles', process.env['__ifNoFilesFound__']); +if (process.env['__logLevel__']) tmr.setInput('verbosity', process.env['__logLevel__']); +if (process.env['__missingVarAction__']) tmr.setInput('missingVarAction', process.env['__missingVarAction__']); +if (process.env['__missingVarDefault__']) tmr.setInput('defaultValue', process.env['__missingVarDefault__']); +if (process.env['__missingVarLog__']) tmr.setInput('actionOnMissing', process.env['__missingVarLog__']); +if (process.env['__recursive__']) tmr.setInput('enableRecursion', process.env['__recursive__']); +if (process.env['__root__']) tmr.setInput('rootDirectory', process.env['__root__']); +if (process.env['__separator__']) tmr.setInput('variableSeparator', process.env['__separator__']); +if (process.env['__telemetryOptout__']) tmr.setInput('telemetryOptout', process.env['__telemetryOptout__']); +if (process.env['__tokenPattern__']) tmr.setInput('tokenPattern', process.env['__tokenPattern__']); +if (process.env['__tokenPrefix__']) tmr.setInput('tokenPrefix', process.env['__tokenPrefix__']); +if (process.env['__tokenSuffix__']) tmr.setInput('tokenSuffix', process.env['__tokenSuffix__']); +if (process.env['__transforms__']) tmr.setInput('enableTransforms', process.env['__transforms__']); +if (process.env['__transformsPrefix__']) tmr.setInput('transformPrefix', process.env['__transformsPrefix__']); +if (process.env['__transformsSuffix__']) tmr.setInput('transformSuffix', process.env['__transformsSuffix__']); +if (process.env['__useAdditionalVariablesOnly__']) tmr.setInput('useAdditionalVariablesOnly', process.env['__useAdditionalVariablesOnly__']); + +// mocks +const axiosClone = Object.assign({}, require('axios')); +axiosClone.default = Object.assign({}, axiosClone.default); +axiosClone.default.post = function () { + console.log('telemetry sent'); + + return Promise.resolve(); +}; + +tmr.registerMock('axios', axiosClone); + +// act +tmr.run(); diff --git a/tasks/ReplaceTokensV7/tests/L0_Run.ts b/tasks/ReplaceTokensV7/tests/L0_Run.ts new file mode 100644 index 0000000..406c053 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/L0_Run.ts @@ -0,0 +1,62 @@ +import * as tmrm from 'azure-pipelines-task-lib/mock-run'; +import * as path from 'path'; + +const taskPath = path.join(__dirname, '..', 'index.js'); +const tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +// inputs +if (process.env['__sources__']) tmr.setInput('targetFiles', process.env['__sources__']); +if (process.env['__addBOM__']) tmr.setInput('writeBOM', process.env['__addBOM__']); +if (process.env['__additionalVariables__']) tmr.setInput('additionalVariables', process.env['__additionalVariables__']); +if (process.env['__caseInsensitivePaths__']) tmr.setInput('caseInsensitivePaths', process.env['__caseInsensitivePaths__']); +if (process.env['__charsToEscape__']) tmr.setInput('charsToEscape', process.env['__charsToEscape__']); +if (process.env['__encoding__']) tmr.setInput('encoding', process.env['__encoding__']); +if (process.env['__escape__']) tmr.setInput('escapeType', process.env['__escape__']); +if (process.env['__escapeChar__']) tmr.setInput('escapeChar', process.env['__escapeChar__']); +if (process.env['__ifNoFilesFound__']) tmr.setInput('actionOnNoFiles', process.env['__ifNoFilesFound__']); +if (process.env['__includeDotPaths__']) tmr.setInput('includeDotPaths', process.env['__includeDotPaths__']); +if (process.env['__logLevel__']) tmr.setInput('verbosity', process.env['__logLevel__']); +if (process.env['__missingVarAction__']) tmr.setInput('missingVarAction', process.env['__missingVarAction__']); +if (process.env['__missingVarDefault__']) tmr.setInput('defaultValue', process.env['__missingVarDefault__']); +if (process.env['__missingVarLog__']) tmr.setInput('actionOnMissing', process.env['__missingVarLog__']); +if (process.env['__recursive__']) tmr.setInput('enableRecursion', process.env['__recursive__']); +if (process.env['__root__']) tmr.setInput('rootDirectory', process.env['__root__']); +if (process.env['__separator__']) tmr.setInput('variableSeparator', process.env['__separator__']); +if (process.env['__telemetryOptout__']) tmr.setInput('telemetryOptout', process.env['__telemetryOptout__']); +if (process.env['__tokenPattern__']) tmr.setInput('tokenPattern', process.env['__tokenPattern__']); +if (process.env['__tokenPrefix__']) tmr.setInput('tokenPrefix', process.env['__tokenPrefix__']); +if (process.env['__tokenSuffix__']) tmr.setInput('tokenSuffix', process.env['__tokenSuffix__']); +if (process.env['__transforms__']) tmr.setInput('enableTransforms', process.env['__transforms__']); +if (process.env['__transformsPrefix__']) tmr.setInput('transformPrefix', process.env['__transformsPrefix__']); +if (process.env['__transformsSuffix__']) tmr.setInput('transformSuffix', process.env['__transformsSuffix__']); +if (process.env['__useAdditionalVariablesOnly__']) tmr.setInput('useAdditionalVariablesOnly', process.env['__useAdditionalVariablesOnly__']); + +// mocks +const rtClone = Object.assign({}, require('@qetza/replacetokens')); +rtClone.loadVariables = function (variables, options) { + console.log(`loadVariables_variables: ${JSON.stringify(variables)}`); + console.log(`loadVariables_options: ${JSON.stringify(options)}`); + + return Promise.resolve({}); +}; +rtClone.replaceTokens = function (sources, variables, options) { + console.log(`sources: ${JSON.stringify(sources)}`); + console.log(`options: ${JSON.stringify(options)}`); + + return Promise.resolve({ defaults: 1, files: 2, replaced: 3, tokens: 4, transforms: 5 }); +}; + +tmr.registerMock('@qetza/replacetokens', rtClone); + +const axiosClone = Object.assign({}, require('axios')); +axiosClone.default = Object.assign({}, axiosClone.default); +axiosClone.default.post = function () { + console.log('telemetry sent'); + + return Promise.resolve(); +}; + +tmr.registerMock('axios', axiosClone); + +// act +tmr.run(); diff --git a/tasks/ReplaceTokensV7/tests/_data/empty.expected.txt b/tasks/ReplaceTokensV7/tests/_data/empty.expected.txt new file mode 100644 index 0000000..69728ce --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/empty.expected.txt @@ -0,0 +1,2 @@ +var.var: var +empty: #{}# \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/empty.txt b/tasks/ReplaceTokensV7/tests/_data/empty.txt new file mode 100644 index 0000000..6d69125 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/empty.txt @@ -0,0 +1,2 @@ +var.var: #{var.VAR}# +empty: #{}# \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/file.expected.txt b/tasks/ReplaceTokensV7/tests/_data/file.expected.txt new file mode 100644 index 0000000..a59ea05 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/file.expected.txt @@ -0,0 +1,10 @@ +var.var: var +var.secret: secret +var1: env +var2: inline +var_json: file +var_yaml1: file +var_yaml2: file +var.yml1: file +var.yml2: inline +unknown: DEFAULT \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/file.only_additional_variables.expected.txt b/tasks/ReplaceTokensV7/tests/_data/file.only_additional_variables.expected.txt new file mode 100644 index 0000000..c16a750 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/file.only_additional_variables.expected.txt @@ -0,0 +1,10 @@ +var.var: DEFAULT +var.secret: DEFAULT +var1: env +var2: inline +var_json: file +var_yaml1: file +var_yaml2: file +var.yml1: file +var.yml2: inline +unknown: DEFAULT \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/file.txt b/tasks/ReplaceTokensV7/tests/_data/file.txt new file mode 100644 index 0000000..5099d22 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/file.txt @@ -0,0 +1,10 @@ +var.var: #{var.VAR}# +var.secret: #{VAR_secret}# +var1: #{VAR1}# +var2: #{VAR2}# +var_json: #{var_json}# +var_yaml1: #{var_yaml1}# +var_yaml2: #{var_yaml2}# +var.yml1: #{var.yml1}# +var.yml2: #{var.yml2}# +unknown: #{unknown}# \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/vars.jsonc b/tasks/ReplaceTokensV7/tests/_data/vars.jsonc new file mode 100644 index 0000000..51e3a46 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/vars.jsonc @@ -0,0 +1,3 @@ +{ + "var_json": "file" // comments +} \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/vars.xml b/tasks/ReplaceTokensV7/tests/_data/vars.xml new file mode 100644 index 0000000..0292b41 --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/vars.xml @@ -0,0 +1,3 @@ + + xml + \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/vars.yaml b/tasks/ReplaceTokensV7/tests/_data/vars.yaml new file mode 100644 index 0000000..79ac5bf --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/vars.yaml @@ -0,0 +1,3 @@ +var_yaml1: 'file' +--- +var_yaml2: 'file' \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tests/_data/vars.yml b/tasks/ReplaceTokensV7/tests/_data/vars.yml new file mode 100644 index 0000000..d5615fe --- /dev/null +++ b/tasks/ReplaceTokensV7/tests/_data/vars.yml @@ -0,0 +1,3 @@ +var.yml1: 'file' +--- +var.yml2: 'file' \ No newline at end of file diff --git a/tasks/ReplaceTokensV7/tsconfig.json b/tasks/ReplaceTokensV7/tsconfig.json new file mode 100644 index 0000000..403905a --- /dev/null +++ b/tasks/ReplaceTokensV7/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs", + "outDir": "./dist" + }, + "exclude": ["dist", "node_modules"] +} diff --git a/vss-extension.json b/vss-extension.json index 5726e41..371a1ad 100644 --- a/vss-extension.json +++ b/vss-extension.json @@ -2,7 +2,7 @@ "manifestVersion": 1, "id": "replacetokens", "name": "Replace Tokens", - "version": "5.3.1", + "version": "6.0.0", "public": true, "publisher": "qetza", "targets": [ From 97b65a2b1c9fcff97fce3ef1b8989fc84ec79ce2 Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 08:04:28 +0200 Subject: [PATCH 02/10] update ci workflow --- .github/workflows/ci.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5ea9b9..e75bfec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,10 +25,10 @@ jobs: with: python-version: '3.11' - - name: Setup nodejs 20.x + - name: Setup nodejs 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - name: Install dependencies run: | @@ -37,6 +37,7 @@ jobs: npm --prefix tasks/ReplaceTokensV4 ci npm --prefix tasks/ReplaceTokensV5 ci npm --prefix tasks/ReplaceTokensV6 ci + npm --prefix tasks/ReplaceTokensV7 ci - name: Check code format run: npm run format:check @@ -93,10 +94,10 @@ jobs: cp $env:RUNNER_TEMP/node6/node.exe $env:USERPROFILE/azure-pipelines-task-lib/_download/node6 echo '' > $env:USERPROFILE/azure-pipelines-task-lib/_download/node6.completed - - name: Setup nodejs 20.x + - name: Setup nodejs 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - name: Install dependencies run: | @@ -105,6 +106,7 @@ jobs: npm --prefix tasks/ReplaceTokensV4 ci npm --prefix tasks/ReplaceTokensV5 ci npm --prefix tasks/ReplaceTokensV6 ci + npm --prefix tasks/ReplaceTokensV7 ci - name: Test run: npm run test From ebd1bfc6d39ce96ef1a336e825ad13cc57342bbe Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 08:10:07 +0200 Subject: [PATCH 03/10] update ci workflow --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e75bfec..5509148 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,17 +18,17 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup python 3.11 uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Setup nodejs 24.x - uses: actions/setup-node@v4 + - name: Setup nodejs 24 + uses: actions/setup-node@v6 with: - node-version: 24.x + node-version: 24 - name: Install dependencies run: | @@ -57,7 +57,7 @@ jobs: needs: build steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup python 3.11 uses: actions/setup-python@v5 @@ -94,10 +94,10 @@ jobs: cp $env:RUNNER_TEMP/node6/node.exe $env:USERPROFILE/azure-pipelines-task-lib/_download/node6 echo '' > $env:USERPROFILE/azure-pipelines-task-lib/_download/node6.completed - - name: Setup nodejs 24.x - uses: actions/setup-node@v4 + - name: Setup nodejs 24 + uses: actions/setup-node@v6 with: - node-version: 24.x + node-version: 24 - name: Install dependencies run: | From 540191e8e54f35902e51b07593961a6907cbcb39 Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 08:25:37 +0200 Subject: [PATCH 04/10] macos manual download of node24 --- .github/workflows/ci.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5509148..6acedf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: with: python-version: '3.11' - - name: 'Hack: manual download of node6 (linux)' + - name: 'Hack: manual download of node (linux)' if: runner.os == 'Linux' run: | mkdir -p $RUNNER_TEMP/node6/node-v6.17.1-linux-x64 @@ -74,7 +74,7 @@ jobs: cp $RUNNER_TEMP/node6/node-v6.17.1-linux-x64/bin/node $HOME/azure-pipelines-task-lib/_download/node6/node-v6.17.1-linux-x64/bin echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed - - name: 'Hack: manual download of node6 (macos)' + - name: 'Hack: manual download of node (macos)' if: runner.os == 'macOS' run: | mkdir -p $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64 @@ -84,7 +84,14 @@ jobs: cp $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64/bin/node $HOME/azure-pipelines-task-lib/_download/node6/node-v6.17.1-darwin-x64/bin echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed - - name: 'Hack: manual download of node6 (windows)' + mkdir -p $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64 + curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64.tar.gz + tar xz --strip 1 -C $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64 -f $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64.tar.gz + mkdir -p $HOME/azure-pipelines-task-lib/_download/node24/node-v24.10.0-darwin-x64/bin + cp $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64/bin/node $HOME/azure-pipelines-task-lib/_download/node24/node-v24.10.0-darwin-x64/bin + echo '' > $HOME/azure-pipelines-task-lib/_download/node24.completed + + - name: 'Hack: manual download of node (windows)' if: runner.os == 'Windows' shell: pwsh run: | From d02070056e193cc914940a6f295eb36e3b2529f5 Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 08:44:13 +0200 Subject: [PATCH 05/10] increase test timeout --- .github/workflows/ci.yml | 4 ++-- tasks/ReplaceTokensV7/tests/L0.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6acedf6..af10e98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v6 - name: Setup python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.11' @@ -60,7 +60,7 @@ jobs: - uses: actions/checkout@v6 - name: Setup python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.11' diff --git a/tasks/ReplaceTokensV7/tests/L0.ts b/tasks/ReplaceTokensV7/tests/L0.ts index 7677791..ee5a267 100644 --- a/tasks/ReplaceTokensV7/tests/L0.ts +++ b/tasks/ReplaceTokensV7/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '..', '..', 'tests', '_data'); const tmp = path.join(__dirname, '..', '..', 'tests', '_tmp'); describe('ReplaceTokens v7 L0 suite', function () { - this.timeout(10000); + this.timeout(20000); beforeEach(() => { fs.mkdirSync(tmp, { recursive: true }); From bfd2571e56332659a9ffcf39ff506ccb0bb72cde Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 09:06:00 +0200 Subject: [PATCH 06/10] update manual download --- .github/workflows/ci.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af10e98..5daa92a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,18 +77,16 @@ jobs: - name: 'Hack: manual download of node (macos)' if: runner.os == 'macOS' run: | - mkdir -p $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64 - curl https://nodejs.org/dist/v6.17.1/node-v6.17.1-darwin-x64.tar.gz -o $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64.tar.gz - tar xz --strip 1 -C $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64 -f $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64.tar.gz - mkdir -p $HOME/azure-pipelines-task-lib/_download/node6/node-v6.17.1-darwin-x64/bin - cp $RUNNER_TEMP/node6/node-v6.17.1-darwin-x64/bin/node $HOME/azure-pipelines-task-lib/_download/node6/node-v6.17.1-darwin-x64/bin + rm -rf $HOME/azure-pipelines-task-lib/_download/node6 + mkdir -p $HOME/azure-pipelines-task-lib/_download/node6 + curl https://nodejs.org/dist/v6.17.1/node-v6.17.1-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz + tar -xzf $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed - mkdir -p $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64 - curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64.tar.gz - tar xz --strip 1 -C $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64 -f $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64.tar.gz - mkdir -p $HOME/azure-pipelines-task-lib/_download/node24/node-v24.10.0-darwin-x64/bin - cp $RUNNER_TEMP/node24/node-v24.10.0-darwin-x64/bin/node $HOME/azure-pipelines-task-lib/_download/node24/node-v24.10.0-darwin-x64/bin + rm -rf $HOME/azure-pipelines-task-lib/_download/node24 + mkdir -p $HOME/azure-pipelines-task-lib/_download/node24 + curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz + tar -xzf $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node24.completed - name: 'Hack: manual download of node (windows)' @@ -96,9 +94,14 @@ jobs: shell: pwsh run: | mkdir $env:RUNNER_TEMP/node6 > $null - curl https://nodejs.org/dist/v6.17.1/win-x64/node.exe -o $env:RUNNER_TEMP/node6/node.exe mkdir $env:USERPROFILE/azure-pipelines-task-lib/_download/node6 > $null + + curl https://nodejs.org/dist/v6.17.1/win-x64/node.exe -o $env:RUNNER_TEMP/node6/node.exe cp $env:RUNNER_TEMP/node6/node.exe $env:USERPROFILE/azure-pipelines-task-lib/_download/node6 + + curl https://nodejs.org/dist/v6.17.1/win-x64/node.lib -o $env:RUNNER_TEMP/node6/node.lib + cp $env:RUNNER_TEMP/node6/node.lib $env:USERPROFILE/azure-pipelines-task-lib/_download/node6 + echo '' > $env:USERPROFILE/azure-pipelines-task-lib/_download/node6.completed - name: Setup nodejs 24 From fff7abacd223eee664670fb3588bd407fe619339 Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 09:19:35 +0200 Subject: [PATCH 07/10] fix tar --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5daa92a..903ee19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,13 +80,13 @@ jobs: rm -rf $HOME/azure-pipelines-task-lib/_download/node6 mkdir -p $HOME/azure-pipelines-task-lib/_download/node6 curl https://nodejs.org/dist/v6.17.1/node-v6.17.1-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz - tar -xzf $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz + tar xzf $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed rm -rf $HOME/azure-pipelines-task-lib/_download/node24 mkdir -p $HOME/azure-pipelines-task-lib/_download/node24 curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz - tar -xzf $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz + tar xzf $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node24.completed - name: 'Hack: manual download of node (windows)' From 70e13746dd3b0a520c0c5c26bcdfe8a86ae3980c Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 09:35:45 +0200 Subject: [PATCH 08/10] fix tar --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 903ee19..31bc131 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,13 +80,13 @@ jobs: rm -rf $HOME/azure-pipelines-task-lib/_download/node6 mkdir -p $HOME/azure-pipelines-task-lib/_download/node6 curl https://nodejs.org/dist/v6.17.1/node-v6.17.1-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz - tar xzf $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz + tar xz -C $HOME/azure-pipelines-task-lib/_download/node6 -f $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed rm -rf $HOME/azure-pipelines-task-lib/_download/node24 mkdir -p $HOME/azure-pipelines-task-lib/_download/node24 curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz - tar xzf $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz + tar xz -C $HOME/azure-pipelines-task-lib/_download/node24 -f $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node24.completed - name: 'Hack: manual download of node (windows)' From 15936f15bb7d22a52325d48c6ce8a443217c40ea Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 09:45:35 +0200 Subject: [PATCH 09/10] increase test timeout --- .github/workflows/ci.yml | 6 ++++++ tasks/ReplaceTokensV5/tests/L0.ts | 2 +- tasks/ReplaceTokensV6/tests/L0.ts | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31bc131..ed32913 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,12 @@ jobs: tar xz -C $HOME/azure-pipelines-task-lib/_download/node6 -f $HOME/azure-pipelines-task-lib/_download/node6/node.tar.gz echo '' > $HOME/azure-pipelines-task-lib/_download/node6.completed + rm -rf $HOME/azure-pipelines-task-lib/_download/node20 + mkdir -p $HOME/azure-pipelines-task-lib/_download/node20 + curl https://nodejs.org/dist/v20.13.1/node-v20.13.1-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node20/node.tar.gz + tar xz -C $HOME/azure-pipelines-task-lib/_download/node20 -f $HOME/azure-pipelines-task-lib/_download/node20/node.tar.gz + echo '' > $HOME/azure-pipelines-task-lib/_download/node20.completed + rm -rf $HOME/azure-pipelines-task-lib/_download/node24 mkdir -p $HOME/azure-pipelines-task-lib/_download/node24 curl https://nodejs.org/dist/v24.10.0/node-v24.10.0-darwin-x64.tar.gz -o $HOME/azure-pipelines-task-lib/_download/node24/node.tar.gz diff --git a/tasks/ReplaceTokensV5/tests/L0.ts b/tasks/ReplaceTokensV5/tests/L0.ts index 4b97d04..b4e84fe 100644 --- a/tasks/ReplaceTokensV5/tests/L0.ts +++ b/tasks/ReplaceTokensV5/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '../../tests/_data'); const tmp = path.join(__dirname, '_tmp'); describe('ReplaceTokens v5 L0 suite', function () { - this.timeout(10000); + this.timeout(20000); function runValidation(validator: () => void, tr: ttm.MockTestRunner) { try { diff --git a/tasks/ReplaceTokensV6/tests/L0.ts b/tasks/ReplaceTokensV6/tests/L0.ts index bc849ed..b0b87e6 100644 --- a/tasks/ReplaceTokensV6/tests/L0.ts +++ b/tasks/ReplaceTokensV6/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '..', '..', 'tests', '_data'); const tmp = path.join(__dirname, '..', '..', 'tests', '_tmp'); describe('ReplaceTokens v6 L0 suite', function () { - this.timeout(10000); + this.timeout(20000); beforeEach(() => { fs.mkdirSync(tmp, { recursive: true }); From 2a8bc63365d48db073331cee51b196ae014fc00f Mon Sep 17 00:00:00 2001 From: Guillaume ROUCHON Date: Fri, 10 Apr 2026 09:59:31 +0200 Subject: [PATCH 10/10] increase timeout of first test --- tasks/ReplaceTokensV5/tests/L0.ts | 4 ++-- tasks/ReplaceTokensV6/tests/L0.ts | 4 ++-- tasks/ReplaceTokensV7/tests/L0.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tasks/ReplaceTokensV5/tests/L0.ts b/tasks/ReplaceTokensV5/tests/L0.ts index b4e84fe..19f5fd8 100644 --- a/tasks/ReplaceTokensV5/tests/L0.ts +++ b/tasks/ReplaceTokensV5/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '../../tests/_data'); const tmp = path.join(__dirname, '_tmp'); describe('ReplaceTokens v5 L0 suite', function () { - this.timeout(20000); + this.timeout(5000); function runValidation(validator: () => void, tr: ttm.MockTestRunner) { try { @@ -100,7 +100,7 @@ describe('ReplaceTokens v5 L0 suite', function () { runValidation(() => { tr.stdout.should.not.include('sent usage telemetry:'); }, tr); - }); + }).timeout(60000); it('should not call telemetry when disabled by REPLACETOKENS_DISABLE_TELEMETRY', async () => { // arrange diff --git a/tasks/ReplaceTokensV6/tests/L0.ts b/tasks/ReplaceTokensV6/tests/L0.ts index b0b87e6..9c87007 100644 --- a/tasks/ReplaceTokensV6/tests/L0.ts +++ b/tasks/ReplaceTokensV6/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '..', '..', 'tests', '_data'); const tmp = path.join(__dirname, '..', '..', 'tests', '_tmp'); describe('ReplaceTokens v6 L0 suite', function () { - this.timeout(20000); + this.timeout(5000); beforeEach(() => { fs.mkdirSync(tmp, { recursive: true }); @@ -103,7 +103,7 @@ describe('ReplaceTokens v6 L0 suite', function () { tr.stdout.should.include('##vso[task.complete result=Failed;]Error: Input required: sources'); }, tr); - }); + }).timeout(60000); it('validate: escape', async () => { // arrange diff --git a/tasks/ReplaceTokensV7/tests/L0.ts b/tasks/ReplaceTokensV7/tests/L0.ts index ee5a267..e35b0a2 100644 --- a/tasks/ReplaceTokensV7/tests/L0.ts +++ b/tasks/ReplaceTokensV7/tests/L0.ts @@ -9,7 +9,7 @@ const data = path.join(__dirname, '..', '..', 'tests', '_data'); const tmp = path.join(__dirname, '..', '..', 'tests', '_tmp'); describe('ReplaceTokens v7 L0 suite', function () { - this.timeout(20000); + this.timeout(5000); beforeEach(() => { fs.mkdirSync(tmp, { recursive: true }); @@ -103,7 +103,7 @@ describe('ReplaceTokens v7 L0 suite', function () { tr.stdout.should.include('##vso[task.complete result=Failed;]Error: Input required: sources'); }, tr); - }); + }).timeout(60000); it('validate: escape', async () => { // arrange