Skip to content

Commit

Permalink
Merge pull request #202 from github/sticky_locks_for_noop
Browse files Browse the repository at this point in the history
Sticky Locks for `noop` deployments
  • Loading branch information
GrantBirki authored Sep 5, 2023
2 parents 7b824da + 0285658 commit ae2b8fa
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ As seen above, we have two steps. One for a noop deploy, and one for a regular d
| `skip_completing` | `false` | `"false"` | If set to "true", skip the process of completing a deployment. You must manually create a deployment status after the deployment is complete. Default is "false" |
| `deploy_message_path` | `false` | `".github/deployment_message.md"` | The path to a markdown file which is used as a template for custom deployment messages. Example: `".github/deployment_message.md"` |
| `sticky_locks` | `false` | `"false"` | If set to `"true"`, locks will not be released after a deployment run completes. This applies to both successful, and failed deployments.Sticky locks are also known as ["hubot style deployment locks"](./docs/hubot-style-deployment-locks.md). They will persist until they are manually released by a user, or if you configure [another workflow with the "unlock on merge" mode](./docs/unlock-on-merge.md) to remove them automatically on PR merge. |
| `sticky_locks_for_noop` | `false` | `"false"` | If set to `"true"`, then sticky_locks will also be used for noop deployments. This can be useful in some cases but it often leads to locks being left behind when users test noop deployments. |

## Outputs 📤

Expand Down
33 changes: 33 additions & 0 deletions __tests__/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ beforeEach(() => {
process.env.INPUT_MERGE_DEPLOY_MODE = 'false'
process.env.INPUT_UNLOCK_ON_MERGE_MODE = 'false'
process.env.INPUT_STICKY_LOCKS = 'false'
process.env.INPUT_STICKY_LOCKS_FOR_NOOP = 'false'

github.context.payload = {
issue: {
Expand Down Expand Up @@ -188,6 +189,38 @@ test('successfully runs the action in noop mode', async () => {
expect(saveStateMock).toHaveBeenCalledWith('noop', true)
})

test('successfully runs the action in noop mode when using sticky_locks_for_noop set to true', async () => {
process.env.INPUT_STICKY_LOCKS_FOR_NOOP = 'true'
jest.spyOn(prechecks, 'prechecks').mockImplementation(() => {
return {
ref: 'test-ref',
status: true,
message: '✔️ PR is approved and all CI checks passed - OK',
noopMode: true
}
})

github.context.payload.comment.body = '.noop'

expect(await run()).toBe('success - noop')
expect(debugMock).toHaveBeenCalledWith(
`🔒 noop mode detected and using stickyLocks: true`
)
expect(setOutputMock).toHaveBeenCalledWith('comment_body', '.noop')
expect(setOutputMock).toHaveBeenCalledWith('triggered', 'true')
expect(setOutputMock).toHaveBeenCalledWith('comment_id', 123)
expect(setOutputMock).toHaveBeenCalledWith('ref', 'test-ref')
expect(setOutputMock).toHaveBeenCalledWith('noop', true)
expect(setOutputMock).toHaveBeenCalledWith('continue', 'true')
expect(setOutputMock).toHaveBeenCalledWith('type', 'deploy')
expect(saveStateMock).toHaveBeenCalledWith('isPost', 'true')
expect(saveStateMock).toHaveBeenCalledWith('actionsToken', 'faketoken')
expect(saveStateMock).toHaveBeenCalledWith('environment', 'production')
expect(saveStateMock).toHaveBeenCalledWith('comment_id', 123)
expect(saveStateMock).toHaveBeenCalledWith('ref', 'test-ref')
expect(saveStateMock).toHaveBeenCalledWith('noop', true)
})

test('runs the action in lock mode and fails due to bad permissions', async () => {
jest.spyOn(validPermissions, 'validPermissions').mockImplementation(() => {
return permissionsMsg
Expand Down
10 changes: 10 additions & 0 deletions __tests__/schemas/action.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,16 @@ inputs:
default:
required: true
type: string
sticky_locks_for_noop:
description:
type: string
required: true
required:
type: boolean
required: true
default:
required: true
type: string

# outputs section
outputs:
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ inputs:
description: 'If set to "true", locks will not be released after a deployment run completes. This applies to both successful, and failed deployments.Sticky locks are also known as "hubot style deployment locks". They will persist until they are manually released by a user, or if you configure another workflow with the "unlock on merge" mode to remove them automatically on PR merge.'
required: false
default: "false"
sticky_locks_for_noop:
description: 'If set to "true", then sticky_locks will also be used for noop deployments. This can be useful in some cases but it often leads to locks being left behind when users test noop deployments.'
required: false
default: "false"
outputs:
continue:
description: 'The string "true" if the deployment should continue, otherwise empty - Use this to conditionally control if your deployment should proceed or not'
Expand Down
28 changes: 26 additions & 2 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.

18 changes: 17 additions & 1 deletion docs/hubot-style-deployment-locks.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,29 @@ This behavior is not enabled out of the box and you need to enable it in your Ac

You can still release locks manually with `.unlock` at any time and so can other users. This is helpful if you need to release a lock that is blocking a deployment from another PR or if you were just testing changes and want to release the lock.

## Example
It should be noted that if you want this logic to **also apply to noop deployments** you need to enable another input option called `sticky_locks_for_noop` and also set its value to `"true"`. By default, noop deployments will not claim sticky locks as this often just leads to locks being left behind and never cleaned up.

## Examples

Enabling sticky deployment locks for `.deploy` commands:

```yaml
- name: branch-deploy
id: branch-deploy
uses: github/[email protected]
with:
sticky_locks: "true" # <--- enables sticky deployment lock / hubot style deployment locks
# ... other configuration
```

Enabling sticky deployment locks for `.deploy` and `.noop` commands:

```yaml
- name: branch-deploy
id: branch-deploy
uses: github/[email protected]
with:
sticky_locks: "true" # <--- enables sticky deployment lock / hubot style deployment locks
sticky_locks_for_noop: "true" # <--- enables sticky deployment lock / hubot style deployment locks for noop deployments
# ... other configuration
```
28 changes: 26 additions & 2 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export async function run() {
const param_separator = core.getInput('param_separator')
const permissions = core.getInput('permissions')
const sticky_locks = core.getBooleanInput('sticky_locks')
const sticky_locks_for_noop = core.getBooleanInput('sticky_locks_for_noop')

// Create an octokit client with the retry plugin
const octokit = github.getOctokit(token, {
Expand Down Expand Up @@ -455,17 +456,40 @@ export async function run() {
core.info(
`🍯 sticky_locks: ${COLORS.highlight}${sticky_locks}${COLORS.reset}`
)
core.info(
`🍯 sticky_locks_for_noop: ${COLORS.highlight}${sticky_locks_for_noop}${COLORS.reset}`
)

// conditionally handle how we want to apply locks on deployments
var stickyLocks
// if sticky_locks is true, then we will use the sticky_locks logic
// if sticky_locks_for_noop is also true, then we will also use the sticky_locks logic for noop deployments
// if sticky_locks is false, then no sticky locks will be applied and only non-sticky locks will be used
// if sticky_locks is true but sticky_locks_for_noop is false, then we will only use sticky locks on non-noop deployments
if (precheckResults.noopMode) {
if (sticky_locks_for_noop) {
stickyLocks = true
} else {
stickyLocks = false
}
core.debug(`🔒 noop mode detected and using stickyLocks: ${stickyLocks}`)
} else {
stickyLocks = sticky_locks
}

// if we are using sticky_locks in deployments, don't leave a comment as this is inferred by the user
const leaveComment = sticky_locks === false ? true : false
const leaveComment = stickyLocks === false ? true : false

core.debug(`🔒 stickyLocks: ${stickyLocks}`)
core.debug(`💬 leaveComment: ${leaveComment}`)

// Aquire the branch-deploy lock
const lockResponse = await lock(
octokit,
context,
precheckResults.ref,
reactRes.data.id,
sticky_locks, // sticky / hubot style locks - true/false depending on the input
stickyLocks, // sticky / hubot style locks - true/false depending on the input
environment, // environment
null, // details only flag
false, // postDeployStep
Expand Down

0 comments on commit ae2b8fa

Please sign in to comment.