Writing a Publishing Plugin
The main use for plugins is to automate your release process.
This page will walk you through implementing the git-tag
plugin.
It is recommended that you use TypeScript for the best development experience.
auto
is written in TypeScript and has extensive jsDoc comments throughout the code. To make the following code work without compilation, just remove the types!
Setup
First create a file for your plugins.
Make sure to set the name! It must be consistent with your packages name.
my-plugin.ts
:
import { Auto, IPlugin } from "@auto-it/core"; export default class GitTagPlugin implements IPlugin { /** The name of the plugin */ name = "my-git-tag"; /** Tap into auto plugin points. */ apply(auto: Auto) {} }
import { Auto, IPlugin } from "@auto-it/core"; export default class GitTagPlugin implements IPlugin { /** The name of the plugin */ name = "my-git-tag"; /** Tap into auto plugin points. */ apply(auto: Auto) {} }
Tap Required Hooks
Plugins work by "hooking" into various parts of auto
to control or add to its behavior.
The following hooks you must implement to get a publishing plugin working.
getPreviousVersion
This plugin will manage the version of the project solely using the tag.
Set up this hook to tell auto
the last release version of your project
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { /** 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.getPreviousVersion.tapPromise(this.name, getTag); } }
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { /** 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.getPreviousVersion.tapPromise(this.name, getTag); } }
version
In this hook you should increment the version of your project, tag it, and if necessary commit a file (ex: package.json
).
import { inc, ReleaseType } from "semver"; export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { // ... auto.hooks.version.tapPromise(this.name, async ({ bump }) => { const lastTag = await getTag(); const newTag = inc(lastTag, version as ReleaseType); if (newTag && dryRun) { console.log(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}"`, ]); }); } }
import { inc, ReleaseType } from "semver"; export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { // ... auto.hooks.version.tapPromise(this.name, async ({ bump }) => { const lastTag = await getTag(); const newTag = inc(lastTag, version as ReleaseType); if (newTag && dryRun) { console.log(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}"`, ]); }); } }
publish
Finally publish your new version to a package management platform and push the new tag to GitHub.
In the case of the git-tag
plugin pushing the tag to GitHub is the only thing we need to do.
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { // ... auto.hooks.publish.tapPromise(this.name, async () => { auto.logger.log.info("Pushing new tag to GitHub"); await execPromise("git", [ "push", "--follow-tags", "--set-upstream", auto.remote, getCurrentBranch() || auto.baseBranch, ]); }); } }
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { // ... auto.hooks.publish.tapPromise(this.name, async () => { auto.logger.log.info("Pushing new tag to GitHub"); await execPromise("git", [ "push", "--follow-tags", "--set-upstream", auto.remote, getCurrentBranch() || auto.baseBranch, ]); }); } }
Once you have the above hooks implemented you should be able to successfully use auto
to publish a release!
The above plugins is pretty simple and there are a bunch of features you can add to your plugin through hooks or functions that auto
exports.
Advanced Release Hooks
canary
This hook enables canary
releases for your projects.
A canary
version is a test version you publish for PRs or to test changes.
Your package management platform needs to support a few things for canaries to be possible
- Separate Releases Lines - you should be able to publish to a release line that doesn't effect your main users (ex: when installing for the first time they should never get a
canary
) - Lots of releases - it must support a lot of releases, especially if you make a bunch of PRs
Read more about the canary
hook.
next
This hook enables next
releases for your projects.
A next
release is the next version of your project.
Think of it like an alpha
or beta
release line.
Like the canary
hook your package management platform must support separate release lines.
Read more about the next
hook.
Other Useful Hooks
These hooks are not required for publishing plugins, but can really improve the developer experience of it.
beforeRun
Happens before anything is done. This is a great place to check for platform specific secrets such as a npm token.
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { auto.hooks.beforeRun.tap(this.name, () => { // Use the `checkEnv` function to warn about missing ENV variables auto.checkEnv(this.name, "CLIENT_ID"); }); } }
export default class GitTagPlugin implements IPlugin { // ... apply(auto: Auto) { auto.hooks.beforeRun.tap(this.name, () => { // Use the `checkEnv` function to warn about missing ENV variables auto.checkEnv(this.name, "CLIENT_ID"); }); } }
getAuthor
Get git author to commit with. Typically from a package distribution description file.
auto.hooks.getAuthor.tapPromise("NPM", async () => { const { author } = JSON.parse(await readFile("package.json", "utf-8")); if (author) { return author; } });
auto.hooks.getAuthor.tapPromise("NPM", async () => { const { author } = JSON.parse(await readFile("package.json", "utf-8")); if (author) { return author; } });
getRepository
Get owner and repository for the project to automate releases for.
Typically from a package distribution description file.
Falls back to global git config
author.
auto.hooks.getRepository.tapPromise('NPM', async () => { const owner = // get the owner from package.json const repo = // get the repo from package.json return { owner, repo } });
auto.hooks.getRepository.tapPromise('NPM', async () => { const owner = // get the owner from package.json const repo = // get the repo from package.json return { owner, repo } });