Skip to content

Commit

Permalink
Merge pull request #161 from github/v6-improvements
Browse files Browse the repository at this point in the history
v6.0.0 Improvements
  • Loading branch information
GrantBirki authored Jun 11, 2023
2 parents 21a822a + be40a89 commit c16e98a
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 53 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ As seen above, we have two steps. One for a noop deploy, and one for a regular d
| `unlock_trigger` | `false` | `.unlock` | The string to look for in comments as an IssueOps unlock trigger. Used for unlocking branch deployments. Example: ".unlock" |
| `help_trigger` | `false` | `.help` | The string to look for in comments as an IssueOps help trigger. Example: ".help" |
| `lock_info_alias` | `false` | `.wcid` | An alias or shortcut to get details about the current lock (if it exists) Example: ".info" - Hubbers will find the ".wcid" default helpful ("where can I deploy") |
| `permissions` | `true` | `write,maintain,admin` | The allowed GitHub permissions an actor can have to invoke IssueOps commands - Example: "write,maintain,admin" |
| `param_separator` | `false` | `\|` | The separator to use for parsing parameters in comments in deployment requests. Parameters will are saved as outputs and can be used in subsequent steps - See [Parameters](docs/parameters.md) for additional details |
| `global_lock_flag` | `false` | `--global` | The flag to pass into the lock command to lock all environments. Example: "--global" |
| `environment` | `false` | `production` | The name of the default environment to deploy to. Example: by default, if you type `.deploy`, it will assume "production" as the default environment |
Expand All @@ -287,6 +288,7 @@ As seen above, we have two steps. One for a noop deploy, and one for a regular d
| ------ | ----------- |
| `triggered` | The string "true" if the trigger was found, otherwise the string "false" |
| `comment_body` | The comment body |
| `actor` | The GitHub handle of the actor that invoked the IssueOps command |
| `environment` | The environment that has been selected for a deployment |
| `params` | The raw parameters that were passed into the deployment command (see param_separator) - Further [documentation](docs/parameters.md) |
| `noop` | The string "true" if the noop trigger was found, otherwise the string "false" - Use this to conditionally control whether your deployment runs as a noop or not |
Expand All @@ -295,7 +297,7 @@ As seen above, we have two steps. One for a noop deploy, and one for a regular d
| `comment_id` | The comment id which triggered this deployment |
| `deployment_id` | The ID of the deployment created by running this action |
| `environment_url` | The environment URL detected and used for the deployment (sourced from the environment_urls input) |
| `type` | The type of trigger that was detected (examples: deploy, lock, unlock) |
| `type` | The type of trigger that was detected (examples: deploy, lock, unlock, lock-info-alias) |
| `continue` | The string "true" if the deployment should continue, otherwise empty - Use this to conditionally control if your deployment should proceed or not - ⭐ The main output you should watch for when determining if a deployment shall carry on |
| `fork` | The string "true" if the pull request is a fork, otherwise "false" |
| `fork_ref` | The true ref of the fork |
Expand Down
9 changes: 6 additions & 3 deletions __tests__/functions/help.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ const defaultInputs = {
allowForks: 'true',
skipCi: '',
skipReviews: '',
admins: 'false'
admins: 'false',
permissions: ['write', 'admin', 'maintain']
}

test('successfully calls help with defaults', async () => {
Expand Down Expand Up @@ -71,7 +72,8 @@ test('successfully calls help with non-defaults', async () => {
allowForks: 'false',
skipCi: 'development',
skipReviews: 'development',
admins: 'monalisa'
admins: 'monalisa',
permissions: ['write', 'admin', 'maintain']
}

expect(await help(octokit, context, 123, inputs))
Expand Down Expand Up @@ -100,7 +102,8 @@ test('successfully calls help with non-defaults', async () => {
allowForks: 'false',
skipCi: 'development',
skipReviews: 'development',
admins: 'monalisa'
admins: 'monalisa',
permissions: ['write', 'admin', 'maintain']
}

expect(await help(octokit, context, 123, inputs))
Expand Down
1 change: 1 addition & 0 deletions __tests__/functions/prechecks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ beforeEach(() => {
jest.spyOn(core, 'info').mockImplementation(() => {})
jest.spyOn(core, 'debug').mockImplementation(() => {})
jest.spyOn(core, 'setOutput').mockImplementation(() => {})
process.env.INPUT_PERMISSIONS = 'admin,write,maintain'

context = {
actor: 'monalisa',
Expand Down
8 changes: 4 additions & 4 deletions __tests__/functions/trigger-check.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import {triggerCheck} from '../../src/functions/trigger-check'
import * as core from '@actions/core'

const setOutputMock = jest.spyOn(core, 'setOutput')
const debugMock = jest.spyOn(core, 'debug')
const infoMock = jest.spyOn(core, 'info')

beforeEach(() => {
jest.clearAllMocks()
jest.spyOn(core, 'setOutput').mockImplementation(() => {})
jest.spyOn(core, 'saveState').mockImplementation(() => {})
jest.spyOn(core, 'debug').mockImplementation(() => {})
jest.spyOn(core, 'info').mockImplementation(() => {})
})

test('checks a message and finds a standard trigger', async () => {
Expand All @@ -23,7 +23,7 @@ test('checks a message and does not find trigger', async () => {
const trigger = '.deploy'
expect(await triggerCheck(body, trigger)).toBe(false)
expect(setOutputMock).toHaveBeenCalledWith('comment_body', '.bad')
expect(debugMock).toHaveBeenCalledWith(
expect(infoMock).toHaveBeenCalledWith(
'Trigger ".deploy" not found in the comment body'
)
})
Expand Down Expand Up @@ -69,7 +69,7 @@ test('checks a message and does not find global trigger', async () => {
'comment_body',
'I want to .ping a website'
)
expect(debugMock).toHaveBeenCalledWith(
expect(infoMock).toHaveBeenCalledWith(
'Trigger ".deploy" not found in the comment body'
)
})
63 changes: 63 additions & 0 deletions __tests__/functions/valid-permissions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as core from '@actions/core'
import {validPermissions} from '../../src/functions/valid-permissions'

const setOutputMock = jest.spyOn(core, 'setOutput')

var octokit
var context
beforeEach(() => {
jest.clearAllMocks()
jest.spyOn(core, 'setOutput').mockImplementation(() => {})
process.env.INPUT_PERMISSIONS = 'write,maintain,admin'

context = {
actor: 'monalisa'
}

octokit = {
rest: {
repos: {
getCollaboratorPermissionLevel: jest.fn().mockReturnValueOnce({
status: 200,
data: {
permission: 'write'
}
})
}
}
}
})

test('determines that a user has valid permissions to invoke the Action', async () => {
expect(await validPermissions(octokit, context)).toEqual(true)
expect(setOutputMock).toHaveBeenCalledWith('actor', 'monalisa')
})

test('determines that a user has does not valid permissions to invoke the Action', async () => {
octokit.rest.repos.getCollaboratorPermissionLevel = jest
.fn()
.mockReturnValue({
status: 200,
data: {
permission: 'read'
}
})

expect(await validPermissions(octokit, context)).toEqual(
'👋 __monalisa__, seems as if you have not write/maintain/admin permissions in this repo, permissions: read'
)
expect(setOutputMock).toHaveBeenCalledWith('actor', 'monalisa')
})

test('fails to get actor permissions due to a bad status code', async () => {
octokit.rest.repos.getCollaboratorPermissionLevel = jest
.fn()
.mockReturnValue({
status: 500
})

expect(await validPermissions(octokit, context)).toEqual(
'Permission check returns non-200 status: 500'
)
expect(setOutputMock).toHaveBeenCalledWith('actor', 'monalisa')
})
14 changes: 14 additions & 0 deletions __tests__/schemas/action.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,16 @@ inputs:
default:
type: string
required: true
permissions:
description:
type: string
required: true
default:
type: string
required: true
required:
type: boolean
required: true
param_separator:
description:
type: string
Expand Down Expand Up @@ -311,6 +321,10 @@ outputs:
description:
type: string
required: true
actor:
description:
type: string
required: true
environment:
description:
type: string
Expand Down
8 changes: 7 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ inputs:
description: 'An alias or shortcut to get details about the current lock (if it exists) Example: ".info"'
required: false
default: ".wcid"
permissions:
description: 'The allowed GitHub permissions an actor can have to invoke IssueOps commands - Example: "write,maintain,admin"'
required: true
default: "write,maintain,admin"
param_separator:
description: 'The separator to use for parsing parameters in comments in deployment requests. Parameters will are saved as outputs and can be used in subsequent steps'
required: false
Expand Down Expand Up @@ -118,6 +122,8 @@ outputs:
description: 'The string "true" if the trigger was found, otherwise the string "false"'
comment_body:
description: The comment body
actor:
description: The GitHub handle of the actor that invoked the IssueOps command
environment:
description: The environment that has been selected for a deployment
params:
Expand All @@ -131,7 +137,7 @@ outputs:
comment_id:
description: The comment id which triggered this deployment
type:
description: "The type of trigger that was detected (examples: deploy, lock, unlock)"
description: "The type of trigger that was detected (examples: deploy, lock, unlock, lock-info-alias)"
continue:
description: 'The string "true" if the deployment should continue, otherwise empty - Use this to conditionally control if your deployment should proceed or not'
fork:
Expand Down
93 changes: 53 additions & 40 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/functions/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ export async function help(octokit, context, reactionId, inputs) {
- \`skipCi: ${inputs.skipCi}\` - ${skip_ci_message}
- \`skipReviews: ${inputs.skipReviews}\` - ${skip_reviews_message}
- \`admins: ${inputs.admins}\` - ${admins_message}
- \`permissions: ${inputs.permissions.join(
','
)}\` - The acceptable permissions that this Action will require to run
---
Expand Down
2 changes: 1 addition & 1 deletion src/functions/trigger-check.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function triggerCheck(body, trigger) {

// If the trigger is not activated, set the output to false and return with false
if (!body.startsWith(trigger)) {
core.debug(`Trigger "${trigger}" not found in the comment body`)
core.info(`Trigger "${trigger}" not found in the comment body`)
return false
}

Expand Down
10 changes: 9 additions & 1 deletion src/functions/valid-permissions.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
const validPermissionsArray = ['admin', 'write', 'maintain']
import * as core from '@actions/core'
import {stringToArray} from './string-to-array'

// Helper function to check if an actor has permissions to use this Action in a given repository
// :param octokit: The octokit client
// :param context: The GitHub Actions event context
// :returns: An error string if the actor doesn't have permissions, otherwise true
export async function validPermissions(octokit, context) {
// fetch the defined permissions from the Action input
const validPermissionsArray = await stringToArray(
core.getInput('permissions')
)

core.setOutput('actor', context.actor)

// Get the permissions of the user who made the comment
const permissionRes = await octokit.rest.repos.getCollaboratorPermissionLevel(
{
Expand Down
Loading

0 comments on commit c16e98a

Please sign in to comment.