diff --git a/setup-env/config/constants.js b/setup-env/config/constants.js index f53a8a4..7b02a89 100644 --- a/setup-env/config/constants.js +++ b/setup-env/config/constants.js @@ -4,6 +4,7 @@ module.exports = { ACCESS_KEY: 'access-key', BUILD_NAME: 'build-name', PROJECT_NAME: 'project-name', + GITHUB_TOKEN: 'github-token', GITHUB_APP: 'github-app', GITHUB_TOKEN: 'github-token', }, diff --git a/setup-env/dist/index.js b/setup-env/dist/index.js index 9b01ce4..ef37f81 100644 --- a/setup-env/dist/index.js +++ b/setup-env/dist/index.js @@ -10,6 +10,7 @@ module.exports = { ACCESS_KEY: 'access-key', BUILD_NAME: 'build-name', PROJECT_NAME: 'project-name', + GITHUB_TOKEN: 'github-token', GITHUB_APP: 'github-app', GITHUB_TOKEN: 'github-token', }, @@ -9363,6 +9364,7 @@ class ActionInput { this.buildName = core.getInput(INPUT.BUILD_NAME); this.projectName = core.getInput(INPUT.PROJECT_NAME); this.githubApp = core.getInput(INPUT.GITHUB_APP); + this.githubToken = core.getInput(INPUT.GITHUB_TOKEN); this.rerunAttempt = process?.env?.GITHUB_RUN_ATTEMPT; this.runId = process?.env?.GITHUB_RUN_ID; this.repository = process?.env?.GITHUB_REPOSITORY; @@ -9380,6 +9382,7 @@ class ActionInput { this.buildName = InputValidator.validateBuildName(this.buildName); this.projectName = InputValidator.validateProjectName(this.projectName); this.githubApp = InputValidator.validateGithubAppName(this.githubApp); + this.githubToken = InputValidator.validateGithubToken(this.githubToken); } /** @@ -9416,7 +9419,8 @@ class ActionInput { } // Ensure runId, repository, username, and accessKey are valid - if (!this.runId || !this.repository || this.repository === 'none' || !this.username || !this.accessKey) { + if (!this.runId || !this.repository || this.repository === 'none' + || !this.githubToken || this.githubToken === 'none' || !this.username || !this.accessKey) { return false; } @@ -9618,6 +9622,29 @@ class InputValidator { throw new Error("Invalid input for 'github-app'. Must be a valid string."); } + + /** + * Validates the GitHub token input to ensure it is a valid non-empty string. + * If the input is 'none' or not provided, it returns 'none'. + * @param {string} githubToken Input for 'github-token' + * @returns {string} The validated GitHub token, or 'none' if input is 'none' or invalid + * @throws {Error} If the input is not a valid non-empty string + */ + static validateGithubToken(githubToken) { + if (typeof githubToken !== 'string') { + throw new Error("Invalid input for 'github-token'. Must be a valid non-empty string."); + } + + if (githubToken.toLowerCase() === 'none') { + return 'none'; + } + + if (githubToken.trim().length > 0) { + return githubToken; + } + + throw new Error("Invalid input for 'github-token'. Must be a valid non-empty string."); + } } module.exports = InputValidator; diff --git a/setup-env/src/actionInput/index.js b/setup-env/src/actionInput/index.js index 6976458..790a86d 100644 --- a/setup-env/src/actionInput/index.js +++ b/setup-env/src/actionInput/index.js @@ -33,6 +33,7 @@ class ActionInput { this.buildName = core.getInput(INPUT.BUILD_NAME); this.projectName = core.getInput(INPUT.PROJECT_NAME); this.githubApp = core.getInput(INPUT.GITHUB_APP); + this.githubToken = core.getInput(INPUT.GITHUB_TOKEN); this.rerunAttempt = process?.env?.GITHUB_RUN_ATTEMPT; this.runId = process?.env?.GITHUB_RUN_ID; this.repository = process?.env?.GITHUB_REPOSITORY; @@ -50,6 +51,7 @@ class ActionInput { this.buildName = InputValidator.validateBuildName(this.buildName); this.projectName = InputValidator.validateProjectName(this.projectName); this.githubApp = InputValidator.validateGithubAppName(this.githubApp); + this.githubToken = InputValidator.validateGithubToken(this.githubToken); } /** @@ -86,7 +88,8 @@ class ActionInput { } // Ensure runId, repository, username, and accessKey are valid - if (!this.runId || !this.repository || this.repository === 'none' || !this.username || !this.accessKey) { + if (!this.runId || !this.repository || this.repository === 'none' + || !this.githubToken || this.githubToken === 'none' || !this.username || !this.accessKey) { return false; } diff --git a/setup-env/src/actionInput/inputValidator.js b/setup-env/src/actionInput/inputValidator.js index f427caa..b6fb275 100644 --- a/setup-env/src/actionInput/inputValidator.js +++ b/setup-env/src/actionInput/inputValidator.js @@ -137,6 +137,29 @@ class InputValidator { throw new Error("Invalid input for 'github-app'. Must be a valid string."); } + + /** + * Validates the GitHub token input to ensure it is a valid non-empty string. + * If the input is 'none' or not provided, it returns 'none'. + * @param {string} githubToken Input for 'github-token' + * @returns {string} The validated GitHub token, or 'none' if input is 'none' or invalid + * @throws {Error} If the input is not a valid non-empty string + */ + static validateGithubToken(githubToken) { + if (typeof githubToken !== 'string') { + throw new Error("Invalid input for 'github-token'. Must be a valid non-empty string."); + } + + if (githubToken.toLowerCase() === 'none') { + return 'none'; + } + + if (githubToken.trim().length > 0) { + return githubToken; + } + + throw new Error("Invalid input for 'github-token'. Must be a valid non-empty string."); + } } module.exports = InputValidator; diff --git a/setup-env/test/actionInput/index.test.js b/setup-env/test/actionInput/index.test.js index 516f446..4463441 100644 --- a/setup-env/test/actionInput/index.test.js +++ b/setup-env/test/actionInput/index.test.js @@ -21,6 +21,7 @@ describe('Action Input operations for fetching all inputs, triggering validation sinon.stub(InputValidator, 'validateBuildName').returns('validatedBuildName'); sinon.stub(InputValidator, 'validateProjectName').returns('validatedProjectName'); sinon.stub(InputValidator, 'validateGithubAppName').returns('validatedAppName'); + sinon.stub(InputValidator, 'validateGithubToken').returns('validatedToken'); // Provide required inputs stubbedInput.withArgs(INPUT.USERNAME, { required: true }).returns('someUsername'); @@ -66,9 +67,19 @@ describe('Action Input operations for fetching all inputs, triggering validation expect(e.message).to.eq('Action input failed for reason: Access Key Required'); } }); + + it('Takes input and validates GitHub token and app name successfully', () => { + stubbedInput.withArgs(INPUT.GITHUB_TOKEN).returns('someToken'); + stubbedInput.withArgs(INPUT.GITHUB_APP).returns('someApp'); + const actionInput = new ActionInput(); + expect(actionInput.githubToken).to.eq('validatedToken'); + expect(actionInput.githubApp).to.eq('validatedAppName'); + }); }); context('Set Environment Variables', () => { + let actionInput; + beforeEach(() => { sinon.stub(core, 'exportVariable'); sinon.stub(core, 'info'); @@ -76,6 +87,16 @@ describe('Action Input operations for fetching all inputs, triggering validation sinon.stub(core, 'endGroup'); sinon.stub(ActionInput.prototype, '_fetchAllInput'); sinon.stub(ActionInput.prototype, '_validateInput'); + + // Mock required properties + actionInput = new ActionInput(); + actionInput.username = 'someUsername'; + actionInput.accessKey = 'someAccessKey'; + actionInput.buildName = 'someBuildName'; + actionInput.projectName = 'someProjectName'; + + // Stub checkIfBStackReRun to return true + sinon.stub(actionInput, 'checkIfBStackReRun').returns(Promise.resolve(true)); }); afterEach(() => { @@ -83,17 +104,20 @@ describe('Action Input operations for fetching all inputs, triggering validation }); it('Sets the environment variables required in test scripts for BrowserStack', () => { - const actionInput = new ActionInput(); - actionInput.username = 'someUsername'; - actionInput.accessKey = 'someAccessKey'; - actionInput.buildName = 'someBuildName'; - actionInput.projectName = 'someProjectName'; actionInput.setEnvVariables(); sinon.assert.calledWith(core.exportVariable, ENV_VARS.BROWSERSTACK_USERNAME, 'someUsername'); sinon.assert.calledWith(core.exportVariable, ENV_VARS.BROWSERSTACK_ACCESS_KEY, 'someAccessKey'); sinon.assert.calledWith(core.exportVariable, ENV_VARS.BROWSERSTACK_PROJECT_NAME, 'someProjectName'); sinon.assert.calledWith(core.exportVariable, ENV_VARS.BROWSERSTACK_BUILD_NAME, 'someBuildName'); }); + + it('Calls setBStackRerunEnvVars when checkIfBStackReRun returns true', async () => { + const setBStackRerunEnvVarsStub = sinon.stub(actionInput, 'setBStackRerunEnvVars').resolves(); + + await actionInput.setEnvVariables(); + + sinon.assert.calledOnce(setBStackRerunEnvVarsStub); + }); }); context('Check if BrowserStack Rerun', () => { @@ -105,6 +129,7 @@ describe('Action Input operations for fetching all inputs, triggering validation sinon.stub(InputValidator, 'validateBuildName').returns('validatedBuildName'); sinon.stub(InputValidator, 'validateProjectName').returns('validatedProjectName'); sinon.stub(InputValidator, 'validateGithubAppName').returns('validatedAppName'); + sinon.stub(InputValidator, 'validateGithubToken').returns('validatedToken'); // Provide required inputs stubbedInput.withArgs(INPUT.USERNAME, { required: true }).returns('someUsername'); @@ -162,6 +187,7 @@ describe('Action Input operations for fetching all inputs, triggering validation sinon.stub(InputValidator, 'validateBuildName').returns('validatedBuildName'); sinon.stub(InputValidator, 'validateProjectName').returns('validatedProjectName'); sinon.stub(InputValidator, 'validateGithubAppName').returns('validatedAppName'); + sinon.stub(InputValidator, 'validateGithubToken').returns('validatedToken'); // Provide required inputs stubbedInput.withArgs(INPUT.USERNAME, { required: true }).returns('someUsername'); @@ -212,6 +238,7 @@ describe('Action Input operations for fetching all inputs, triggering validation sinon.stub(InputValidator, 'validateBuildName').returns('validatedBuildName'); sinon.stub(InputValidator, 'validateProjectName').returns('validatedProjectName'); sinon.stub(InputValidator, 'validateGithubAppName').returns('validatedAppName'); + sinon.stub(InputValidator, 'validateGithubToken').returns('validatedToken'); // Provide required inputs stubbedInput.withArgs(INPUT.USERNAME, { required: true }).returns('someUsername'); diff --git a/setup-env/test/actionInput/inputValidator.test.js b/setup-env/test/actionInput/inputValidator.test.js index 14db306..168dad6 100644 --- a/setup-env/test/actionInput/inputValidator.test.js +++ b/setup-env/test/actionInput/inputValidator.test.js @@ -175,6 +175,29 @@ describe('InputValidator class to validate individual fields of the action input expect(InputValidator.validateGithubAppName(validAppName)).to.eq(validAppName); }); }); + + context('Validates GitHub Token', () => { + it("Returns 'none' if the token is not provided", () => { + expect(() => InputValidator.validateGithubToken()).to.throw("Invalid input for 'github-token'. Must be a valid non-empty string."); + }); + + it("Returns 'none' if the token is 'none' (case insensitive)", () => { + expect(InputValidator.validateGithubToken('None')).to.eq('none'); + }); + + it('Throws an error if the token is an empty string', () => { + expect(() => InputValidator.validateGithubToken('')).to.throw("Invalid input for 'github-token'. Must be a valid non-empty string."); + }); + + it('Throws an error if the token is not a valid string', () => { + expect(() => InputValidator.validateGithubToken(123)).to.throw("Invalid input for 'github-token'. Must be a valid non-empty string."); + }); + + it('Returns the token if it is a valid non-empty string and not "none"', () => { + const validToken = 'someValidToken'; + expect(InputValidator.validateGithubToken(validToken)).to.eq(validToken); + }); + }); }); }); });