node-package-release-action 0.1.9 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,7 +16,6 @@ name: Release
16
16
  on:
17
17
  schedule:
18
18
  - cron: "0 12 * * 0" # every sunday noon
19
- workflow_dispatch:
20
19
 
21
20
  jobs:
22
21
  release:
@@ -25,12 +24,27 @@ jobs:
25
24
  steps:
26
25
  - uses: actions/checkout@v3
27
26
 
28
- - uses: CatChen/node-package-release-action@v0.1
27
+ - id: release
28
+ uses: CatChen/node-package-release-action@v1
29
29
  with:
30
30
  github-token: ${{ secrets.GITHUB_TOKEN }} # optional
31
+ directory: "./" #optional
31
32
  release-type: prerelease # optional
32
- prerelease: true # optional
33
+ prerelease: false # optional
34
+ update-shorthand-release: false
35
+ skip-if-no-diff: false
33
36
  dry-run: false # optional
37
+
38
+ - env:
39
+ TAG: ${{ steps.release.outputs.tag }}
40
+ SKIPPED: ${{ steps.release.outputs.skipped }}
41
+ run: |
42
+ if [[ "$SKIPPED"='true' ]]
43
+ then
44
+ echo 'Release is skipped.'
45
+ else
46
+ echo "Release $TAG successfully."
47
+ fi
34
48
  ```
35
49
 
36
50
  ## Options
@@ -55,6 +69,10 @@ This controls whether the GitHub Release should be marked as a prerelease. The d
55
69
 
56
70
  [GitHub Action documentation](https://docs.github.com/en/actions/creating-actions/about-custom-actions#using-tags-for-release-management) recommends updating shorthand releases like `v1` and `v1.2` when releasing the latest `v1.2.*`. Set this to `true` when using this Action to release other Actions. The default value is `false`.
57
71
 
72
+ ### `skip-if-no-diff`
73
+
74
+ The controls whether this action should do nothing if there's no changes since last release of the same release type. If we release a minor upgrade to `1.2.3` or `1.2.3-4` it should be `1.2.4`. If `1.2.4` and `1.2.3` are the same and if `skip-if-no-diff` is set to `true`, `1.2.4` won't be created. `1.2.3-*` won't be used in the comparison. The default value is `false`.
75
+
58
76
  ### `dry-run`
59
77
 
60
78
  This controls whether this is a dry run. The default value is `false`. It's used for debugging only.
@@ -82,3 +100,59 @@ Let's start with the easy ones. `major`, `minor` and `patch` increase their corr
82
100
  - `2.3.4-5` + `preminor` => `2.4.0-0`
83
101
  - `2.3.4` + `prepatch` => `2.3.5-0`
84
102
  - `2.3.4-5` + `prepatch` => `2.3.5-0`
103
+
104
+ ### Can I create a Workflow to manually release with any release type I want at the time?
105
+
106
+ <img width="359" alt="Screenshot 2022-11-14 at 5 35 13 PM" src="https://user-images.githubusercontent.com/112175/201804995-7cb572b4-87a6-4662-9e24-7c4d3b0ff844.png">
107
+
108
+ Yes! You can provide inputs in the Action web interface before manually triggering a Workflow. [GitHub Action documentation](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#providing-inputs) describes how to do this. Below is an example.
109
+
110
+ ```yaml
111
+ name: Release
112
+
113
+ on:
114
+ workflow_dispatch:
115
+ inputs:
116
+ release-type:
117
+ description: "Release Type"
118
+ required: true
119
+ default: "patch"
120
+ type: choice
121
+ options:
122
+ - major
123
+ - minor
124
+ - patch
125
+ - premajor
126
+ - preminor
127
+ - prepatch
128
+ - prerelease
129
+ prerelease:
130
+ description: "Prerelease"
131
+ required: true
132
+ default: false
133
+ type: boolean
134
+ dry-run:
135
+ description: "Dry run"
136
+ required: true
137
+ default: false
138
+ type: boolean
139
+
140
+ release:
141
+ name: Release
142
+ concurrency: release
143
+ runs-on: ubuntu-latest
144
+ steps:
145
+ - uses: actions/checkout@v3
146
+ with:
147
+ ref: "main"
148
+
149
+ - uses: CatChen/node-package-release-action@v1
150
+ with:
151
+ release-type: ${{ inputs.release-type || 'patch' }}
152
+ prerelease: ${{ inputs.prerelease || false }}
153
+ dry-run: ${{ inputs.dry-run || false }}
154
+ ```
155
+
156
+ ### How do I know if `skip-if-no-diff` took effect?
157
+
158
+ Use an output called `skipped`. See the first code example as a reference.
@@ -0,0 +1,2 @@
1
+ export declare const RELEASE_TYPES: readonly ["major", "premajor", "minor", "preminor", "patch", "prepatch", "prerelease"];
2
+ export type ReleaseType = typeof RELEASE_TYPES[number];
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RELEASE_TYPES = void 0;
4
+ exports.RELEASE_TYPES = [
5
+ "major",
6
+ "premajor",
7
+ "minor",
8
+ "preminor",
9
+ "patch",
10
+ "prepatch",
11
+ "prerelease",
12
+ ];
@@ -0,0 +1 @@
1
+ export declare function checkDiff(tag: string): Promise<boolean>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.checkDiff = void 0;
13
+ const core_1 = require("@actions/core");
14
+ const exec_1 = require("@actions/exec");
15
+ function checkDiff(tag) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const diffOutput = yield (0, exec_1.getExecOutput)("git", ["diff", tag, "--name-only"]);
18
+ if (diffOutput.exitCode !== core_1.ExitCode.Success) {
19
+ throw new Error(diffOutput.stderr);
20
+ }
21
+ (0, core_1.debug)(`Diff against ${tag}:` +
22
+ "\n" +
23
+ diffOutput.stdout
24
+ .split("\n")
25
+ .map((line) => ` ${line}`)
26
+ .join("\n"));
27
+ return diffOutput.stdout.split("\n").join("") !== "";
28
+ });
29
+ }
30
+ exports.checkDiff = checkDiff;
@@ -29,7 +29,7 @@ function fetchEverything() {
29
29
  if (gitIsShallowRepositoryOutput.exitCode !== core_1.ExitCode.Success) {
30
30
  throw new Error(gitIsShallowRepositoryOutput.stderr);
31
31
  }
32
- if (gitIsShallowRepositoryOutput.stdout === "true") {
32
+ if (gitIsShallowRepositoryOutput.stdout.trim() === "true") {
33
33
  const gitFetchUnshallowOutput = yield (0, exec_1.getExecOutput)("git", [
34
34
  "fetch",
35
35
  "--unshallow",
@@ -0,0 +1,2 @@
1
+ import { ReleaseType } from "semver";
2
+ export declare function findLastSameReleaseTypeVersion(releaseVersion: string, releaseType: ReleaseType): Promise<string | null>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.findLastSameReleaseTypeVersion = void 0;
13
+ const core_1 = require("@actions/core");
14
+ const semver_1 = require("semver");
15
+ const getAllGitTags_1 = require("./getAllGitTags");
16
+ function findLastSameReleaseTypeVersion(releaseVersion, releaseType) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const versionTags = yield (0, getAllGitTags_1.getAllGitTags)();
19
+ if (versionTags.length === 0) {
20
+ (0, core_1.warning)(`No tag found.`);
21
+ return null;
22
+ }
23
+ const sortedTags = (0, semver_1.rsort)(versionTags);
24
+ let candidateTag = sortedTags.shift();
25
+ while (candidateTag !== undefined &&
26
+ ((0, semver_1.gte)(candidateTag, releaseVersion) ||
27
+ (0, semver_1.diff)(candidateTag, releaseVersion) !== releaseType)) {
28
+ candidateTag = sortedTags.shift();
29
+ }
30
+ if (candidateTag === undefined) {
31
+ (0, core_1.warning)(`No tag found.`);
32
+ return null;
33
+ }
34
+ return candidateTag;
35
+ });
36
+ }
37
+ exports.findLastSameReleaseTypeVersion = findLastSameReleaseTypeVersion;
@@ -0,0 +1 @@
1
+ export declare function getAllGitTags(): Promise<string[]>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getAllGitTags = void 0;
13
+ const core_1 = require("@actions/core");
14
+ const exec_1 = require("@actions/exec");
15
+ const semver_1 = require("semver");
16
+ function getAllGitTags() {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const tagOutput = yield (0, exec_1.getExecOutput)("git", ["tag"]);
19
+ if (tagOutput.exitCode !== core_1.ExitCode.Success) {
20
+ throw new Error(tagOutput.stderr);
21
+ }
22
+ const allTags = tagOutput.stdout.split("\n");
23
+ const versionTags = allTags.filter((tag) => (0, semver_1.valid)(tag));
24
+ return versionTags;
25
+ });
26
+ }
27
+ exports.getAllGitTags = getAllGitTags;
@@ -11,21 +11,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getLastGitTag = void 0;
13
13
  const core_1 = require("@actions/core");
14
- const exec_1 = require("@actions/exec");
15
14
  const semver_1 = require("semver");
15
+ const getAllGitTags_1 = require("./getAllGitTags");
16
16
  function getLastGitTag() {
17
17
  return __awaiter(this, void 0, void 0, function* () {
18
- const tagOutput = yield (0, exec_1.getExecOutput)("git", ["tag"]);
19
- if (tagOutput.exitCode !== core_1.ExitCode.Success) {
20
- throw new Error(tagOutput.stderr);
21
- }
22
- const allTags = tagOutput.stdout.split("\n");
23
- const versionTags = allTags.filter((tag) => /v\d+\.\d+\.\d+(\-\d+)?/.test(tag));
24
- const sortedTags = (0, semver_1.rsort)(versionTags);
25
- if (sortedTags.length === 0) {
18
+ const versionTags = yield (0, getAllGitTags_1.getAllGitTags)();
19
+ if (versionTags.length === 0) {
26
20
  (0, core_1.warning)(`No tag found.`);
27
21
  return null;
28
22
  }
23
+ const sortedTags = (0, semver_1.rsort)(versionTags);
29
24
  const lastTag = sortedTags[0];
30
25
  return lastTag;
31
26
  });
@@ -1,3 +1,3 @@
1
1
  import type { Octokit } from "@octokit/core";
2
2
  import type { Api } from "@octokit/plugin-rest-endpoint-methods/dist-types/types";
3
- export declare function getLatestRelease(owner: string, repo: string, octokit: Octokit & Api): Promise<string | null>;
3
+ export declare function getlatestReleaseTag(owner: string, repo: string, octokit: Octokit & Api): Promise<string | null>;
@@ -9,10 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getLatestRelease = void 0;
12
+ exports.getlatestReleaseTag = void 0;
13
13
  const core_1 = require("@actions/core");
14
14
  const request_error_1 = require("@octokit/request-error");
15
- function getLatestRelease(owner, repo, octokit) {
15
+ const semver_1 = require("semver");
16
+ function getlatestReleaseTag(owner, repo, octokit) {
16
17
  return __awaiter(this, void 0, void 0, function* () {
17
18
  try {
18
19
  const latestReleaseResponse = yield octokit.rest.repos.getLatestRelease({
@@ -21,27 +22,43 @@ function getLatestRelease(owner, repo, octokit) {
21
22
  });
22
23
  // Latest release doesn't include pre-release.
23
24
  const latestRelease = latestReleaseResponse.data;
24
- return latestRelease.tag_name;
25
+ if ((0, semver_1.valid)(latestRelease.tag_name) !== null) {
26
+ return latestRelease.tag_name;
27
+ }
28
+ else {
29
+ (0, core_1.warning)(`Latest release tag is not a valid semver: ${latestRelease.tag_name}`);
30
+ }
25
31
  }
26
32
  catch (error) {
27
33
  if (error instanceof request_error_1.RequestError) {
28
34
  if (error.status === 404) {
29
35
  (0, core_1.warning)(`Latest release not found but pre-release may exist`);
30
- const releasesResponse = yield octokit.rest.repos.listReleases({
31
- owner,
32
- repo,
33
- });
34
- if (releasesResponse.data.length === 0) {
35
- // No release or pre-release available.
36
- (0, core_1.warning)(`Pre-release not found`);
37
- return null;
38
- }
39
- const latestRelease = releasesResponse.data[0];
40
- return latestRelease.tag_name;
36
+ }
37
+ else {
38
+ throw new Error(`Unexpected status code: ${error.status}`);
41
39
  }
42
40
  }
41
+ else {
42
+ throw error;
43
+ }
44
+ }
45
+ const releasesResponse = yield octokit.rest.repos.listReleases({
46
+ owner,
47
+ repo,
48
+ });
49
+ if (releasesResponse.data.length === 0) {
50
+ (0, core_1.warning)(`No release found`);
51
+ return null;
52
+ }
53
+ const releaseTags = releasesResponse.data.map((release) => release.tag_name);
54
+ const validReleaseTags = releaseTags.filter((tag) => (0, semver_1.valid)(tag) !== null);
55
+ if (validReleaseTags.length === 0) {
56
+ (0, core_1.warning)(`No valid release tag found`);
57
+ (0, core_1.debug)("Release tags:\n" + releaseTags.map((tag) => ` ${tag}`).join("\n"));
58
+ return null;
43
59
  }
44
- return null;
60
+ const sortedReleaseTags = (0, semver_1.rsort)(validReleaseTags);
61
+ return sortedReleaseTags[0];
45
62
  });
46
63
  }
47
- exports.getLatestRelease = getLatestRelease;
64
+ exports.getlatestReleaseTag = getlatestReleaseTag;
package/lib/index.js CHANGED
@@ -12,25 +12,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const core_1 = require("@actions/core");
13
13
  const github_1 = require("@actions/github");
14
14
  const semver_1 = require("semver");
15
+ const ReleaseType_1 = require("./ReleaseType");
15
16
  const getOctokit_1 = require("./getOctokit");
16
17
  const configGit_1 = require("./configGit");
17
18
  const fetchEverything_1 = require("./fetchEverything");
18
19
  const getLastGitTag_1 = require("./getLastGitTag");
19
20
  const getPackageVersion_1 = require("./getPackageVersion");
20
- const getLatestRelease_1 = require("./getLatestRelease");
21
+ const getlatestReleaseTag_1 = require("./getlatestReleaseTag");
22
+ const findLastSameReleaseTypeVersion_1 = require("./findLastSameReleaseTypeVersion");
21
23
  const setVersion_1 = require("./setVersion");
22
24
  const pushBranch_1 = require("./pushBranch");
23
25
  const createRelease_1 = require("./createRelease");
24
26
  const updateTags_1 = require("./updateTags");
25
- const RELEASE_TYPES = [
26
- "major",
27
- "premajor",
28
- "minor",
29
- "preminor",
30
- "patch",
31
- "prepatch",
32
- "prerelease",
33
- ];
27
+ const checkDiff_1 = require("./checkDiff");
34
28
  const DEFAULT_VERSION = "0.1.0";
35
29
  function run() {
36
30
  return __awaiter(this, void 0, void 0, function* () {
@@ -42,13 +36,13 @@ function run() {
42
36
  (0, core_1.notice)(`package.json version: ${packageVersion}`);
43
37
  const { owner, repo } = github_1.context.repo;
44
38
  const octokit = (0, getOctokit_1.getOctokit)();
45
- const latestRelease = yield (0, getLatestRelease_1.getLatestRelease)(owner, repo, octokit);
46
- (0, core_1.notice)(`Latest release: ${latestRelease}`);
47
- const versions = [lastGitTag, packageVersion, latestRelease].flatMap((version) => (version === null ? [] : [version]));
39
+ const latestReleaseTag = yield (0, getlatestReleaseTag_1.getlatestReleaseTag)(owner, repo, octokit);
40
+ (0, core_1.notice)(`Latest release tag: ${latestReleaseTag}`);
41
+ const versions = [lastGitTag, packageVersion, latestReleaseTag].flatMap((version) => (version === null ? [] : [version]));
48
42
  const sortedVersions = (0, semver_1.rsort)(versions);
49
43
  const highestVersion = sortedVersions.length === 0 ? DEFAULT_VERSION : sortedVersions[0];
50
44
  (0, core_1.notice)(`Highest version: ${highestVersion}`);
51
- const releaseType = RELEASE_TYPES.find((releaseType) => (0, core_1.getInput)("release-type").toLowerCase() === releaseType);
45
+ const releaseType = ReleaseType_1.RELEASE_TYPES.find((releaseType) => (0, core_1.getInput)("release-type").toLowerCase() === releaseType);
52
46
  if (releaseType === undefined) {
53
47
  (0, core_1.setFailed)(`Invalid release-type input: ${(0, core_1.getInput)("release-type")}`);
54
48
  return;
@@ -59,6 +53,20 @@ function run() {
59
53
  return;
60
54
  }
61
55
  (0, core_1.notice)(`Release version: ${releaseVersion}`);
56
+ if ((0, core_1.getBooleanInput)("skip-if-no-diff")) {
57
+ const lastSameReleaseTypeVersion = yield (0, findLastSameReleaseTypeVersion_1.findLastSameReleaseTypeVersion)(releaseVersion, releaseType);
58
+ (0, core_1.notice)(`Last same release type version: ${lastSameReleaseTypeVersion}`);
59
+ if (lastSameReleaseTypeVersion !== null) {
60
+ const diff = yield (0, checkDiff_1.checkDiff)(lastSameReleaseTypeVersion);
61
+ if (!diff) {
62
+ (0, core_1.notice)(`Skip due to lack of diff between HEAD..${lastSameReleaseTypeVersion}`);
63
+ (0, core_1.setOutput)("skipped", true);
64
+ return;
65
+ }
66
+ }
67
+ (0, core_1.setOutput)("skipped", false);
68
+ }
69
+ (0, core_1.setOutput)("tag", `v${releaseVersion}`);
62
70
  yield (0, setVersion_1.setVersion)(releaseVersion);
63
71
  yield (0, pushBranch_1.pushBranch)();
64
72
  yield (0, createRelease_1.createRelease)(owner, repo, releaseVersion, octokit);
package/lib/updateTags.js CHANGED
@@ -21,8 +21,8 @@ function updateTags(version) {
21
21
  throw new Error(`Failed to parse the version as semver: ${version}`);
22
22
  }
23
23
  if (semver.prerelease.length !== 0) {
24
- (0, core_1.warning)(`Pre-release version should not be used to update shorthand tags: ${version}`);
25
- (0, core_1.warning)("Please don't set release-type to prerelease and update-shorthand-release to true at the same time");
24
+ (0, core_1.warning)(`Pre-release version should not be used to update shorthand tags: ${version}` +
25
+ "\nPlease don't set release-type to prerelease and update-shorthand-release to true at the same time");
26
26
  }
27
27
  if (semver.major > 0) {
28
28
  const gitTagMajorOutput = yield (0, exec_1.getExecOutput)("git", [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-package-release-action",
3
- "version": "0.1.9",
3
+ "version": "1.0.4",
4
4
  "description": "A template to create custom GitHub Action with TypeScript/JavaScript.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.js",