diff --git a/README.md b/README.md index 67a43b1..221df3c 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,12 @@ The parameters of the task are described bellow, in parenthesis is the YAML name - **Escape character** (escapeChar): when using `custom` escape type, the escape character to use when escaping characters in the variable values. - **Characters to escape** (charsToEscape): when using `custom` escape type, characters in variable values to escape before replacing tokens. - **Verbosity** (verbosity): specify the level of log verbosity. (note: error and system debug are always on) -- **Action** (actionOnMissing): specify the action to take on a missing variable. +- **Action on missing variable** (actionOnMissing): specify the action to take on a missing variable. - _silently continue_: the task will continue without displaying any message. - _log warning_: the task will continue but log a warning with the missing variable name. - _fail_: the task will fail and log the missing variable name. -- **Keep token** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Keep token for missing variable** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Action on no file processed** (actionOnNoFiles): specify the action when no file was processed. - **Token pattern** (tokenPattern): specify the pattern of the tokens to search in the target files. - **Token prefix** (tokenPrefix): when using `custom` token pattern, the prefix of the tokens to search in the target files. - **Token suffix** (tokenSuffix): when using `custom` token pattern, the suffix of the tokens to search in the target files. @@ -87,6 +88,15 @@ If you want to use tokens in XML based configuration files to be replaced during - replace tokens in your updated configuration file ## Release notes +**New in 4.1.0** +- Task **4.0.1** + - Promoted to release. + - Add `base64` transform ([#163](https://github.com/qetza/vsts-replacetokens-task/issues/163)). + - Add action on no file processed ([#210](https://github.com/qetza/vsts-replacetokens-task/issues/210)). +- Task **3.8.0** + - Add `base64` transform ([#163](https://github.com/qetza/vsts-replacetokens-task/issues/163)). + - Add action on no file processed ([#210](https://github.com/qetza/vsts-replacetokens-task/issues/210)). + **New in 4.0.0** - Add support for multiple task versions. - Add task 4.x (preview) diff --git a/ReplaceTokens/ReplaceTokensV3/README.md b/ReplaceTokens/ReplaceTokensV3/README.md index 10fd060..206d1f0 100644 --- a/ReplaceTokens/ReplaceTokensV3/README.md +++ b/ReplaceTokens/ReplaceTokensV3/README.md @@ -44,11 +44,12 @@ The parameters of the task are described bellow, in parenthesis is the YAML name - **Escape character** (escapeChar): when using `custom` escape type, the escape character to use when escaping characters in the variable values. - **Characters to escape** (charsToEscape): when using `custom` escape type, characters in variable values to escape before replacing tokens. - **Verbosity** (verbosity): specify the level of log verbosity. (note: error and system debug are always on) -- **Action** (actionOnMissing): specify the action to take on a missing variable. +- **Action on missing variable** (actionOnMissing): specify the action to take on a missing variable. - _silently continue_: the task will continue without displaying any message. - _log warning_: the task will continue but log a warning with the missing variable name. - _fail_: the task will fail and log the missing variable name. -- **Keep token** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Keep token for missing variable** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Action on no file processed** (actionOnNoFiles): specify the action when no file was processed. - **Token prefix** (tokenPrefix): the prefix of the tokens to search in the target files. - **Token suffix** (tokenSuffix): the suffix of the tokens to search in the target files. - **Use legacy pattern** (useLegacyPattern): if checked whitespaces between the token prefix/suffix and the variable name are not ignored. @@ -78,6 +79,7 @@ If you want to use tokens in XML based configuration files to be replaced during ## Release notes **New in 3.8.0** - Add `base64` transform ([#163](https://github.com/qetza/vsts-replacetokens-task/issues/163)). +- Add action on no file processed ([#210](https://github.com/qetza/vsts-replacetokens-task/issues/210)). **New in 3.7.1** - Fix issue on binary files ([#193](https://github.com/qetza/vsts-replacetokens-task/issues/193)). diff --git a/ReplaceTokens/ReplaceTokensV3/index.ts b/ReplaceTokens/ReplaceTokensV3/index.ts index 88dc539..bd494fe 100644 --- a/ReplaceTokens/ReplaceTokensV3/index.ts +++ b/ReplaceTokens/ReplaceTokensV3/index.ts @@ -337,7 +337,7 @@ var replaceTokensInFile = function ( case 'base64': value = Buffer.from(value).toString('base64'); break; - + default: --localCounter.Transforms; logger.warn(' unknown transform: ' + transformName); @@ -505,6 +505,7 @@ async function run() { }; let transformPrefix: string = tl.getInput('transformPrefix', true); let transformSuffix: string = tl.getInput('transformSuffix', true); + let actionOnNoFiles: string = tl.getInput('actionOnNoFiles', true); logger = new Logger(mapLogLevel(options.verbosity)); @@ -628,6 +629,7 @@ async function run() { telemetryEvent.transformSuffix = transformSuffix; telemetryEvent.transformPattern = transformPattern; telemetryEvent.defaultValue = options.defaultValue; + telemetryEvent.actionOnNoFiles = actionOnNoFiles; // process files rules.forEach(rule => { @@ -668,7 +670,19 @@ async function run() { // display summary let duration = (+new Date() - (+startTime)) / 1000; - logger.info('replaced ' + globalCounters.Replaced + ' tokens out of ' + globalCounters.Tokens + (globalCounters.DefaultValues ? ' (using ' + globalCounters.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + globalCounters.Transforms + ' functions' : '') + ' in ' + globalCounters.Files + ' file(s) in ' + duration + ' seconds.'); + + if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_WARN) + { + logger.warn('found no files to process.'); + } + else if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_FAIL) + { + logger.error('found no files to process.'); + } + else + { + logger.info('replaced ' + globalCounters.Replaced + ' tokens out of ' + globalCounters.Tokens + (globalCounters.DefaultValues ? ' (using ' + globalCounters.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + globalCounters.Transforms + ' functions' : '') + ' in ' + globalCounters.Files + ' file(s) in ' + duration + ' seconds.'); + } telemetryEvent.duration = duration; telemetryEvent.tokenReplaced = globalCounters.Replaced; diff --git a/ReplaceTokens/ReplaceTokensV3/task.json b/ReplaceTokens/ReplaceTokensV3/task.json index 250f3f5..31567bd 100644 --- a/ReplaceTokens/ReplaceTokensV3/task.json +++ b/ReplaceTokens/ReplaceTokensV3/task.json @@ -19,10 +19,20 @@ "minimumAgentVersion": "2.105.0", "groups": [ { - "name": "missing", - "displayName": "Missing variables", + "name": "validations", + "displayName": "Validations", "isExpanded": true }, + { + "name": "transforms", + "displayName": "Transformations", + "isExpanded": false + }, + { + "name": "variables", + "displayName": "Variables", + "isExpanded": false + }, { "name": "advanced", "displayName": "Advanced", @@ -116,9 +126,9 @@ { "name": "actionOnMissing", "type": "pickList", - "label": "Action", + "label": "Action on missing variable", "defaultValue": "warn", - "groupName": "missing", + "groupName": "validations", "required": true, "options": { "continue": "silently continue", @@ -130,12 +140,73 @@ { "name": "keepToken", "type": "boolean", - "label": "Keep token", + "label": "Keep token for missing variable", "defaultValue": "false", - "groupName": "missing", + "groupName": "validations", "required": true, "helpMarkDown": "If checked tokens with missing variables will not be replaced by empty string." }, + { + "name": "actionOnNoFiles", + "type": "pickList", + "label": "Action on no file found", + "defaultValue": "continue", + "groupName": "validations", + "required": true, + "options": { + "continue": "silently continue", + "warn": "log warning", + "fail": "fail" + }, + "helpMarkDown": "Specify the action when no file was found." + }, + { + "name": "enableTransforms", + "type": "boolean", + "label": "Enable transformations", + "defaultValue": "false", + "groupName": "transforms", + "required": true, + "helpMarkDown": "If checked transformations can be applied on variable values.
Syntax: {token prefix}{transformation name}{transform prefix}{token}{transform suffix}{token suffix}
Example: #{lower(MyVar)}#" + }, + { + "name": "transformPrefix", + "type": "string", + "label": "Transform prefix", + "defaultValue": "(", + "groupName": "transforms", + "required": true, + "helpMarkDown": "The prefix between transform name and token name.", + "visibleRule": "enableTransforms == true" + }, + { + "name": "transformSuffix", + "type": "string", + "label": "Transform suffix", + "defaultValue": ")", + "groupName": "transforms", + "required": true, + "helpMarkDown": "The suffix after the token name.", + "visibleRule": "enableTransforms == true" + }, + { + "name": "variableFiles", + "type": "multiLine", + "label": "Files (JSON or YAML)", + "defaultValue": "", + "groupName": "variables", + "required": false, + "helpMarkDown": "Absolute or relative comma or newline-separated paths to the files containing additional variables (wildcards can be used). YAML files must have the .yml or .yaml extension otherwise the file is treated as JSON." + }, + { + "name": "variableSeparator", + "type": "string", + "label": "Separator", + "defaultValue": ".", + "groupName": "variables", + "required": false, + "helpMarkDown": "The separtor to use in variable names for nested objects in variable files.
Example: {'My':{'Value':'Hello World!'}} will create a variable 'My.Value' with the value 'Hello World!'" + }, { "name": "tokenPrefix", "type": "string", @@ -181,54 +252,6 @@ "required": false, "helpMarkDown": "The value to be used if a variable is not found. Do not set to disable default value feature." }, - { - "name": "enableTransforms", - "type": "boolean", - "label": "Enable transformations", - "defaultValue": "false", - "groupName": "advanced", - "required": true, - "helpMarkDown": "If checked transformations can be applied on variable values.
Syntax: {token prefix}{transformation name}{transform prefix}{token}{transform suffix}{token suffix}
Example: #{lower(MyVar)}#" - }, - { - "name": "transformPrefix", - "type": "string", - "label": "Transform prefix", - "defaultValue": "(", - "groupName": "advanced", - "required": true, - "helpMarkDown": "The prefix between transform name and token name.", - "visibleRule": "enableTransforms == true" - }, - { - "name": "transformSuffix", - "type": "string", - "label": "Transform suffix", - "defaultValue": ")", - "groupName": "advanced", - "required": true, - "helpMarkDown": "The suffix after the token name.", - "visibleRule": "enableTransforms == true" - }, - { - "name": "variableFiles", - "type": "multiLine", - "label": "Variable files (JSON or YAML)", - "defaultValue": "", - "groupName": "advanced", - "required": false, - "helpMarkDown": "Absolute or relative comma or newline-separated paths to the files containing additional variables (wildcards can be used). YAML files must have the .yml or .yaml extension otherwise the file is treated as JSON." - }, - { - "name": "variableSeparator", - "type": "string", - "label": "Variable separator", - "defaultValue": ".", - "groupName": "advanced", - "required": false, - "visibleRule": "variableFiles != \"\"", - "helpMarkDown": "The separtor to use in variable names for nested objects in variable files.
Example: {'My':{'Value':'Hello World!'}} will create a variable 'My.Value' with the value 'Hello World!'" - }, { "name": "enableTelemetry", "type": "boolean", diff --git a/ReplaceTokens/ReplaceTokensV3/telemetry.ts b/ReplaceTokens/ReplaceTokensV3/telemetry.ts index 2d5a1b8..ddc4ffa 100644 --- a/ReplaceTokens/ReplaceTokensV3/telemetry.ts +++ b/ReplaceTokens/ReplaceTokensV3/telemetry.ts @@ -69,7 +69,8 @@ export default function trackEvent(event: TelemetryEvent, proxyUrl?: string): st transformPattern: event.transformPattern, transformExecuted: event.transformExecuted, defaultValue: event.defaultValue, - defaultValueReplaced: event.defaultValueReplaced + defaultValueReplaced: event.defaultValueReplaced, + actionOnNoFiles: event.actionOnNoFiles } } } @@ -172,4 +173,5 @@ export interface TelemetryEvent { transformExecuted: number; defaultValue: string; defaultValueReplaced: number; + actionOnNoFiles: string; } \ No newline at end of file diff --git a/ReplaceTokens/ReplaceTokensV4/README.md b/ReplaceTokens/ReplaceTokensV4/README.md index 4afe924..980e0be 100644 --- a/ReplaceTokens/ReplaceTokensV4/README.md +++ b/ReplaceTokens/ReplaceTokensV4/README.md @@ -44,11 +44,12 @@ The parameters of the task are described bellow, in parenthesis is the YAML name - **Escape character** (escapeChar): when using `custom` escape type, the escape character to use when escaping characters in the variable values. - **Characters to escape** (charsToEscape): when using `custom` escape type, characters in variable values to escape before replacing tokens. - **Verbosity** (verbosity): specify the level of log verbosity. (note: error and system debug are always on) -- **Action** (actionOnMissing): specify the action to take on a missing variable. +- **Action on missing variable** (actionOnMissing): specify the action to take on a missing variable. - _silently continue_: the task will continue without displaying any message. - _log warning_: the task will continue but log a warning with the missing variable name. - _fail_: the task will fail and log the missing variable name. -- **Keep token** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Keep token for missing variable** (keepToken): if checked tokens with missing variables will not be replaced by empty string. +- **Action on no file processed** (actionOnNoFiles): specify the action when no file was processed. - **Token pattern** (tokenPattern): specify the pattern of the tokens to search in the target files. - **Token prefix** (tokenPrefix): when using `custom` token pattern, the prefix of the tokens to search in the target files. - **Token suffix** (tokenSuffix): when using `custom` token pattern, the suffix of the tokens to search in the target files. @@ -88,4 +89,5 @@ If you want to use tokens in XML based configuration files to be replaced during **New in 4.0.0** - **Breaking change**: Add output variables ([#160](https://github.com/qetza/vsts-replacetokens-task/issues/160)). (some older version of TFS/Azure Pipelines doesn't support output variables when used in release pipelines) - **Breaking change**: Add dropdown parameter _Token pattern_ to select token pattern ([#131](https://github.com/qetza/vsts-replacetokens-task/issues/131)). (users with customized token pattern will need to manually select one or `custom`) -- Add `base64` transform ([#163](https://github.com/qetza/vsts-replacetokens-task/issues/163)). \ No newline at end of file +- Add `base64` transform ([#163](https://github.com/qetza/vsts-replacetokens-task/issues/163)). +- Add action on no file processed ([#210](https://github.com/qetza/vsts-replacetokens-task/issues/210)). \ No newline at end of file diff --git a/ReplaceTokens/ReplaceTokensV4/index.ts b/ReplaceTokens/ReplaceTokensV4/index.ts index a6549b7..4fd9617 100644 --- a/ReplaceTokens/ReplaceTokensV4/index.ts +++ b/ReplaceTokens/ReplaceTokensV4/index.ts @@ -333,7 +333,7 @@ var replaceTokensInFile = function ( case 'noescape': // nothing done here, disable escaping later break; - + case 'base64': value = Buffer.from(value).toString('base64'); break; @@ -506,6 +506,7 @@ async function run() { }; let transformPrefix: string = tl.getInput('transformPrefix', true); let transformSuffix: string = tl.getInput('transformSuffix', true); + let actionOnNoFiles: string = tl.getInput('actionOnNoFiles', true); logger = new Logger(mapLogLevel(options.verbosity)); @@ -658,6 +659,7 @@ async function run() { telemetryEvent.transformPattern = transformPattern; telemetryEvent.defaultValue = options.defaultValue; telemetryEvent.tokenPattern = tokenPattern; + telemetryEvent.actionOnNoFiles = actionOnNoFiles; // process files rules.forEach(rule => { @@ -705,7 +707,19 @@ async function run() { // display summary let duration = (+new Date() - (+startTime)) / 1000; - logger.info('replaced ' + globalCounters.Replaced + ' tokens out of ' + globalCounters.Tokens + (globalCounters.DefaultValues ? ' (using ' + globalCounters.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + globalCounters.Transforms + ' functions' : '') + ' in ' + globalCounters.Files + ' file(s) in ' + duration + ' seconds.'); + + if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_WARN) + { + logger.warn('found no files to process in ' + duration + ' seconds.'); + } + else if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_FAIL) + { + logger.error('found no files to process in ' + duration + ' seconds.'); + } + else + { + logger.info('replaced ' + globalCounters.Replaced + ' tokens out of ' + globalCounters.Tokens + (globalCounters.DefaultValues ? ' (using ' + globalCounters.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + globalCounters.Transforms + ' functions' : '') + ' in ' + globalCounters.Files + ' file(s) in ' + duration + ' seconds.'); + } telemetryEvent.duration = duration; telemetryEvent.tokenReplaced = globalCounters.Replaced; diff --git a/ReplaceTokens/ReplaceTokensV4/task.json b/ReplaceTokens/ReplaceTokensV4/task.json index cb39483..dbad899 100644 --- a/ReplaceTokens/ReplaceTokensV4/task.json +++ b/ReplaceTokens/ReplaceTokensV4/task.json @@ -13,17 +13,27 @@ "version": { "Major": 4, "Minor": 0, - "Patch": 0 + "Patch": 1 }, "releaseNotes": "Added output variables (breaking change).
Added token pattern dropdown (breaking change).", "instanceNameFormat": "Replace tokens in $(targetFiles)", "minimumAgentVersion": "2.105.0", "groups": [ { - "name": "missing", - "displayName": "Missing variables", + "name": "validations", + "displayName": "Validations", "isExpanded": true }, + { + "name": "transforms", + "displayName": "Transformations", + "isExpanded": false + }, + { + "name": "variables", + "displayName": "Variables", + "isExpanded": false + }, { "name": "advanced", "displayName": "Advanced", @@ -151,9 +161,9 @@ { "name": "actionOnMissing", "type": "pickList", - "label": "Action", + "label": "Action on missing variable", "defaultValue": "warn", - "groupName": "missing", + "groupName": "validations", "required": true, "options": { "continue": "silently continue", @@ -165,45 +175,32 @@ { "name": "keepToken", "type": "boolean", - "label": "Keep token", + "label": "Keep token for missing variable", "defaultValue": "false", - "groupName": "missing", + "groupName": "validations", "required": true, "helpMarkDown": "If checked tokens with missing variables will not be replaced by empty string." }, { - "name": "useLegacyPattern", - "type": "boolean", - "label": "Use legacy pattern", - "defaultValue": "false", - "groupName": "advanced", + "name": "actionOnNoFiles", + "type": "pickList", + "label": "Action on no file processed", + "defaultValue": "continue", + "groupName": "validations", "required": true, - "helpMarkDown": "If checked whitespaces between the token prefix/suffix and the variable name are not ignored." - }, - { - "name": "emptyValue", - "type": "string", - "label": "Empty value", - "defaultValue": "(empty)", - "groupName": "advanced", - "required": false, - "helpMarkDown": "The variable value which will be replaced by an empty string." - }, - { - "name": "defaultValue", - "type": "string", - "label": "Default value", - "defaultValue": "", - "groupName": "advanced", - "required": false, - "helpMarkDown": "The value to be used if a variable is not found. Do not set to disable default value feature." + "options": { + "continue": "silently continue", + "warn": "log warning", + "fail": "fail" + }, + "helpMarkDown": "Specify the action when no file was processed." }, { "name": "enableTransforms", "type": "boolean", "label": "Enable transformations", "defaultValue": "false", - "groupName": "advanced", + "groupName": "transforms", "required": true, "helpMarkDown": "If checked transformations can be applied on variable values.
Syntax: {token prefix}{transformation name}{transform prefix}{token}{transform suffix}{token suffix}
Example: #{lower(MyVar)}#" }, @@ -212,7 +209,7 @@ "type": "string", "label": "Transform prefix", "defaultValue": "(", - "groupName": "advanced", + "groupName": "transforms", "required": true, "helpMarkDown": "The prefix between transform name and token name.", "visibleRule": "enableTransforms == true" @@ -222,7 +219,7 @@ "type": "string", "label": "Transform suffix", "defaultValue": ")", - "groupName": "advanced", + "groupName": "transforms", "required": true, "helpMarkDown": "The suffix after the token name.", "visibleRule": "enableTransforms == true" @@ -230,22 +227,48 @@ { "name": "variableFiles", "type": "multiLine", - "label": "Variable files (JSON or YAML)", + "label": "Files (JSON or YAML)", "defaultValue": "", - "groupName": "advanced", + "groupName": "variables", "required": false, "helpMarkDown": "Absolute or relative comma or newline-separated paths to the files containing additional variables (wildcards can be used). YAML files must have the .yml or .yaml extension otherwise the file is treated as JSON." }, { "name": "variableSeparator", "type": "string", - "label": "Variable separator", + "label": "Separator", "defaultValue": ".", - "groupName": "advanced", + "groupName": "variables", "required": false, - "visibleRule": "variableFiles != \"\"", "helpMarkDown": "The separtor to use in variable names for nested objects in variable files.
Example: {'My':{'Value':'Hello World!'}} will create a variable 'My.Value' with the value 'Hello World!'" }, + { + "name": "useLegacyPattern", + "type": "boolean", + "label": "Use legacy pattern", + "defaultValue": "false", + "groupName": "advanced", + "required": true, + "helpMarkDown": "If checked whitespaces between the token prefix/suffix and the variable name are not ignored." + }, + { + "name": "emptyValue", + "type": "string", + "label": "Empty value", + "defaultValue": "(empty)", + "groupName": "advanced", + "required": false, + "helpMarkDown": "The variable value which will be replaced by an empty string." + }, + { + "name": "defaultValue", + "type": "string", + "label": "Default value", + "defaultValue": "", + "groupName": "advanced", + "required": false, + "helpMarkDown": "The value to be used if a variable is not found. Do not set to disable default value feature." + }, { "name": "enableTelemetry", "type": "boolean", diff --git a/ReplaceTokens/ReplaceTokensV4/telemetry.ts b/ReplaceTokens/ReplaceTokensV4/telemetry.ts index 67080e3..035d326 100644 --- a/ReplaceTokens/ReplaceTokensV4/telemetry.ts +++ b/ReplaceTokens/ReplaceTokensV4/telemetry.ts @@ -70,7 +70,8 @@ export default function trackEvent(event: TelemetryEvent, proxyUrl?: string): st transformExecuted: event.transformExecuted, defaultValue: event.defaultValue, defaultValueReplaced: event.defaultValueReplaced, - tokenPattern: event.tokenPattern + tokenPattern: event.tokenPattern, + actionOnNoFiles: event.actionOnNoFiles } } } @@ -174,4 +175,5 @@ export interface TelemetryEvent { defaultValue: string; defaultValueReplaced: number; tokenPattern: string; + actionOnNoFiles: string; } \ No newline at end of file