From 12144953c7207386b65ae4201015fd035b02ea6a Mon Sep 17 00:00:00 2001 From: Chris Syme Date: Tue, 2 Jan 2024 13:43:03 +1100 Subject: [PATCH] feat: Add support for providing a base branch and return diff of commits --- README.md | 2 + action.yml | 4 + dist/index.js | 796 +++++++++++++++------------------- src/input-parameters.ts | 6 +- src/push-build-information.ts | 44 +- 5 files changed, 400 insertions(+), 452 deletions(-) diff --git a/README.md b/README.md index c43ca038..90d24189 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ steps: | `server` | The instance URL hosting Octopus Deploy (i.e. "https://octopus.example.com/"). The instance URL is required, but you may also use the OCTOPUS_URL environment variable. | | `api_key` | The API key used to access Octopus Deploy. An API key is required, but you may also use the OCTOPUS_API_KEY environment variable. It is strongly recommended that this value retrieved from a GitHub secret. | | `space` | The name of a space within which this command will be executed. The space name is required, but you may also use the OCTOPUS_SPACE environment variable. | +| `base_branch` | The base branch to compare the commits to. If omitted only the last push commit will be used. | +| `github_token` | GitHub_Token used for API call. Used when base_branch is provided. | ## 🤝 Contributions diff --git a/action.yml b/action.yml index d44c2b36..c2009fc5 100644 --- a/action.yml +++ b/action.yml @@ -21,6 +21,10 @@ inputs: description: 'The base URL hosting Octopus Deploy (i.e. "https://octopus.example.com/"). It is recommended to retrieve this value from an environment variable.' space: description: 'The name or ID of a space within which this command will be executed. If omitted, the default space will be used.' + base_branch: + description: 'The base branch to compare the commits to. If omitted only the last push commit will be used.' + github_token: + description: 'GitHub_Token used for API call. Used when base_branch is provided.' runs: using: 'node20' diff --git a/dist/index.js b/dist/index.js index ed284d34..a47415b4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -558,7 +558,7 @@ class OidcClient { .catch(error => { throw new Error(`Failed to get ID Token. \n Error Code : ${error.statusCode}\n - Error Message: ${error.message}`); + Error Message: ${error.result.message}`); }); const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; if (!id_token) { @@ -38787,7 +38787,6 @@ class Comparator { } } - comp = comp.trim().split(/\s+/).join(' ') debug('comparator', comp, options) this.options = options this.loose = !!options.loose @@ -38850,6 +38849,13 @@ class Comparator { throw new TypeError('a Comparator is required') } + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false, + } + } + if (this.operator === '') { if (this.value === '') { return true @@ -38862,50 +38868,39 @@ class Comparator { return new Range(this.value, options).test(comp.semver) } - options = parseOptions(options) - - // Special cases where nothing can possibly be lower - if (options.includePrerelease && - (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) { - return false - } - if (!options.includePrerelease && - (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) { - return false - } + const sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>') + const sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<') + const sameSemVer = this.semver.version === comp.semver.version + const differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<=') + const oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, options) && + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<') + const oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, options) && + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>') - // Same direction increasing (> or >=) - if (this.operator.startsWith('>') && comp.operator.startsWith('>')) { - return true - } - // Same direction decreasing (< or <=) - if (this.operator.startsWith('<') && comp.operator.startsWith('<')) { - return true - } - // same SemVer and both sides are inclusive (<= or >=) - if ( - (this.semver.version === comp.semver.version) && - this.operator.includes('=') && comp.operator.includes('=')) { - return true - } - // opposite directions less than - if (cmp(this.semver, '<', comp.semver, options) && - this.operator.startsWith('>') && comp.operator.startsWith('<')) { - return true - } - // opposite directions greater than - if (cmp(this.semver, '>', comp.semver, options) && - this.operator.startsWith('<') && comp.operator.startsWith('>')) { - return true - } - return false + return ( + sameDirectionIncreasing || + sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || + oppositeDirectionsGreaterThan + ) } } module.exports = Comparator const parseOptions = __nccwpck_require__(785) -const { safeRe: re, t } = __nccwpck_require__(9523) +const { re, t } = __nccwpck_require__(9523) const cmp = __nccwpck_require__(5098) const debug = __nccwpck_require__(427) const SemVer = __nccwpck_require__(8088) @@ -38945,16 +38940,9 @@ class Range { this.loose = !!options.loose this.includePrerelease = !!options.includePrerelease - // First reduce all whitespace as much as possible so we do not have to rely - // on potentially slow regexes like \s*. This is then stored and used for - // future error messages as well. + // First, split based on boolean or || this.raw = range - .trim() - .split(/\s+/) - .join(' ') - - // First, split on || - this.set = this.raw + this.set = range .split('||') // map the range to a 2d array of comparators .map(r => this.parseRange(r.trim())) @@ -38964,7 +38952,7 @@ class Range { .filter(c => c.length) if (!this.set.length) { - throw new TypeError(`Invalid SemVer Range: ${this.raw}`) + throw new TypeError(`Invalid SemVer Range: ${range}`) } // if we have any that are not the null set, throw out null sets. @@ -38990,7 +38978,9 @@ class Range { format () { this.range = this.set - .map((comps) => comps.join(' ').trim()) + .map((comps) => { + return comps.join(' ').trim() + }) .join('||') .trim() return this.range @@ -39001,12 +38991,12 @@ class Range { } parseRange (range) { + range = range.trim() + // memoize range parsing for performance. // this is a very hot path, and fully deterministic. - const memoOpts = - (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | - (this.options.loose && FLAG_LOOSE) - const memoKey = memoOpts + ':' + range + const memoOpts = Object.keys(this.options).join(',') + const memoKey = `parseRange:${memoOpts}:${range}` const cached = cache.get(memoKey) if (cached) { return cached @@ -39017,18 +39007,18 @@ class Range { const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] range = range.replace(hr, hyphenReplace(this.options.includePrerelease)) debug('hyphen replace', range) - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) debug('comparator trim', range) // `~ 1.2.3` => `~1.2.3` range = range.replace(re[t.TILDETRIM], tildeTrimReplace) - debug('tilde trim', range) // `^ 1.2.3` => `^1.2.3` range = range.replace(re[t.CARETTRIM], caretTrimReplace) - debug('caret trim', range) + + // normalize spaces + range = range.split(/\s+/).join(' ') // At this point, the range is completely trimmed and // ready to be split into comparators. @@ -39114,7 +39104,6 @@ class Range { return false } } - module.exports = Range const LRU = __nccwpck_require__(1196) @@ -39125,13 +39114,12 @@ const Comparator = __nccwpck_require__(1532) const debug = __nccwpck_require__(427) const SemVer = __nccwpck_require__(8088) const { - safeRe: re, + re, t, comparatorTrimReplace, tildeTrimReplace, caretTrimReplace, } = __nccwpck_require__(9523) -const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = __nccwpck_require__(2293) const isNullSet = c => c.value === '<0.0.0-0' const isAny = c => c.value === '' @@ -39179,13 +39167,10 @@ const isX = id => !id || id.toLowerCase() === 'x' || id === '*' // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0 // ~0.0.1 --> >=0.0.1 <0.1.0-0 -const replaceTildes = (comp, options) => { - return comp - .trim() - .split(/\s+/) - .map((c) => replaceTilde(c, options)) - .join(' ') -} +const replaceTildes = (comp, options) => + comp.trim().split(/\s+/).map((c) => { + return replaceTilde(c, options) + }).join(' ') const replaceTilde = (comp, options) => { const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] @@ -39223,13 +39208,10 @@ const replaceTilde = (comp, options) => { // ^1.2.0 --> >=1.2.0 <2.0.0-0 // ^0.0.1 --> >=0.0.1 <0.0.2-0 // ^0.1.0 --> >=0.1.0 <0.2.0-0 -const replaceCarets = (comp, options) => { - return comp - .trim() - .split(/\s+/) - .map((c) => replaceCaret(c, options)) - .join(' ') -} +const replaceCarets = (comp, options) => + comp.trim().split(/\s+/).map((c) => { + return replaceCaret(c, options) + }).join(' ') const replaceCaret = (comp, options) => { debug('caret', comp, options) @@ -39286,10 +39268,9 @@ const replaceCaret = (comp, options) => { const replaceXRanges = (comp, options) => { debug('replaceXRanges', comp, options) - return comp - .split(/\s+/) - .map((c) => replaceXRange(c, options)) - .join(' ') + return comp.split(/\s+/).map((c) => { + return replaceXRange(c, options) + }).join(' ') } const replaceXRange = (comp, options) => { @@ -39372,15 +39353,12 @@ const replaceXRange = (comp, options) => { const replaceStars = (comp, options) => { debug('replaceStars', comp, options) // Looseness is ignored here. star is always as loose as it gets! - return comp - .trim() - .replace(re[t.STAR], '') + return comp.trim().replace(re[t.STAR], '') } const replaceGTE0 = (comp, options) => { debug('replaceGTE0', comp, options) - return comp - .trim() + return comp.trim() .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '') } @@ -39418,7 +39396,7 @@ const hyphenReplace = incPr => ($0, to = `<=${to}` } - return `${from} ${to}`.trim() + return (`${from} ${to}`).trim() } const testSet = (set, version, options) => { @@ -39465,7 +39443,7 @@ const testSet = (set, version, options) => { const debug = __nccwpck_require__(427) const { MAX_LENGTH, MAX_SAFE_INTEGER } = __nccwpck_require__(2293) -const { safeRe: re, t } = __nccwpck_require__(9523) +const { re, t } = __nccwpck_require__(9523) const parseOptions = __nccwpck_require__(785) const { compareIdentifiers } = __nccwpck_require__(2463) @@ -39481,7 +39459,7 @@ class SemVer { version = version.version } } else if (typeof version !== 'string') { - throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) + throw new TypeError(`Invalid Version: ${version}`) } if (version.length > MAX_LENGTH) { @@ -39640,36 +39618,36 @@ class SemVer { // preminor will bump the version up to the next minor release, and immediately // down to pre-release. premajor and prepatch work the same way. - inc (release, identifier, identifierBase) { + inc (release, identifier) { switch (release) { case 'premajor': this.prerelease.length = 0 this.patch = 0 this.minor = 0 this.major++ - this.inc('pre', identifier, identifierBase) + this.inc('pre', identifier) break case 'preminor': this.prerelease.length = 0 this.patch = 0 this.minor++ - this.inc('pre', identifier, identifierBase) + this.inc('pre', identifier) break case 'prepatch': // If this is already a prerelease, it will bump to the next version // drop any prereleases that might already exist, since they are not // relevant at this point. this.prerelease.length = 0 - this.inc('patch', identifier, identifierBase) - this.inc('pre', identifier, identifierBase) + this.inc('patch', identifier) + this.inc('pre', identifier) break // If the input is a non-prerelease version, this acts the same as // prepatch. case 'prerelease': if (this.prerelease.length === 0) { - this.inc('patch', identifier, identifierBase) + this.inc('patch', identifier) } - this.inc('pre', identifier, identifierBase) + this.inc('pre', identifier) break case 'major': @@ -39711,15 +39689,9 @@ class SemVer { break // This probably shouldn't be used publicly. // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. - case 'pre': { - const base = Number(identifierBase) ? 1 : 0 - - if (!identifier && identifierBase === false) { - throw new Error('invalid increment argument: identifier is empty') - } - + case 'pre': if (this.prerelease.length === 0) { - this.prerelease = [base] + this.prerelease = [0] } else { let i = this.prerelease.length while (--i >= 0) { @@ -39730,36 +39702,27 @@ class SemVer { } if (i === -1) { // didn't increment anything - if (identifier === this.prerelease.join('.') && identifierBase === false) { - throw new Error('invalid increment argument: identifier already exists') - } - this.prerelease.push(base) + this.prerelease.push(0) } } if (identifier) { // 1.2.0-beta.1 bumps to 1.2.0-beta.2, // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - let prerelease = [identifier, base] - if (identifierBase === false) { - prerelease = [identifier] - } if (compareIdentifiers(this.prerelease[0], identifier) === 0) { if (isNaN(this.prerelease[1])) { - this.prerelease = prerelease + this.prerelease = [identifier, 0] } } else { - this.prerelease = prerelease + this.prerelease = [identifier, 0] } } break - } + default: throw new Error(`invalid increment argument: ${release}`) } - this.raw = this.format() - if (this.build.length) { - this.raw += `+${this.build.join('.')}` - } + this.format() + this.raw = this.version return this } } @@ -39846,7 +39809,7 @@ module.exports = cmp const SemVer = __nccwpck_require__(8088) const parse = __nccwpck_require__(5925) -const { safeRe: re, t } = __nccwpck_require__(9523) +const { re, t } = __nccwpck_require__(9523) const coerce = (version, options) => { if (version instanceof SemVer) { @@ -39940,69 +39903,27 @@ module.exports = compare /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const parse = __nccwpck_require__(5925) +const eq = __nccwpck_require__(1898) const diff = (version1, version2) => { - const v1 = parse(version1, null, true) - const v2 = parse(version2, null, true) - const comparison = v1.compare(v2) - - if (comparison === 0) { + if (eq(version1, version2)) { return null - } - - const v1Higher = comparison > 0 - const highVersion = v1Higher ? v1 : v2 - const lowVersion = v1Higher ? v2 : v1 - const highHasPre = !!highVersion.prerelease.length - const lowHasPre = !!lowVersion.prerelease.length - - if (lowHasPre && !highHasPre) { - // Going from prerelease -> no prerelease requires some special casing - - // If the low version has only a major, then it will always be a major - // Some examples: - // 1.0.0-1 -> 1.0.0 - // 1.0.0-1 -> 1.1.1 - // 1.0.0-1 -> 2.0.0 - if (!lowVersion.patch && !lowVersion.minor) { - return 'major' - } - - // Otherwise it can be determined by checking the high version - - if (highVersion.patch) { - // anything higher than a patch bump would result in the wrong version - return 'patch' - } - - if (highVersion.minor) { - // anything higher than a minor bump would result in the wrong version - return 'minor' + } else { + const v1 = parse(version1) + const v2 = parse(version2) + const hasPre = v1.prerelease.length || v2.prerelease.length + const prefix = hasPre ? 'pre' : '' + const defaultResult = hasPre ? 'prerelease' : '' + for (const key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return prefix + key + } + } } - - // bumping major/minor/patch all have same result - return 'major' - } - - // add the `pre` prefix if we are going to a prerelease version - const prefix = highHasPre ? 'pre' : '' - - if (v1.major !== v2.major) { - return prefix + 'major' - } - - if (v1.minor !== v2.minor) { - return prefix + 'minor' - } - - if (v1.patch !== v2.patch) { - return prefix + 'patch' + return defaultResult // may be undefined } - - // high and low are preleases - return 'prerelease' } - module.exports = diff @@ -40043,9 +39964,8 @@ module.exports = gte const SemVer = __nccwpck_require__(8088) -const inc = (version, release, options, identifier, identifierBase) => { +const inc = (version, release, options, identifier) => { if (typeof (options) === 'string') { - identifierBase = identifier identifier = options options = undefined } @@ -40054,7 +39974,7 @@ const inc = (version, release, options, identifier, identifierBase) => { return new SemVer( version instanceof SemVer ? version.version : version, options - ).inc(release, identifier, identifierBase).version + ).inc(release, identifier).version } catch (er) { return null } @@ -40117,18 +40037,35 @@ module.exports = neq /***/ 5925: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +const { MAX_LENGTH } = __nccwpck_require__(2293) +const { re, t } = __nccwpck_require__(9523) const SemVer = __nccwpck_require__(8088) -const parse = (version, options, throwErrors = false) => { + +const parseOptions = __nccwpck_require__(785) +const parse = (version, options) => { + options = parseOptions(options) + if (version instanceof SemVer) { return version } + + if (typeof version !== 'string') { + return null + } + + if (version.length > MAX_LENGTH) { + return null + } + + const r = options.loose ? re[t.LOOSE] : re[t.FULL] + if (!r.test(version)) { + return null + } + try { return new SemVer(version, options) } catch (er) { - if (!throwErrors) { - return null - } - throw er + return null } } @@ -40308,7 +40245,6 @@ module.exports = { src: internalRe.src, tokens: internalRe.t, SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION, - RELEASE_TYPES: constants.RELEASE_TYPES, compareIdentifiers: identifiers.compareIdentifiers, rcompareIdentifiers: identifiers.rcompareIdentifiers, } @@ -40330,29 +40266,11 @@ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || // Max safe segment length for coercion. const MAX_SAFE_COMPONENT_LENGTH = 16 -// Max safe length for a build identifier. The max length minus 6 characters for -// the shortest version with a build 0.0.0+BUILD. -const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 - -const RELEASE_TYPES = [ - 'major', - 'premajor', - 'minor', - 'preminor', - 'patch', - 'prepatch', - 'prerelease', -] - module.exports = { + SEMVER_SPEC_VERSION, MAX_LENGTH, - MAX_SAFE_COMPONENT_LENGTH, - MAX_SAFE_BUILD_LENGTH, MAX_SAFE_INTEGER, - RELEASE_TYPES, - SEMVER_SPEC_VERSION, - FLAG_INCLUDE_PRERELEASE: 0b001, - FLAG_LOOSE: 0b010, + MAX_SAFE_COMPONENT_LENGTH, } @@ -40407,20 +40325,16 @@ module.exports = { /***/ 785: /***/ ((module) => { -// parse out just the options we care about -const looseOption = Object.freeze({ loose: true }) -const emptyOpts = Object.freeze({ }) -const parseOptions = options => { - if (!options) { - return emptyOpts - } - - if (typeof options !== 'object') { - return looseOption - } - - return options -} +// parse out just the options we care about so we always get a consistent +// obj with keys in a consistent order. +const opts = ['includePrerelease', 'loose', 'rtl'] +const parseOptions = options => + !options ? {} + : typeof options !== 'object' ? { loose: true } + : opts.filter(k => options[k]).reduce((o, k) => { + o[k] = true + return o + }, {}) module.exports = parseOptions @@ -40429,52 +40343,22 @@ module.exports = parseOptions /***/ 9523: /***/ ((module, exports, __nccwpck_require__) => { -const { - MAX_SAFE_COMPONENT_LENGTH, - MAX_SAFE_BUILD_LENGTH, - MAX_LENGTH, -} = __nccwpck_require__(2293) +const { MAX_SAFE_COMPONENT_LENGTH } = __nccwpck_require__(2293) const debug = __nccwpck_require__(427) exports = module.exports = {} // The actual regexps go on exports.re const re = exports.re = [] -const safeRe = exports.safeRe = [] const src = exports.src = [] const t = exports.t = {} let R = 0 -const LETTERDASHNUMBER = '[a-zA-Z0-9-]' - -// Replace some greedy regex tokens to prevent regex dos issues. These regex are -// used internally via the safeRe object since all inputs in this library get -// normalized first to trim and collapse all extra whitespace. The original -// regexes are exported for userland consumption and lower level usage. A -// future breaking change could export the safer regex only with a note that -// all input should have extra whitespace removed. -const safeRegexReplacements = [ - ['\\s', 1], - ['\\d', MAX_LENGTH], - [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], -] - -const makeSafeRegex = (value) => { - for (const [token, max] of safeRegexReplacements) { - value = value - .split(`${token}*`).join(`${token}{0,${max}}`) - .split(`${token}+`).join(`${token}{1,${max}}`) - } - return value -} - const createToken = (name, value, isGlobal) => { - const safe = makeSafeRegex(value) const index = R++ debug(name, index, value) t[name] = index src[index] = value re[index] = new RegExp(value, isGlobal ? 'g' : undefined) - safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) } // The following Regular Expressions can be used for tokenizing, @@ -40484,13 +40368,13 @@ const createToken = (name, value, isGlobal) => { // A single `0`, or a non-zero digit followed by zero or more digits. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') -createToken('NUMERICIDENTIFIERLOOSE', '\\d+') +createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+') // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. -createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) +createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*') // ## Main Version // Three dot-separated numeric identifiers. @@ -40525,7 +40409,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. -createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) +createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+') // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata @@ -41455,7 +41339,7 @@ const Range = __nccwpck_require__(9828) const intersects = (r1, r2, options) => { r1 = new Range(r1, options) r2 = new Range(r2, options) - return r1.intersects(r2, options) + return r1.intersects(r2) } module.exports = intersects @@ -41818,9 +41702,6 @@ const subset = (sub, dom, options = {}) => { return true } -const minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')] -const minimumVersion = [new Comparator('>=0.0.0')] - const simpleSubset = (sub, dom, options) => { if (sub === dom) { return true @@ -41830,9 +41711,9 @@ const simpleSubset = (sub, dom, options) => { if (dom.length === 1 && dom[0].semver === ANY) { return true } else if (options.includePrerelease) { - sub = minimumVersionWithPreRelease + sub = [new Comparator('>=0.0.0-0')] } else { - sub = minimumVersion + sub = [new Comparator('>=0.0.0')] } } @@ -41840,7 +41721,7 @@ const simpleSubset = (sub, dom, options) => { if (options.includePrerelease) { return true } else { - dom = minimumVersion + dom = [new Comparator('>=0.0.0')] } } @@ -49212,95 +49093,95 @@ function wrappy (fn, cb) { /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -const core_1 = __nccwpck_require__(2186); -const github_1 = __nccwpck_require__(5438); -const inputs = __importStar(__nccwpck_require__(9519)); -const octopus = __importStar(__nccwpck_require__(3269)); -const api_client_1 = __nccwpck_require__(586); -const process_1 = __importDefault(__nccwpck_require__(7282)); -(() => __awaiter(void 0, void 0, void 0, function* () { - try { - const runId = github_1.context.runId; - if (runId === undefined) { - (0, core_1.setFailed)('GitHub run number is not defined'); - return; - } - const logger = { - debug: message => { - if ((0, core_1.isDebug)()) { - (0, core_1.debug)(message); - } - }, - info: message => (0, core_1.info)(message), - warn: message => (0, core_1.warning)(message), - error: (message, err) => { - if (err !== undefined) { - (0, core_1.error)(err.message); - } - else { - (0, core_1.error)(message); - } - } - }; - const inputParameters = inputs.get(parseInt(process_1.default.env['GITHUB_RUN_ATTEMPT'] || '0') > 1); - const config = { - userAgentApp: 'GitHubActions (build-information;push;v3)', - instanceURL: inputParameters.server, - apiKey: inputParameters.apiKey, - accessToken: inputParameters.accessToken, - logging: logger - }; - const client = yield api_client_1.Client.create(config); - if (client === undefined) - throw new Error('Client could not be constructed'); - yield octopus.pushBuildInformationFromInputs(client, runId, inputParameters); - } - catch (e) { - if (e instanceof Error) { - (0, core_1.setFailed)(e); - } - else { - (0, core_1.setFailed)(`Unknown error: ${e}`); - } - } -}))(); + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const core_1 = __nccwpck_require__(2186); +const github_1 = __nccwpck_require__(5438); +const inputs = __importStar(__nccwpck_require__(9519)); +const octopus = __importStar(__nccwpck_require__(3269)); +const api_client_1 = __nccwpck_require__(586); +const process_1 = __importDefault(__nccwpck_require__(7282)); +(() => __awaiter(void 0, void 0, void 0, function* () { + try { + const runId = github_1.context.runId; + if (runId === undefined) { + (0, core_1.setFailed)('GitHub run number is not defined'); + return; + } + const logger = { + debug: message => { + if ((0, core_1.isDebug)()) { + (0, core_1.debug)(message); + } + }, + info: message => (0, core_1.info)(message), + warn: message => (0, core_1.warning)(message), + error: (message, err) => { + if (err !== undefined) { + (0, core_1.error)(err.message); + } + else { + (0, core_1.error)(message); + } + } + }; + const inputParameters = inputs.get(parseInt(process_1.default.env['GITHUB_RUN_ATTEMPT'] || '0') > 1); + const config = { + userAgentApp: 'GitHubActions (build-information;push;v3)', + instanceURL: inputParameters.server, + apiKey: inputParameters.apiKey, + accessToken: inputParameters.accessToken, + logging: logger + }; + const client = yield api_client_1.Client.create(config); + if (client === undefined) + throw new Error('Client could not be constructed'); + yield octopus.pushBuildInformationFromInputs(client, runId, inputParameters); + } + catch (e) { + if (e instanceof Error) { + (0, core_1.setFailed)(e); + } + else { + (0, core_1.setFailed)(`Unknown error: ${e}`); + } + } +}))(); /***/ }), @@ -49309,46 +49190,48 @@ const process_1 = __importDefault(__nccwpck_require__(7282)); /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.get = void 0; -const core_1 = __nccwpck_require__(2186); -const api_client_1 = __nccwpck_require__(586); -const EnvironmentVariables = { - URL: 'OCTOPUS_URL', - ApiKey: 'OCTOPUS_API_KEY', - AccessToken: 'OCTOPUS_ACCESS_TOKEN', - Space: 'OCTOPUS_SPACE' -}; -function get(isRetry) { - const overwriteMode = api_client_1.OverwriteMode[(0, core_1.getInput)('overwrite_mode')] || - (isRetry ? api_client_1.OverwriteMode.IgnoreIfExists : api_client_1.OverwriteMode.FailIfExists); - const parameters = { - server: (0, core_1.getInput)('server') || process.env[EnvironmentVariables.URL] || '', - apiKey: (0, core_1.getInput)('api_key') || process.env[EnvironmentVariables.ApiKey], - accessToken: process.env[EnvironmentVariables.AccessToken], - space: (0, core_1.getInput)('space') || process.env[EnvironmentVariables.Space] || '', - packages: (0, core_1.getMultilineInput)('packages', { required: true }), - version: (0, core_1.getInput)('version', { required: true }), - branch: (0, core_1.getInput)('branch') || undefined, - overwriteMode - }; - const errors = []; - if (!parameters.server) { - errors.push("The Octopus instance URL is required, please specify explicitly through the 'server' input or set the OCTOPUS_URL environment variable."); - } - if (!parameters.apiKey && !parameters.accessToken) { - errors.push("The Octopus API Key is required, please specify explicitly through the 'api_key' input or set the OCTOPUS_API_KEY environment variable."); - } - if (!parameters.space) { - errors.push("The Octopus space name is required, please specify explicitly through the 'space' input or set the OCTOPUS_SPACE environment variable."); - } - if (errors.length > 0) { - throw new Error(errors.join('\n')); - } - return parameters; -} -exports.get = get; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.get = void 0; +const core_1 = __nccwpck_require__(2186); +const api_client_1 = __nccwpck_require__(586); +const EnvironmentVariables = { + URL: 'OCTOPUS_URL', + ApiKey: 'OCTOPUS_API_KEY', + AccessToken: 'OCTOPUS_ACCESS_TOKEN', + Space: 'OCTOPUS_SPACE' +}; +function get(isRetry) { + const overwriteMode = api_client_1.OverwriteMode[(0, core_1.getInput)('overwrite_mode')] || + (isRetry ? api_client_1.OverwriteMode.IgnoreIfExists : api_client_1.OverwriteMode.FailIfExists); + const parameters = { + server: (0, core_1.getInput)('server') || process.env[EnvironmentVariables.URL] || '', + apiKey: (0, core_1.getInput)('api_key') || process.env[EnvironmentVariables.ApiKey], + accessToken: process.env[EnvironmentVariables.AccessToken], + space: (0, core_1.getInput)('space') || process.env[EnvironmentVariables.Space] || '', + packages: (0, core_1.getMultilineInput)('packages', { required: true }), + version: (0, core_1.getInput)('version', { required: true }), + branch: (0, core_1.getInput)('branch') || undefined, + overwriteMode, + baseBranch: (0, core_1.getInput)('base_branch') || undefined, + githubToken: (0, core_1.getInput)('github_token') + }; + const errors = []; + if (!parameters.server) { + errors.push("The Octopus instance URL is required, please specify explicitly through the 'server' input or set the OCTOPUS_URL environment variable."); + } + if (!parameters.apiKey && !parameters.accessToken) { + errors.push("The Octopus API Key is required, please specify explicitly through the 'api_key' input or set the OCTOPUS_API_KEY environment variable."); + } + if (!parameters.space) { + errors.push("The Octopus space name is required, please specify explicitly through the 'space' input or set the OCTOPUS_SPACE environment variable."); + } + if (errors.length > 0) { + throw new Error(errors.join('\n')); + } + return parameters; +} +exports.get = get; /***/ }), @@ -49357,64 +49240,87 @@ exports.get = get; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.pushBuildInformationFromInputs = void 0; -const core_1 = __nccwpck_require__(2186); -const github_1 = __nccwpck_require__(5438); -const api_client_1 = __nccwpck_require__(586); -function pushBuildInformationFromInputs(client, runId, parameters) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - let branch = parameters.branch || github_1.context.ref; - if (branch.startsWith('refs/heads/')) { - branch = branch.substring('refs/heads/'.length); - } - const repoUri = `${github_1.context.serverUrl}/${github_1.context.repo.owner}/${github_1.context.repo.repo}`; - const pushEvent = github_1.context.payload; - const commits = ((_a = pushEvent === null || pushEvent === void 0 ? void 0 : pushEvent.commits) === null || _a === void 0 ? void 0 : _a.map((commit) => { - return { - Id: commit.id, - Comment: commit.message - }; - })) || []; - const packages = []; - for (const packageId of parameters.packages) { - packages.push({ - Id: packageId, - Version: parameters.version - }); - } - const command = { - spaceName: parameters.space, - BuildEnvironment: 'GitHub Actions', - BuildNumber: github_1.context.runNumber.toString(), - BuildUrl: `${repoUri}/actions/runs/${runId}`, - Branch: branch, - VcsType: 'Git', - VcsRoot: `${repoUri}`, - VcsCommitNumber: github_1.context.sha, - Commits: commits, - Packages: packages - }; - if ((0, core_1.isDebug)()) { - client.info(`Build Information:\n${JSON.stringify(command, null, 2)}`); - } - const repository = new api_client_1.BuildInformationRepository(client, parameters.space); - yield repository.push(command, parameters.overwriteMode); - client.info('Successfully pushed build information to Octopus'); - }); -} -exports.pushBuildInformationFromInputs = pushBuildInformationFromInputs; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.pushBuildInformationFromInputs = void 0; +const core_1 = __nccwpck_require__(2186); +const github_1 = __nccwpck_require__(5438); +const api_client_1 = __nccwpck_require__(586); +function pushBuildInformationFromInputs(client, runId, parameters) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + let branch = parameters.branch || github_1.context.ref; + if (branch.startsWith('refs/heads/')) { + branch = branch.substring('refs/heads/'.length); + } + const repoUri = `${github_1.context.serverUrl}/${github_1.context.repo.owner}/${github_1.context.repo.repo}`; + const pushEvent = github_1.context.payload; + const baseBranch = parameters.baseBranch; + let commits; + if (baseBranch) { + client.debug(`Comparing branches ${branch} and ${baseBranch} to obtain a list of commits`); + const octokit = (0, github_1.getOctokit)(parameters.githubToken); + const commitDetails = yield octokit.paginate(octokit.rest.repos.compareCommits, { + repo: github_1.context.repo.repo, + owner: github_1.context.repo.owner, + head: branch, + base: baseBranch + }, response => response.data.commits.map(commit => ({ + sha: commit.sha, + message: commit.commit.message + }))); + commits = commitDetails + .flatMap(commit => ({ + Id: commit.sha, + Comment: commit.message + })) + .reverse(); + } + else { + client.debug('Obtaining last commit if push event'); + commits = + ((_a = pushEvent === null || pushEvent === void 0 ? void 0 : pushEvent.commits) === null || _a === void 0 ? void 0 : _a.map((commit) => ({ + Id: commit.id, + Comment: commit.message + }))) || []; + } + const packages = []; + for (const packageId of parameters.packages) { + packages.push({ + Id: packageId, + Version: parameters.version + }); + } + const command = { + spaceName: parameters.space, + BuildEnvironment: 'GitHub Actions', + BuildNumber: github_1.context.runNumber.toString(), + BuildUrl: `${repoUri}/actions/runs/${runId}`, + Branch: branch, + VcsType: 'Git', + VcsRoot: `${repoUri}`, + VcsCommitNumber: github_1.context.sha, + Commits: commits, + Packages: packages + }; + if ((0, core_1.isDebug)()) { + client.info(`Build Information:\n${JSON.stringify(command, null, 2)}`); + } + const repository = new api_client_1.BuildInformationRepository(client, parameters.space); + yield repository.push(command, parameters.overwriteMode); + client.info('Successfully pushed build information to Octopus'); + }); +} +exports.pushBuildInformationFromInputs = pushBuildInformationFromInputs; /***/ }), diff --git a/src/input-parameters.ts b/src/input-parameters.ts index ce02cc23..9039ab3c 100644 --- a/src/input-parameters.ts +++ b/src/input-parameters.ts @@ -21,6 +21,8 @@ export interface InputParameters { version: string branch?: string overwriteMode: OverwriteMode + baseBranch?: string + githubToken: string } export function get(isRetry: boolean): InputParameters { @@ -36,7 +38,9 @@ export function get(isRetry: boolean): InputParameters { packages: getMultilineInput('packages', { required: true }), version: getInput('version', { required: true }), branch: getInput('branch') || undefined, - overwriteMode + overwriteMode, + baseBranch: getInput('base_branch') || undefined, + githubToken: getInput('github_token') } const errors: string[] = [] diff --git a/src/push-build-information.ts b/src/push-build-information.ts index e6681cde..915c6b0a 100644 --- a/src/push-build-information.ts +++ b/src/push-build-information.ts @@ -1,5 +1,5 @@ import { isDebug } from '@actions/core' -import { context } from '@actions/github' +import { context, getOctokit } from '@actions/github' import { Commit, PushEvent } from '@octokit/webhooks-types/schema' import { BuildInformationRepository, @@ -23,13 +23,45 @@ export async function pushBuildInformationFromInputs( const repoUri = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}` const pushEvent = context.payload as PushEvent | undefined - const commits: IOctopusBuildInformationCommit[] = - pushEvent?.commits?.map((commit: Commit) => { - return { + const baseBranch = parameters.baseBranch + let commits: IOctopusBuildInformationCommit[] + + if (baseBranch) { + client.debug(`Comparing branches ${branch} and ${baseBranch} to obtain a list of commits`) + // Get the list of commits between the two branches + const octokit = getOctokit(parameters.githubToken) + + const commitDetails = await octokit.paginate( + octokit.rest.repos.compareCommits, + { + repo: context.repo.repo, + owner: context.repo.owner, + head: branch, + base: baseBranch + }, + response => + response.data.commits.map(commit => ({ + sha: commit.sha, + message: commit.commit.message + })) + ) + + // Map commits from the comparison result + commits = commitDetails + .flatMap(commit => ({ + Id: commit.sha, + Comment: commit.message + })) + .reverse() // Octokit returns reverse order so need to make newest commit is first) + } else { + client.debug('Obtaining last commit if push event') + // Retrieve commit from the last push event + commits = + pushEvent?.commits?.map((commit: Commit) => ({ Id: commit.id, Comment: commit.message - } - }) || [] + })) || [] + } const packages: PackageIdentity[] = [] for (const packageId of parameters.packages) {