From 2dec41f53ecf4afc7241f01cbcc71799b78c232c Mon Sep 17 00:00:00 2001 From: Lessley Dennington Date: Thu, 16 Sep 2021 19:32:40 -0700 Subject: [PATCH] Allow updates to existing winget manifests We recently received notification from a customer that installing `microsoft/git` via winget was broken due to a signing issue. This happened because we accidentally deployed an incorrect SHA for the `microsoft/git` version `2.33.0.0.0` manifest on `microsoft/winget-pkgs` then replaced the asset on GitHub with a new version with a new SHA. When we tried to re-run the `update-winget` workflow to correct the SHA, we discovered some issues with the action that make it impossible to update existing manifests. This PR updates the action to allow us to both create new winget manifests and update existing ones. [Here](https://github.com/ldennington/winget-playground/pull/47) is an example of a test PR opened to update an existing manifest with these changes. And [here](https://github.com/ldennington/winget-playground/pull/48) is an example of a test PR that creates a new manifest with these changes. --- dist/index.js | 1127 +++++++++++++++++++++++---------------------- package-lock.json | 1 + src/main.ts | 30 +- src/winget.ts | 33 +- 4 files changed, 616 insertions(+), 575 deletions(-) diff --git a/dist/index.js b/dist/index.js index 0e74025..7b1cb34 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8205,198 +8205,207 @@ function checkMode (stat, options) { /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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.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()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const core = __importStar(__webpack_require__(470)); -const winget_1 = __webpack_require__(918); -const git_1 = __webpack_require__(453); -const version_1 = __webpack_require__(775); -const github_1 = __webpack_require__(469); -const hash_1 = __webpack_require__(652); -function formatUrl(format, version) { - return version.format(format); -} -function formatMessage(format, id, filePath, version) { - return version - .format(format) - .replace(/{{id}}/g, id) - .replace(/{{file}}/g, filePath); -} -function formatManifest(format, id, sha256, url, version) { - return version - .format(format) - .replace(/{{id}}/g, id) - .replace(/{{sha256}}/g, sha256) - .replace(/{{url}}/g, url); -} -function run() { - var _a, _b, _c, _d; - return __awaiter(this, void 0, void 0, function* () { - try { - const token = core.getInput('token'); - const gitHub = new github_1.GitHub(token); - const repoStr = core.getInput('repo') || 'microsoft/winget-pkgs'; - const repoBranch = core.getInput('branch'); - const manifestRepo = yield winget_1.ManifestRepo.createAsync(gitHub, repoStr, repoBranch); - const id = core.getInput('id', { required: true }); - let manifestText = core.getInput('manifestText', { required: true }); - const versionStr = core.getInput('version'); - let sha256 = core.getInput('sha256'); - const url = core.getInput('url'); - const message = core.getInput('message'); - const releaseRepo = core.getInput('releaseRepo') || process.env.GITHUB_REPOSITORY; - const releaseTag = core.getInput('releaseTag') || process.env.GITHUB_REF; - const releaseAsset = core.getInput('releaseAsset'); - const alwaysUsePullRequest = core.getInput('alwaysUsePullRequest') === 'true'; - core.debug(`repo=${repoStr}`); - core.debug(`repoBranch=${repoBranch}`); - core.debug(`id=${id}`); - core.debug(`manifestText=${manifestText}`); - core.debug(`version=${versionStr}`); - core.debug(`sha256=${sha256}`); - core.debug(`url=${url}`); - core.debug(`message=${message}`); - core.debug(`releaseRepo=${releaseRepo}`); - core.debug(`releaseTag=${releaseTag}`); - core.debug(`releaseAsset=${releaseAsset}`); - core.debug(`alwaysUsePullRequest=${alwaysUsePullRequest}`); - core.debug(`process.env.GITHUB_REPOSITORY=${process.env.GITHUB_REPOSITORY}`); - core.debug(`process.env.GITHUB_REF=${process.env.GITHUB_REF}`); - if (!versionStr && !releaseAsset) { - throw new Error("must specify either the 'version' parameter OR 'releaseAsset' parameters."); - } - if (versionStr && releaseAsset) { - core.warning("'version' parameter specified as well as 'releaseAsset' parameter; using 'version' parameter only"); - } - let asset; - let version; - let fullUrl; - // locate asset if we need to compute either the version or url - if (!versionStr || !url) { - core.debug(`locating release asset in repo '${releaseRepo}' @ '${releaseTag}'`); - const repoName = git_1.Repository.splitRepoName(releaseRepo); - const sourceRepo = yield git_1.Repository.createAsync(gitHub, repoName.owner, repoName.repoName); - const assets = yield sourceRepo.getReleaseAssetsAsync(releaseTag); - const nameRegex = new RegExp(releaseAsset); - asset = assets.find(x => nameRegex.test(x.name)); - if (!asset) { - throw new Error(`unable to find an asset matching '${releaseAsset}' in repo '${releaseRepo}'`); - } - } - // if we have an explicit version string, format and use that - if (versionStr) { - version = new version_1.Version(versionStr); - } - else { - // compute the version from the asset - if (!asset) { - throw new Error('missing asset to compute version number from'); - } - core.debug(`computing new manifest version number from asset in repo '${releaseRepo}' @ '${releaseTag}'`); - const nameRegex = new RegExp(releaseAsset); - const matches = asset.name.match(nameRegex); - if (!matches || matches.length < 2) { - throw new Error(`unable to match at least one capture group in asset name '${asset.name}' with regular expression '${nameRegex}'`); - } - if ((_a = matches.groups) === null || _a === void 0 ? void 0 : _a.version) { - core.debug(`using 'version' named capture group for new package version: ${(_b = matches.groups) === null || _b === void 0 ? void 0 : _b.version}`); - version = new version_1.Version(matches.groups.version); - } - else { - core.debug(`using first capture group for new package version: ${matches[1]}`); - version = new version_1.Version(matches[1]); - } - } - if (url) { - // if we have an explicit url, format and use that - fullUrl = formatUrl(url, version); - } - else { - // use the download URL of the asset - if (!asset) { - throw new Error('missing asset to compute URL from'); - } - core.debug(`computing new manifest URL from asset in repo '${releaseRepo}' @ '${releaseTag}'`); - fullUrl = asset.downloadUrl; - } - // if we have an explicit sha256 checksum, use that! - // otherwise compute it from the download URL - if (!sha256) { - if (!fullUrl) { - throw new Error('missing URL to compute checksum from'); - } - core.debug(`computing SHA256 hash of data from asset at '${fullUrl}'...`); - sha256 = yield hash_1.computeSha256Async(fullUrl); - core.debug(`sha256=${sha256}`); - } - core.debug(`computing path version, using regex if applicable...`); - const versionRegEx = /{{version:.+}}/g; - const pathVersion = (_d = (_c = manifestText.match(versionRegEx)) === null || _c === void 0 ? void 0 : _c.shift()) !== null && _d !== void 0 ? _d : version.toString(); - core.debug('generating manifest...'); - manifestText = formatManifest(manifestText, id, sha256, fullUrl, version); - core.debug('final manifest is:'); - core.debug(manifestText); - core.debug('computing manifest file path...'); - const manifestFilePath = `manifests/${id - .charAt(0) - .toLowerCase()}/${id.replace('.', '/')}/${version.format(pathVersion)}/${id}.yaml`.trim(); - core.debug(`manifest file path is: ${manifestFilePath}`); - core.debug('generating message...'); - const fullMessage = formatMessage(message, id, manifestFilePath, version); - core.debug('final message is:'); - core.debug(fullMessage); - core.debug('publishing manifest...'); - const uploadOptions = { - manifest: manifestText, - filePath: manifestFilePath, - message: fullMessage, - alwaysUsePullRequest - }; - const result = yield manifestRepo.uploadManifestAsync(uploadOptions); - if (result instanceof git_1.Commit) { - core.info(`Created commit '${result.sha}': ${result.url}`); - } - else if (result instanceof git_1.PullRequest) { - core.info(`Created pull request '${result.id}': ${result.url}`); - } - else { - core.warning('unknown type of package update'); - } - } - catch (error) { - core.setFailed(error.message); - } - }); -} -run(); + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (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.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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const core = __importStar(__webpack_require__(470)); +const winget_1 = __webpack_require__(918); +const git_1 = __webpack_require__(453); +const version_1 = __webpack_require__(775); +const github_1 = __webpack_require__(469); +const hash_1 = __webpack_require__(652); +function formatUrl(format, version) { + return version.format(format); +} +function formatMessage(format, id, filePath, version) { + return version + .format(format) + .replace(/{{id}}/g, id) + .replace(/{{file}}/g, filePath); +} +function formatManifest(format, id, sha256, url, version) { + return version + .format(format) + .replace(/{{id}}/g, id) + .replace(/{{sha256}}/g, sha256) + .replace(/{{url}}/g, url); +} +function run() { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function* () { + try { + const token = core.getInput('token'); + const gitHub = new github_1.GitHub(token); + const repoStr = core.getInput('repo') || 'microsoft/winget-pkgs'; + const repoBranch = core.getInput('branch'); + const manifestRepo = yield winget_1.ManifestRepo.createAsync(gitHub, repoStr, repoBranch); + const id = core.getInput('id', { required: true }); + let manifestText = core.getInput('manifestText', { required: true }); + const versionStr = core.getInput('version'); + let sha256 = core.getInput('sha256'); + const url = core.getInput('url'); + const message = core.getInput('message'); + const releaseRepo = core.getInput('releaseRepo') || process.env.GITHUB_REPOSITORY; + const releaseTag = core.getInput('releaseTag') || process.env.GITHUB_REF; + const releaseAsset = core.getInput('releaseAsset'); + const alwaysUsePullRequest = core.getInput('alwaysUsePullRequest') === 'true'; + core.debug(`repo=${repoStr}`); + core.debug(`repoBranch=${repoBranch}`); + core.debug(`id=${id}`); + core.debug(`manifestText=${manifestText}`); + core.debug(`version=${versionStr}`); + core.debug(`sha256=${sha256}`); + core.debug(`url=${url}`); + core.debug(`message=${message}`); + core.debug(`releaseRepo=${releaseRepo}`); + core.debug(`releaseTag=${releaseTag}`); + core.debug(`releaseAsset=${releaseAsset}`); + core.debug(`alwaysUsePullRequest=${alwaysUsePullRequest}`); + core.debug(`process.env.GITHUB_REPOSITORY=${process.env.GITHUB_REPOSITORY}`); + core.debug(`process.env.GITHUB_REF=${process.env.GITHUB_REF}`); + if (!versionStr && !releaseAsset) { + throw new Error("must specify either the 'version' parameter OR 'releaseAsset' parameters."); + } + if (versionStr && releaseAsset) { + core.warning("'version' parameter specified as well as 'releaseAsset' parameter; using 'version' parameter only"); + } + let asset; + let version; + let fullUrl; + // locate asset if we need to compute either the version or url + if (!versionStr || !url) { + core.debug(`locating release asset in repo '${releaseRepo}' @ '${releaseTag}'`); + const repoName = git_1.Repository.splitRepoName(releaseRepo); + const sourceRepo = yield git_1.Repository.createAsync(gitHub, repoName.owner, repoName.repoName); + const assets = yield sourceRepo.getReleaseAssetsAsync(releaseTag); + const nameRegex = new RegExp(releaseAsset); + asset = assets.find(x => nameRegex.test(x.name)); + if (!asset) { + throw new Error(`unable to find an asset matching '${releaseAsset}' in repo '${releaseRepo}'`); + } + } + // if we have an explicit version string, format and use that + if (versionStr) { + version = new version_1.Version(versionStr); + } + else { + // compute the version from the asset + if (!asset) { + throw new Error('missing asset to compute version number from'); + } + core.debug(`computing new manifest version number from asset in repo '${releaseRepo}' @ '${releaseTag}'`); + const nameRegex = new RegExp(releaseAsset); + const matches = asset.name.match(nameRegex); + if (!matches || matches.length < 2) { + throw new Error(`unable to match at least one capture group in asset name '${asset.name}' with regular expression '${nameRegex}'`); + } + if ((_a = matches.groups) === null || _a === void 0 ? void 0 : _a.version) { + core.debug(`using 'version' named capture group for new package version: ${(_b = matches.groups) === null || _b === void 0 ? void 0 : _b.version}`); + version = new version_1.Version(matches.groups.version); + } + else { + core.debug(`using first capture group for new package version: ${matches[1]}`); + version = new version_1.Version(matches[1]); + } + } + if (url) { + // if we have an explicit url, format and use that + fullUrl = formatUrl(url, version); + } + else { + // use the download URL of the asset + if (!asset) { + throw new Error('missing asset to compute URL from'); + } + core.debug(`computing new manifest URL from asset in repo '${releaseRepo}' @ '${releaseTag}'`); + fullUrl = asset.downloadUrl; + } + // if we have an explicit sha256 checksum, use that! + // otherwise compute it from the download URL + if (!sha256) { + if (!fullUrl) { + throw new Error('missing URL to compute checksum from'); + } + core.debug(`computing SHA256 hash of data from asset at '${fullUrl}'...`); + sha256 = yield hash_1.computeSha256Async(fullUrl); + core.debug(`sha256=${sha256}`); + } + core.debug('generating manifest...'); + manifestText = formatManifest(manifestText, id, sha256, fullUrl, version); + core.debug('final manifest is:'); + core.debug(manifestText); + core.debug("computing file path version from final manifest property 'PackageVersion'..."); + const pkgVerRegEx = /PackageVersion:\s*(?.*)/; + const pkgVerMatch = manifestText.match(pkgVerRegEx); + let pathVersion; + if ((_c = pkgVerMatch === null || pkgVerMatch === void 0 ? void 0 : pkgVerMatch.groups) === null || _c === void 0 ? void 0 : _c.version) { + pathVersion = pkgVerMatch.groups.version; + } + else { + core.warning("could not match 'PackageVersion' property in manifest; manifest may not be valid!"); + pathVersion = version.toString(); + } + core.debug(`path version is ${pathVersion}`); + core.debug('computing manifest file path...'); + const manifestFilePath = `manifests/${id + .charAt(0) + .toLowerCase()}/${id.replace('.', '/')}/${pathVersion}/${id}.yaml`.trim(); + core.debug(`manifest file path is: ${manifestFilePath}`); + core.debug('generating message...'); + const fullMessage = formatMessage(message, id, manifestFilePath, version); + core.debug('final message is:'); + core.debug(fullMessage); + core.debug('publishing manifest...'); + const uploadOptions = { + manifest: manifestText, + filePath: manifestFilePath, + message: fullMessage, + alwaysUsePullRequest + }; + const result = yield manifestRepo.uploadManifestAsync(uploadOptions); + if (result instanceof git_1.Commit) { + core.info(`Created commit '${result.sha}': ${result.url}`); + } + else if (result instanceof git_1.PullRequest) { + core.info(`Created pull request '${result.id}': ${result.url}`); + } + else { + core.warning('unknown type of package update'); + } + } + catch (error) { + core.setFailed(error.message); + } + }); +} +run(); /***/ }), @@ -17066,146 +17075,146 @@ module.exports = function (str) { /***/ (function(__unusedmodule, exports) { "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.Repository = exports.ReleaseAsset = exports.PullRequest = exports.Commit = exports.Branch = exports.File = void 0; -class File { - constructor(path, blob, content) { - this.path = path; - this.blob = blob; - this.content = content; - } -} -exports.File = File; -class Branch { - constructor(name, sha, isProtected) { - this.name = name; - this.sha = sha; - this.isProtected = isProtected; - } -} -exports.Branch = Branch; -class Commit { - constructor(sha, url) { - this.sha = sha; - this.url = url; - } -} -exports.Commit = Commit; -class PullRequest { - constructor(id, url) { - this.id = id; - this.url = url; - } -} -exports.PullRequest = PullRequest; -class ReleaseAsset { - constructor(name, url, downloadUrl) { - this.name = name; - this.url = url; - this.downloadUrl = downloadUrl; - } -} -exports.ReleaseAsset = ReleaseAsset; -class Repository { - constructor(api, owner, name, defaultBranch, canPush) { - this.api = api; - this.owner = owner; - this.name = name; - this.defaultBranch = defaultBranch; - this.canPush = canPush; - this.req = { owner, repo: name }; - } - static createAsync(api, owner, name) { - return __awaiter(this, void 0, void 0, function* () { - const req = { owner, repo: name }; - const { data: repoData } = yield api.repos.get(req); - const { data: branchData } = yield api.repos.getBranch(Object.assign(Object.assign({}, req), { branch: repoData.default_branch })); - const defaultBranch = new Branch(branchData.name, branchData.commit.sha, branchData.protected); - return new Repository(api, owner, name, defaultBranch, repoData.permissions.push); - }); - } - static splitRepoName(ownerAndName) { - const nameParts = ownerAndName.split('/'); - if (nameParts.length !== 2) { - throw new Error(`invalid repo name '${ownerAndName}'`); - } - return { owner: nameParts[0], repoName: nameParts[1] }; - } - getFileAsync(filePath, branch) { - return __awaiter(this, void 0, void 0, function* () { - const { data, status } = yield this.api.repos.getContents(Object.assign(Object.assign({}, this.req), { path: filePath, ref: branch || this.defaultBranch.name })); - assertOk(status, `failed to download '${filePath}' @ '${branch || - this.defaultBranch.name}' from '${this.owner}/${this.name}'`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const d = data; - const content = Buffer.from(d.content, 'base64').toString(); - return new File(filePath, d.sha, content); - }); - } - commitFileAsync(branch, filePath, content, message, existingBlob) { - return __awaiter(this, void 0, void 0, function* () { - const { status, data } = yield this.api.repos.createOrUpdateFile(Object.assign(Object.assign({}, this.req), { content: Buffer.from(content).toString('base64'), branch, path: filePath, message, sha: existingBlob })); - assertOk(status, `failed to create commit on branch '${branch}' in '${this.owner}/${this.name}'`); - return new Commit(data.commit.sha, data.commit.html_url); - }); - } - getBranchAsync(name) { - return __awaiter(this, void 0, void 0, function* () { - const { status: branchStatus, data } = yield this.api.repos.getBranch(Object.assign(Object.assign({}, this.req), { branch: name })); - assertOk(branchStatus, `failed to get branch information for '${name}' in '${this.owner}/${this.name}'`); - return new Branch(name, data.commit.sha, data.protected); - }); - } - createBranchAsync(name, sha) { - return __awaiter(this, void 0, void 0, function* () { - const { status: refStatus } = yield this.api.git.createRef(Object.assign(Object.assign({}, this.req), { sha, ref: `refs/heads/${name}` })); - assertOk(refStatus, `failed to create branch '${name}' at '${sha}' in '${this.owner}/${this.name}'`); - return yield this.getBranchAsync(name); - }); - } - createForkAsync(owner) { - return __awaiter(this, void 0, void 0, function* () { - const { status, data } = yield this.api.repos.createFork(Object.assign(Object.assign({}, this.req), { organization: owner })); - assertOk(status, `failed to fork repo '${this.owner}/${this.name}' into '${owner}'`); - return yield Repository.createAsync(this.api, data.owner.login, data.name); - }); - } - createPullRequestAsync(targetBranch, sourceBranch, title, body, sourceOwner) { - return __awaiter(this, void 0, void 0, function* () { - const headRef = sourceOwner - ? `${sourceOwner}:${sourceBranch}` - : sourceBranch; - const { status, data } = yield this.api.pulls.create(Object.assign(Object.assign({}, this.req), { head: headRef, base: targetBranch, title, - body })); - assertOk(status, `failed to create pull request from '${headRef}' to '${targetBranch} in '${this.owner}/${this.name}'`); - return new PullRequest(data.number, data.html_url); - }); - } - getReleaseAssetsAsync(tag) { - return __awaiter(this, void 0, void 0, function* () { - const tagName = tag.replace(/^(refs\/tags\/)/, ''); - const { status, data } = yield this.api.repos.getReleaseByTag(Object.assign(Object.assign({}, this.req), { tag: tagName })); - assertOk(status, `failed to locate release with tag '${tagName}' in '${this.owner}/${this.name}'`); - return data.assets.map(x => new ReleaseAsset(x.name, x.url, x.browser_download_url)); - }); - } -} -exports.Repository = Repository; -function assertOk(status, errorMessage) { - if (status < 200 || status > 299) { - throw new Error(errorMessage); - } -} + +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.Repository = exports.ReleaseAsset = exports.PullRequest = exports.Commit = exports.Branch = exports.File = void 0; +class File { + constructor(path, blob, content) { + this.path = path; + this.blob = blob; + this.content = content; + } +} +exports.File = File; +class Branch { + constructor(name, sha, isProtected) { + this.name = name; + this.sha = sha; + this.isProtected = isProtected; + } +} +exports.Branch = Branch; +class Commit { + constructor(sha, url) { + this.sha = sha; + this.url = url; + } +} +exports.Commit = Commit; +class PullRequest { + constructor(id, url) { + this.id = id; + this.url = url; + } +} +exports.PullRequest = PullRequest; +class ReleaseAsset { + constructor(name, url, downloadUrl) { + this.name = name; + this.url = url; + this.downloadUrl = downloadUrl; + } +} +exports.ReleaseAsset = ReleaseAsset; +class Repository { + constructor(api, owner, name, defaultBranch, canPush) { + this.api = api; + this.owner = owner; + this.name = name; + this.defaultBranch = defaultBranch; + this.canPush = canPush; + this.req = { owner, repo: name }; + } + static createAsync(api, owner, name) { + return __awaiter(this, void 0, void 0, function* () { + const req = { owner, repo: name }; + const { data: repoData } = yield api.repos.get(req); + const { data: branchData } = yield api.repos.getBranch(Object.assign(Object.assign({}, req), { branch: repoData.default_branch })); + const defaultBranch = new Branch(branchData.name, branchData.commit.sha, branchData.protected); + return new Repository(api, owner, name, defaultBranch, repoData.permissions.push); + }); + } + static splitRepoName(ownerAndName) { + const nameParts = ownerAndName.split('/'); + if (nameParts.length !== 2) { + throw new Error(`invalid repo name '${ownerAndName}'`); + } + return { owner: nameParts[0], repoName: nameParts[1] }; + } + getFileAsync(filePath, branch) { + return __awaiter(this, void 0, void 0, function* () { + const { data, status } = yield this.api.repos.getContents(Object.assign(Object.assign({}, this.req), { path: filePath, ref: branch || this.defaultBranch.name })); + assertOk(status, `failed to download '${filePath}' @ '${branch || + this.defaultBranch.name}' from '${this.owner}/${this.name}'`); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const d = data; + const content = Buffer.from(d.content, 'base64').toString(); + return new File(filePath, d.sha, content); + }); + } + commitFileAsync(branch, filePath, content, message, existingBlob) { + return __awaiter(this, void 0, void 0, function* () { + const { status, data } = yield this.api.repos.createOrUpdateFile(Object.assign(Object.assign({}, this.req), { content: Buffer.from(content).toString('base64'), branch, path: filePath, message, sha: existingBlob })); + assertOk(status, `failed to create commit on branch '${branch}' in '${this.owner}/${this.name}'`); + return new Commit(data.commit.sha, data.commit.html_url); + }); + } + getBranchAsync(name) { + return __awaiter(this, void 0, void 0, function* () { + const { status: branchStatus, data } = yield this.api.repos.getBranch(Object.assign(Object.assign({}, this.req), { branch: name })); + assertOk(branchStatus, `failed to get branch information for '${name}' in '${this.owner}/${this.name}'`); + return new Branch(name, data.commit.sha, data.protected); + }); + } + createBranchAsync(name, sha) { + return __awaiter(this, void 0, void 0, function* () { + const { status: refStatus } = yield this.api.git.createRef(Object.assign(Object.assign({}, this.req), { sha, ref: `refs/heads/${name}` })); + assertOk(refStatus, `failed to create branch '${name}' at '${sha}' in '${this.owner}/${this.name}'`); + return yield this.getBranchAsync(name); + }); + } + createForkAsync(owner) { + return __awaiter(this, void 0, void 0, function* () { + const { status, data } = yield this.api.repos.createFork(Object.assign(Object.assign({}, this.req), { organization: owner })); + assertOk(status, `failed to fork repo '${this.owner}/${this.name}' into '${owner}'`); + return yield Repository.createAsync(this.api, data.owner.login, data.name); + }); + } + createPullRequestAsync(targetBranch, sourceBranch, title, body, sourceOwner) { + return __awaiter(this, void 0, void 0, function* () { + const headRef = sourceOwner + ? `${sourceOwner}:${sourceBranch}` + : sourceBranch; + const { status, data } = yield this.api.pulls.create(Object.assign(Object.assign({}, this.req), { head: headRef, base: targetBranch, title, + body })); + assertOk(status, `failed to create pull request from '${headRef}' to '${targetBranch} in '${this.owner}/${this.name}'`); + return new PullRequest(data.number, data.html_url); + }); + } + getReleaseAssetsAsync(tag) { + return __awaiter(this, void 0, void 0, function* () { + const tagName = tag.replace(/^(refs\/tags\/)/, ''); + const { status, data } = yield this.api.repos.getReleaseByTag(Object.assign(Object.assign({}, this.req), { tag: tagName })); + assertOk(status, `failed to locate release with tag '${tagName}' in '${this.owner}/${this.name}'`); + return data.assets.map(x => new ReleaseAsset(x.name, x.url, x.browser_download_url)); + }); + } +} +exports.Repository = Repository; +function assertOk(status, errorMessage) { + if (status < 200 || status > 299) { + throw new Error(errorMessage); + } +} /***/ }), @@ -26765,44 +26774,44 @@ module.exports = { /***/ (function(__unusedmodule, exports, __webpack_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()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.computeSha256Async = void 0; -const crypto_1 = __webpack_require__(417); -const request_1 = __importDefault(__webpack_require__(830)); -function computeSha256Async(url) { - return __awaiter(this, void 0, void 0, function* () { - const lowerUrl = url.toLowerCase(); - if (!lowerUrl.startsWith('https://') && !lowerUrl.startsWith('http://')) { - throw new Error(`unknown scheme type in URL '${url}'`); - } - const sha256 = crypto_1.createHash('sha256'); - return new Promise((resolve, reject) => { - request_1.default(url) - .on('error', err => { - reject(new Error(`failed to download ${url}: [${err.name}] ${err.message}`)); - }) - .on('complete', () => { - sha256.end(); - resolve(sha256.digest('hex')); - }) - .pipe(sha256); - }); - }); -} -exports.computeSha256Async = computeSha256Async; + +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 }); +exports.computeSha256Async = void 0; +const crypto_1 = __webpack_require__(417); +const request_1 = __importDefault(__webpack_require__(830)); +function computeSha256Async(url) { + return __awaiter(this, void 0, void 0, function* () { + const lowerUrl = url.toLowerCase(); + if (!lowerUrl.startsWith('https://') && !lowerUrl.startsWith('http://')) { + throw new Error(`unknown scheme type in URL '${url}'`); + } + const sha256 = crypto_1.createHash('sha256'); + return new Promise((resolve, reject) => { + request_1.default(url) + .on('error', err => { + reject(new Error(`failed to download ${url}: [${err.name}] ${err.message}`)); + }) + .on('complete', () => { + sha256.end(); + resolve(sha256.digest('hex')); + }) + .pipe(sha256); + }); + }); +} +exports.computeSha256Async = computeSha256Async; /***/ }), @@ -31447,81 +31456,81 @@ module.exports = function generate__limitLength(it, $keyword, $ruleType) { /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Version = void 0; -const core = __importStar(__webpack_require__(470)); -class Version { - constructor(version) { - this.version = version; - this.components = version.split('.'); - if (!this.components) { - return; - } - } - toString(components) { - if (components === undefined) { - return this.version; - } - if (components < 1) { - return ''; - } - let result = this.components[0]; - for (let i = 1; i < components; i++) { - result += `.${this.components[i]}`; - } - return result; - } - format(str) { - var _a, _b; - let result = str; - const formatRegex = /{{version:.+}}/g; - const specifiers = str.match(formatRegex); - if (specifiers) { - for (const specifier of specifiers) { - core.debug(`Replacing version specifier: ${specifier}`); - const substRegex = /s\/(?.*)\/(?.*)\//; - const regexResult = substRegex.exec(specifier); - if (regexResult && ((_a = regexResult.groups) === null || _a === void 0 ? void 0 : _a.search)) { - const searchRegex = new RegExp(regexResult.groups.search, 'g'); - core.debug(` Search: ${searchRegex}`); - const replacementPattern = ((_b = regexResult.groups) === null || _b === void 0 ? void 0 : _b.replacement) || ''; - core.debug(` Replace: ${replacementPattern}`); - const versionStr = this.version.replace(searchRegex, replacementPattern); - core.debug(` Version => ${versionStr}`); - result = result.replace(specifier, versionStr); - } - } - } - // Replace legacy format specifiers - core.debug('Replacing legacy version specifiers'); - return result - .replace(/{{version}}/g, this.version) - .replace(/{{version\.major}}/g, this.toString(1)) - .replace(/{{version\.major_minor}}/g, this.toString(2)) - .replace(/{{version\.major_minor_patch}}/g, this.toString(3)); - } -} -exports.Version = Version; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (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.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Version = void 0; +const core = __importStar(__webpack_require__(470)); +class Version { + constructor(version) { + this.version = version; + this.components = version.split('.'); + if (!this.components) { + return; + } + } + toString(components) { + if (components === undefined) { + return this.version; + } + if (components < 1) { + return ''; + } + let result = this.components[0]; + for (let i = 1; i < components; i++) { + result += `.${this.components[i]}`; + } + return result; + } + format(str) { + var _a, _b; + let result = str; + const formatRegex = /{{version:.+}}/g; + const specifiers = str.match(formatRegex); + if (specifiers) { + for (const specifier of specifiers) { + core.debug(`Replacing version specifier: ${specifier}`); + const substRegex = /s\/(?.*)\/(?.*)\//; + const regexResult = substRegex.exec(specifier); + if (regexResult && ((_a = regexResult.groups) === null || _a === void 0 ? void 0 : _a.search)) { + const searchRegex = new RegExp(regexResult.groups.search, 'g'); + core.debug(` Search: ${searchRegex}`); + const replacementPattern = ((_b = regexResult.groups) === null || _b === void 0 ? void 0 : _b.replacement) || ''; + core.debug(` Replace: ${replacementPattern}`); + const versionStr = this.version.replace(searchRegex, replacementPattern); + core.debug(` Version => ${versionStr}`); + result = result.replace(specifier, versionStr); + } + } + } + // Replace legacy format specifiers + core.debug('Replacing legacy version specifiers'); + return result + .replace(/{{version}}/g, this.version) + .replace(/{{version\.major}}/g, this.toString(1)) + .replace(/{{version\.major_minor}}/g, this.toString(2)) + .replace(/{{version\.major_minor_patch}}/g, this.toString(3)); + } +} +exports.Version = Version; /***/ }), @@ -53473,115 +53482,125 @@ exports.requestLog = requestLog; /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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.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()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ManifestRepo = void 0; -const core = __importStar(__webpack_require__(470)); -const Git = __importStar(__webpack_require__(453)); -class ManifestRepo { - constructor(repo, branch) { - this.repo = repo; - this.branch = branch; - } - static createAsync(api, name, branch) { - return __awaiter(this, void 0, void 0, function* () { - const nameParts = Git.Repository.splitRepoName(name); - const tapOwner = nameParts.owner; - const tapRepoName = nameParts.repoName; - const repo = yield Git.Repository.createAsync(api, tapOwner, tapRepoName); - const tapBranch = branch - ? yield repo.getBranchAsync(branch) - : repo.defaultBranch; - return new ManifestRepo(repo, tapBranch); - }); - } - uploadManifestAsync(options) { - return __awaiter(this, void 0, void 0, function* () { - let commitRepo; - let commitBranch; - let createPull; - core.debug(`canPush=${this.repo.canPush}, isProtected=${this.branch.isProtected}, alwaysUsePullRequest=${options.alwaysUsePullRequest}`); - if (this.repo.canPush && - (this.branch.isProtected || options.alwaysUsePullRequest)) { - core.debug('updating via PR in repo'); - // Need to update via a PR in this repo - commitRepo = this.repo; - commitBranch = yield this.repo.createBranchAsync(`update-${Date.now().toString()}`, this.branch.sha); - createPull = true; - } - else if (this.repo.canPush && - !this.branch.isProtected && - !options.alwaysUsePullRequest) { - core.debug('updating via commit in repo'); - // Commit directly to the branch in this repo - commitRepo = this.repo; - commitBranch = this.branch; - createPull = false; - } - else { - core.debug('updating via PR in fork repo'); - // Need to update via PR from a fork - commitRepo = yield this.repo.createForkAsync(options.forkOwner); - commitBranch = yield commitRepo.createBranchAsync(`update-${Date.now().toString()}`, this.repo.defaultBranch.sha); - createPull = true; - } - // Create the commit - core.debug('creating commit...'); - const commit = yield commitRepo.commitFileAsync(commitBranch.name, options.filePath, options.manifest, options.message); - if (!createPull) { - return commit; - } - core.debug('generating pull request message...'); - let pullTitle; - let pullBody; - const msgParts = options.message.split('\n'); - if (msgParts.length === 1) { - pullTitle = options.message; - pullBody = ''; - } - else if (msgParts.length > 1) { - pullTitle = msgParts[0]; - pullBody = msgParts.slice(1).join('\n'); - } - else { - pullTitle = `Update ${options.filePath}`; - pullBody = ''; - } - core.debug(`PR message is: ${pullTitle}\n${pullBody}`); - core.debug('creating pull request...'); - return yield this.repo.createPullRequestAsync(this.branch.name, commitBranch.name, pullTitle, pullBody, commitRepo.owner); - }); - } -} -exports.ManifestRepo = ManifestRepo; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (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.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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ManifestRepo = void 0; +const core = __importStar(__webpack_require__(470)); +const Git = __importStar(__webpack_require__(453)); +class ManifestRepo { + constructor(repo, branch) { + this.repo = repo; + this.branch = branch; + } + static createAsync(api, name, branch) { + return __awaiter(this, void 0, void 0, function* () { + const nameParts = Git.Repository.splitRepoName(name); + const tapOwner = nameParts.owner; + const tapRepoName = nameParts.repoName; + const repo = yield Git.Repository.createAsync(api, tapOwner, tapRepoName); + const tapBranch = branch + ? yield repo.getBranchAsync(branch) + : repo.defaultBranch; + return new ManifestRepo(repo, tapBranch); + }); + } + uploadManifestAsync(options) { + return __awaiter(this, void 0, void 0, function* () { + let commitRepo; + let commitBranch; + let createPull; + core.debug(`canPush=${this.repo.canPush}, isProtected=${this.branch.isProtected}, alwaysUsePullRequest=${options.alwaysUsePullRequest}`); + if (this.repo.canPush && + (this.branch.isProtected || options.alwaysUsePullRequest)) { + core.debug('updating via PR in repo'); + // Need to update via a PR in this repo + commitRepo = this.repo; + commitBranch = yield this.repo.createBranchAsync(`update-${Date.now().toString()}`, this.branch.sha); + createPull = true; + } + else if (this.repo.canPush && + !this.branch.isProtected && + !options.alwaysUsePullRequest) { + core.debug('updating via commit in repo'); + // Commit directly to the branch in this repo + commitRepo = this.repo; + commitBranch = this.branch; + createPull = false; + } + else { + core.debug('updating via PR in fork repo'); + // Need to update via PR from a fork + commitRepo = yield this.repo.createForkAsync(options.forkOwner); + commitBranch = yield commitRepo.createBranchAsync(`update-${Date.now().toString()}`, this.repo.defaultBranch.sha); + createPull = true; + } + let commit; + // Create the commit + core.debug('creating commit...'); + try { + core.debug('checking if file exists...'); + const existingSha = (yield commitRepo.getFileAsync(options.filePath, commitRepo.defaultBranch.name)).blob; + core.debug('file exists, updating...'); + commit = yield commitRepo.commitFileAsync(commitBranch.name, options.filePath, options.manifest, options.message, existingSha); + } + catch (_a) { + core.debug('file does not exist, creating...'); + commit = yield commitRepo.commitFileAsync(commitBranch.name, options.filePath, options.manifest, options.message); + } + if (!createPull) { + return commit; + } + core.debug('generating pull request message...'); + let pullTitle; + let pullBody; + const msgParts = options.message.split('\n'); + if (msgParts.length === 1) { + pullTitle = options.message; + pullBody = ''; + } + else if (msgParts.length > 1) { + pullTitle = msgParts[0]; + pullBody = msgParts.slice(1).join('\n'); + } + else { + pullTitle = `Update ${options.filePath}`; + pullBody = ''; + } + core.debug(`PR message is: ${pullTitle}\n${pullBody}`); + core.debug('creating pull request...'); + return yield this.repo.createPullRequestAsync(this.branch.name, commitBranch.name, pullTitle, pullBody, commitRepo.owner); + }); + } +} +exports.ManifestRepo = ManifestRepo; /***/ }), diff --git a/package-lock.json b/package-lock.json index 6fa869c..c8c5c27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "update-winget", "version": "0.0.0", "license": "MIT", "dependencies": { diff --git a/src/main.ts b/src/main.ts index ac47d19..bdbe044 100644 --- a/src/main.ts +++ b/src/main.ts @@ -184,21 +184,21 @@ async function run(): Promise { core.debug('final manifest is:'); core.debug(manifestText); -core.debug( - "computing file path version from final manifest property 'PackageVersion'..." -); -const pkgVerRegEx = /PackageVersion:\s*(?.*)/; -const pkgVerMatch = manifestText.match(pkgVerRegEx); -let pathVersion: string | undefined; -if (pkgVerMatch?.groups?.version) { - pathVersion = pkgVerMatch.groups.version; -} else { - core.warning( - "could not match 'PackageVersion' property in manifest; manifest may not be valid!" - ); - pathVersion = version.toString(); -} -core.debug(`path version is ${pathVersion}`); + core.debug( + "computing file path version from final manifest property 'PackageVersion'..." + ); + const pkgVerRegEx = /PackageVersion:\s*(?.*)/; + const pkgVerMatch = manifestText.match(pkgVerRegEx); + let pathVersion: string | undefined; + if (pkgVerMatch?.groups?.version) { + pathVersion = pkgVerMatch.groups.version; + } else { + core.warning( + "could not match 'PackageVersion' property in manifest; manifest may not be valid!" + ); + pathVersion = version.toString(); + } + core.debug(`path version is ${pathVersion}`); core.debug('computing manifest file path...'); const manifestFilePath = `manifests/${id diff --git a/src/winget.ts b/src/winget.ts index acf8f58..7f99c03 100644 --- a/src/winget.ts +++ b/src/winget.ts @@ -81,14 +81,35 @@ export class ManifestRepo { createPull = true; } + let commit: Git.Commit; + // Create the commit core.debug('creating commit...'); - const commit = await commitRepo.commitFileAsync( - commitBranch.name, - options.filePath, - options.manifest, - options.message - ); + try { + core.debug('checking if file exists...'); + const existingSha = ( + await commitRepo.getFileAsync( + options.filePath, + commitRepo.defaultBranch.name + ) + ).blob; + core.debug('file exists, updating...'); + commit = await commitRepo.commitFileAsync( + commitBranch.name, + options.filePath, + options.manifest, + options.message, + existingSha + ); + } catch { + core.debug('file does not exist, creating...'); + commit = await commitRepo.commitFileAsync( + commitBranch.name, + options.filePath, + options.manifest, + options.message + ); + } if (!createPull) { return commit;