From d1f68225dd03b735c83c70c1bd09ec8f1328947f Mon Sep 17 00:00:00 2001 From: Corey Butler Date: Wed, 1 Apr 2020 12:27:19 -0500 Subject: [PATCH] Updated to use new strategies with controlled Docker environment. --- .github/workflows/test.yml | 30 ++++ .gitignore | 13 +- Dockerfile | 5 + LICENSE | 2 +- README.md | 127 +++++++++------ action.yml | 22 ++- app/lib/docker.js | 15 ++ app/lib/package.js | 23 +++ app/lib/regex.js | 34 ++++ app/lib/setup.js | 33 ++++ app/lib/tag.js | 135 ++++++++++++++++ app/main.js | 72 +++++++++ package-lock.json => app/package-lock.json | 0 package.json => app/package.json | 3 - lib/main.js | 174 --------------------- 15 files changed, 447 insertions(+), 241 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 Dockerfile create mode 100644 app/lib/docker.js create mode 100644 app/lib/package.js create mode 100644 app/lib/regex.js create mode 100644 app/lib/setup.js create mode 100644 app/lib/tag.js create mode 100644 app/main.js rename package-lock.json => app/package-lock.json (100%) rename package.json => app/package.json (92%) delete mode 100644 lib/main.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..687e1fb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: Test + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + # Checkout updated source code + - uses: actions/checkout@v2 + + # If the version has changed, create a new git tag for it. + - name: Tag + id: autotagger + uses: butlerlogic/action-autotag@master + with: + tag_prefix: 'test_' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Rollback Release + if: failure() && steps.create_release.outputs.id != '' + uses: author/action-rollback@stable + with: + tag: ${{ steps.autotagger.outputs.tagname }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7c0c456..35aa180 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,9 @@ -# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore -# Logs logs *.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - +*.log* .* !.gitignore !.github +!.dockerignore _* +node_modules diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..25f4ba1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM node:13-alpine +ADD ./app /app +WORKDIR /app +RUN npm i +CMD ["node", "main.js"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7775d4e..7a4dee7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2019 Corey Butler and contributors +Copyright (c) 2020 Corey Butler and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8cdae73..ea5f8ca 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ # Autotag -This action will read a `package.json` file and compare the `version` attribute to the project's known tags. If a corresponding tag does not exist, it will be created. +This action will auto-generate a Github tag whenever a new version is detected. The following "detection strategies" are available: -This tag works well in combination with: +1. **package**: Monitor a `package.json` for new versions. +1. **docker**: Monitor a `Dockerfile` for a `LABEL version=x.x.x` value. +1. **regex**: Use a JavaScript [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) with any file for your own custom extraction. + +When a version is detected, it is compared to the current list of tags in the Github repository. If a tag does not exist, it will be created. + +This action works well in combination with: - [actions/create-release](https://github.com/actions/create-release) (Auto-release) - [author/action-publish](https://github.com/author/action-publish) (Auto-publish JavaScript/Node modules) @@ -44,7 +50,7 @@ This **order** is important! ## Configuration -The `GITHUB_TOKEN` must be passed in. Without this, it is not possible to create a new tag. Make sure the autotag action looks like the following example: +The `GITHUB_TOKEN` **must** be provided. Without this, it is not possible to create a new tag. Make sure the autotag action looks like the following example: ```yaml - uses: butlerlogic/action-autotag@stable @@ -58,62 +64,88 @@ The action will automatically extract the token at runtime. **DO NOT MANUALLY EN There are several options to customize how the tag is created. -1. `package_root` +#### strategy - By default, autotag will look for the `package.json` file in the project root. If the file is located in a subdirectory, this option can be used to point to the correct file. +This is the strategy used to identify the version number/tag from within the code base. - ```yaml - - uses: butlerlogic/action-autotag@1.0.0 - with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - package_root: "/path/to/subdirectory" - ``` +1. _package_: Monitor a `package.json` for new versions. Use this for JavaScript projects based on Node modules (npm, yarn, etc). +1. _docker_: Monitor a `Dockerfile` for a `LABEL version=x.x.x` value. USe this for container projects. +1. _regex*_: Use a JavaScript [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) with any file for your own custom extraction. -1. `tag_prefix` +*An example " - By default, `package.json` uses [semantic versioning](https://semver.org/), such as `1.0.0`. A prefix can be used to add text before the tag name. For example, if `tag_prefix` is set to `v`, then the tag would be labeled as `v1.0.0`. +#### root `(required)` +_Formerly `package_root`_ - ```yaml - - uses: butlerlogic/action-autotag@1.0.0 - with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - tag_prefix: "v" - ``` +By default, autotag will look for the `package.json` file in the project root. If the file is located in a subdirectory, this option can be used to point to the correct file. -1. `tag_suffix` +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + root: "/path/to/subdirectory" +``` - Text can also be applied to the end of the tag by setting `tag_suffix`. For example, if `tag_suffix` is ` (beta)`, the tag would be `1.0.0 (beta)`. Please note this example violates semantic versioning and is merely here to illustrate how to add text to the end of a tag name if you _really_ want to. +> **EXCEPTION**: This property is not required if the regex_pattern property is defined. In that case, this property is assumed to be "regex". - ```yaml - - uses: butlerlogic/action-autotag@1.0.0 - with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - tag_suffix: " (beta)" - ``` +#### tag_prefix -1. `tag_message` +By default, [semantic versioning](https://semver.org/) is used, such as `1.0.0`. A prefix can be used to add text before the tag name. For example, if `tag_prefix` is set to `v`, then the tag would be labeled as `v1.0.0`. - This is the annotated commit message associated with the tag. By default, a - changelog will be generated from the commits between the latest tag and the new tag (HEAD). Setting this option will override it witha custom message. +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + tag_prefix: "v" +``` - ```yaml - - uses: butlerlogic/action-autotag@1.0.0 - with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - tag_message: "Custom message goes here." - ``` +#### tag_suffix -1. `version` +Text can be applied to the end of the tag by setting `tag_suffix`. For example, if `tag_suffix` is ` (beta)`, the tag would be `1.0.0 (beta)`. Please note this example violates semantic versioning and is merely here to illustrate how to add text to the end of a tag name if you _really_ want to. - Explicitly set the version instead of automatically detecting from `package.json`. - Useful for non-JavaScript projects where version may be output by a previous action. +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + tag_suffix: " (beta)" +``` - ```yaml - - uses: butlerlogic/action-autotag@1.0.0 - with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - version: "${{ steps.previous_step.outputs.version }}" - ``` +#### tag_message + +This is the annotated commit message associated with the tag. By default, a changelog will be generated from the commits between the latest tag and the current reference (HEAD). Setting this option will override the message. + +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + tag_message: "Custom message goes here." +``` + +#### version + +Explicitly set the version instead of using automatic detection. + +Useful for projects where the version number may be output by a previous action. + +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + version: "${{ steps.previous_step.outputs.version }}" +``` + +#### regex_pattern + +An optional attribute containing the regular expression used to extract the version number. + +```yaml +- uses: butlerlogic/action-autotag@1.0.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + regex_pattern: "version=([0-9\.]+)" +``` + +This attribute is used as the first argument of a [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp) object. The first "group" (i.e. what's in parenthesis) will be used as the version number. For an example, see this [working example](regexr.com/51i6n). ## Developer Notes @@ -123,6 +155,7 @@ If you are building an action that runs after this one, be aware this action pro 1. `tagsha`: The SHA of the new tag. 1. `taguri`: The URI/URL of the new tag reference. 1. `tagmessage`: The messge applied to the tag reference (this is what shows up on the tag screen on Github). +1. `tagcreated`: `yes` or `no`. 1. `version` will be the version attribute found in the `package.json` file. --- @@ -135,10 +168,10 @@ This action was written and is primarily maintained by [Corey Butler](https://gi If you use this or find value in it, please consider contributing in one or more of the following ways: -1. Click the "Sponsor" button at the top of the page. +1. Click the "Sponsor" button at the top of the page and make a contribution. 1. Star it! 1. [Tweet about it!](https://twitter.com/intent/tweet?hashtags=github,actions&original_referer=http%3A%2F%2F127.0.0.1%3A91%2F&text=I%20am%20automating%20my%20workflow%20with%20the%20Autotagger%20Github%20action!&tw_p=tweetbutton&url=https%3A%2F%2Fgithub.com%2Fmarketplace%2Factions%2Fautotagger&via=goldglovecb) 1. Fix an issue. 1. Add a feature (post a proposal in an issue first!). -Copyright © 2019 ButlerLogic, Corey Butler, and Contributors. +Copyright © 2020 Butler Logic, Corey Butler, and Contributors. diff --git a/action.yml b/action.yml index 5b11a2c..a9bdf25 100644 --- a/action.yml +++ b/action.yml @@ -1,12 +1,20 @@ name: "Autotagger" -description: "Automatically generate new tags when the package.json version changes." -author: "ButlerLogic" +description: "Automatically generate new tags for new versions. Supports several tagging strategies, including package.json, Dockerfiles, and Regex." +author: "Butler Logic" branding: icon: "tag" - color: "black" + color: "blue" inputs: + root: + description: Autotag will look for the appropriate file in in this location (relative to project root). + required: false + default: './' + strategy: + description: Options include 'package' (for package.json), 'docker' (for Dockerfile), and 'regex' to extract from an arbitrary file. This does not need to be specified if the "regex_pattern" property is provided. + required: false + default: 'package' package_root: - description: Autotag will look for the package.json file in in this location. + description: (DEPRECATED. Use 'root' instead.) Autotag will look for the package.json file in in this location. required: false default: './' tag_prefix: @@ -32,6 +40,8 @@ outputs: description: The messge applied to the tag reference (this is what shows up on the tag screen on Github). version: description: The version, as defined in package.json or explicitly set in the input. + tagcreated: + description: A "yes" or "no", indicating a new tag was created. runs: - using: "node12" - main: "lib/main.js" + using: 'docker' + image: 'Dockerfile' diff --git a/app/lib/docker.js b/app/lib/docker.js new file mode 100644 index 0000000..e2764d9 --- /dev/null +++ b/app/lib/docker.js @@ -0,0 +1,15 @@ +import Regex from './regex.js' +import path from 'path' +import fs from 'fs' + +export default class Dockerfile extends Regex { + constructor (root = null) { + root = path.join(process.env.GITHUB_WORKSPACE, root) + + if (fs.statSync(root).isDirectory()) { + root = path.join(root, 'Dockerfile') + } + + super(root, /LABEL[\s\t]+version=[\t\s+]?[\"\']?([0-9\.]+)[\"\']?/i) + } +} diff --git a/app/lib/package.js b/app/lib/package.js new file mode 100644 index 0000000..d54ac61 --- /dev/null +++ b/app/lib/package.js @@ -0,0 +1,23 @@ +import fs from 'fs' +import path from 'path' + +export default class Package { + constructor (root = './') { + root = path.join(process.env.GITHUB_WORKSPACE, root) + + if (fs.statSync(root).isDirectory()) { + root = path.join(root, 'package.json') + } + + if (!fs.existsSync(root)) { + throw new Error(`package.json does not exist at ${root}.`) + } + + this.root = root + this.data = JSON.parse(fs.readFileSync(root)) + } + + get version () { + return this.data.version + } +} diff --git a/app/lib/regex.js b/app/lib/regex.js new file mode 100644 index 0000000..c34ba90 --- /dev/null +++ b/app/lib/regex.js @@ -0,0 +1,34 @@ +import fs from 'fs' +import path from 'path' + +export default class Regex { + constructor (root = null, pattern) { + root = path.join(process.env.GITHUB_WORKSPACE, root) + + if (fs.statSync(root).isDirectory()) { + throw new Error(`${root} is a directory. The Regex tag identification strategy requires a file.`) + } + + if (!fs.existsSync(root)) { + throw new Error(`"${root}" does not exist.`) + } + + this.content = fs.readFileSync(root).toString() + + let content = pattern.exec(this.content) + if (!content) { + this._version = null + // throw new Error(`Could not find pattern matching "${pattern.toString()}" in "${root}".`) + } else { + this._version = content[1] + } + } + + get version () { + return this._version + } + + get versionFound () { + return this._version !== null + } +} diff --git a/app/lib/setup.js b/app/lib/setup.js new file mode 100644 index 0000000..4109c2b --- /dev/null +++ b/app/lib/setup.js @@ -0,0 +1,33 @@ +import core from '@actions/core' +import fs from 'fs' +import path from 'path' + +export default class Setup { + static debug () { + // Metadate for debugging + core.debug( + ` Available environment variables:\n -> ${Object.keys(process.env) + .map(i => i + ' :: ' + process.env[i]) + .join('\n -> ')}` + ) + + const dir = fs + .readdirSync(path.resolve(process.env.GITHUB_WORKSPACE), { withFileTypes: true }) + .map(entry => { + return `${entry.isDirectory() ? '> ' : ' - '}${entry.name}` + }) + .join('\n') + + core.debug(` Working Directory: ${process.env.GITHUB_WORKSPACE}:\n${dir}`) + } + + static requireAnyEnv () { + for (const arg of arguments) { + if (!process.env.hasOwnProperty(arg)) { + return + } + } + + throw new Error('At least one of the following environment variables is required: ' + Array.slice(arguments).join(', ')) + } +} diff --git a/app/lib/tag.js b/app/lib/tag.js new file mode 100644 index 0000000..050b08e --- /dev/null +++ b/app/lib/tag.js @@ -0,0 +1,135 @@ +import core from '@actions/core' +import os from 'os' +import { GitHub, context } from '@actions/github' + +// Get authenticated GitHub client (Ocktokit): https://github.com/actions/toolkit/tree/master/packages/github#usage +const github = new GitHub(process.env.GITHUB_TOKEN || process.env.INPUT_GITHUB_TOKEN) +// Get owner and repo from context of payload that triggered the action +const { owner, repo } = context.repo + +export default class Tag { + constructor (prefix, version, postfix) { + this.prefix = prefix + this.version = version + this.postfix = postfix + this._tags = null + this._message = null + this._exists = null + } + + get name () { + return `${this.prefix.trim()}${this.version.trim()}${this.postfix.trim()}` + } + + set message (value) { + if (value && value.length > 0) { + this._message = value + } + } + + async getMessage () { + if (this._message !== null) { + return this._message + } + + try { + const changelog = await github.repos.compareCommits({ owner, repo, base: tags.data.shift().name, head: 'master' }) + + return changelog.data.commits + .map( + (commit, i) => + `${i + 1}) ${commit.commit.message}${ + commit.hasOwnProperty('author') + ? commit.author.hasOwnProperty('login') + ? ' (' + commit.author.login + ')' + : '' + : '' + }\n(SHA: ${commit.sha})\n` + ) + .join('\n') + } catch (e) { + core.warning('Failed to generate changelog from commits: ' + e.message + os.EOL) + return `Version ${this.version}` + } + } + + async getTags () { + if (this._tags !== null) { + return this._tags.data + } + + this._tags = await github.repos.listTags({ owner, repo, per_page: 100 }) + + return this._tags.data + } + + async exists () { + if (this._exists !== null) { + return this._exists + } + const currentTag = this.name + const tags = await this.getTags() + + for (const tag of tags) { + if (tag.name === currentTag) { + this._exists = true + return true + } + } + + this._exists = false + return false + } + + async push () { + let tagexists = await this.exists() + + if (!tagexists) { + // Create tag + const newTag = await github.git.createTag({ + owner, + repo, + tag: this.name, + message: this.message, + object: process.env.GITHUB_SHA, + type: 'commit' + }) + + core.warning(`Created new tag: ${newTag.data.tag}`) + + // Create reference + let newReference + try { + newReference = await github.git.createRef({ + owner, + repo, + ref: `refs/tags/${newTag.data.tag}`, + sha: newTag.data.sha + }) + } catch (e) { + core.warning({ + owner, + repo, + ref: `refs/tags/${newTag.data.tag}`, + sha: newTag.data.sha + }) + + throw e + } + + core.warning(`Reference ${newReference.data.ref} available at ${newReference.data.url}` + os.EOL) + + // Store values for other actions + if (typeof newTag === 'object' && typeof newReference === 'object') { + core.setOutput('tagname', this.name) + core.setOutput('tagsha', newTag.data.sha) + core.setOutput('taguri', newReference.data.url) + core.setOutput('tagmessage', this.message) + core.setOutput('tagref', newReference.data.ref) + core.setOutput('tagcreated', 'yes') + } + } else { + core.warning('Cannot push tag (it already exists).') + } + } +} diff --git a/app/main.js b/app/main.js new file mode 100644 index 0000000..2c957f4 --- /dev/null +++ b/app/main.js @@ -0,0 +1,72 @@ +import core from '@actions/core' +import os from 'os' +import Setup from './lib/setup.js' +import Package from './lib/package.js' +import Tag from './lib/tag.js' +import Regex from './lib/regex.js' + +async function run () { + try { + Setup.debug() + Setup.requireAnyEnv('GITHUB_TOKEN', 'INPUT_GITHUB_TOKEN') + + // Identify the tag parsing strategy + const root = core.getInput('root', { required: false }) || core.getInput('package_root', { required: false }) || './' + const strategy = (core.getInput('strategy', { required: false }) || '').trim().length > 0 ? 'regex' : ((core.getInput('strategy', { required: false }) || 'package').trim().toLowerCase()) + + // Extract the version number using the supplied strategy + let version = core.getInput('root', { required: false }) + version = version === null || version.trim().length === 0 ? null : version + + switch (strategy) { + case 'docker': + version = (new Dockerfile(root)).version + break + + case 'package': + // Extract using the package strategy (this is the default strategy) + version = (new Package(root)).version + break + + case 'regex': + version = (new Regex(root, new RegExp(pattern, 'i'))).version + break + + default: + core.setFailed(`"${strategy}" is not a recognized tagging strategy. Choose from: 'package' (package.json), 'docker' (uses Dockerfile), or 'regex' (JS-based RegExp).`) + return + } + + core.setOutput('version', version) + core.debug(` Detected version ${version}`) + + // Configure a tag using the identified version + const tag = new Tag( + core.getInput('tag_prefix', { required: false }), + version, + core.getInput('tag_suffix', { required: false }) + ) + + // Check for existance of tag and abort (short circuit) if it already exists. + if (await tag.exists()) { + core.warning(`"${tag.name}" tag already exists.` + os.EOL) + core.setOutput('tagname', '') + core.setOutput('tagcreated', 'no') + return + } + + // The tag setter will autocorrect the message if necessary. + tag.message = core.getInput('tag_message', { required: false }).trim() + await tag.push() + } catch (error) { + core.warning(error.message) + core.setOutput('tagname', '') + core.setOutput('tagsha', '') + core.setOutput('taguri', '') + core.setOutput('tagmessage', '') + core.setOutput('tagref', '') + core.setOutput('tagcreated', 'no') + } +} + +run() diff --git a/package-lock.json b/app/package-lock.json similarity index 100% rename from package-lock.json rename to app/package-lock.json diff --git a/package.json b/app/package.json similarity index 92% rename from package.json rename to app/package.json index 93159b1..8427cfe 100644 --- a/package.json +++ b/app/package.json @@ -4,9 +4,6 @@ "private": true, "description": "Automatically create a tag whenever the version changes in package.json", "main": "lib/main.js", - "scripts": { - "test": "jest" - }, "repository": { "type": "git", "url": "git+https://github.com/butlerlogic/action-autotag.git" diff --git a/lib/main.js b/lib/main.js deleted file mode 100644 index 26bc899..0000000 --- a/lib/main.js +++ /dev/null @@ -1,174 +0,0 @@ -const core = require('@actions/core') -const { GitHub, context } = require('@actions/github') -const fs = require('fs') -const path = require('path') -const os = require('os') - -async function run() { - try { - core.debug( - ` Available environment variables:\n -> ${Object.keys(process.env) - .map(i => i + ' :: ' + process.env[i]) - .join('\n -> ')}` - ) - - const dir = fs - .readdirSync(path.resolve(process.env.GITHUB_WORKSPACE), { withFileTypes: true }) - .map(entry => { - return `${entry.isDirectory() ? '> ' : ' - '}${entry.name}` - }) - .join('\n') - - core.debug(` Working Directory: ${process.env.GITHUB_WORKSPACE}:\n${dir}`) - - if (!process.env.hasOwnProperty('GITHUB_TOKEN')) { - if (!process.env.hasOwnProperty('INPUT_GITHUB_TOKEN')) { - core.setFailed('Invalid or missing GITHUB_TOKEN.') - return - } - } - - const pkg_root = core.getInput('package_root', { required: false }) - const pkgfile = path.join(process.env.GITHUB_WORKSPACE, pkg_root, 'package.json') - if (!fs.existsSync(pkgfile)) { - core.setFailed('package.json does not exist.') - return - } - - const pkg = require(pkgfile) - core.setOutput('version', pkg.version) - core.debug(` Detected version ${pkg.version}`) - - // Get authenticated GitHub client (Ocktokit): https://github.com/actions/toolkit/tree/master/packages/github#usage - const github = new GitHub(process.env.GITHUB_TOKEN || process.env.INPUT_GITHUB_TOKEN) - - // Get owner and repo from context of payload that triggered the action - const { owner, repo } = context.repo - - // // Check for existing tag - // const git = new github.GitHub(process.env.INPUT_GITHUB_TOKEN || process.env.GITHUB_TOKEN) - // const owner = process.env.GITHUB_REPOSITORY.split('/').shift() - // const repo = process.env.GITHUB_REPOSITORY.split('/').pop() - - let tags - try { - tags = await github.repos.listTags({ - owner, - repo, - per_page: 100, - }) - } catch (e) { - tags = { - data: [], - } - } - - const tagPrefix = core.getInput('tag_prefix', { required: false }) - const tagSuffix = core.getInput('tag_suffix', { required: false }) - - const getTagName = version => { - return `${tagPrefix}${version}${tagSuffix}` - } - - // Check for existance of tag and abort (short circuit) if it already exists. - for (let tag of tags.data) { - if (tag.name === getTagName(pkg.version)) { - core.warning(`"${tag.name.trim()}" tag already exists.` + os.EOL) - core.setOutput('tagname', '') - return - } - } - - // Create the new tag name - const tagName = getTagName(pkg.version) - - let tagMsg = core.getInput('tag_message', { required: false }).trim() - if (tagMsg.length === 0 && tags.data.length > 0) { - try { - latestTag = tags.data.shift() - - let changelog = await github.repos.compareCommits({ - owner, - repo, - base: latestTag.name, - head: 'master', - }) - - tagMsg = changelog.data.commits - .map( - commit => - `**1) ${commit.commit.message}**${ - commit.hasOwnProperty('author') - ? commit.author.hasOwnProperty('login') - ? ' (' + commit.author.login + ')' - : '' - : '' - }\n(SHA: ${commit.sha})\n` - ) - .join('\n') - } catch (e) { - core.warning('Failed to generate changelog from commits: ' + e.message + os.EOL) - tagMsg = tagName - } - } - - let newTag - try { - tagMsg = tagMsg.trim().length > 0 ? tagMsg : `Version ${pkg.version}` - - newTag = await github.git.createTag({ - owner, - repo, - tag: tagName, - message: tagMsg, - object: process.env.GITHUB_SHA, - type: 'commit' - }) - - core.warning(`Created new tag: ${newTag.data.tag}`) - } catch (e) { - core.setFailed(e.message) - return - } - - let newReference - try { - newReference = await github.git.createRef({ - owner, - repo, - ref: `refs/tags/${newTag.data.tag}`, - sha: newTag.data.sha, - }) - - core.warning(`Reference ${newReference.data.ref} available at ${newReference.data.url}` + os.EOL) - } catch (e) { - core.warning({ - owner, - repo, - ref: `refs/tags/${newTag.data.tag}`, - sha: newTag.data.sha, - }) - - core.setFailed(e.message) - return - } - - // Store values for other actions - if (typeof newTag === 'object' && typeof newReference === 'object') { - core.setOutput('tagname', tagName) - core.setOutput('tagsha', newTag.data.sha) - core.setOutput('taguri', newReference.data.url) - core.setOutput('tagmessage', tagMsg.trim()) - core.setOutput('tagref', newReference.data.ref) - } - } catch (error) { - core.warning(error.message) - core.setOutput('tagname', '') - core.setOutput('tagsha', '') - core.setOutput('taguri', '') - core.setOutput('tagmessage', '') - core.setOutput('tagref', '') - } -} - -run()