From 7fabc67218e5cb9f38c990da440065def21359ec Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Thu, 22 Apr 2021 02:00:24 +0200 Subject: [PATCH 01/31] generate sbt plugin --- plugins/sbt/README.md | 24 ++++++++++++++++ plugins/sbt/__tests__/sbt.test.ts | 7 +++++ plugins/sbt/package.json | 46 +++++++++++++++++++++++++++++++ plugins/sbt/src/index.ts | 31 +++++++++++++++++++++ plugins/sbt/tsconfig.json | 16 +++++++++++ tsconfig.dev.json | 5 +++- 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 plugins/sbt/README.md create mode 100644 plugins/sbt/__tests__/sbt.test.ts create mode 100644 plugins/sbt/package.json create mode 100644 plugins/sbt/src/index.ts create mode 100644 plugins/sbt/tsconfig.json diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md new file mode 100644 index 000000000..25fa6a266 --- /dev/null +++ b/plugins/sbt/README.md @@ -0,0 +1,24 @@ +# Sbt Plugin + +Publish Scala projects with sbt + +## Installation + +This plugin is not included with the `auto` CLI installed via NPM. To install: + +```bash +npm i --save-dev @auto-it/sbt +# or +yarn add -D @auto-it/sbt +``` + +## Usage + +```json +{ + "plugins": [ + "sbt" + // other plugins + ] +} +``` diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts new file mode 100644 index 000000000..5ad6efe56 --- /dev/null +++ b/plugins/sbt/__tests__/sbt.test.ts @@ -0,0 +1,7 @@ +import Auto from '@auto-it/core'; +import Sbt from '../src'; + +describe('Sbt Plugin', () => { + test('should do something', async () => { + }); +}); diff --git a/plugins/sbt/package.json b/plugins/sbt/package.json new file mode 100644 index 000000000..be05cceb2 --- /dev/null +++ b/plugins/sbt/package.json @@ -0,0 +1,46 @@ +{ + "name": "@auto-it/sbt", + "version": "10.25.1", + "main": "dist/index.js", + "description": "Publish Scala projects with sbt", + "license": "MIT", + "author": { + "name": "Alexey Alekhin", + "email": "laughedelic@gmail.com" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/intuit/auto" + }, + "files": [ + "dist" + ], + "keywords": [ + "automation", + "semantic", + "release", + "github", + "labels", + "automated", + "continuos integration", + "changelog", + "scala", + "sbt" + ], + "scripts": { + "build": "tsc -b", + "start": "npm run build -- -w", + "lint": "eslint src --ext .ts", + "test": "jest --maxWorkers=2 --config ../../package.json" + }, + "dependencies": { + "@auto-it/core": "link:../../packages/core", + "fp-ts": "^2.5.3", + "io-ts": "^2.1.2", + "tslib": "1.10.0" + } +} diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts new file mode 100644 index 000000000..99a0cb60f --- /dev/null +++ b/plugins/sbt/src/index.ts @@ -0,0 +1,31 @@ +import { Auto, IPlugin, validatePluginConfiguration } from '@auto-it/core'; +import * as t from "io-ts"; + +const pluginOptions = t.partial({ +}); + +export type ISbtPluginOptions = t.TypeOf; + +/** Publish Scala projects with sbt */ +export default class SbtPlugin implements IPlugin { + /** The name of the plugin */ + name = 'sbt'; + + /** The options of the plugin */ + readonly options: ISbtPluginOptions; + + /** Initialize the plugin with it's options */ + constructor(options: ISbtPluginOptions) { + this.options = options; + } + + /** Tap into auto plugin points. */ + apply(auto: Auto) { + auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { + // If it's a string thats valid config + if (name === this.name && typeof options !== "string") { + return validatePluginConfiguration(this.name, pluginOptions, options); + } + }); + } +} diff --git a/plugins/sbt/tsconfig.json b/plugins/sbt/tsconfig.json new file mode 100644 index 000000000..bfbef6fc7 --- /dev/null +++ b/plugins/sbt/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*", "../../typings/**/*"], + + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "composite": true + }, + + "references": [ + { + "path": "../../packages/core" + } + ] +} diff --git a/tsconfig.dev.json b/tsconfig.dev.json index 72275a469..827e03a84 100644 --- a/tsconfig.dev.json +++ b/tsconfig.dev.json @@ -88,6 +88,9 @@ }, { "path": "plugins/s3" + }, + { + "path": "plugins/sbt" } ] -} +} \ No newline at end of file From 357200256ba085fe530297d5cec4d345c01bcb18 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 02:32:04 +0200 Subject: [PATCH 02/31] add code from git-tag, implement publish/canary hooks --- plugins/sbt/src/index.ts | 127 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 99a0cb60f..f925183e0 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -1,15 +1,21 @@ -import { Auto, IPlugin, validatePluginConfiguration } from '@auto-it/core'; +import { + Auto, + execPromise, + getCurrentBranch, + IPlugin, + validatePluginConfiguration, +} from "@auto-it/core"; +import { inc, ReleaseType } from "semver"; import * as t from "io-ts"; -const pluginOptions = t.partial({ -}); +const pluginOptions = t.partial({}); export type ISbtPluginOptions = t.TypeOf; /** Publish Scala projects with sbt */ export default class SbtPlugin implements IPlugin { /** The name of the plugin */ - name = 'sbt'; + name = "sbt"; /** The options of the plugin */ readonly options: ISbtPluginOptions; @@ -21,11 +27,124 @@ export default class SbtPlugin implements IPlugin { /** Tap into auto plugin points. */ apply(auto: Auto) { + // exact copy-paste from the git-tag plugin + /** Get the latest tag in the repo, if none then the first commit */ + async function getTag() { + try { + return await auto.git!.getLatestTagInBranch(); + } catch (error) { + return auto.prefixRelease("0.0.0"); + } + } + auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { // If it's a string thats valid config if (name === this.name && typeof options !== "string") { return validatePluginConfiguration(this.name, pluginOptions, options); } }); + + // exact copy-paste from the git-tag plugin + auto.hooks.getPreviousVersion.tapPromise(this.name, async () => { + if (!auto.git) { + throw new Error( + "Can't calculate previous version without Git initialized!", + ); + } + + return getTag(); + }); + + // exact copy-paste from the git-tag plugin + auto.hooks.version.tapPromise( + this.name, + async ({ bump, dryRun, quiet }) => { + if (!auto.git) { + return; + } + + const lastTag = await getTag(); + const newTag = inc(lastTag, bump as ReleaseType); + + if (dryRun && newTag) { + if (quiet) { + console.log(newTag); + } else { + auto.logger.log.info(`Would have published: ${newTag}`); + } + return; + } + + if (!newTag) { + auto.logger.log.info("No release found, doing nothing"); + return; + } + + const prefixedTag = auto.prefixRelease(newTag); + + auto.logger.log.info(`Tagging new tag: ${lastTag} => ${prefixedTag}`); + await execPromise("git", [ + "tag", + prefixedTag, + "-m", + `"Update version to ${prefixedTag}"`, + ]); + + auto.logger.log.info("Set version in sbt"); + await execPromise("sbt", [ + "--client", + `set every version := "${newTag}"`, + ]); + }, + ); + + auto.hooks.publish.tapPromise(this.name, async () => { + auto.logger.log.info("Run sbt publish"); + await execPromise("sbt", ["--client", "publish"]); + + auto.logger.log.info("Pushing new tag to GitHub"); + await execPromise("git", [ + "push", + "--follow-tags", + "--set-upstream", + auto.remote, + getCurrentBranch() || auto.baseBranch, + ]); + }); + + auto.hooks.canary.tapPromise( + this.name, + async ({ canaryIdentifier, dryRun, quiet }) => { + if (!auto.git) { + return; + } + + const lastRelease = await auto.git.getLatestRelease(); + const lastVersion = await auto.getCurrentVersion(lastRelease); + const canaryVersion = `${lastVersion}-${canaryIdentifier}`; + auto.logger.log.info(`Canary version: ${canaryVersion}`); + + if (dryRun) { + if (quiet) { + console.log(canaryVersion); + } else { + auto.logger.log.info(`Would have published: ${canaryVersion}`); + } + return; + } + + auto.logger.log.info("Set version in sbt"); + await execPromise("sbt", [ + "--client", + `set every version := "${canaryVersion}"`, + ]); + + auto.logger.log.info("Run sbt publish"); + await execPromise("sbt", ["--client", "publish"]); + + auto.logger.verbose.info("Successfully published canary version"); + return canaryVersion; + }, + ); } } From ca9252a270812c6ef6a89b7123e80b502fa9ddd2 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 02:44:16 +0200 Subject: [PATCH 03/31] add publish logs to the canary details --- plugins/sbt/src/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index f925183e0..19a5a2d9b 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -140,10 +140,13 @@ export default class SbtPlugin implements IPlugin { ]); auto.logger.log.info("Run sbt publish"); - await execPromise("sbt", ["--client", "publish"]); + const publishLogs = await execPromise("sbt", ["--client", "publish"]); auto.logger.verbose.info("Successfully published canary version"); - return canaryVersion; + return { + newVersion: canaryVersion, + details: publishLogs, + }; }, ); } From 136aa7b648d246a29ac1fdf65e85ae1525f7b551 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 03:26:26 +0200 Subject: [PATCH 04/31] blank lines --- plugins/sbt/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 19a5a2d9b..bf6b2fa8a 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -72,6 +72,7 @@ export default class SbtPlugin implements IPlugin { } else { auto.logger.log.info(`Would have published: ${newTag}`); } + return; } @@ -130,6 +131,7 @@ export default class SbtPlugin implements IPlugin { } else { auto.logger.log.info(`Would have published: ${canaryVersion}`); } + return; } From 28fd6d64a3049403421c06e5f261548d122ed44d Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 03:30:08 +0200 Subject: [PATCH 05/31] add semver dependency --- plugins/sbt/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/sbt/package.json b/plugins/sbt/package.json index be05cceb2..c41c942fb 100644 --- a/plugins/sbt/package.json +++ b/plugins/sbt/package.json @@ -41,6 +41,7 @@ "@auto-it/core": "link:../../packages/core", "fp-ts": "^2.5.3", "io-ts": "^2.1.2", + "semver": "^7.0.0", "tslib": "1.10.0" } } From 437b4d340ab1b22cde3c75650fdfce0fa93ce73c Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 04:22:49 +0200 Subject: [PATCH 06/31] refactor --- plugins/sbt/src/index.ts | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index bf6b2fa8a..af18d90be 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -37,6 +37,20 @@ export default class SbtPlugin implements IPlugin { } } + async function sbtClient(...args: string[]) { + return await execPromise("sbt", ["--client", ...args]); + } + + async function sbtSetVersion(version: string) { + auto.logger.log.info(`Set version in sbt to ${version}`); + return await sbtClient(`set every version := \\"${version}\\"`); + } + + async function sbtPublish() { + auto.logger.log.info("Run sbt publish"); + return await sbtClient("publish"); + } + auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { // If it's a string thats valid config if (name === this.name && typeof options !== "string") { @@ -91,17 +105,12 @@ export default class SbtPlugin implements IPlugin { `"Update version to ${prefixedTag}"`, ]); - auto.logger.log.info("Set version in sbt"); - await execPromise("sbt", [ - "--client", - `set every version := "${newTag}"`, - ]); + await sbtSetVersion(newTag); }, ); auto.hooks.publish.tapPromise(this.name, async () => { - auto.logger.log.info("Run sbt publish"); - await execPromise("sbt", ["--client", "publish"]); + await sbtPublish(); auto.logger.log.info("Pushing new tag to GitHub"); await execPromise("git", [ @@ -135,19 +144,17 @@ export default class SbtPlugin implements IPlugin { return; } - auto.logger.log.info("Set version in sbt"); - await execPromise("sbt", [ - "--client", - `set every version := "${canaryVersion}"`, - ]); - - auto.logger.log.info("Run sbt publish"); - const publishLogs = await execPromise("sbt", ["--client", "publish"]); + await sbtSetVersion(canaryVersion); + const publishLogs = await sbtPublish(); auto.logger.verbose.info("Successfully published canary version"); return { newVersion: canaryVersion, - details: publishLogs, + details: [ + "```", + publishLogs, + "```", + ].join("\n"), }; }, ); From 1f557128cf4de70a5fbbda0ba4ca18737eb0d935 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 04:42:13 +0200 Subject: [PATCH 07/31] add SNAPSHOT suffix to the canary version --- plugins/sbt/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index af18d90be..cfb837602 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -131,7 +131,7 @@ export default class SbtPlugin implements IPlugin { const lastRelease = await auto.git.getLatestRelease(); const lastVersion = await auto.getCurrentVersion(lastRelease); - const canaryVersion = `${lastVersion}-${canaryIdentifier}`; + const canaryVersion = `${lastVersion}${canaryIdentifier}-SNAPSHOT`; auto.logger.log.info(`Canary version: ${canaryVersion}`); if (dryRun) { From 730b776db77139aa09d96ff64de92199b721d7c0 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 05:14:36 +0200 Subject: [PATCH 08/31] use strip-ansi --- plugins/sbt/package.json | 1 + plugins/sbt/src/index.ts | 4 +++- yarn.lock | 23 ++++++++++++++++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/plugins/sbt/package.json b/plugins/sbt/package.json index c41c942fb..b88736e83 100644 --- a/plugins/sbt/package.json +++ b/plugins/sbt/package.json @@ -42,6 +42,7 @@ "fp-ts": "^2.5.3", "io-ts": "^2.1.2", "semver": "^7.0.0", + "strip-ansi": "^7.0.0", "tslib": "1.10.0" } } diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index cfb837602..124205982 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -7,6 +7,7 @@ import { } from "@auto-it/core"; import { inc, ReleaseType } from "semver"; import * as t from "io-ts"; +import stripAnsi from "strip-ansi"; const pluginOptions = t.partial({}); @@ -38,7 +39,8 @@ export default class SbtPlugin implements IPlugin { } async function sbtClient(...args: string[]) { - return await execPromise("sbt", ["--client", ...args]); + const output = await execPromise("sbt", ["--client", ...args]); + return stripAnsi(output); } async function sbtSetVersion(version: string) { diff --git a/yarn.lock b/yarn.lock index 5cf7f1064..3c2db0500 100644 --- a/yarn.lock +++ b/yarn.lock @@ -69,10 +69,10 @@ integrity sha512-TYiuOxy5Pf9ORn94X/ujl7PY9opIh+l6NzRAV8EBLpIv3IC9gmEoev4wmmyP7Q33J0/nGjqxAaZcq/n2SZrYaQ== "@auto-it/bot-list@link:packages/bot-list": - version "10.23.0" + version "10.25.1" "@auto-it/core@link:packages/core": - version "10.23.0" + version "10.25.1" dependencies: "@auto-it/bot-list" "link:packages/bot-list" "@endemolshinegroup/cosmiconfig-typescript-loader" "^3.0.2" @@ -102,6 +102,7 @@ parse-author "^2.0.0" parse-github-url "1.0.2" pretty-ms "^7.0.0" + requireg "^0.2.2" semver "^7.0.0" signale "^1.4.0" tapable "^2.0.0-beta.2" @@ -114,7 +115,7 @@ url-join "^4.0.0" "@auto-it/npm@link:plugins/npm": - version "10.23.0" + version "10.25.1" dependencies: "@auto-it/core" "link:packages/core" "@auto-it/package-json-utils" "link:packages/package-json-utils" @@ -132,13 +133,13 @@ user-home "^2.0.0" "@auto-it/package-json-utils@link:packages/package-json-utils": - version "10.23.0" + version "10.25.1" dependencies: parse-author "^2.0.0" parse-github-url "1.0.2" "@auto-it/released@link:plugins/released": - version "10.23.0" + version "10.25.1" dependencies: "@auto-it/bot-list" "link:packages/bot-list" "@auto-it/core" "link:packages/core" @@ -3886,6 +3887,11 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.0.tgz#ecc7f5933cbe5ac7b33e209a5ff409ab1669c6b2" + integrity sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -14713,6 +14719,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0" + integrity sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg== + dependencies: + ansi-regex "^6.0.0" + strip-bom-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" From db009e1b39b8b29a77f442f6e29405040f8134dd Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 05:34:14 +0200 Subject: [PATCH 09/31] cut off v prefix --- plugins/sbt/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 124205982..a3efae632 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -131,8 +131,8 @@ export default class SbtPlugin implements IPlugin { return; } - const lastRelease = await auto.git.getLatestRelease(); - const lastVersion = await auto.getCurrentVersion(lastRelease); + const lastTag = await getTag(); + const lastVersion = lastTag.replace(/^v/, ""); const canaryVersion = `${lastVersion}${canaryIdentifier}-SNAPSHOT`; auto.logger.log.info(`Canary version: ${canaryVersion}`); From 5e717035551a5a981c9c5709a6ba0903071d21b4 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 05:47:11 +0200 Subject: [PATCH 10/31] clean output log --- plugins/sbt/src/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index a3efae632..9e454befa 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -5,7 +5,7 @@ import { IPlugin, validatePluginConfiguration, } from "@auto-it/core"; -import { inc, ReleaseType } from "semver"; +import { clean, inc, ReleaseType } from "semver"; import * as t from "io-ts"; import stripAnsi from "strip-ansi"; @@ -40,7 +40,8 @@ export default class SbtPlugin implements IPlugin { async function sbtClient(...args: string[]) { const output = await execPromise("sbt", ["--client", ...args]); - return stripAnsi(output); + const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); + return cleanOutput; } async function sbtSetVersion(version: string) { @@ -50,7 +51,9 @@ export default class SbtPlugin implements IPlugin { async function sbtPublish() { auto.logger.log.info("Run sbt publish"); - return await sbtClient("publish"); + const publishLog = await sbtClient("publish"); + auto.logger.log.info("Output:\n" + publishLog); + return publishLog; } auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { From baa64ecab5922ff6753255122fa95705a24bacdf Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 15:16:29 +0200 Subject: [PATCH 11/31] unused import --- plugins/sbt/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 9e454befa..df4894405 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -5,7 +5,7 @@ import { IPlugin, validatePluginConfiguration, } from "@auto-it/core"; -import { clean, inc, ReleaseType } from "semver"; +import { inc, ReleaseType } from "semver"; import * as t from "io-ts"; import stripAnsi from "strip-ansi"; From c820bfd619597bbd27d75448e23c5f887b0e8a7f Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Sun, 25 Apr 2021 17:14:05 +0200 Subject: [PATCH 12/31] add manageVersion config option --- plugins/sbt/src/index.ts | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index df4894405..ead153899 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -9,7 +9,9 @@ import { inc, ReleaseType } from "semver"; import * as t from "io-ts"; import stripAnsi from "strip-ansi"; -const pluginOptions = t.partial({}); +const pluginOptions = t.partial({ + manageVersion: t.boolean, +}); export type ISbtPluginOptions = t.TypeOf; @@ -44,6 +46,16 @@ export default class SbtPlugin implements IPlugin { return cleanOutput; } + async function sbtGetVersion() { + const output = await sbtClient("print version"); + const version = output.split("\n").shift(); + if (!version) { + throw new Error(`Failed to read version from sbt: ${output}`); + } + auto.logger.log.info(`Got version from sbt: ${version}`); + return version; + } + async function sbtSetVersion(version: string) { auto.logger.log.info(`Set version in sbt to ${version}`); return await sbtClient(`set every version := \\"${version}\\"`); @@ -110,7 +122,9 @@ export default class SbtPlugin implements IPlugin { `"Update version to ${prefixedTag}"`, ]); - await sbtSetVersion(newTag); + if (this.options.manageVersion) { + await sbtSetVersion(newTag); + } }, ); @@ -127,6 +141,12 @@ export default class SbtPlugin implements IPlugin { ]); }); + async function getCanaryVersion(canaryIdentifier: string) { + const lastTag = await getTag(); + const lastVersion = lastTag.replace(/^v/, ""); + return `${lastVersion}${canaryIdentifier}-SNAPSHOT`; + } + auto.hooks.canary.tapPromise( this.name, async ({ canaryIdentifier, dryRun, quiet }) => { @@ -134,9 +154,9 @@ export default class SbtPlugin implements IPlugin { return; } - const lastTag = await getTag(); - const lastVersion = lastTag.replace(/^v/, ""); - const canaryVersion = `${lastVersion}${canaryIdentifier}-SNAPSHOT`; + const canaryVersion = this.options.manageVersion + ? await getCanaryVersion(canaryIdentifier) + : await sbtGetVersion(); auto.logger.log.info(`Canary version: ${canaryVersion}`); if (dryRun) { @@ -149,7 +169,10 @@ export default class SbtPlugin implements IPlugin { return; } - await sbtSetVersion(canaryVersion); + if (this.options.manageVersion) { + await sbtSetVersion(canaryVersion); + } + const publishLogs = await sbtPublish(); auto.logger.verbose.info("Successfully published canary version"); From 7c6925e145224a769c2ac76f0a5420dc2c274ed8 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 01:19:59 +0200 Subject: [PATCH 13/31] docs --- plugins/sbt/README.md | 53 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md index 25fa6a266..3b52b892c 100644 --- a/plugins/sbt/README.md +++ b/plugins/sbt/README.md @@ -1,4 +1,4 @@ -# Sbt Plugin +# sbt plugin Publish Scala projects with sbt @@ -18,7 +18,56 @@ yarn add -D @auto-it/sbt { "plugins": [ "sbt" - // other plugins ] } ``` + +It is strongly recommended to use an sbt plugin to manage the version. There are a few options, but the most reliable and well maintained is [sbt-dynver](https://github.com/dwijnand/sbt-dynver). To enable it in your project add this line to `project/plugins.sbt`: + +```scala +addSbtPlugin("com.dwijnand" % "sbt-dynver" % "x.y.z") +``` + +and then, depending on the publishing repository (e.g. if you are publishing to Sonatype Nexus), you might want to add + +```scala +ThisBuild / dynverSeparator := "-" +ThisBuild / dynverSonatypeSnapshots := true +``` + +to your `build.sbt`. + +With this setup canary versions will look like this: `{last_tag}-{number_of_commits}-{commit_sha}-SNAPSHOT`, for example: + +``` +0.1.2-5-fcdf268c-SNAPSHOT +``` + +## Options + +### `manageVersion: boolean` (default: `false`) + +If you don't want to use an sbt plugin for version management, you can let Auto manage the version: + +```json +{ + "plugins": [ + [ + "sbt", + { + "manageVersion": true + } + ] + ] +} +``` + +With this option Auto will override the version in sbt during the release process. + +Canary versions will look like this: `{last_tag}-canary.{pr_number}.{build_number}-SNAPSHOT`, for example: + +``` +0.1.2-canary.47.5fa1736-SNAPSHOT +``` + +Here build number is the git commit SHA. From 84ca44dd86ba5d291f9b39580a805f48d810e5c7 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 01:35:13 +0200 Subject: [PATCH 14/31] linting --- plugins/sbt/src/index.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index ead153899..4d99b1475 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -40,27 +40,32 @@ export default class SbtPlugin implements IPlugin { } } + /** Calls sbt in the client and returns cleaned up logs */ async function sbtClient(...args: string[]) { const output = await execPromise("sbt", ["--client", ...args]); const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); return cleanOutput; } + /** Read version from sbt */ async function sbtGetVersion() { const output = await sbtClient("print version"); const version = output.split("\n").shift(); if (!version) { throw new Error(`Failed to read version from sbt: ${output}`); } + auto.logger.log.info(`Got version from sbt: ${version}`); return version; } + /** Set version in sbt to the given value */ async function sbtSetVersion(version: string) { - auto.logger.log.info(`Set version in sbt to ${version}`); - return await sbtClient(`set every version := \\"${version}\\"`); + auto.logger.log.info(`Set version in sbt to "${version}"`); + return sbtClient(`set every version := \\"${version}\\"`); } + /** Run sbt publish */ async function sbtPublish() { auto.logger.log.info("Run sbt publish"); const publishLog = await sbtClient("publish"); @@ -68,6 +73,13 @@ export default class SbtPlugin implements IPlugin { return publishLog; } + /** Construct canary version using Auto-provided suffix */ + async function getCanaryVersion(canaryIdentifier: string) { + const lastTag = await getTag(); + const lastVersion = lastTag.replace(/^v/, ""); + return `${lastVersion}${canaryIdentifier}-SNAPSHOT`; + } + auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { // If it's a string thats valid config if (name === this.name && typeof options !== "string") { @@ -141,12 +153,6 @@ export default class SbtPlugin implements IPlugin { ]); }); - async function getCanaryVersion(canaryIdentifier: string) { - const lastTag = await getTag(); - const lastVersion = lastTag.replace(/^v/, ""); - return `${lastVersion}${canaryIdentifier}-SNAPSHOT`; - } - auto.hooks.canary.tapPromise( this.name, async ({ canaryIdentifier, dryRun, quiet }) => { From 5f91ad3f21f7bb48fdeb4fb047ed4951a42e60cd Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 01:47:46 +0200 Subject: [PATCH 15/31] note about sbt version --- plugins/sbt/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md index 3b52b892c..eb0275d4e 100644 --- a/plugins/sbt/README.md +++ b/plugins/sbt/README.md @@ -2,6 +2,8 @@ Publish Scala projects with sbt +> :warning: only sbt 1.4+ is supported at the moment because this plugin uses `sbt --client` functionality + ## Installation This plugin is not included with the `auto` CLI installed via NPM. To install: From 5f65920715169ce95b472a71c1d80256910c98ea Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 01:50:19 +0200 Subject: [PATCH 16/31] remove unused test --- plugins/sbt/__tests__/sbt.test.ts | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 plugins/sbt/__tests__/sbt.test.ts diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts deleted file mode 100644 index 5ad6efe56..000000000 --- a/plugins/sbt/__tests__/sbt.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import Auto from '@auto-it/core'; -import Sbt from '../src'; - -describe('Sbt Plugin', () => { - test('should do something', async () => { - }); -}); From 6b1ae33dfa07d06097b51c30daee6eba7b77fac3 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 02:09:35 +0200 Subject: [PATCH 17/31] don't aggregate version --- plugins/sbt/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 4d99b1475..daa2c66dd 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -49,6 +49,7 @@ export default class SbtPlugin implements IPlugin { /** Read version from sbt */ async function sbtGetVersion() { + await sbtClient("set version/aggregate := false"); const output = await sbtClient("print version"); const version = output.split("\n").shift(); if (!version) { From 20bd60afb55ddc803f9a07d32216b2950cf3736f Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 02:11:28 +0200 Subject: [PATCH 18/31] trim version output --- plugins/sbt/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index daa2c66dd..74a027e8a 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -49,9 +49,10 @@ export default class SbtPlugin implements IPlugin { /** Read version from sbt */ async function sbtGetVersion() { + // in multi-module projects, we want to get only ThisBuild/version await sbtClient("set version/aggregate := false"); const output = await sbtClient("print version"); - const version = output.split("\n").shift(); + const version = output.split("\n").shift()?.trim(); if (!version) { throw new Error(`Failed to read version from sbt: ${output}`); } From bef0fe9a8b6ac924cd0e47a3a867b02dc1efaa63 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Mon, 26 Apr 2021 19:17:02 +0200 Subject: [PATCH 19/31] downgrade strip-ansi --- plugins/sbt/package.json | 2 +- yarn.lock | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/plugins/sbt/package.json b/plugins/sbt/package.json index b88736e83..6636f5824 100644 --- a/plugins/sbt/package.json +++ b/plugins/sbt/package.json @@ -42,7 +42,7 @@ "fp-ts": "^2.5.3", "io-ts": "^2.1.2", "semver": "^7.0.0", - "strip-ansi": "^7.0.0", + "strip-ansi": "^6.0.0", "tslib": "1.10.0" } } diff --git a/yarn.lock b/yarn.lock index 3c2db0500..9ac9c14f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3887,11 +3887,6 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-regex@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.0.tgz#ecc7f5933cbe5ac7b33e209a5ff409ab1669c6b2" - integrity sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ== - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -14719,13 +14714,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0" - integrity sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg== - dependencies: - ansi-regex "^6.0.0" - strip-bom-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" From d600aae82acfe2579d627e082ebb7f97539f2921 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 02:11:38 +0200 Subject: [PATCH 20/31] add publishCommand option --- plugins/sbt/README.md | 17 +++++++++++++++++ plugins/sbt/src/index.ts | 9 +++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md index eb0275d4e..fdd94403c 100644 --- a/plugins/sbt/README.md +++ b/plugins/sbt/README.md @@ -73,3 +73,20 @@ Canary versions will look like this: `{last_tag}-canary.{pr_number}.{build_numbe ``` Here build number is the git commit SHA. + +### `publishCommand: string` (default: `publish`) + +If you need to run some custom publishing command, you can change this option. For example, to cross-publish a library: + +```json +{ + "plugins": [ + [ + "sbt", + { + "publishCommand": "+publish" + } + ] + ] +} +``` diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 74a027e8a..e9cfad44e 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -11,6 +11,7 @@ import stripAnsi from "strip-ansi"; const pluginOptions = t.partial({ manageVersion: t.boolean, + publishCommand: t.string, }); export type ISbtPluginOptions = t.TypeOf; @@ -68,9 +69,9 @@ export default class SbtPlugin implements IPlugin { } /** Run sbt publish */ - async function sbtPublish() { + async function sbtPublish(command?: string) { auto.logger.log.info("Run sbt publish"); - const publishLog = await sbtClient("publish"); + const publishLog = await sbtClient(command || "publish"); auto.logger.log.info("Output:\n" + publishLog); return publishLog; } @@ -143,7 +144,7 @@ export default class SbtPlugin implements IPlugin { ); auto.hooks.publish.tapPromise(this.name, async () => { - await sbtPublish(); + await sbtPublish(this.options.publishCommand); auto.logger.log.info("Pushing new tag to GitHub"); await execPromise("git", [ @@ -181,7 +182,7 @@ export default class SbtPlugin implements IPlugin { await sbtSetVersion(canaryVersion); } - const publishLogs = await sbtPublish(); + const publishLogs = await sbtPublish(this.options.publishCommand); auto.logger.verbose.info("Successfully published canary version"); return { From 8c2dda9a71d9029919f02bb3ad75ced15b2a6d9a Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 02:16:49 +0200 Subject: [PATCH 21/31] switch sbt-specific logs to verbose logger --- plugins/sbt/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index e9cfad44e..f75614edd 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -58,21 +58,21 @@ export default class SbtPlugin implements IPlugin { throw new Error(`Failed to read version from sbt: ${output}`); } - auto.logger.log.info(`Got version from sbt: ${version}`); + auto.logger.verbose.info(`Got version from sbt: ${version}`); return version; } /** Set version in sbt to the given value */ async function sbtSetVersion(version: string) { - auto.logger.log.info(`Set version in sbt to "${version}"`); + auto.logger.verbose.info(`Set version in sbt to "${version}"`); return sbtClient(`set every version := \\"${version}\\"`); } /** Run sbt publish */ async function sbtPublish(command?: string) { - auto.logger.log.info("Run sbt publish"); + auto.logger.verbose.info("Run sbt publish"); const publishLog = await sbtClient(command || "publish"); - auto.logger.log.info("Output:\n" + publishLog); + auto.logger.verbose.info("Output:\n" + publishLog); return publishLog; } From f6cfefc4274ceeeb7991d4a0e035bf70a5c29f25 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 02:19:29 +0200 Subject: [PATCH 22/31] adjust sbtClient interface --- plugins/sbt/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index f75614edd..60353b609 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -42,8 +42,8 @@ export default class SbtPlugin implements IPlugin { } /** Calls sbt in the client and returns cleaned up logs */ - async function sbtClient(...args: string[]) { - const output = await execPromise("sbt", ["--client", ...args]); + async function sbtClient(input: string) { + const output = await execPromise("sbt", ["--client", input]); const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); return cleanOutput; } From 6de4587a1d1a876d5ab03e470c5c5ae8545e5163 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 02:23:43 +0200 Subject: [PATCH 23/31] always set version on release --- plugins/sbt/src/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index 60353b609..bbf202bd4 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -137,9 +137,7 @@ export default class SbtPlugin implements IPlugin { `"Update version to ${prefixedTag}"`, ]); - if (this.options.manageVersion) { - await sbtSetVersion(newTag); - } + await sbtSetVersion(newTag); }, ); From 552297ef21e7a29162f9c531b855753a2edec395 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 02:25:16 +0200 Subject: [PATCH 24/31] rename manageVersion to setCanaryVersion --- plugins/sbt/README.md | 8 ++++---- plugins/sbt/src/index.ts | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md index fdd94403c..e287f09e9 100644 --- a/plugins/sbt/README.md +++ b/plugins/sbt/README.md @@ -47,9 +47,9 @@ With this setup canary versions will look like this: `{last_tag}-{number_of_comm ## Options -### `manageVersion: boolean` (default: `false`) +### `setCanaryVersion: boolean` (default: `false`) -If you don't want to use an sbt plugin for version management, you can let Auto manage the version: +If you don't want to use an sbt plugin for version management, you can let Auto manage the canary version: ```json { @@ -57,14 +57,14 @@ If you don't want to use an sbt plugin for version management, you can let Auto [ "sbt", { - "manageVersion": true + "setCanaryVersion": true } ] ] } ``` -With this option Auto will override the version in sbt during the release process. +With this option Auto will override the version in sbt during canary release process. Canary versions will look like this: `{last_tag}-canary.{pr_number}.{build_number}-SNAPSHOT`, for example: diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index bbf202bd4..b9255688e 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -10,7 +10,7 @@ import * as t from "io-ts"; import stripAnsi from "strip-ansi"; const pluginOptions = t.partial({ - manageVersion: t.boolean, + setCanaryVersion: t.boolean, publishCommand: t.string, }); @@ -161,7 +161,7 @@ export default class SbtPlugin implements IPlugin { return; } - const canaryVersion = this.options.manageVersion + const canaryVersion = this.options.setCanaryVersion ? await getCanaryVersion(canaryIdentifier) : await sbtGetVersion(); auto.logger.log.info(`Canary version: ${canaryVersion}`); @@ -176,7 +176,7 @@ export default class SbtPlugin implements IPlugin { return; } - if (this.options.manageVersion) { + if (this.options.setCanaryVersion) { await sbtSetVersion(canaryVersion); } From 266fdb6a853fd5d11e2f97f54f36cbef06a8c32f Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 03:02:36 +0200 Subject: [PATCH 25/31] pull sbt helpers out for testing --- plugins/sbt/src/index.ts | 89 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index b9255688e..ededd0023 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -16,6 +16,36 @@ const pluginOptions = t.partial({ export type ISbtPluginOptions = t.TypeOf; +/** Calls sbt in the client and returns cleaned up logs */ +async function sbtClient(input: string): Promise { + const output = await execPromise("sbt", ["--client", input]); + const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); + return cleanOutput; +} + +/** Read version from sbt */ +async function sbtGetVersion(): Promise { + // in multi-module projects, we want to get only ThisBuild/version + await sbtClient("set version/aggregate := false"); + const output = await sbtClient("print version"); + const version = output.split("\n").shift()?.trim(); + if (!version) { + throw new Error(`Failed to read version from sbt: ${output}`); + } + + return version; +} + +/** Set version in sbt to the given value */ +async function sbtSetVersion(version: string): Promise { + return sbtClient(`set every version := \\"${version}\\"`); +} + +/** Run sbt publish */ +async function sbtPublish(command?: string): Promise { + return sbtClient(command || "publish"); +} + /** Publish Scala projects with sbt */ export default class SbtPlugin implements IPlugin { /** The name of the plugin */ @@ -41,48 +71,6 @@ export default class SbtPlugin implements IPlugin { } } - /** Calls sbt in the client and returns cleaned up logs */ - async function sbtClient(input: string) { - const output = await execPromise("sbt", ["--client", input]); - const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); - return cleanOutput; - } - - /** Read version from sbt */ - async function sbtGetVersion() { - // in multi-module projects, we want to get only ThisBuild/version - await sbtClient("set version/aggregate := false"); - const output = await sbtClient("print version"); - const version = output.split("\n").shift()?.trim(); - if (!version) { - throw new Error(`Failed to read version from sbt: ${output}`); - } - - auto.logger.verbose.info(`Got version from sbt: ${version}`); - return version; - } - - /** Set version in sbt to the given value */ - async function sbtSetVersion(version: string) { - auto.logger.verbose.info(`Set version in sbt to "${version}"`); - return sbtClient(`set every version := \\"${version}\\"`); - } - - /** Run sbt publish */ - async function sbtPublish(command?: string) { - auto.logger.verbose.info("Run sbt publish"); - const publishLog = await sbtClient(command || "publish"); - auto.logger.verbose.info("Output:\n" + publishLog); - return publishLog; - } - - /** Construct canary version using Auto-provided suffix */ - async function getCanaryVersion(canaryIdentifier: string) { - const lastTag = await getTag(); - const lastVersion = lastTag.replace(/^v/, ""); - return `${lastVersion}${canaryIdentifier}-SNAPSHOT`; - } - auto.hooks.validateConfig.tapPromise(this.name, async (name, options) => { // If it's a string thats valid config if (name === this.name && typeof options !== "string") { @@ -137,12 +125,15 @@ export default class SbtPlugin implements IPlugin { `"Update version to ${prefixedTag}"`, ]); + auto.logger.verbose.info(`Set version in sbt to "${newTag}"`); await sbtSetVersion(newTag); }, ); auto.hooks.publish.tapPromise(this.name, async () => { - await sbtPublish(this.options.publishCommand); + auto.logger.verbose.info("Run sbt publish"); + const publishLogs = await sbtPublish(this.options.publishCommand); + auto.logger.verbose.info("Output:\n", publishLogs); auto.logger.log.info("Pushing new tag to GitHub"); await execPromise("git", [ @@ -161,8 +152,15 @@ export default class SbtPlugin implements IPlugin { return; } + /** Construct canary version using Auto-provided suffix */ + const constructCanaryVersion = async () => { + const lastTag = await getTag(); + const lastVersion = lastTag.replace(/^v/, ""); + return `${lastVersion}${canaryIdentifier}-SNAPSHOT`; + }; + const canaryVersion = this.options.setCanaryVersion - ? await getCanaryVersion(canaryIdentifier) + ? await constructCanaryVersion() : await sbtGetVersion(); auto.logger.log.info(`Canary version: ${canaryVersion}`); @@ -177,10 +175,13 @@ export default class SbtPlugin implements IPlugin { } if (this.options.setCanaryVersion) { + auto.logger.verbose.info(`Set version in sbt to "${canaryVersion}"`); await sbtSetVersion(canaryVersion); } + auto.logger.verbose.info("Run sbt publish"); const publishLogs = await sbtPublish(this.options.publishCommand); + auto.logger.verbose.info("Output:\n", publishLogs); auto.logger.verbose.info("Successfully published canary version"); return { From ec195d3675fc4f1bb8744f6af3210766fed5231d Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 03:48:19 +0200 Subject: [PATCH 26/31] first test for cleaning sbt client output --- plugins/sbt/__tests__/sbt.test.ts | 64 +++++++++++++++++++++++++++++++ plugins/sbt/src/index.ts | 8 ++-- 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 plugins/sbt/__tests__/sbt.test.ts diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts new file mode 100644 index 000000000..355e76360 --- /dev/null +++ b/plugins/sbt/__tests__/sbt.test.ts @@ -0,0 +1,64 @@ +import * as Auto from "@auto-it/core"; +import { dummyLog } from "@auto-it/core/dist/utils/logger"; +import { makeHooks } from "@auto-it/core/dist/utils/make-hooks"; +import SbtPlugin, { ISbtPluginOptions, sbtClient } from "../src"; + +// const sbt = jest.fn(); +const exec = jest.fn(); + +// @ts-ignore +// sbtClient.mockImplementation(sbt); + +jest.mock( + "../../../packages/core/dist/utils/exec-promise", + () => (...args: any[]) => exec(...args), +); + +const rawOutput = + `[info] entering *experimental* thin client - BEEP WHIRR +[info] terminate the server with \`shutdown\` +> print version +1.2.3 +[success] Total time: 2 s, completed Apr 27, 2021 3:39:23 AM +`; + +const cleanedOutput = `1.2.3 +[success] Total time: 2 s, completed Apr 27, 2021 3:39:23 AM`; + +describe("sbt Plugin", () => { + let hooks: Auto.IAutoHooks; + const prefixRelease: (a: string) => string = jest.fn( + (version) => `v${version}`, + ); + const options: ISbtPluginOptions = {}; + const logger = dummyLog(); + + beforeEach(() => { + exec.mockClear(); + const plugin = new SbtPlugin(options); + hooks = makeHooks(); + plugin.apply( + ({ + hooks, + logger, + remote: "stubRemote", + prefixRelease, + git: { + getLastTagNotInBaseBranch: async () => undefined, + getLatestRelease: async () => "0.0.1", + }, + getCurrentVersion: async () => "0.0.1", + } as unknown) as Auto.Auto, + ); + }); + + describe("sbt client", () => { + test("should clean output", async () => { + exec.mockReturnValueOnce(rawOutput); + + const output = await sbtClient(""); + + expect(output).toBe(cleanedOutput); + }); + }); +}); diff --git a/plugins/sbt/src/index.ts b/plugins/sbt/src/index.ts index ededd0023..faf8e1989 100644 --- a/plugins/sbt/src/index.ts +++ b/plugins/sbt/src/index.ts @@ -17,14 +17,14 @@ const pluginOptions = t.partial({ export type ISbtPluginOptions = t.TypeOf; /** Calls sbt in the client and returns cleaned up logs */ -async function sbtClient(input: string): Promise { +export async function sbtClient(input: string): Promise { const output = await execPromise("sbt", ["--client", input]); const cleanOutput = stripAnsi(output).replace(/(.*\n)*^>.*$/m, "").trim(); return cleanOutput; } /** Read version from sbt */ -async function sbtGetVersion(): Promise { +export async function sbtGetVersion(): Promise { // in multi-module projects, we want to get only ThisBuild/version await sbtClient("set version/aggregate := false"); const output = await sbtClient("print version"); @@ -37,12 +37,12 @@ async function sbtGetVersion(): Promise { } /** Set version in sbt to the given value */ -async function sbtSetVersion(version: string): Promise { +export async function sbtSetVersion(version: string): Promise { return sbtClient(`set every version := \\"${version}\\"`); } /** Run sbt publish */ -async function sbtPublish(command?: string): Promise { +export async function sbtPublish(command?: string): Promise { return sbtClient(command || "publish"); } From 788db29c107a2a895b966a641366bfad76c8e10b Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 04:01:52 +0200 Subject: [PATCH 27/31] tests for sbtGetVersion --- plugins/sbt/__tests__/sbt.test.ts | 38 ++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts index 355e76360..ad3234f63 100644 --- a/plugins/sbt/__tests__/sbt.test.ts +++ b/plugins/sbt/__tests__/sbt.test.ts @@ -1,7 +1,13 @@ import * as Auto from "@auto-it/core"; import { dummyLog } from "@auto-it/core/dist/utils/logger"; import { makeHooks } from "@auto-it/core/dist/utils/make-hooks"; -import SbtPlugin, { ISbtPluginOptions, sbtClient } from "../src"; +import SbtPlugin, { + ISbtPluginOptions, + sbtClient, + sbtGetVersion, + sbtPublish, + sbtSetVersion, +} from "../src"; // const sbt = jest.fn(); const exec = jest.fn(); @@ -25,6 +31,17 @@ const rawOutput = const cleanedOutput = `1.2.3 [success] Total time: 2 s, completed Apr 27, 2021 3:39:23 AM`; +const rawAggregationOutput = + `[info] entering *experimental* thin client - BEEP WHIRR +[info] terminate the server with \`shutdown\` +> set version/aggregate := false +[info] Defining version / aggregate +[info] The new value will be used by no settings or tasks. +[info] Reapplying settings... +[info] set current project to auto-release-test-scala (in build file:/Users/user/project/) +[success] Total time: 2 s, completed Apr 27, 2021 3:52:04 AM +v`; + describe("sbt Plugin", () => { let hooks: Auto.IAutoHooks; const prefixRelease: (a: string) => string = jest.fn( @@ -55,10 +72,25 @@ describe("sbt Plugin", () => { describe("sbt client", () => { test("should clean output", async () => { exec.mockReturnValueOnce(rawOutput); - const output = await sbtClient(""); - expect(output).toBe(cleanedOutput); }); + + test("should parse version value", async () => { + exec + .mockReturnValueOnce(rawAggregationOutput) + .mockReturnValueOnce(rawOutput); + const output = await sbtGetVersion(); + expect(output).toBe("1.2.3"); + }); + + test("should error if it can't parse version value", async () => { + exec + .mockReturnValueOnce(rawAggregationOutput) + .mockReturnValueOnce(""); + await expect(sbtGetVersion()).rejects.toThrowError( + `Failed to read version from sbt: `, + ); + }); }); }); From eba3fabd2c8107fe92b5a5c649d110f863e5e38d Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 05:37:46 +0200 Subject: [PATCH 28/31] moar tests! --- plugins/sbt/__tests__/sbt.test.ts | 138 ++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts index ad3234f63..58d3d8506 100644 --- a/plugins/sbt/__tests__/sbt.test.ts +++ b/plugins/sbt/__tests__/sbt.test.ts @@ -5,16 +5,11 @@ import SbtPlugin, { ISbtPluginOptions, sbtClient, sbtGetVersion, - sbtPublish, sbtSetVersion, } from "../src"; -// const sbt = jest.fn(); const exec = jest.fn(); -// @ts-ignore -// sbtClient.mockImplementation(sbt); - jest.mock( "../../../packages/core/dist/utils/exec-promise", () => (...args: any[]) => exec(...args), @@ -42,7 +37,7 @@ const rawAggregationOutput = [success] Total time: 2 s, completed Apr 27, 2021 3:52:04 AM v`; -describe("sbt Plugin", () => { +describe("sbt plugin", () => { let hooks: Auto.IAutoHooks; const prefixRelease: (a: string) => string = jest.fn( (version) => `v${version}`, @@ -50,8 +45,7 @@ describe("sbt Plugin", () => { const options: ISbtPluginOptions = {}; const logger = dummyLog(); - beforeEach(() => { - exec.mockClear(); + const setup = (options: ISbtPluginOptions) => { const plugin = new SbtPlugin(options); hooks = makeHooks(); plugin.apply( @@ -67,6 +61,11 @@ describe("sbt Plugin", () => { getCurrentVersion: async () => "0.0.1", } as unknown) as Auto.Auto, ); + }; + + beforeEach(() => { + exec.mockClear(); + setup(options); }); describe("sbt client", () => { @@ -93,4 +92,127 @@ describe("sbt Plugin", () => { ); }); }); + + describe("version hook", () => { + test("should set version in sbt", async () => { + exec.mockReturnValue(""); + + await hooks.version.promise({ + bump: Auto.SEMVER.minor, + }); + expect(exec).toHaveBeenCalledTimes(2); + expect(exec).lastCalledWith("sbt", [ + "--client", + 'set every version := \\"0.1.0\\"', + ]); + }); + }); + + describe("publish hook", () => { + test("should call sbt publish", async () => { + exec.mockReturnValue(""); + + await hooks.publish.promise({ + bump: Auto.SEMVER.minor, + }); + + expect(exec).toHaveBeenCalledWith("sbt", [ + "--client", + "publish", + ]); + }); + + test("should call sbt publish with custom command", async () => { + setup({ + publishCommand: "+publishLocal", + }); + exec.mockReturnValue(""); + + await hooks.publish.promise({ + bump: Auto.SEMVER.minor, + }); + + expect(exec).toHaveBeenCalledWith("sbt", [ + "--client", + "+publishLocal", + ]); + }); + }); + + describe("canary hook", () => { + test("should only read version from sbt on dry run", async () => { + exec + .mockReturnValueOnce(rawAggregationOutput) + .mockReturnValueOnce(rawOutput); + + await hooks.canary.promise({ + bump: Auto.SEMVER.minor, + canaryIdentifier: "-canary.42.1", + dryRun: true, + }); + + expect(exec).toHaveBeenCalledTimes(2); // 2 calls in sbtGetVersion + }); + + test("should return version from sbt as canary", async () => { + exec.mockReturnValue(rawOutput); + + const result = await hooks.canary.promise({ + bump: Auto.SEMVER.minor, + canaryIdentifier: "-canary.42.1", + }); + + expect(exec).not.toHaveBeenCalledWith("sbt", [ + "--client", + 'set every version := \\"0.1.0\\"', + ]); + + expect(result).toMatchObject({ + newVersion: "1.2.3", + details: [ + "```", + cleanedOutput, + "```", + ].join("\n"), + }); + }); + + test("should construct canary version when configured", async () => { + setup({ + setCanaryVersion: true, + }); + exec.mockReturnValue(rawOutput); + + const result = await hooks.canary.promise({ + bump: Auto.SEMVER.minor, + canaryIdentifier: "-canary.42.1", + }); + + const newVersion = "0.0.0-canary.42.1-SNAPSHOT"; + + expect(exec).toHaveBeenCalledWith("sbt", [ + "--client", + `set every version := \\"${newVersion}\\"`, + ]); + + expect(result).toMatchObject({ newVersion }); + }); + + test("should call sbt publish with custom command", async () => { + setup({ + publishCommand: "+publishLocal", + }); + exec.mockReturnValue(rawOutput); + + await hooks.canary.promise({ + bump: Auto.SEMVER.minor, + canaryIdentifier: "-canary.42.1", + }); + + expect(exec).toHaveBeenCalledWith("sbt", [ + "--client", + "+publishLocal", + ]); + }); + }); }); From 47627ce7862db95347c7784fbda3bd1e363808c3 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Tue, 27 Apr 2021 15:57:28 +0200 Subject: [PATCH 29/31] unused import --- plugins/sbt/__tests__/sbt.test.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/sbt/__tests__/sbt.test.ts b/plugins/sbt/__tests__/sbt.test.ts index 58d3d8506..eec2fac39 100644 --- a/plugins/sbt/__tests__/sbt.test.ts +++ b/plugins/sbt/__tests__/sbt.test.ts @@ -1,12 +1,7 @@ import * as Auto from "@auto-it/core"; import { dummyLog } from "@auto-it/core/dist/utils/logger"; import { makeHooks } from "@auto-it/core/dist/utils/make-hooks"; -import SbtPlugin, { - ISbtPluginOptions, - sbtClient, - sbtGetVersion, - sbtSetVersion, -} from "../src"; +import SbtPlugin, { ISbtPluginOptions, sbtClient, sbtGetVersion } from "../src"; const exec = jest.fn(); From bd18523d33787e11263dafce437cd909c27d3ec1 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Thu, 29 Apr 2021 02:41:56 +0200 Subject: [PATCH 30/31] mention new plugin in the docs --- README.md | 1 + docs/pages/docs/_sidebar.mdx | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 610986a86..a3e552be2 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Auto has an extensive plugin system and wide variety of official plugins. Make a - [gradle](./plugins/gradle) - Publish code with gradle - [maven](./plugins/maven) - Publish code with maven - [npm](./plugins/npm) - Publish code to npm (`default` when installed through `npm`) +- [sbt](./plugins/sbt) - Publish Scala projects with [sbt](https://www.scala-sbt.org) - [vscode](./plugins/vscode) - Publish code to the VSCode extension marketplace **Extra Functionality:** diff --git a/docs/pages/docs/_sidebar.mdx b/docs/pages/docs/_sidebar.mdx index 114c57ac7..5e8285887 100644 --- a/docs/pages/docs/_sidebar.mdx +++ b/docs/pages/docs/_sidebar.mdx @@ -55,6 +55,7 @@ Package Manager Plugins - [Gradle](./generated/gradle) - [Maven](./generated/maven) - [NPM](./generated/npm) +- [sbt](./generated/sbt) - [VSCode](./generated/vscode) Functionality Plugins From 7ef81a87fd42e2ede1262a29948648dc1db02267 Mon Sep 17 00:00:00 2001 From: Alexey Alekhin Date: Thu, 29 Apr 2021 02:43:52 +0200 Subject: [PATCH 31/31] add link to sbt's readme --- plugins/sbt/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sbt/README.md b/plugins/sbt/README.md index e287f09e9..c501edd79 100644 --- a/plugins/sbt/README.md +++ b/plugins/sbt/README.md @@ -1,6 +1,6 @@ # sbt plugin -Publish Scala projects with sbt +Publish Scala projects with [sbt](https://www.scala-sbt.org) > :warning: only sbt 1.4+ is supported at the moment because this plugin uses `sbt --client` functionality