diff --git a/.release-me.json b/.release-me.json index d15fce7..ff233ad 100644 --- a/.release-me.json +++ b/.release-me.json @@ -4,7 +4,13 @@ "release": true }, "regex": { - "patterns": ["/(?<=@)(.*)(?=\/)/gm", "(?<=release-me\/)(.*)(?=\/cli)"] + "patterns": [ + "/(?<=@)(.*)(?=\/)/gm", + "(?<=release-me\/)(.*)(?=\/cli)" + ] }, - "versionFile": {} + "versionFile": {}, + "testRemote": { + "path": "./plugins/testRemote/mod.ts" + } } diff --git a/README.md b/README.md index 51aaefa..0b2cdc6 100644 --- a/README.md +++ b/README.md @@ -33,28 +33,64 @@ example: release-me major ## Plugins -Release-me supports plugins. The current ones are +Release-me supports local and remote plugins. By default, plugins are **NOT** +enabled. To enable them, create a `.release-me.json` file that has a key +matching the plugin. Example of configuration. + +```json +// .release-me.json +{ + "changelog": {}, + "github": { + "release": true + }, + "regex": { + "patterns": [ + "/(?<=@)(.*)(?=\/)/gm", + "(?<=release-me\/)(.*)(?=\/cli)" + ] + }, + "versionFile": {}, + "myRemotePlugin": { + "path": "./plugins/testRemote/mod.ts" + } +} +``` + +### Baked-in plugins +- [github](./plugin/github/mod.ts): Create a draft release on Github - [changelog](./plugin/changelog/mod.ts): Create a changelog -- github: Create a draft release on Github -- regex: Apply a regex on the Readme to update the version number following `@` to the new one -- versionFile: Create a `version.json` file with the new version number +- [regex](./plugin/regex/mod.ts): Apply a regex on the Readme the regex can be + configure in the config file. For to update the version number following `@` + to the new one +- [versionFile](./plugin/versionFile/mod.ts): Create a `version.json` file with + the new version number -They are currently all enabled, but this will change soon... +### Remote plugins -To develop new plugins, refer to [./plugins.ts](/plugins.ts) api +Plugins can also be defined externally. In that case they must have a "path" +property in their config. The path can be either a local path or http(s) path. + +A plugin must contain a default export with the signature defined at +[./plugins.ts](/plugins.ts) ## Secrets -Release-me uses dotenv to load environment variables +Release-me uses dotenv to load environment variables. For example for +interactiong with Github, set a `.env` file with the below -### Contribution - -Pull request, issues and feedback are very welcome. Code style is formatted with -deno fmt. +``` +GITHUB_TOKEN= +``` ## Credits Big Credits to [denosaurs](https://github.com/denosaurs). This project is a fork -of [release](https://github.com/denosaurs/release). However due to the lack of -development on the original package, I have done some update. +of [release](https://github.com/denosaurs/release). The current core features +have been implemented by it. + +### Contribution + +Pull request, issues and feedback are very welcome. Code style is formatted with +deno fmt. diff --git a/cli.ts b/cli.ts index 854c60a..c5a0415 100644 --- a/cli.ts +++ b/cli.ts @@ -6,10 +6,10 @@ import { fetchRepo, Repo } from "./src/repo.ts"; import { ezgit } from "./src/git.ts"; // Plugins -import { github } from "./plugins/github/mod.ts"; -import { changelog } from "./plugins/changelog/mod.ts"; -import { regex } from "./plugins/regex/mod.ts"; -import { versionFile } from "./plugins/versionFile/mod.ts"; +import github from "./plugins/github/mod.ts"; +import changelog from "./plugins/changelog/mod.ts"; +import regex from "./plugins/regex/mod.ts"; +import versionFile from "./plugins/versionFile/mod.ts"; import version from "./version.json" assert { type: "json" }; import { ReleasePlugin } from "./plugin.ts"; @@ -55,9 +55,9 @@ await new Command() default: ".release-me.json", }) .action(async (opts, release_type, name) => { - await initLogger(opts.debug) + await initLogger(opts.debug); log.debug(opts, release_type, name); - + let suffix: string | undefined = undefined; if (["prepatch", "preminor", "premajor"].includes(release_type)) { suffix = (name as string | undefined) ?? "canary"; @@ -66,7 +66,10 @@ await new Command() // Load config, if any let config: ReleaseConfig = { options: opts }; try { - config = { ...(JSON.parse(Deno.readTextFileSync(opts.config))), ...config} ; + config = { + ...(JSON.parse(Deno.readTextFileSync(opts.config))), + ...config, + }; } catch (err) { if (err.code !== "ENOENT") { log.error(`error parsing the config file at ${opts.config}`); @@ -84,14 +87,14 @@ await new Command() else if (key === "regex") plugins.push(regex); else if (key === "versionFile") plugins.push(versionFile); else { - const def = val as { path: string; }; - if (!def.path) throw Error(`Invalid config entry ${val}`) - const remotePlugin = await import(def.path) - plugins.push(remotePlugin); + const def = val as { path: string }; + if (!def.path) throw Error(`Invalid config entry ${val}`); + const remotePlugin = await import(def.path); + plugins.push(remotePlugin.default); } } - - log.debug(`plugins loaded: ${plugins.map(p => p.name).join(', ')}`) + + log.debug(`plugins loaded: ${plugins.map((p) => p.name).join(", ")}`); // Plugins setup for (const plugin of plugins) { @@ -140,7 +143,7 @@ await new Command() for (const plugin of plugins) { if (!plugin.preCommit) continue; try { - log.debug(`Executing preCommit ${plugin.name}`) + log.debug(`Executing preCommit ${plugin.name}`); await plugin.preCommit(repo, release_type, from, to, config, log); } catch (err) { log.critical(err.message); @@ -190,7 +193,7 @@ await new Command() for (const plugin of plugins) { if (!plugin.postCommit) continue; try { - log.debug(`Executing postCommit ${plugin.name}`) + log.debug(`Executing postCommit ${plugin.name}`); await plugin.postCommit(repo, release_type, from, to, config, log); } catch (err) { log.critical(err.message); diff --git a/config.ts b/config.ts index 5292484..5d61e9f 100644 --- a/config.ts +++ b/config.ts @@ -4,7 +4,8 @@ interface CliConfig { options: { dry?: boolean; allowUncommitted?: boolean; - } + debug?: boolean; + }; } -export type ReleaseConfig = T & CliConfig +export type ReleaseConfig = T & CliConfig; diff --git a/deps.ts b/deps.ts index 68fbf23..720c6d4 100644 --- a/deps.ts +++ b/deps.ts @@ -15,4 +15,7 @@ export { parse as ccparse } from "https://deno.land/x/commit@0.1.5/mod.ts"; export * as semver from "https://deno.land/x/semver@v1.4.0/mod.ts"; export * as ini from "https://deno.land/x/ini@v2.1.0/mod.ts"; -export { Command, EnumType } from "https://deno.land/x/cliffy@v0.24.2/command/mod.ts"; +export { + Command, + EnumType, +} from "https://deno.land/x/cliffy@v0.24.2/command/mod.ts"; diff --git a/plugin.ts b/plugin.ts index 79d8883..6107d5d 100644 --- a/plugin.ts +++ b/plugin.ts @@ -1,4 +1,4 @@ -import { log } from './deps.ts' +import { log } from "./deps.ts"; import type { ReleaseConfig } from "./config.ts"; import type { ReleaseType } from "./cli.ts"; import type { Repo } from "./src/repo.ts"; @@ -11,21 +11,32 @@ export type { Commit } from "./src/commits.ts"; export interface ReleasePlugin { name: string; + /** + * This run at the start of the cli + */ setup?: (logs: typeof log) => Promise; + + /** + * This run before a commit is done + */ preCommit?: ( repo: Repo, releaseType: ReleaseType, from: string, to: string, config: ReleaseConfig, - logger: typeof log + logger: typeof log, ) => Promise; + + /** + * This run after a commit with all the changes is done + */ postCommit?: ( repo: Repo, releaseType: ReleaseType, from: string, to: string, config: ReleaseConfig, - logger: typeof log + logger: typeof log, ) => Promise; } diff --git a/plugins/changelog/mod.ts b/plugins/changelog/mod.ts index 19e1810..8921958 100644 --- a/plugins/changelog/mod.ts +++ b/plugins/changelog/mod.ts @@ -1,8 +1,6 @@ import { join } from "./deps.ts"; -import type { - ReleasePlugin, -} from "../../plugin.ts"; +import type { ReleasePlugin } from "../../plugin.ts"; import { Document, Filter, @@ -12,7 +10,7 @@ import { render, } from "../../src/changelog.ts"; -export const changelog = { +const plugin: ReleasePlugin = { name: "Changelog", async preCommit( repo, @@ -20,7 +18,7 @@ export const changelog = { _from, to, config, - log + log, ): Promise { const doc: Document = { sections: [], links: [] }; pushHeader(doc); @@ -52,3 +50,5 @@ export const changelog = { } }, }; + +export default plugin; diff --git a/plugins/github/mod.ts b/plugins/github/mod.ts index 9addb1a..74a43cc 100644 --- a/plugins/github/mod.ts +++ b/plugins/github/mod.ts @@ -1,6 +1,4 @@ -import { - ReleasePlugin, -} from "../../plugin.ts"; +import { ReleasePlugin } from "../../plugin.ts"; import { Document, Filter, @@ -14,7 +12,7 @@ import { ReleaseError } from "../../src/error.ts"; const GITHUB_TOKEN = "GITHUB_TOKEN"; -export const github = { +const plugin: ReleasePlugin = { name: "GitHub", async setup(log): Promise { const token = Deno.env.get(GITHUB_TOKEN); @@ -73,3 +71,5 @@ export const github = { } }, }; + +export default plugin; diff --git a/plugins/regex/mod.ts b/plugins/regex/mod.ts index cbdbb26..0399efe 100644 --- a/plugins/regex/mod.ts +++ b/plugins/regex/mod.ts @@ -1,15 +1,13 @@ -import type { - ReleasePlugin, -} from "../../plugin.ts"; +import type { ReleasePlugin } from "../../plugin.ts"; import { join } from "./deps.ts"; interface RegexConfig { regex: { - patterns: string[] - } + patterns: string[]; + }; } -export const regex: ReleasePlugin = { +const plugin: ReleasePlugin = { name: "Regex", async preCommit( repo, @@ -17,12 +15,12 @@ export const regex: ReleasePlugin = { _from, to, config, - log + log, ): Promise { const readmePath = "README.md"; let text = await Deno.readTextFile(readmePath); // apply regex. This should come from a config loaded on setup step - // as a prototype, it is harcoded to update versions in urls + // as a prototype, it is harcoded to update versions in urls for (const pattern of config.regex.patterns) { text = text.replace(new RegExp(pattern), to); } @@ -33,3 +31,5 @@ export const regex: ReleasePlugin = { } }, }; + +export default plugin; diff --git a/plugins/testRemote/deps.ts b/plugins/testRemote/deps.ts new file mode 100644 index 0000000..223bb84 --- /dev/null +++ b/plugins/testRemote/deps.ts @@ -0,0 +1,2 @@ +export { join } from "https://deno.land/std@0.141.0/path/mod.ts"; +export { EOL } from "https://deno.land/std@0.141.0/fs/mod.ts"; diff --git a/plugins/testRemote/mod.ts b/plugins/testRemote/mod.ts new file mode 100644 index 0000000..1aeeebe --- /dev/null +++ b/plugins/testRemote/mod.ts @@ -0,0 +1,34 @@ +import type { ReleasePlugin } from "../../plugin.ts"; +import { join } from "./deps.ts"; + +/** + * Export a version file with the new version number + */ +const plugin: ReleasePlugin = { + name: "TestRemote", + async preCommit( + repo, + _releaseType, + _from, + to, + config, + log, + ): Promise { + const versionFile = "versionTest.json"; + const version = { + version: to, + }; + if (!config.options.dry) { + await Deno.writeTextFile( + join(repo.path, versionFile), + JSON.stringify(version, null, 2) + + // to comply with deno fmt + "\n", + ); + } else { + log.info(`dryRun: Would have created ${versionFile} file`); + } + }, +}; + +export default plugin; diff --git a/plugins/versionFile/mod.ts b/plugins/versionFile/mod.ts index 1fb3b8f..de7a0a7 100644 --- a/plugins/versionFile/mod.ts +++ b/plugins/versionFile/mod.ts @@ -1,12 +1,10 @@ -import type { - ReleasePlugin, -} from "../../plugin.ts"; +import type { ReleasePlugin } from "../../plugin.ts"; import { join } from "./deps.ts"; /** * Export a version file with the new version number */ -export const versionFile: ReleasePlugin = { +const plugin: ReleasePlugin = { name: "VersionFile", async preCommit( repo, @@ -14,7 +12,7 @@ export const versionFile: ReleasePlugin = { _from, to, config, - log + log, ): Promise { const versionFile = "version.json"; const version = { @@ -28,7 +26,9 @@ export const versionFile: ReleasePlugin = { "\n", ); } else { - log.info('dryRun: Would have created version.json file'); + log.info(`dryRun: Would have created ${versionFile} file`); } }, }; + +export default plugin; diff --git a/src/log.ts b/src/log.ts index b82aabd..68231c7 100644 --- a/src/log.ts +++ b/src/log.ts @@ -1,9 +1,9 @@ import { log } from "../deps.ts"; -export async function initLogger(useDebug?: boolean){ +export async function initLogger(useDebug?: boolean) { await log.setup({ handlers: { - console: new log.handlers.ConsoleHandler(useDebug ? "DEBUG" : "INFO" ), + console: new log.handlers.ConsoleHandler(useDebug ? "DEBUG" : "INFO"), }, loggers: { // configure default logger available via short-hand methods above. @@ -13,4 +13,4 @@ export async function initLogger(useDebug?: boolean){ }, }, }); -} \ No newline at end of file +}