Skip to content

Commit

Permalink
Fixes #219 Add argument to allow only updating drafts and prereleases
Browse files Browse the repository at this point in the history
  • Loading branch information
ncipollo committed Oct 2, 2022
1 parent fc32419 commit 5b3ed26
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 7 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ This action will create a GitHub release and optionally upload an artifact to it
| omitName | Indicates if the release name should be omitted. | false | false |
| omitNameDuringUpdate | Indicates if the release name should be omitted during updates. The name will still be applied for newly created releases. This will preserve the existing name during updates. | false | false |
| omitPrereleaseDuringUpdate | Indicates if the prerelease flag should be omitted during updates. The prerelease flag will still be applied for newly created releases. This will preserve the existing prerelease state during updates. | false | false |
| owner | Optionally specify the owner of the repo where the release should be generated. Defaults to current repo's owner. | false | "current repo owner" |
| owner | Optionally specify the owner of the repo where the release should be generated. Defaults to current repo's owner. | false | "current repo owner" |
| prerelease | Optionally marks this release as prerelease. Set to true to enable. | false | "" |
| removeArtifacts | Indicates if existing release artifacts should be removed. | false | false |
| replacesArtifacts | Indicates if existing release artifacts should be replaced. | false | true |
| repo | Optionally specify the repo where the release should be generated. | false | current repo |
| tag | An optional tag for the release. If this is omitted the git ref will be used (if it is a tag). | false | "" |
| token | The GitHub token. This will default to the GitHub app token. This is primarily useful if you want to use your personal token (for targeting other repos, etc). If you are using a personal access token it should have access to the `repo` scope. | false | github.token |
| updateOnlyUnreleased | When allowUpdates is enabled, this will fail the action if the release it is updating is not a draft or a prerelease. | false | false |

## Action Outputs
| Output name | Description |
Expand Down
8 changes: 6 additions & 2 deletions __tests__/Action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const updateBody = 'updateBody'
const updateDraft = false
const updateName = 'updateName'
const updatePrerelease = false
const updateOnlyUnreleased = false
const url = 'http://api.example.com'

describe("Action", () => {
Expand Down Expand Up @@ -317,7 +318,9 @@ describe("Action", () => {
expect(applyReleaseDataMock).toBeCalledWith({id: releaseId, upload_url: url})
}

function createAction(allowUpdates: boolean, hasArtifact: boolean, removeArtifacts: boolean = false): Action {
function createAction(allowUpdates: boolean,
hasArtifact: boolean,
removeArtifacts: boolean = false): Action {
let inputArtifact: Artifact[]
if (hasArtifact) {
inputArtifact = artifacts
Expand Down Expand Up @@ -379,7 +382,8 @@ describe("Action", () => {
updatedDraft: updateDraft,
updatedReleaseBody: updateBody,
updatedReleaseName: updateName,
updatedPrerelease: updatePrerelease
updatedPrerelease: updatePrerelease,
updateOnlyUnreleased: updateOnlyUnreleased
}
})
const MockOutputs = jest.fn<Outputs, any>(() => {
Expand Down
11 changes: 11 additions & 0 deletions __tests__/Inputs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,17 @@ describe('Inputs', () => {
})
})

describe('updateOnlyUnreleased', () => {
it('returns false', () => {
expect(inputs.updateOnlyUnreleased).toBe(false)
})

it('returns true', () => {
mockGetInput.mockReturnValueOnce('true')
expect(inputs.updateOnlyUnreleased).toBe(true)
})
})

function createGlobber(): ArtifactGlobber {
const MockGlobber = jest.fn<ArtifactGlobber, any>(() => {
return {
Expand Down
3 changes: 2 additions & 1 deletion __tests__/Integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ describe.skip('Integration Test', () => {
updatedDraft: false,
updatedReleaseBody: "This release was generated by release-action's integration test",
updatedReleaseName: "Releases Action Integration Test",
updatedPrerelease: false
updatedPrerelease: false,
updateOnlyUnreleased: false
}
})
return new MockInputs();
Expand Down
74 changes: 74 additions & 0 deletions __tests__/ReleaseValidator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {ReleaseValidator} from "../src/ReleaseValidator";

describe("validateReleaseUpdate", () => {
describe("updateOnlyUnreleased is disabled", () => {
const validator = new ReleaseValidator(false)
it('should not throw', () => {
const releaseResponse = {
draft: false,
prerelease: false,
name: "Name"
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).not.toThrow()
})
})
describe("updateOnlyUnreleased is enabled", () => {
const validator = new ReleaseValidator(true)
it('should throw if neither draft or prerelease are enabled', () => {
const releaseResponse = {
draft: false,
prerelease: false,
name: "Name"
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).toThrow()
})

it('should not throw if draft is enabled', () => {
const releaseResponse = {
draft: true,
prerelease: false,
name: "Name"
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).not.toThrow()
})

it('should not throw if prerelease is enabled', () => {
const releaseResponse = {
draft: false,
prerelease: true,
name: "Name"
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).not.toThrow()
})

it('should not throw if draft & prerelease is enabled', () => {
const releaseResponse = {
draft: true,
prerelease: true,
name: "Name"
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).not.toThrow()
})

it('should default error message release name to release', () => {
const releaseResponse = {
draft: false,
prerelease: false,
name: null
}
expect(() => {
validator.validateReleaseUpdate(releaseResponse)
}).toThrow(`Tried to update "release" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`)
})
})
})
6 changes: 5 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ inputs:
repo:
description: "Optionally specify the repo where the release should be generated. Defaults to current repo"
required: false
default: ''
default: ''
tag:
description: 'An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).'
required: false
Expand All @@ -103,6 +103,10 @@ inputs:
description: 'The Github token.'
required: false
default: ${{ github.token }}
updateOnlyUnreleased:
description: "When allowUpdates is enabled, this will fail the action if the release it is updating is not a draft or a prerelease."
required: false
default: 'true'
outputs:
id:
description: 'The identifier of the created release.'
Expand Down
33 changes: 33 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Action = void 0;
const GithubError_1 = __nccwpck_require__(7433);
const ReleaseValidator_1 = __nccwpck_require__(7579);
class Action {
constructor(inputs, outputs, releases, uploader, artifactDestroyer) {
this.inputs = inputs;
this.outputs = outputs;
this.releases = releases;
this.uploader = uploader;
this.artifactDestroyer = artifactDestroyer;
this.releaseValidator = new ReleaseValidator_1.ReleaseValidator(inputs.updateOnlyUnreleased);
}
perform() {
return __awaiter(this, void 0, void 0, function* () {
Expand Down Expand Up @@ -52,6 +54,8 @@ class Action {
catch (error) {
return yield this.checkForMissingReleaseError(error);
}
// Fail if this isn't an unreleased release & updateOnlyUnreleased is enabled.
this.releaseValidator.validateReleaseUpdate(getResponse.data);
return yield this.updateRelease(getResponse.data.id);
}
else {
Expand Down Expand Up @@ -766,6 +770,9 @@ class CoreInputs {
return undefined;
return this.name;
}
get updateOnlyUnreleased() {
return core.getInput('updateOnlyUnreleased') == 'true';
}
static get omitNameDuringUpdate() {
return core.getInput('omitNameDuringUpdate') == 'true';
}
Expand Down Expand Up @@ -819,6 +826,32 @@ class CoreOutputs {
exports.CoreOutputs = CoreOutputs;


/***/ }),

/***/ 7579:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ReleaseValidator = void 0;
class ReleaseValidator {
constructor(updateOnlyUnreleased) {
this.updateOnlyUnreleased = updateOnlyUnreleased;
}
validateReleaseUpdate(releaseResponse) {
var _a;
if (!this.updateOnlyUnreleased) {
return;
}
if (!releaseResponse.draft && !releaseResponse.prerelease) {
throw new Error(`Tried to update "${(_a = releaseResponse.name) !== null && _a !== void 0 ? _a : "release"}" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`);
}
}
}
exports.ReleaseValidator = ReleaseValidator;


/***/ }),

/***/ 184:
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions lib/Action.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", { value: true });
exports.Action = void 0;
const GithubError_1 = require("./GithubError");
const ReleaseValidator_1 = require("./ReleaseValidator");
class Action {
constructor(inputs, outputs, releases, uploader, artifactDestroyer) {
this.inputs = inputs;
this.outputs = outputs;
this.releases = releases;
this.uploader = uploader;
this.artifactDestroyer = artifactDestroyer;
this.releaseValidator = new ReleaseValidator_1.ReleaseValidator(inputs.updateOnlyUnreleased);
}
perform() {
return __awaiter(this, void 0, void 0, function* () {
Expand Down Expand Up @@ -45,6 +47,8 @@ class Action {
catch (error) {
return yield this.checkForMissingReleaseError(error);
}
// Fail if this isn't an unreleased release & updateOnlyUnreleased is enabled.
this.releaseValidator.validateReleaseUpdate(getResponse.data);
return yield this.updateRelease(getResponse.data.id);
}
else {
Expand Down
3 changes: 3 additions & 0 deletions lib/Inputs.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ class CoreInputs {
return undefined;
return this.name;
}
get updateOnlyUnreleased() {
return core.getInput('updateOnlyUnreleased') == 'true';
}
static get omitNameDuringUpdate() {
return core.getInput('omitNameDuringUpdate') == 'true';
}
Expand Down
18 changes: 18 additions & 0 deletions lib/ReleaseValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReleaseValidator = void 0;
class ReleaseValidator {
constructor(updateOnlyUnreleased) {
this.updateOnlyUnreleased = updateOnlyUnreleased;
}
validateReleaseUpdate(releaseResponse) {
var _a;
if (!this.updateOnlyUnreleased) {
return;
}
if (!releaseResponse.draft && !releaseResponse.prerelease) {
throw new Error(`Tried to update "${(_a = releaseResponse.name) !== null && _a !== void 0 ? _a : "release"}" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`);
}
}
}
exports.ReleaseValidator = ReleaseValidator;
9 changes: 8 additions & 1 deletion src/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import {ArtifactUploader} from "./ArtifactUploader";
import {GithubError} from "./GithubError";
import {Outputs} from "./Outputs";
import {ArtifactDestroyer} from "./ArtifactDestroyer";
import {ReleaseValidator} from "./ReleaseValidator";

export class Action {
private inputs: Inputs
private outputs: Outputs
private releases: Releases
private artifactDestroyer: ArtifactDestroyer
private uploader: ArtifactUploader
private artifactDestroyer: ArtifactDestroyer

private releaseValidator: ReleaseValidator

constructor(inputs: Inputs,
outputs: Outputs,
Expand All @@ -28,6 +31,7 @@ export class Action {
this.releases = releases
this.uploader = uploader
this.artifactDestroyer = artifactDestroyer
this.releaseValidator = new ReleaseValidator(inputs.updateOnlyUnreleased)
}

async perform() {
Expand Down Expand Up @@ -56,6 +60,9 @@ export class Action {
} catch (error: any) {
return await this.checkForMissingReleaseError(error)
}

// Fail if this isn't an unreleased release & updateOnlyUnreleased is enabled.
this.releaseValidator.validateReleaseUpdate(getResponse.data)

return await this.updateRelease(getResponse.data.id)
} else {
Expand Down
5 changes: 5 additions & 0 deletions src/Inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface Inputs {
readonly updatedReleaseBody?: string
readonly updatedReleaseName?: string
readonly updatedPrerelease?: boolean
readonly updateOnlyUnreleased: boolean
}

export class CoreInputs implements Inputs {
Expand Down Expand Up @@ -209,6 +210,10 @@ export class CoreInputs implements Inputs {
if (CoreInputs.omitName || CoreInputs.omitNameDuringUpdate) return undefined
return this.name
}

get updateOnlyUnreleased(): boolean {
return core.getInput('updateOnlyUnreleased') == 'true'
}

private static get omitNameDuringUpdate(): boolean {
return core.getInput('omitNameDuringUpdate') == 'true'
Expand Down
20 changes: 20 additions & 0 deletions src/ReleaseValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export class ReleaseValidator {
constructor(private updateOnlyUnreleased: boolean) {
}

validateReleaseUpdate(releaseResponse: ReleaseStageArguments) {
if (!this.updateOnlyUnreleased) {
return
}

if (!releaseResponse.draft && !releaseResponse.prerelease) {
throw new Error(`Tried to update "${releaseResponse.name ?? "release"}" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`)
}
}
}

export type ReleaseStageArguments = {
draft: boolean
name: string | null
prerelease: boolean
}

0 comments on commit 5b3ed26

Please sign in to comment.