diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bd1026ec..d3bdade3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ All notable changes to the Wazuh App for Splunk project will be documented in th - Added support for Wazuh 4.6.0. - Added Files and Registries limits sections in configurations [#1395](https://github.com/wazuh/wazuh-splunk/pull/1395) +## Wazuh v4.5.2 - Splunk Enterprise v8.1.[1-10], v8.2.x - Revision 4503 + +### Added +- Added support for Wazuh 4.5.2. + ## Wazuh v4.5.1 - Splunk Enterprise v8.1.[1-10], v8.2.x - Revision 4502 ### Added diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 000000000..12dff9f32 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,241 @@ +## Releasing + +## Runbook + +### Overview + +### Release Phase 1 - Preparation + +#### Files + +The following files must be updated: + +- `package.json`: Defines the package manifest. It contains the following properties: + - `version`: Plugin version. Schema: `{major}.{minor}.{patch}`. Example: 4.4.5 + - `revision`: Plugin revision. Schema: number with 2 digits. This value is reset for each version to `01` and increament for following revisions. + - `splunk`: version of the plugin platform. +- `SplunkAppForWazuh/appserver/static/js/services/app-version/appVersionService.js`: Defines the plugin metadata. It contains the following properties: + - `version`: plugin version. + - `revision`: plugin revision. +- `SplunkAppForWazuh/default/app.conf`: Defines the plugin manifest. It contains the: + - `launcher.version`: plugin version. + - `install.build`: plugin revision. +- `SplunkAppForWazuh/default/package.conf`: Defines the another plugin manifest. It contains the `splunk.version` property. +- `CHANGELOG.md`: Changelog of the new release. +- `SplunkAppForWazuh/bin/api_info/endpoints.json`: Data related to endpoints and extracted from server's API +- `SplunkAppForWazuh/bin/api_info/security-actions.json`: Data related to security actions of extracted from server's API + +To bump the version, see [# Bump](#Bump) + +#### Create tags + +After the base branches have set the expected [# Files](#files), we must create the tags. + +The tag name follows the pattern: +- final release tag: `v{version}-{platform version}`. Example: `v4.4.5-8.1`. +- non-final release tag: `v{version}-{platform version}{suffix}`. Example: `v4.4.5-8.1-pre-alpha1`, `v4.4.5-8.1-alpha1`, `v4.4.5-8.1-rc1`. + +> See the [script instructions](#create-tags---script) that reduces this job. + +#### Create tags - Manually + +Steps: + +1. Switch and update the base branch + +``` +git checkout +git pull +``` + +2. Review if the version, revision and platform values are defined to the target release in the [#Files](#files), if not accomodate them (creating a new commit). + +3. Create the tag + +``` +git tag {tag} -a -m "Wazuh {version} for {platform} {platform version}" +``` + +> replace the placeholders: +> +> - `{tag}`: tag name. Use this schema: `v{version}-{platform version}`. We add suffixes for release candidates or alpha versions: +> - pre-alpha: `-pre-alpha{number}`. Example: `-pre-alpha1`. +> - release candidates: `-rc{number}`. Example: `-rc1`. +> - `{version}`: plugin version +> - `{platform}`: platform name. One of `OpenSearch` or `Kibana` +> - `{platform version}`: platform version. + +4. Push the tag + +``` +git push origin {tag} +``` + +> replace the placeholder: + +- `{tag}`: tag name + +#### Create tags - Script + +The process to create all the required tags can be run through a script ( `scripts/release/tag` ). + +For each supported version defined in `scripts/release/tag` + +- edit `version`, `revision` and `splunk` in package manifest file: `package.json` +- run a process to modify the rest of the manifest files. +- commit +- create tag +- push tag + +The script can be run through the package script `yarn release:tag` too. This is the prefered method because defines some required parameters. + +Steps: + +1. Ensure the target versions are defined as the supported versions in `scripts/release/tag` and the others files are updated. + Currently there are 2 versions: Splunk 8.1 and 8.2. + +2. Bump version/revision/platform version and create the local and remote tag using the package script + +```console +yarn release:tag --revision +``` + +> If the version or the revision is not specified, then it will use the current values from the package manifest file (package.json). +> You can bump the `version` or `platform-version` too or combine them. +> :warning: if the `version` is set, the base branches must exist in the remote repository. + +```console +yarn release:tag --version +yarn release:tag --revision +yarn release:tag --version --revision +``` + +Examples: + +- Change the plugin version + +``` +yarn release:tag --version 4.5.0 +``` +- Change the plugin revision + +``` +yarn release:tag --revision 02 +``` +``` +- Change the plugin version and revision + +``` +yarn release:tag --version 4.5.0 --revision 02 +``` +For tags that needs a suffix, use the `--tag-suffix ` flag. + +``` +yarn release:tag --tag-suffix +``` + +Example: + +``` +yarn release:tag --tag-suffix -rc2 --revision 02 +``` + +If you want to get a report of the tags generated and stored locally, use the `--export-tags `. + +``` +yarn release:tag --revision --export-tags +``` + +Example: + +``` +yarn release:tag --version 4.5.0 --export-tags tags.log +``` + +3. Review the new tags were pushed to the remote repository. + +### Build packages + +## Release Phase 2 - Release testing + +### Release Phase 3 - Release Announcement + +### Release Phase 4 - Post-Release + +### Bump + +It means to increment the version number to a new, unique value. + +Bumping the version requires to do some changes in the source code of the application. See [# Files](#files). + +We have a script (`scripts/release/bump`) to update some of these files: + +- package.json +- opensearch_dashboards.json or kibana.json + +This can be run through the `yarn release:bump` package script too. This is the prefered method because defines some required parameters. **The rest of the files should be changed manually.** + +> The package script sets some required parameters related to manifest files. + +Steps: + +1. Switch to new branch from the base branch to bump + +```console +git checkout +git pull +git checkout -b +``` + +2. Bump the version/revision/platform version using the package script + +```console +yarn release:bump --version +``` + +> You can bump the `revision` or `platform-version` too or combine them. + +```console +yarn release:bump --version +yarn release:bump --revision +yarn release:bump --platform-version +yarn release:bump --version --revision --platform-version +``` + +Examples: + +- Change the plugin version + +``` +yarn release:bump --version 4.5.0 +``` + +- Change the plugin revision + +``` +yarn release:bump --revision 02 +``` + +- Change the platform version + +``` +yarn release:bump --platform-version 8.2 +``` + +- Change the plugin version, revision and platform version + +``` +yarn release:bump --version 4.5.0 --revision 02 --platform-version 8.2 +``` + +3. Apply manually the changes to the rest of files if needed it. See [# Files](#Files). + +4. Optional. Commit and push the new branch to the remote repository. + +``` +git add . +git commit -m "bump: Bump version/revision/platform version to " +git push origin +``` + +A new branch will be created in the remote and will be ready to receive pull requests or use as source to create the tags. diff --git a/package.json b/package.json index 10b8b74fc..2828c66c1 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,9 @@ "lint": "make lint", "prebuild": "make prebuild", "pretty": "make pretty", - "test": "mocha tests/manager.js" + "test": "mocha tests/manager.js", + "release:bump": "node scripts/release/bump --manifest-package package.json", + "release:tag": "node scripts/release/tag --manifest-package package.json" }, "version": "4.8.0", "revision": "4800", diff --git a/scripts/release/bump.js b/scripts/release/bump.js new file mode 100644 index 000000000..7838fab2d --- /dev/null +++ b/scripts/release/bump.js @@ -0,0 +1,287 @@ +// NodeJS script which receives a version, revision and/or platform version and updates +// the package.json file +// Usage: node bump.js +// Help: node bump.js --help +// Examples: node bump.js --examples + +// Process +// 1. Take values from stdin +// 2. Edit the package and plugin manifest files +// 3. Display warning about manual changes + +const cliName = 'bump'; +const cliDescription = `Bump the plugin version, revision and/or platform version +Some warning messages are sent to stderr.`; + +// Default configuration +const defaultConfiguration = { + displayConfiguration: false, + displayExamples: false, + displayHelp: false, + version: '', + revision: '', + platformVersion: '', + manifestPackage: '', + manifestPlugin: '', +}; + +const logger = require('./lib/logger'); + +const { readPackageManifest } = require('./lib/read-manifest-package'); +const { updatePackageManifest } = require('./lib/update-manifest-package'); +const { updatePluginManifest } = require('./lib/update-manifest-plugin'); + +/** + * + * @param {String[]} input Input parameters + * @returns {Object} the configuration values + */ +function parse(input) { + const configuration = {}; + // Parse the input parameters + while (input.length) { + // Extract the first parameter + const [parameter] = input.splice(0, 1); + + // Compare the parameter + switch (parameter) { + case '--debug': + // Set the logger to debug mode + logger.setLevel(0); + break; + case '--display-configuration': + // Display the configuration + configuration.displayConfiguration = true; + break; + case '--examples': + // Display the examples + configuration.displayExamples = true; + break; + case '--help': + // Display the help + configuration.displayHelp = true; + break; + case '--version': { + // Set the version + const version = typeof input[0] === 'string' && input[0]; + + if (version) { + if (/\d+\.\d+\.\d+/.test(version)) { + configuration.version = version; + input.splice(0, 1); + } else { + logger.error( + 'version parameter is not valid. Expected format: X.Y.Z where X,Y, and Z are numbers.', + ); + process.exit(1); + } + } else { + logger.error('version parameter is not defined.'); + process.exit(1); + } + break; + } + case '--revision': { + // Set the version + const revision = typeof input[0] === 'string' && input[0]; + + if (revision) { + if (/\d{2}/.test(revision)) { + configuration.revision = revision; + input.splice(0, 1); + } else { + logger.error( + 'revision parameter is not valid. Expected format: Number', + ); + process.exit(1); + } + } else { + logger.error('revision parameter is not defined.'); + process.exit(1); + } + break; + } + case '--platform-version': { + // Set the version + const platformVersion = typeof input[0] === 'string' && input[0]; + + if (platformVersion) { + if (/\d+\.\d+(\.\d+)?/.test(platformVersion)) { + configuration.platformVersion = platformVersion; + input.splice(0, 1); + } else { + logger.error( + 'platform-version parameter is not valid. Expected format: X.Y.Z where X,Y, and Z are numbers.', + ); + process.exit(1); + } + } else { + logger.error('platform-version parameter is not defined.'); + process.exit(1); + } + break; + } + case '--manifest-package': { + // Set the version + const manifestPackage = typeof input[0] === 'string' && input[0]; + + if (manifestPackage) { + configuration.manifestPackage = manifestPackage; + input.splice(0, 1); + } else { + logger.error('manifest-package parameter is not defined.'); + process.exit(1); + } + break; + } + default: { + } + } + } + return configuration; +} + +const usageOptionsMessage = `Options: + --debug Set the logger to debug mode. + --display-configuration Display the configuration. Log to sterr. + --examples Display examples of usage. + --help Display the help. + --manifest-package Set the package manifest file location. + --platform-version Set the platform version. + --revision Set the revision. + --version Set the version.`; + +/** + * Display the CLI help + */ +function displayHelp() { + console.log(`${cliName} - Help +${cliDescription} + +Usage: node ${cliFilePath} [options] + +${usageOptionsMessage} +`); +} + +/** + * Display the examples + */ +function displayExamples() { + console.log(` +- Change the plugin version +node ${cliFilePath} --manifest-package package.json --version 4.5.0 + +- Change the plugin revision +node ${cliFilePath} --manifest-package package.json --revision 02 --manifest-package ../package.json + +- Change the platform version +node ${cliFilePath} --manifest-package package.json --platform-version 2.8.0 + +- Change the plugin version, revision and platform version +node ${cliFilePath} --manifest-package package.json --version 4.5.0 --revision 02 --platform-version 2.8.0 +`); +} + +// Display the message to do manual changes +function displayMessageManualChanges() { + logger.warn( + 'Some files could require to do changes manually. See RELEASING.md.', + ); +} + +function run(configuration) { + const { + version, + revision, + platformVersion, + manifestPackage, + manifestPlugin, + } = configuration; + version && logger.info(`Version: ${version}`); + revision && logger.info(`Revision: ${revision}`); + platformVersion && logger.info(`Platform version: ${platformVersion}`); + manifestPackage && logger.info(`Package manifest: ${manifestPackage}`); + manifestPlugin && logger.info(`Plugin manifest: ${manifestPlugin}`); + + logger.info( + 'This will update the manifest files: package and platform plugin.', + ); + + updatePackageManifest(manifestPackage, { + version, + revision, + platformVersion, + }); + + updatePluginManifest(); + + displayMessageManualChanges(); +} + +function main(input) { + try { + // Display the help information and exit if there is no parameters + if (input.length === 0) { + displayHelp(); + process.exit(1); + } + + const configuration = { + ...defaultConfiguration, + ...parse(input), + }; + + // Display the configuration + if (configuration.displayConfiguration) { + /* Send to stderr. This does the configuration can be displayed and redirect the stdout output + to a file */ + console.error(configuration); + } + + // Display the help + if (configuration.displayHelp) { + displayHelp(); + process.exit(0); + } + + // Display the examples of usage + if (configuration.displayExamples) { + displayExamples(); + process.exit(0); + } + + // Check version is set + if (!configuration.version || !configuration.revision) { + const { version: manifestVersion, revision: manifestRevision } = + readPackageManifest(configuration.manifestPackage); + if (!configuration.version) { + logger.warn( + `version is not defined. Using from the current package manifest ${configuration.manifestPackage}: ${manifestVersion}`, + ); + configuration.version = manifestVersion; + } + if (!configuration.revision) { + logger.warn( + `revision is not defined. Using from the current package manifest ${configuration.manifestPackage}: ${manifestRevision}`, + ); + configuration.revision = manifestRevision; + } + } + + run(configuration); + } catch (error) { + logger.error(`An unexpected error: ${error}. ${error.stack}`); + process.exit(1); + } +} + +module.exports = run; + +let cliFilePath = __dirname; + +if (require.main === module) { + cliFilePath = process.argv[1]; + const consoleInputParameters = [...process.argv].slice(2); + main(consoleInputParameters); +} diff --git a/scripts/release/lib/logger.js b/scripts/release/lib/logger.js new file mode 100644 index 000000000..17659895e --- /dev/null +++ b/scripts/release/lib/logger.js @@ -0,0 +1,20 @@ +let minimumLevel = 1; + +function setLevel(level) { + minimumLevel = level; +} + +function createLogLevel(tag, level, fn) { + return function (message) { + level >= minimumLevel && fn(`[${tag}]: ${message}`); + }; +} + +module.exports = { + info: createLogLevel('INFO', 2, console.log), + warn: createLogLevel('WARN', 1, console.log), + error: createLogLevel('ERROR', 2, console.log), + debug: createLogLevel('DEBUG', 0, console.log), + getLevel: () => minimumLevel, + setLevel: setLevel, +}; diff --git a/scripts/release/lib/read-manifest-package.js b/scripts/release/lib/read-manifest-package.js new file mode 100644 index 000000000..e4bdbbff2 --- /dev/null +++ b/scripts/release/lib/read-manifest-package.js @@ -0,0 +1,20 @@ +const logger = require('./logger'); + +function readPackageManifest(manifestPath) { + if (!manifestPath) { + logger.error( + `package manifest file is not defined. Use --manifest-package .`, + ); + process.exit(1); + } + const fs = require('fs'); + logger.debug(`Reading file ${manifestPath}`); + const packageJson = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + logger.debug(`Read file ${manifestPath}: ${JSON.stringify(packageJson)}`); + + return packageJson; +} + +module.exports = { + readPackageManifest: readPackageManifest, +}; diff --git a/scripts/release/lib/update-manifest-package.js b/scripts/release/lib/update-manifest-package.js new file mode 100644 index 000000000..290dc49ea --- /dev/null +++ b/scripts/release/lib/update-manifest-package.js @@ -0,0 +1,36 @@ +const logger = require('./logger'); + +function updatePackageManifest( + manifestPath, + { version, revision, platformVersion }, +) { + if (!manifestPath) { + logger.error( + `package manifest file is not defined. Use --manifest-package .`, + ); + process.exit(1); + } + const fs = require('fs'); + logger.debug(`Reading file ${manifestPath}`); + const packageJson = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + logger.debug(`Read file ${manifestPath}: ${JSON.stringify(packageJson)}`); + version && + (packageJson.version = version) && + logger.debug(`Change version to ${packageJson.version}`); + revision && + (packageJson.revision = revision) && + logger.debug(`Change revision to ${packageJson.revision}`); + platformVersion && + (packageJson.splunk = platformVersion) && + logger.debug( + `Change platform version to ${packageJson.splunk}`, + ); + + logger.debug(`Updating ${manifestPath}: ${JSON.stringify(packageJson)}`); + fs.writeFileSync(manifestPath, JSON.stringify(packageJson, null, 2)); + logger.info(`Updated ${manifestPath}`); +} + +module.exports = { + updatePackageManifest: updatePackageManifest, +}; diff --git a/scripts/release/lib/update-manifest-plugin.js b/scripts/release/lib/update-manifest-plugin.js new file mode 100644 index 000000000..bb0404157 --- /dev/null +++ b/scripts/release/lib/update-manifest-plugin.js @@ -0,0 +1,14 @@ +const logger = require('./logger'); +const { execSync } = require('child_process'); + +function updatePluginManifest() { + function execSystem(command) { + logger.info(`Run command: ${command}`); + execSync(command); + } + execSystem('node scripts/generate-build-version'); +} + +module.exports = { + updatePluginManifest: updatePluginManifest, +}; diff --git a/scripts/release/tag.js b/scripts/release/tag.js new file mode 100644 index 000000000..4e62d636f --- /dev/null +++ b/scripts/release/tag.js @@ -0,0 +1,428 @@ +// NodeJS script which creates the tags in local and remote for the supported versions. +// It receives a version, revision and/or platform version and for each +// supported version: updates the package and plugin manifest files and create the tag. +// Usage: node tag.js +// Help: node tag.js --help +// Examples: node tag.js --examples + +// Process +// 1. Parse stdin +// 2. For each supported platform version +// 2.1. Checkout to the platform base branch +// 2.2. Prune local branches and tags +// 2.3. Edit the package manifest file +// 2.4. Edit the plugin manifest file +// 2.5. Commit +// 2.6. Create tag +// 2.7. Push tag +// 2.8. Reset local branch to remote branch +// 3. Optional. Export tags to file + +const cliName = 'tag'; +const cliDescription = `Create the tags in remote repository for the supported versions. +Some warning messages are sent to stderr.`; + +// Default configuration +const defaultConfiguration = { + displayConfiguration: false, + displayExamples: false, + displayHelp: false, + version: '', + revision: '', + platformVersion: '', + ignoreConfirmation: false, + manifestPackage: '', + manifestPlugin: '', + tagSuffix: '', + exportTagsToFile: '', +}; + +const logger = require('./lib/logger'); + +const { readPackageManifest } = require('./lib/read-manifest-package'); +const bump = require('./bump'); +const readline = require('readline'); + +// Supported versions +function getSupportedVersions(pluginVersion) { + return { + Splunk: { + branch: pluginVersion, + versions: ['8.1', '8.2'], + } + }; +} + +/** + * + * @param {String[]} input Input parameters + * @returns {Object} the configuration values + */ +function parse(input) { + const configuration = {}; + // Parse the input parameters + while (input.length) { + // Extract the first parameter + const [parameter] = input.splice(0, 1); + + // Compare the parameter + switch (parameter) { + case '--debug': + // Set the logger to debug mode + logger.setLevel(0); + break; + case '--display-configuration': + // Display the configuration + configuration.displayConfiguration = true; + break; + case '--export-tags': { + // Export tags to file + const exportTagsToFile = typeof input[0] === 'string' && input[0]; + if (exportTagsToFile) { + configuration.exportTagsToFile = exportTagsToFile; + input.splice(0, 1); + } else { + logger.error('export-tags parameter is not defined.'); + process.exit(1); + } + break; + } + case '--examples': + // Display the examples + configuration.displayExamples = true; + break; + case '--help': + // Display the help + configuration.displayHelp = true; + break; + case '--ignore-confirmation': + // Display the help + configuration.ignoreConfirmation = true; + break; + case '--version': { + // Set the version + const version = typeof input[0] === 'string' && input[0]; + + if (version) { + if (/\d+\.\d+\.\d+/.test(version)) { + configuration.version = version; + input.splice(0, 1); + } else { + logger.error( + 'version parameter is not valid. Expected format: X.Y.Z where X,Y, and Z are numbers.', + ); + process.exit(1); + } + } else { + logger.error('version parameter is not defined.'); + process.exit(1); + } + break; + } + case '--revision': { + // Set the version + const revision = typeof input[0] === 'string' && input[0]; + + if (revision) { + if (/\d{2}/.test(revision)) { + configuration.revision = revision; + input.splice(0, 1); + } else { + logger.error( + 'revision parameter is not valid. Expected format: Number', + ); + process.exit(1); + } + } else { + logger.error('revision parameter is not defined.'); + process.exit(1); + } + break; + } + case '--tag-suffix': { + // Set the version + const tagSuffix = typeof input[0] === 'string' && input[0]; + + if (tagSuffix) { + configuration.tagSuffix = tagSuffix; + input.splice(0, 1); + } else { + logger.error('tag-suffix parameter is not defined.'); + process.exit(1); + } + break; + } + case '--manifest-package': { + // Set the version + const manifestPackage = typeof input[0] === 'string' && input[0]; + + if (manifestPackage) { + configuration.manifestPackage = manifestPackage; + input.splice(0, 1); + } else { + logger.error('manifest-package parameter is not defined.'); + process.exit(1); + } + break; + } + default: { + } + } + } + return configuration; +} + +const usageOptionsMessage = `Options: + --debug Set the logger to debug mode. + --display-configuration Display the configuration. Log to sterr. + --examples Display examples of usage. + --export-tags Export tags to file. + --help Display the help. + --ignore-confirmation Ignore the confirmation. + --manifest-package Set the package manifest file location. + --revision Set the revision. + --tag-suffix Set the tag suffix. + --version Set the version.`; + +/** + * Display the CLI help + */ +function displayHelp() { + console.log(`${cliName} - Help +${cliDescription} + +Usage: node ${cliFilePath} [options] + +${usageOptionsMessage} +`); +} + +/** + * Display the examples + */ +function displayExamples() { + console.log(` +- Change the plugin version +node ${cliFilePath} --manifest-package package.json --version 4.5.0 + +- Change the plugin revision +node ${cliFilePath} --manifest-package package.json --revision 02 + +- Change the plugin version, revision and platform version +node ${cliFilePath} --manifest-package package.json --version 4.5.0 + +- Change plugin revision and export tags to file +node ${cliFilePath} --manifest-package package.json --export-tags tags.log --revision 02 + +- Change plugin revision and ignoring the confirmation +node ${cliFilePath} --manifest-package package.json --ignore-confirmation --revision 02 + +- Change plugin revision and redirect the stdout and stderr to a file +node ${cliFilePath} --manifest-package package.json --ignore-confirmation --revision 02 &> /path/to/create_tags.log + +- Change plugin revision, redirect the stdout and stderr to a file and export tags to file +node ${cliFilePath} --manifest-package package.json --ignore-confirmation --revision 02 --export-tags tags.log &> /path/to/create_tags.log +`); +} + +async function question(question) { + return new Promise(res => { + const rd = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + rd.question(question, input => { + rd.close(); + res(input); + }); + }); +} + +async function requireConfirmation({ ignoreConfirmation }) { + logger.warn( + 'Ensure the base branches are created in the remote and they have updated the files: ' + + 'README.md, CHANGELOG.md, unit tests files, API data files. ' + + 'It does not modify these files.', + ); + + logger.warn( + 'This script will commit and push the tags to the remote repository, ' + + 'deleting any unpushed changes.', + ); + + if (!ignoreConfirmation) { + const response = await question('Do you want to continue? [y/N] '); + if (response.toLowerCase() !== 'y') { + logger.info('Aborting...'); + process.exit(0); + } + } +} + +async function run(configuration) { + let { + version, + revision, + platformVersion, + tagSuffix, + exportTagsToFile, + ignoreConfirmation, + } = configuration; + if (!version || !revision) { + const { version: manifestVersion, revision: manifestRevision } = + readPackageManifest(configuration.manifestPackage); + if (!version) { + logger.warn( + `version is not defined. Using from the current package manifest ${configuration.manifestPackage}: ${manifestVersion}`, + ); + configuration.version = version = manifestVersion; + } + if (!revision) { + logger.warn( + `revision is not defined. Using from the current package manifest ${configuration.manifestPackage}: ${manifestRevision}`, + ); + configuration.revision = revision = manifestRevision; + } + } + version && logger.info(`Version: ${version}`); + revision && logger.info(`Revision: ${revision}`); + platformVersion && logger.info(`Platform version: ${platformVersion}`); + tagSuffix && logger.info(`Tag suffix: ${tagSuffix}`); + exportTagsToFile && logger.info(`Export tags to file: ${exportTagsToFile}`); + + const supportedVersions = getSupportedVersions(version); + logger.info('Supported platforms'); + for (const platformID in supportedVersions) { + const { + branch, + versions: pluginPlatformVersions, + } = supportedVersions[platformID]; + logger.info( + `Platform: ${platformID} - Base branch: ${branch} - Versions: [${pluginPlatformVersions.join( + ', ', + )}]`, + ); + } + + await requireConfirmation({ ignoreConfirmation }); + + const { execSync } = require('child_process'); + + function execSystem(command) { + logger.info(`Run command: ${command}`); + return execSync(command); + } + + for (const platformID in supportedVersions) { + const { + branch, + versions: pluginPlatformVersions, + } = supportedVersions[platformID]; + + for (const pluginPlatformVersion of pluginPlatformVersions) { + logger.debug(`Switching to branch: ${branch}`); + execSystem(`git checkout ${branch}`); + logger.info(`Switched to branch: ${branch}`); + logger.debug('Pruning local branches and tags'); + execSystem('git fetch --prune --prune-tags'); + logger.info('Pruned local branches and tags'); + + const tag = `v${version}-${pluginPlatformVersion}${tagSuffix}`; + logger.info(`Generating tag: ${tag}...`); + + logger.info('Calling to bump script'); + const configurationBump = { + ...configuration, + platformVersion: pluginPlatformVersion, + }; + logger.debug( + `Configuration to use with the bump script: ${configurationBump}`, + ); + + bump(configurationBump); + + logger.debug('Checking if there are changes to commit'); + const thereChangesToCommit = + execSystem('git diff --exit-code --no-patch;echo -n $?').toString() === + '1'; + logger.debug(`Are there changes to commit?: ${thereChangesToCommit}`); + + if (thereChangesToCommit) { + logger.info('There are changes to commit.'); + logger.debug('Commiting'); + execSystem(`git commit -am "Bump ${tag}"`); + logger.info('Commited'); + } else { + logger.info('There are not changes to commit.'); + } + + logger.debug(`Creating tag: ${tag}`); + execSystem( + `git tag -a ${tag} -m "Wazuh ${version} for ${platformID} ${pluginPlatformVersion}"`, + ); + logger.info(`Created tag: ${tag}`); + logger.debug(`Pushing tag ${tag} to remote`); + execSystem(`git push origin ${tag}`); + logger.info(`Pushed tag ${tag} to remote`); + logger.debug('Undoing changes'); + execSystem(`git reset --hard origin/${branch}`); + logger.info('Undone changes'); + } + } + + if (exportTagsToFile) { + logger.debug(`Exporting tags to file ${exportTagsToFile}`); + execSystem( + `git tag | grep -P -i "^v${version}-.*${tagSuffix}" > ${exportTagsToFile}`, + ); + logger.info(`Exported tags to file ${exportTagsToFile}`); + } +} + +async function main(input) { + try { + // Display the help information and exit if there is no parameters + if (input.length === 0) { + displayHelp(); + process.exit(1); + } + + const configuration = { + ...defaultConfiguration, + ...parse(input), + }; + + // Display the configuration + if (configuration.displayConfiguration) { + console.error(configuration); // Send to stderr. This does the configuration can be displayed and redirect the stdout output to a file + } + + // Display the help + if (configuration.displayHelp) { + displayHelp(); + process.exit(0); + } + + // Display the examples of usage + if (configuration.displayExamples) { + displayExamples(); + process.exit(0); + } + + await run(configuration); + } catch (error) { + logger.error(`An unexpected error: ${error}. ${error.stack}`); + process.exit(1); + } +} + +module.exports = run; + +let cliFilePath; + +if (require.main === module) { + cliFilePath = process.argv[1]; + const consoleInputParameters = [...process.argv].slice(2); + main(consoleInputParameters); +}