mirror of
https://github.com/actions/publish-action.git
synced 2025-02-24 16:22:31 +00:00
Implement the "publish-action" action
This commit is contained in:
parent
d90d23df2a
commit
d8eb8e53b7
48
.github/workflows/release-new-action-version.yml
vendored
Normal file
48
.github/workflows/release-new-action-version.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
name: Release new action version
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
TAG_NAME:
|
||||||
|
description: 'Tag name that the major tag will point to'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: pwsh
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update_tag:
|
||||||
|
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
|
||||||
|
environment:
|
||||||
|
name: releaseNewActionVersion
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Update the ${{ env.TAG_NAME }} tag
|
||||||
|
id: update-major-tag
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
source-tag: ${{ env.TAG_NAME }}
|
||||||
|
|
||||||
|
- name: Send slack message
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
curl `
|
||||||
|
-X POST `
|
||||||
|
-H 'Content-type: application/json' `
|
||||||
|
--data '{\"text\":\"Failed to update a major tag for the ${{ github.repository }} action\"}' `
|
||||||
|
${{ secrets.SLACK }}
|
||||||
|
|
||||||
|
- name: Send slack message
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
curl `
|
||||||
|
-X POST `
|
||||||
|
-H 'Content-type: application/json' `
|
||||||
|
--data '{\"text\":\"The ${{ steps.update-major-tag.outputs.major-tag }} tag has been successfully updated for the ${{ github.repository }} action to include changes from the ${{ env.TAG_NAME }}\"}' `
|
||||||
|
${{ secrets.SLACK }}
|
27
.github/workflows/test.yml
vendored
Normal file
27
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set Node.JS
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 12.x
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: npm run test
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
lib/
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 GitHub, Inc. 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
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
25
README.md
25
README.md
@ -1 +1,26 @@
|
|||||||
# publish-action
|
# publish-action
|
||||||
|
|
||||||
|
**Please note: this action is for internal usage only, we don't track issues or accept any contributions. We also do not recommend it for public or production usage.**
|
||||||
|
|
||||||
|
This action adds reliability to the new action versions publishing and handles the following cases:
|
||||||
|
- Update a major tag (v1, for example) to point to the latest release (v1.2.1, for example).
|
||||||
|
- Create a major tag from the latest released tag if a major tag doesn't exist
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Alpha. Action is under development and internal testing.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Action can be triggered on release creation or manually. The actual major tag update will require manual approval.
|
||||||
|
See [release-new-action-version.yml](./.github/workflows/release-new-action-version.yml) for usage example.
|
||||||
|
|
||||||
|
See [action.yml](action.yml) for a complete description of input and output fields.
|
||||||
|
Read more about action versioning notation in [action-versioning.md](https://github.com/actions/toolkit/blob/main/docs/action-versioning.md).
|
||||||
|
|
||||||
|
To roll back a release in case of customer impact, start the workflow manually and specify the previous stable tag.
|
||||||
|
|
||||||
|
## Conributions
|
||||||
|
|
||||||
|
We don't accept contributions until the action is ready for production.
|
||||||
|
|
||||||
|
## License
|
||||||
|
The scripts and documentation in this project are released under the [MIT License](LICENSE).
|
||||||
|
39
__tests__/api-utils.test.ts
Normal file
39
__tests__/api-utils.test.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import * as github from "@actions/github";
|
||||||
|
import * as apiUtils from "../src/api-utils";
|
||||||
|
|
||||||
|
const prereleaseData = require("./data/pre-release.json");
|
||||||
|
const releaseData = require("./data/release.json");
|
||||||
|
|
||||||
|
const token = "faketoken";
|
||||||
|
const octokitClient = github.getOctokit(token);
|
||||||
|
|
||||||
|
let getReleaseSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
process.env.GITHUB_REPOSITORY = "test/repository";
|
||||||
|
|
||||||
|
describe("validateIfReleaseIsPublished", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
getReleaseSpy = jest.spyOn(octokitClient.repos, "getReleaseByTag");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throw if release is marked as pre-release", async () => {
|
||||||
|
getReleaseSpy.mockReturnValue(prereleaseData);
|
||||||
|
|
||||||
|
expect.assertions(1);
|
||||||
|
await expect(apiUtils.validateIfReleaseIsPublished("v1.0.0", octokitClient)).rejects.toThrowError(
|
||||||
|
"The 'v1.0.0' release is marked as pre-release. Updating tags for pre-release is not supported"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate that release is published", async () => {
|
||||||
|
getReleaseSpy.mockReturnValue(releaseData);
|
||||||
|
|
||||||
|
expect.assertions(1);
|
||||||
|
await expect(apiUtils.validateIfReleaseIsPublished("v1.1.0", octokitClient)).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
});
|
14
__tests__/data/pre-release.json
Normal file
14
__tests__/data/pre-release.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"node_id": "MDc6UmVsZWFzZTE=",
|
||||||
|
"tag_name": "v1.0.0",
|
||||||
|
"target_commitish": "main",
|
||||||
|
"name": "v1.0.0",
|
||||||
|
"body": "Description of the release",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": true,
|
||||||
|
"created_at": "2013-02-27T19:35:32Z",
|
||||||
|
"published_at": "2013-02-27T19:35:32Z"
|
||||||
|
}
|
||||||
|
}
|
12
__tests__/data/prerelease-build-semver.json
Normal file
12
__tests__/data/prerelease-build-semver.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"options": {},
|
||||||
|
"loose": false,
|
||||||
|
"includePrerelease": false,
|
||||||
|
"raw": "v1.0.0-beta.1+20130313144700",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 0,
|
||||||
|
"patch": 0,
|
||||||
|
"prerelease": [ "beta", 1 ],
|
||||||
|
"build": [ "20130313144700" ],
|
||||||
|
"version": "1.0.0-beta.1"
|
||||||
|
}
|
12
__tests__/data/prerelease-semver.json
Normal file
12
__tests__/data/prerelease-semver.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"options": {},
|
||||||
|
"loose": false,
|
||||||
|
"includePrerelease": false,
|
||||||
|
"raw": "v1.0.0-beta.1",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 0,
|
||||||
|
"patch": 0,
|
||||||
|
"prerelease": [ "beta", 1 ],
|
||||||
|
"build": [],
|
||||||
|
"version": "1.0.0-beta.1"
|
||||||
|
}
|
14
__tests__/data/release.json
Normal file
14
__tests__/data/release.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"node_id": "MDc6UmVsZWFzZTE=",
|
||||||
|
"tag_name": "v1.1.0",
|
||||||
|
"target_commitish": "main",
|
||||||
|
"name": "v1.1.0",
|
||||||
|
"body": "Description of the release",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false,
|
||||||
|
"created_at": "2013-02-27T19:35:32Z",
|
||||||
|
"published_at": "2013-02-27T19:35:32Z"
|
||||||
|
}
|
||||||
|
}
|
12
__tests__/data/stable-build-semver.json
Normal file
12
__tests__/data/stable-build-semver.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"options": {},
|
||||||
|
"loose": false,
|
||||||
|
"includePrerelease": false,
|
||||||
|
"raw": "1.0.0+20130313144700",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 0,
|
||||||
|
"patch": 0,
|
||||||
|
"prerelease": [],
|
||||||
|
"build": [ "20130313144700" ],
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
12
__tests__/data/stable-semver.json
Normal file
12
__tests__/data/stable-semver.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"options": {},
|
||||||
|
"loose": false,
|
||||||
|
"includePrerelease": false,
|
||||||
|
"raw": "v1.0.0",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 0,
|
||||||
|
"patch": 0,
|
||||||
|
"prerelease": [],
|
||||||
|
"build": [],
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
69
__tests__/version-utils.test.ts
Normal file
69
__tests__/version-utils.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import * as versionUtils from "../src/version-utils";
|
||||||
|
|
||||||
|
describe("isStableSemverVersion", () => {
|
||||||
|
it("validate if a version is stable", () => {
|
||||||
|
const semverVersion = require("./data/stable-semver.json");
|
||||||
|
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate if a version with build metadata is stable", () => {
|
||||||
|
const semverVersion = require("./data/stable-build-semver.json");
|
||||||
|
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate if a pre-release version is not stable", () => {
|
||||||
|
const semverVersion = require("./data/prerelease-semver.json");
|
||||||
|
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate if a pre-release version with build metadata is not stable", () => {
|
||||||
|
const semverVersion = require("./data/prerelease-build-semver.json");
|
||||||
|
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("validateSemverVersionFromTag", () => {
|
||||||
|
it("validate a tag containing an valid semantic version", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0")).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate a tag containing an valid semantic version with 'v' prefix", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0")).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validate a tag containing an valid semantic version with build metadata", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0+20130313144700")).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throw when a tag contains an invalid semantic version", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0invalid")).toThrowError(
|
||||||
|
"The '1.0.0invalid' doesn't satisfy semantic versioning specification"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throw when a tag contains an valid unstable semantic version", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1")).toThrowError(
|
||||||
|
"It is not allowed to specify pre-release version to update the major tag"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throw when a tag contains an valid unstable semantic version with build metadata", () => {
|
||||||
|
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1+20130313144700")).toThrowError(
|
||||||
|
"It is not allowed to specify pre-release version to update the major tag"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getMajorTagFromFullTag", () => {
|
||||||
|
describe("get a valid major tag from full tag", () => {
|
||||||
|
it.each([
|
||||||
|
["1.0.0", "1"],
|
||||||
|
["v1.0.0", "v1"],
|
||||||
|
["v1.0.0-beta.1", "v1"],
|
||||||
|
["v1.0.0+20130313144700", "v1"],
|
||||||
|
] as [string, string][])("%s -> %s", (sourceTag: string, expectedMajorTag: string) => {
|
||||||
|
const resultantMajorTag = versionUtils.getMajorTagFromFullTag(sourceTag);
|
||||||
|
expect(resultantMajorTag).toBe(expectedMajorTag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
15
action.yml
Normal file
15
action.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
name: 'Publish action versions'
|
||||||
|
description: 'Move the major version tag to point to the specified ref'
|
||||||
|
inputs:
|
||||||
|
source-tag:
|
||||||
|
description: 'Tag name that the major tag will point to. Examples: v1.2.3, 1.2.3'
|
||||||
|
required: true
|
||||||
|
token:
|
||||||
|
description: 'Token to get an authenticated Octokit'
|
||||||
|
default: ${{ github.token }}
|
||||||
|
outputs:
|
||||||
|
major-tag:
|
||||||
|
description: 'The major version tag that has been updated (created). Examples: v1, 1'
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'dist/index.js'
|
6844
dist/index.js
vendored
Normal file
6844
dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
jest.config.js
Normal file
11
jest.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
testRunner: 'jest-circus/runner',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
5086
package-lock.json
generated
Normal file
5086
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "publish-action",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Update the major version tag (v1, v2, etc.) to point to the specified tag",
|
||||||
|
"main": "lib/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc && ncc build",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/actions/publish-action.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"actions",
|
||||||
|
"publish"
|
||||||
|
],
|
||||||
|
"author": "GitHub",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/actions/publish-action/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/actions/publish-action#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.2.7",
|
||||||
|
"@actions/github": "^4.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^26.0.23",
|
||||||
|
"@types/semver": "^7.3.6",
|
||||||
|
"@vercel/ncc": "^0.28.5",
|
||||||
|
"jest": "^26.6.3",
|
||||||
|
"jest-circus": "^26.6.3",
|
||||||
|
"semver": "^7.3.5",
|
||||||
|
"ts-jest": "^26.5.6",
|
||||||
|
"typescript": "^4.2.4"
|
||||||
|
}
|
||||||
|
}
|
103
src/api-utils.ts
Normal file
103
src/api-utils.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import { context } from '@actions/github';
|
||||||
|
import { GitHub } from '@actions/github/lib/utils';
|
||||||
|
|
||||||
|
interface GitRef {
|
||||||
|
ref: string;
|
||||||
|
node_id: string;
|
||||||
|
url: string;
|
||||||
|
object: {
|
||||||
|
type: string;
|
||||||
|
sha: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findTag(
|
||||||
|
tag: string,
|
||||||
|
octokitClient: InstanceType<typeof GitHub>
|
||||||
|
): Promise<GitRef | null> {
|
||||||
|
try {
|
||||||
|
const { data: foundTag } = await octokitClient.git.getRef({
|
||||||
|
...context.repo,
|
||||||
|
ref: `tags/${tag}`
|
||||||
|
});
|
||||||
|
|
||||||
|
return foundTag;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.status === 404) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getTagSHA(
|
||||||
|
tag: string,
|
||||||
|
octokitClient: InstanceType<typeof GitHub>
|
||||||
|
): Promise<string> {
|
||||||
|
const foundTag = await findTag(tag, octokitClient);
|
||||||
|
if (!foundTag) {
|
||||||
|
throw new Error(
|
||||||
|
`The '${tag}' tag does not exist in the remote repository`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundTag.object.sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function validateIfReleaseIsPublished(
|
||||||
|
tag: string,
|
||||||
|
octokitClient: InstanceType<typeof GitHub>
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { data: foundRelease } = await octokitClient.repos.getReleaseByTag({
|
||||||
|
...context.repo,
|
||||||
|
tag,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundRelease.prerelease){
|
||||||
|
throw new Error(
|
||||||
|
`The '${foundRelease.name}' release is marked as pre-release. Updating tags for pre-release is not supported`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.status === 404) {
|
||||||
|
throw new Error(
|
||||||
|
`No GitHub release found for the ${tag} tag`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateTag(
|
||||||
|
sourceTag: string,
|
||||||
|
targetTag: string,
|
||||||
|
octokitClient: InstanceType<typeof GitHub>
|
||||||
|
): Promise<void> {
|
||||||
|
const sourceTagSHA = await getTagSHA(sourceTag, octokitClient);
|
||||||
|
const foundTargetTag = await findTag(targetTag, octokitClient);
|
||||||
|
const refName = `tags/${targetTag}`;
|
||||||
|
|
||||||
|
if (foundTargetTag) {
|
||||||
|
core.info(`Updating the '${targetTag}' tag to point to the '${sourceTag}' tag`);
|
||||||
|
|
||||||
|
await octokitClient.git.updateRef({
|
||||||
|
...context.repo,
|
||||||
|
ref: refName,
|
||||||
|
sha: sourceTagSHA,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.info(`Creating the '${targetTag}' tag from the '${sourceTag}' tag`);
|
||||||
|
|
||||||
|
await octokitClient.git.createRef({
|
||||||
|
...context.repo,
|
||||||
|
ref: `refs/${refName}`,
|
||||||
|
sha: sourceTagSHA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
26
src/main.ts
Normal file
26
src/main.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as github from '@actions/github';
|
||||||
|
import { updateTag, validateIfReleaseIsPublished } from './api-utils';
|
||||||
|
import { validateSemverVersionFromTag, getMajorTagFromFullTag } from './version-utils';
|
||||||
|
|
||||||
|
async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const token = core.getInput('token');
|
||||||
|
const octokitClient = github.getOctokit(token);
|
||||||
|
const sourceTagName = core.getInput('source-tag');
|
||||||
|
|
||||||
|
validateSemverVersionFromTag(sourceTagName);
|
||||||
|
|
||||||
|
await validateIfReleaseIsPublished(sourceTagName, octokitClient);
|
||||||
|
|
||||||
|
const majorTag = getMajorTagFromFullTag(sourceTagName);
|
||||||
|
await updateTag(sourceTagName, majorTag, octokitClient);
|
||||||
|
|
||||||
|
core.setOutput('major-tag', majorTag);
|
||||||
|
core.info(`The '${majorTag}' major tag now points to the '${sourceTagName}' tag`);
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
run();
|
25
src/version-utils.ts
Normal file
25
src/version-utils.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import semverParse from 'semver/functions/parse';
|
||||||
|
import SemVer from 'semver/classes/semver';
|
||||||
|
|
||||||
|
export function isStableSemverVersion(version: SemVer): boolean {
|
||||||
|
return version.prerelease.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMajorTagFromFullTag(fullTag: string): string {
|
||||||
|
return fullTag.split('.')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateSemverVersionFromTag(tag: string): void {
|
||||||
|
const semverVersion = semverParse(tag);
|
||||||
|
if (!semverVersion) {
|
||||||
|
throw new Error(
|
||||||
|
`The '${tag}' doesn't satisfy semantic versioning specification`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isStableSemverVersion(semverVersion)) {
|
||||||
|
throw new Error(
|
||||||
|
'It is not allowed to specify pre-release version to update the major tag'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2019",
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "./lib",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noImplicitReturns": true
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user