From a355600e7640df07cb787376ada5fe069d571364 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 1 Jun 2021 10:39:31 +0200 Subject: [PATCH] Plugin Repo: Add plugin assets to a release and save plugin stats --- .eslintignore | 3 + .gitignore | 3 + .../plugin-repo-cli/commands/updateRelease.ts | 143 ++++++++++++++ packages/plugin-repo-cli/index.ts | 12 ++ packages/plugin-repo-cli/package-lock.json | 179 ++++++++++++++++-- packages/plugin-repo-cli/package.json | 2 + 6 files changed, 328 insertions(+), 14 deletions(-) create mode 100644 packages/plugin-repo-cli/commands/updateRelease.ts diff --git a/.eslintignore b/.eslintignore index 2019b0d18..8c0b8fc62 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1475,6 +1475,9 @@ packages/lib/uuid.js.map packages/lib/versionInfo.d.ts packages/lib/versionInfo.js packages/lib/versionInfo.js.map +packages/plugin-repo-cli/commands/updateRelease.d.ts +packages/plugin-repo-cli/commands/updateRelease.js +packages/plugin-repo-cli/commands/updateRelease.js.map packages/plugin-repo-cli/index.d.ts packages/plugin-repo-cli/index.js packages/plugin-repo-cli/index.js.map diff --git a/.gitignore b/.gitignore index c80170011..318a2be55 100644 --- a/.gitignore +++ b/.gitignore @@ -1461,6 +1461,9 @@ packages/lib/uuid.js.map packages/lib/versionInfo.d.ts packages/lib/versionInfo.js packages/lib/versionInfo.js.map +packages/plugin-repo-cli/commands/updateRelease.d.ts +packages/plugin-repo-cli/commands/updateRelease.js +packages/plugin-repo-cli/commands/updateRelease.js.map packages/plugin-repo-cli/index.d.ts packages/plugin-repo-cli/index.js packages/plugin-repo-cli/index.js.map diff --git a/packages/plugin-repo-cli/commands/updateRelease.ts b/packages/plugin-repo-cli/commands/updateRelease.ts new file mode 100644 index 000000000..a123239fa --- /dev/null +++ b/packages/plugin-repo-cli/commands/updateRelease.ts @@ -0,0 +1,143 @@ +import { githubOauthToken } from '@joplin/tools/tool-utils'; +import { pathExists, readdir, readFile, writeFile } from 'fs-extra'; +const ghReleaseAssets = require('gh-release-assets'); +const fetch = require('node-fetch'); + +const apiBaseUrl = 'https://api.github.com/repos/joplin/plugins'; + +interface Args { + pluginRepoDir: string; + dryRun: boolean; +} + +interface PluginInfo { + id: string; + version: string; + path?: string; +} + +interface ReleaseAsset { + id: number; + name: string; + download_count: number; + created_at: string; +} + +interface Release { + upload_url: string; + assets: ReleaseAsset[]; +} + +async function getRelease(): Promise { + const response = await fetch(`${apiBaseUrl}/releases`); + const releases = await response.json(); + if (!releases.length) throw new Error('No existing release'); + return releases[0]; +} + +async function getPluginInfos(pluginRepoDir: string): Promise { + const pluginDirs = await readdir(`${pluginRepoDir}/plugins`); + const output: PluginInfo[] = []; + + for (const pluginDir of pluginDirs) { + const basePath = `${pluginRepoDir}/plugins/${pluginDir}`; + const manifest = JSON.parse(await readFile(`${basePath}/manifest.json`, 'utf8')); + output.push({ + id: manifest.id, + version: manifest.version, + path: `${basePath}/plugin.jpl`, + }); + } + + return output; +} + +function assetNameFromPluginInfo(pluginInfo: PluginInfo): string { + return `${pluginInfo.id}@${pluginInfo.version}.jpl`; +} + +function pluginInfoFromAssetName(name: string): PluginInfo { + let s = name.split('.'); + s.pop(); + s = s.join('.').split('@'); + return { + id: s[0], + version: s[1], + }; +} + +async function deleteAsset(oauthToken: string, id: number) { + await fetch(`${apiBaseUrl}/releases/assets/${id}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `token ${oauthToken}`, + }, + }); +} + +async function uploadAsset(oauthToken: string, uploadUrl: string, pluginInfo: PluginInfo) { + return new Promise((resolve: Function, reject: Function) => { + ghReleaseAssets({ + url: uploadUrl, + token: oauthToken, + assets: [ + { + name: assetNameFromPluginInfo(pluginInfo), + path: pluginInfo.path, + }, + ], + }, (error: Error, assets: any) => { + if (error) { + reject(error); + } else { + resolve(assets); + } + }); + }); +} + +async function saveStats(statFilePath: string, release: Release) { + const output: Record = await pathExists(statFilePath) ? JSON.parse(await readFile(statFilePath, 'utf8')) : {}; + + if (release.assets) { + for (const asset of release.assets) { + const pluginInfo = pluginInfoFromAssetName(asset.name); + if (!output[pluginInfo.id]) output[pluginInfo.id] = {}; + + output[pluginInfo.id][pluginInfo.version] = { + downloadCount: asset.download_count, + createdAt: asset.created_at, + }; + } + } + + await writeFile(statFilePath, JSON.stringify(output, null, '\t')); +} + +export default async function(args: Args) { + const release = await getRelease(); + await saveStats(`${args.pluginRepoDir}/stats.json`, release); + + const pluginInfos = await getPluginInfos(args.pluginRepoDir); + const oauthToken = await githubOauthToken(); + + for (const pluginInfo of pluginInfos) { + const assetName = assetNameFromPluginInfo(pluginInfo); + + const otherVersionAssets = release.assets.filter(asset => { + const info = pluginInfoFromAssetName(asset.name); + return info.id === pluginInfo.id && info.version !== pluginInfo.version; + }); + + for (const asset of otherVersionAssets) { + console.info(`Deleting old asset ${asset.name}...`); + await deleteAsset(oauthToken, asset.id); + } + + const existingAsset = release.assets.find(asset => asset.name === assetName); + if (existingAsset) continue; + console.info(`Uploading ${assetName}...`); + await uploadAsset(oauthToken, release.upload_url, pluginInfo); + } +} diff --git a/packages/plugin-repo-cli/index.ts b/packages/plugin-repo-cli/index.ts index 8b2e36d36..5401fcbdb 100644 --- a/packages/plugin-repo-cli/index.ts +++ b/packages/plugin-repo-cli/index.ts @@ -15,6 +15,7 @@ import checkIfPluginCanBeAdded from './lib/checkIfPluginCanBeAdded'; import updateReadme from './lib/updateReadme'; import { NpmPackage } from './lib/types'; import gitCompareUrl from './lib/gitCompareUrl'; +import commandUpdateRelease from './commands/updateRelease'; function stripOffPackageOrg(name: string): string { const n = name.split('/'); @@ -249,6 +250,14 @@ async function commandBuild(args: CommandBuildArgs) { await processNpmPackage(npmPackage, repoDir); } + if (!dryRun) { + await commandUpdateRelease(args); + if (!(await gitRepoClean())) { + await execCommand2('git add -A', { showOutput: true }); + await execCommand2('git commit -m "Update stats"', { showOutput: true }); + } + } + if (!dryRun) await execCommand2('git push'); } @@ -263,6 +272,7 @@ async function main() { const commands: Record = { build: commandBuild, version: commandVersion, + updateRelease: commandUpdateRelease, }; let selectedCommand: string = ''; @@ -286,6 +296,8 @@ async function main() { .command('version', 'Gives version info', () => {}, (args: any) => setSelectedCommand('version', args)) + .command('update-release ', 'Update GitHub release', () => {}, (args: any) => setSelectedCommand('updateRelease', args)) + .help() .argv; diff --git a/packages/plugin-repo-cli/package-lock.json b/packages/plugin-repo-cli/package-lock.json index 8d31be9a6..16b72d4e8 100644 --- a/packages/plugin-repo-cli/package-lock.json +++ b/packages/plugin-repo-cli/package-lock.json @@ -1,6 +1,6 @@ { "name": "@joplin/plugin-repo-cli", - "version": "1.8.2", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -907,6 +907,11 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1296,8 +1301,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { "version": "6.0.5", @@ -1382,6 +1386,14 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1470,6 +1482,29 @@ } } }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1495,7 +1530,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -1889,6 +1923,19 @@ "assert-plus": "^1.0.0" } }, + "gh-release-assets": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gh-release-assets/-/gh-release-assets-2.0.0.tgz", + "integrity": "sha512-I+Gy+e86o7A6J7sJRX4uA3EvLlLFcXxsRre22YTJ5dzpl/elZA75bMWfoBd0WVY3Mp9M8KtROfn3zlzDkptyWw==", + "requires": { + "async": "^3.2.0", + "mime": "^2.4.6", + "progress-stream": "^2.0.0", + "pumpify": "^2.0.1", + "simple-get": "^4.0.0", + "util-extend": "^1.0.1" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -2080,8 +2127,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip-regex": { "version": "2.1.0", @@ -2254,8 +2300,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -3225,6 +3270,11 @@ "picomatch": "^2.0.5" } }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + }, "mime-db": { "version": "1.45.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", @@ -3246,6 +3296,11 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3319,6 +3374,11 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3460,7 +3520,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -3626,6 +3685,20 @@ "react-is": "^17.0.1" } }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-2.0.0.tgz", + "integrity": "sha1-+sY6Cz0R3qy7CWmrzJOyFLzhntU=", + "requires": { + "speedometer": "~1.0.0", + "through2": "~2.0.3" + } + }, "prompts": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", @@ -3646,12 +3719,21 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, + "pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -3701,6 +3783,20 @@ "type-fest": "^0.8.1" } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3873,8 +3969,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -4104,6 +4199,21 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.0.tgz", + "integrity": "sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -4311,6 +4421,11 @@ "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", "dev": true }, + "speedometer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-1.0.0.tgz", + "integrity": "sha1-zWccsGdSwivKM3Di8zREC+T8YuI=" + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -4387,6 +4502,11 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, "string-length": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", @@ -4407,6 +4527,14 @@ "strip-ansi": "^6.0.0" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -4485,6 +4613,15 @@ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "dev": true }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -4687,6 +4824,16 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4827,8 +4974,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "3.0.3", @@ -4860,6 +5006,11 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", diff --git a/packages/plugin-repo-cli/package.json b/packages/plugin-repo-cli/package.json index d767200bd..0304ab2cf 100644 --- a/packages/plugin-repo-cli/package.json +++ b/packages/plugin-repo-cli/package.json @@ -21,6 +21,8 @@ "@joplin/lib": "^1.8.2", "@joplin/tools": "^1.8.2", "fs-extra": "^9.0.1", + "gh-release-assets": "^2.0.0", + "node-fetch": "^2.6.1", "yargs": "^16.0.3" }, "devDependencies": {