From 86803765dacdd6458e297a7b2fd44cd3f6c02baf Mon Sep 17 00:00:00 2001 From: David Knise Date: Mon, 25 Sep 2023 11:27:43 -0700 Subject: [PATCH] v1.9.0 (#24) * v1.8.0 * Remove reverse feed direction change * Port over find latest version work to not assume a feed direction (#23) * v1.9.0 --- CHANGELOG.md | 26 -------- package-lock.json | 4 +- package.json | 2 +- src/msdo-nuget-client.ts | 139 +++++++++++++++++++++++++++++++-------- 4 files changed, 116 insertions(+), 55 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index df1066a..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,26 +0,0 @@ -# security-devops-azdevops-task-lib change log -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). - -## v1.7.2 - 06/21/2023 - -### Fixed -- Added try-catch best effort for gzip json response decompression from nuget.org -- Compile with nodenext moduleResolution so it implements a Promise resolver intead of yield on dynamic module resolution (node v13.2+) - - Resolves node and node10 task runners - -## v1.7.0 - 06/13/2023 - -### Added -- The `msdo-nuget-client.ts` javascript nuget client -- Dependency on adm-zip -- Dependency on decompress-response - -### Changed -- Install the MSDO nuget package via javascript - - Removes a dependency on dotnet to leverage restore to install the platform cross-platform -- Upgraded dependencies - - azure-pipelines-task-lib to v4.3.1 - - azure-pipelines-tool-lib to v2.0.4 - - typescript to v5.1.3 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 75b1ff8..91c2ff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@microsoft/security-devops-azdevops-task-lib", - "version": "1.7.2", + "version": "1.9.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@microsoft/security-devops-azdevops-task-lib", - "version": "1.7.2", + "version": "1.9.0", "license": "MIT", "dependencies": { "adm-zip": "0.5.10", diff --git a/package.json b/package.json index f68631c..fe27419 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/security-devops-azdevops-task-lib", - "version": "1.7.2", + "version": "1.9.0", "description": "Microsoft Security DevOps for Azure DevOps task library.", "author": "Microsoft Corporation", "license": "MIT", diff --git a/src/msdo-nuget-client.ts b/src/msdo-nuget-client.ts index 2333a62..b7cda61 100644 --- a/src/msdo-nuget-client.ts +++ b/src/msdo-nuget-client.ts @@ -228,50 +228,137 @@ async function _resolveVersion( let result = await requestJson(searchQueryServiceUrlWithQuery, requestOptions); const findPreRelease = common.isLatestPreRelease(packageVersion); + resolvedVersion = findLatestVersion(result, findPreRelease); + + if (resolvedVersion == null) { + throw new Error(`Package not found: ${packageName}`); + } + + return resolvedVersion; +} + +/** + * Finds the latest version in a SearchQueryService response. + * + * @param result A JSON object returned from the SearchQueryService + * @param findPreRelease Whether or not to find a pre-release version + * @returns The latest version of the package + */ +function findLatestVersion( + result: object, + findPreRelease: boolean): string { + let latestVersion = null; + let latestVersionParts = null; + let latestIsPreRelease = false; + let latestPreReleaseFlag = null; + + if (result == null || result['items'] == null) { + return latestVersion; + } + + let currentCatalogEntry = null; + let currentVersion = null; + let currentVersionParts = null; + let currentFullVersionParts = null; + let currentVersionNumbersString = null; + let currentIsLatest = false; + let currentIsPreRelease = false; + let currentPreReleaseFlag = null; + for (let packageGroup of result['items']) { for (let packageInfo of packageGroup['items']) { - let catalogEntry = packageInfo['catalogEntry']; - if (catalogEntry['listed'] != true) { + currentCatalogEntry = packageInfo['catalogEntry']; + + if (currentCatalogEntry['listed'] != true) { // skip delisted packages continue; } - if (!findPreRelease && common.isPreRelease(catalogEntry['version'])) { + currentVersion = currentCatalogEntry['version']; + currentIsPreRelease = common.isPreRelease(currentVersion); + + if (!findPreRelease && currentIsPreRelease) { // skip prerelease packages if we're looking for a stable version continue; } - resolvedVersion = catalogEntry['version']; - break; - } + currentFullVersionParts = currentVersion.split("-"); + if (currentIsPreRelease) { + currentPreReleaseFlag = currentFullVersionParts[1]; + } - if (resolvedVersion != null) { - break; - } - } - - if (resolvedVersion == null) { - throw new Error(`Package not found: ${packageName}`); - } + currentVersionNumbersString = currentFullVersionParts[0]; + currentVersionParts = currentVersionNumbersString.split("."); + currentIsLatest = latestVersion == null; - return resolvedVersion; -} + if (!currentIsLatest) { + // Evaluate the current version against the latest version + + // Handle comparisons of separate level versions + // Some packages exclude Patch or include Revisions up to two levels (Rev1 and Rev2) + let maxVersionParts = currentVersionParts.length; + if (currentVersionParts.length < maxVersionParts) { + maxVersionParts = latestVersionParts.length; + } -function rampedDeployment( - datetime: Date, - rampMinutes: number): boolean { - let ramped = false; + for (let versionPartIndex = 0; versionPartIndex < currentVersionParts.length; versionPartIndex++) { + let versionPart = 0; + let latestVersionPart = 0; - let curDate = new Date(); + let isLastVersionPart = versionPartIndex == (maxVersionParts - 1); - let diff = curDate.getTime() - datetime.getTime(); + if (versionPartIndex < currentVersionParts.length) { + versionPart = parseInt(currentVersionParts[versionPartIndex]); + } - datetime.setMinutes - - - return Math.random() > diff; + if (versionPartIndex < latestVersionParts.length) { + latestVersionPart = parseInt(latestVersionParts[versionPartIndex]); + } + + if (versionPart > latestVersionPart) { + currentIsLatest = true; + } else if (versionPart == latestVersionPart) { + currentIsLatest = isLastVersionPart + && + ( + (currentIsPreRelease && latestIsPreRelease && currentPreReleaseFlag > latestPreReleaseFlag) + || + (!currentIsPreRelease && latestIsPreRelease) + ); + } else { + // Current version is less than latest found + break; + } + + if (currentIsLatest) { + break; + } + } + } + + if (currentIsLatest) { + latestVersion = currentVersion; + latestVersionParts = currentVersionParts; + latestIsPreRelease = currentIsPreRelease; + latestPreReleaseFlag = currentPreReleaseFlag; + } + } + } + + tl.debug(`latestVersion = ${latestVersion}`); + return latestVersion; } +// function rampedDeployment( +// datetime: Date, +// rampMinutes: number): boolean { +// let ramped = false; +// let curDate = new Date(); +// let diff = curDate.getTime() - datetime.getTime(); +// datetime.setMinutes +// return Math.random() > diff; +// } + /** * Top level service call to download a package from a NuGet server. *