mirror of
				https://github.com/ButlerLogic/action-autotag.git
				synced 2025-10-31 07:16:25 +07:00 
			
		
		
		
	Merge pull request #15 from ButlerLogic/master
Updating stable version to 1.1.0
This commit is contained in:
		
							
								
								
									
										63
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| name: Autotag Action Test | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|  | ||||
| jobs: | ||||
|   package: | ||||
|     name: Test Suite - Package Strategy | ||||
|     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 Package | ||||
|         id: package_autotagger | ||||
|         uses: butlerlogic/action-autotag@master | ||||
|         with: | ||||
|           tag_prefix: test_package_ | ||||
|           commit_message_template: "{{number}}) {{message}} ({{author}})\n" | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|      | ||||
|       - name: Rollback Package Test Release | ||||
|         id: package_rollback | ||||
|         if: success() && ${{ steps.package_autotagger.outputs.tagcreated }} = "yes" | ||||
|         uses: author/action-rollback@master | ||||
|         with: | ||||
|           tag: ${{ steps.package_autotagger.outputs.tagrequested }} | ||||
|           delete_orphan_tag: true | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|   docker: | ||||
|     name: Test Suite - Docker Strategy | ||||
|     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 Dockerfile | ||||
|         id: docker_autotagger | ||||
|         uses: butlerlogic/action-autotag@master | ||||
|         with: | ||||
|           strategy: docker | ||||
|           tag_prefix: test_docker_ | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|      | ||||
|       - name: Rollback Docker Test Release | ||||
|         id: docker_rolback | ||||
|         if: success() && ${{ steps.docker_autotagger.outputs.tagcreated }} = "yes" | ||||
|         uses: author/action-rollback@master | ||||
|         env: | ||||
|           TAG: ${{ steps.docker_autotagger.outputs.tagrequested }} | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         with: | ||||
|           tag: ${{ steps.docker_autotagger.outputs.tagrequested }} | ||||
|           delete_orphan_tag: true | ||||
|          | ||||
|       | ||||
							
								
								
									
										13
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -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 | ||||
|  | ||||
							
								
								
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| FROM node:13-alpine | ||||
| LABEL version=1.1.0 | ||||
| ADD ./app /app | ||||
| WORKDIR /app | ||||
| RUN cd /app && npm i | ||||
| CMD ["node", "/app/main.js"] | ||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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 | ||||
|  | ||||
							
								
								
									
										148
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								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,108 @@ 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." | ||||
| ``` | ||||
|  | ||||
| #### commit_message_template | ||||
|  | ||||
| By default, a changelog is generated, containing the commit messages since the last release. The message is generated by applying a commit message template to each commit's data attributes. | ||||
|  | ||||
| ```yaml | ||||
| - uses: butlerlogic/action-autotag@1.0.0 | ||||
|   with: | ||||
|     GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||
|     commit_message_template: "({{sha}} by {{author}}) {{message}}" | ||||
| ``` | ||||
|  | ||||
| Optional data points: | ||||
|  | ||||
| 1. `number` The commit number (relevant to the overall list) | ||||
| 1. `message` The commit message. | ||||
| 1. `author` The author of the commit. | ||||
| 1. `sha` The SHA value representing the commit. | ||||
|  | ||||
| The default is `{{number}}) {{message}} ({{author}})\nSHA: {{sha}}\n`. | ||||
|  | ||||
| #### 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 +175,8 @@ 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. `tagrequested`: The name of the requested tag. This will be populated even if the tag is not created. This will usually be the same as `tagname` and/or `version` for successful executions. | ||||
| 1. `version` will be the version attribute found in the `package.json` file. | ||||
|  | ||||
| --- | ||||
| @ -135,10 +189,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. | ||||
|  | ||||
							
								
								
									
										31
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								action.yml
									
									
									
									
									
								
							| @ -1,14 +1,21 @@ | ||||
| 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." | ||||
| author: "Butler Logic" | ||||
| branding: | ||||
|   icon: "tag" | ||||
|   color: "black" | ||||
|   color: "blue" | ||||
| inputs: | ||||
|   package_root: | ||||
|     description: Autotag will look for the package.json file in in this location. | ||||
|   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: (DEPRECATED. Use 'root' instead.) Autotag will look for the package.json file in in this location. | ||||
|     required: false | ||||
|   tag_prefix: | ||||
|     description: By default, package.json uses semantic versioning, such as "1.0.0". A prefix can be used to add text before the tag name. For example, if tag_prefx is set to "v", then the tag would be labeled as "v1.0.0". | ||||
|     required: false | ||||
| @ -18,9 +25,15 @@ inputs: | ||||
|   tag_message: | ||||
|     description: 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). This will override that with a hard-coded message. | ||||
|     required: false | ||||
|   commit_message_template: | ||||
|     description: "The commit message template (per commit). Default is `{{number}}) {{message}} ({{author}})\nSHA: {{sha}}\n`" | ||||
|     required: false | ||||
|   version: | ||||
|     description: Explicitly set the version here instead of automatically detecting from `package.json`. Useful for non-JavaScript projects where version may be output by a previous action. | ||||
|     required: false | ||||
|   regex_pattern: | ||||
|     description: An optional attribute containing the regular expression used to extract the version number. | ||||
|     required: false | ||||
| outputs: | ||||
|   tagname: | ||||
|     description: Returns the new tag value. Empty if a tag is not created. | ||||
| @ -30,8 +43,12 @@ outputs: | ||||
|     description: The URI/URL of the new tag reference. | ||||
|   tagmessage: | ||||
|     description: The messge applied to the tag reference (this is what shows up on the tag screen on Github). | ||||
|   tagcreated: | ||||
|     description: A "yes" or "no", indicating a new tag was created. | ||||
|   tagrequested: | ||||
|     description: The name of the requested tag. This will be populated even if the tag is not created. | ||||
|   version: | ||||
|     description: The version, as defined in package.json or explicitly set in the input. | ||||
| runs: | ||||
|   using: "node12" | ||||
|   main: "lib/main.js" | ||||
|   using: 'docker' | ||||
|   image: 'Dockerfile' | ||||
|  | ||||
							
								
								
									
										16
									
								
								app/lib/docker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/lib/docker.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| import Regex from './regex.js' | ||||
| import path from 'path' | ||||
| import fs from 'fs' | ||||
| import core from '@actions/core' | ||||
|  | ||||
| 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) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								app/lib/package.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/lib/package.js
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										34
									
								
								app/lib/regex.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/lib/regex.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| import fs from 'fs' | ||||
| import path from 'path' | ||||
|  | ||||
| export default class Regex { | ||||
|   constructor (root = './', pattern) { | ||||
|     root = path.resolve(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 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										33
									
								
								app/lib/setup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/lib/setup.js
									
									
									
									
									
										Normal file
									
								
							| @ -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(', ')) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										161
									
								
								app/lib/tag.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								app/lib/tag.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,161 @@ | ||||
| import core from '@actions/core' | ||||
| import os from 'os' | ||||
| import gh from '@actions/github' | ||||
|  | ||||
| // Get authenticated GitHub client (Ocktokit): https://github.com/actions/toolkit/tree/master/packages/github#usage | ||||
| const github = new gh.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 } = gh.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 | ||||
|     this._sha = '' | ||||
|     this._uri = '' | ||||
|     this._ref = '' | ||||
|   } | ||||
|  | ||||
|   get name () { | ||||
|     return `${this.prefix.trim()}${this.version.trim()}${this.postfix.trim()}` | ||||
|   } | ||||
|  | ||||
|   set message (value) { | ||||
|     if (value && value.length > 0) { | ||||
|       this._message = value | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   get sha () { | ||||
|     return this._sha || '' | ||||
|   } | ||||
|  | ||||
|   get uri () { | ||||
|     return this._uri || '' | ||||
|   } | ||||
|  | ||||
|   get ref () { | ||||
|     return this._ref || '' | ||||
|   } | ||||
|  | ||||
|   async getMessage () { | ||||
|     if (this._message !== null) { | ||||
|       return this._message | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|       let tags = await this.getTags() | ||||
|  | ||||
|       if (tags.length === 0) { | ||||
|         return `Version ${this.version}` | ||||
|       } | ||||
|  | ||||
|       const changelog = await github.repos.compareCommits({ owner, repo, base: tags.shift().name, head: 'master' }) | ||||
|       const tpl = (core.getInput('commit_message_template', { required: false }) || '').trim() | ||||
|  | ||||
|       return changelog.data.commits | ||||
|         .map( | ||||
|           (commit, i) => { | ||||
|             if (tpl.length > 0) { | ||||
|               return tpl | ||||
|                 .replace(/\{\{\s?(number)\s?\}\}/gi, i + 1) | ||||
|                 .replace(/\{\{\s?(message)\s?\}\}/gi, commit.commit.message) | ||||
|                 .replace(/\{\{\s?(author)\s?\}\}/gi, commit.hasOwnProperty('author') ? (commit.author.hasOwnProperty('login') ? commit.author.login : '') : '') | ||||
|                 .replace(/\{\{\s?(sha)\s?\}\}/gi, commit.sha) | ||||
|                 .trim() + '\n' | ||||
|             } else { | ||||
|               return `${i === 0 ? '\n' : ''}${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: await this.getMessage(), | ||||
|         object: process.env.GITHUB_SHA, | ||||
|         type: 'commit' | ||||
|       }) | ||||
|  | ||||
|       this._sha = newTag.data.sha | ||||
|       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 | ||||
|       } | ||||
|  | ||||
|       this._uri = newReference.data.url | ||||
|       this._ref = newReference.data.ref | ||||
|  | ||||
|       core.warning(`Reference ${newReference.data.ref} available at ${newReference.data.url}` + os.EOL) | ||||
|     } else { | ||||
|       core.warning('Cannot push tag (it already exists).') | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										87
									
								
								app/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								app/main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| 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' | ||||
| import Dockerfile from './lib/docker.js' | ||||
|  | ||||
| async function run () { | ||||
|   try { | ||||
|     Setup.debug() | ||||
|     Setup.requireAnyEnv('GITHUB_TOKEN', 'INPUT_GITHUB_TOKEN') | ||||
|  | ||||
|     // Configure the default output | ||||
|     core.setOutput('tagcreated', 'no') | ||||
|  | ||||
|     // Identify the tag parsing strategy | ||||
|     const root = core.getInput('root', { required: false }) || core.getInput('package_root', { required: false }) || './' | ||||
|     const strategy = (core.getInput('regex_pattern', { required: false }) || '').trim().length > 0 ? 'regex' : ((core.getInput('strategy', { required: false }) || 'package').trim().toLowerCase()) | ||||
|     core.warning(`Attempting to use ${strategy} version extraction strategy.`) | ||||
|  | ||||
|     // 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(core.getInput('regex_pattern', { required: false }), '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 }) | ||||
|     ) | ||||
|  | ||||
|     core.warning(`Attempting to create ${tag.name} tag.`) | ||||
|     core.setOutput('tagrequested', tag.name) | ||||
|  | ||||
|     // 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', '') | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     // The tag setter will autocorrect the message if necessary. | ||||
|     tag.message = core.getInput('tag_message', { required: false }).trim() | ||||
|     await tag.push() | ||||
|  | ||||
|     core.setOutput('tagname', tag.name) | ||||
|     core.setOutput('tagsha', tag.sha) | ||||
|     core.setOutput('taguri', tag.uri) | ||||
|     core.setOutput('tagmessage', tag.message) | ||||
|     core.setOutput('tagref', tag.ref) | ||||
|     core.setOutput('tagcreated', 'yes') | ||||
|   } catch (error) { | ||||
|     core.warning(error.message) | ||||
|     core.warning(error.stack) | ||||
|     core.setOutput('tagname', '') | ||||
|     core.setOutput('tagsha', '') | ||||
|     core.setOutput('taguri', '') | ||||
|     core.setOutput('tagmessage', '') | ||||
|     core.setOutput('tagref', '') | ||||
|     core.setOutput('tagcreated', 'no') | ||||
|   } | ||||
| } | ||||
|  | ||||
| run() | ||||
							
								
								
									
										0
									
								
								package-lock.json → app/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										0
									
								
								package-lock.json → app/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
								
								
									
										26
									
								
								app/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| { | ||||
|   "name": "autotag-action", | ||||
|   "version": "1.0.2", | ||||
|   "private": true, | ||||
|   "description": "Automatically create a tag whenever the version changes in package.json", | ||||
|   "main": "lib/main.js", | ||||
|   "scripts": { | ||||
|     "start": "node ./main.js" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git+https://github.com/butlerlogic/action-autotag.git" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "actions", | ||||
|     "node", | ||||
|     "setup" | ||||
|   ], | ||||
|   "author": "ButlerLogic", | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "@actions/core": "^1.2.2", | ||||
|     "@actions/github": "^2.1.0" | ||||
|   }, | ||||
|   "type": "module" | ||||
| } | ||||
							
								
								
									
										174
									
								
								lib/main.js
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								lib/main.js
									
									
									
									
									
								
							| @ -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() | ||||
							
								
								
									
										32
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								package.json
									
									
									
									
									
								
							| @ -1,25 +1,21 @@ | ||||
| { | ||||
|   "name": "autotag-action", | ||||
|   "version": "1.0.2", | ||||
|   "private": true, | ||||
|   "description": "Automatically create a tag whenever the version changes in package.json", | ||||
|   "main": "lib/main.js", | ||||
|   "name": "action-autotag-test", | ||||
|   "version": "1.1.0", | ||||
|   "description": "This is a test file for the action.", | ||||
|   "main": "index.js", | ||||
|   "dependencies": {}, | ||||
|   "devDependencies": {}, | ||||
|   "scripts": { | ||||
|     "test": "jest" | ||||
|     "test": "echo \"Error: no test specified\" && exit 1" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git+https://github.com/butlerlogic/action-autotag.git" | ||||
|     "url": "git+https://github.com/ButlerLogic/action-autotag.git" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "actions", | ||||
|     "node", | ||||
|     "setup" | ||||
|   ], | ||||
|   "author": "ButlerLogic", | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "@actions/core": "^1.2.2", | ||||
|     "@actions/github": "^2.1.0" | ||||
|   } | ||||
|   "author": "", | ||||
|   "license": "ISC", | ||||
|   "bugs": { | ||||
|     "url": "https://github.com/ButlerLogic/action-autotag/issues" | ||||
|   }, | ||||
|   "homepage": "https://github.com/ButlerLogic/action-autotag#readme" | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Corey Butler
					Corey Butler