Skip to content

Commit

Permalink
Merge pull request #9 from urcomputeringpal/jnewland/expand-tests
Browse files Browse the repository at this point in the history
Expand test coverage for required status scenarios
  • Loading branch information
jnewland authored May 24, 2024
2 parents f26d7c9 + 5fdee7a commit 6dbb937
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 90 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check-dist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# If this workflow is run from a feature branch, it will act as an additional CI
# check and fail if the checked-in `dist/` directory does not match what is
# expected from the build.
name: Check Transpiled JavaScript
name: Bundle JavaScript

on:
pull_request:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Continuous Integration
name: CI

on:
pull_request:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linter.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Lint Codebase
name: Lint

on:
pull_request:
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
Configure required workflows in your repository. Use path filters. Leave your
GitHub org administrator alone.

Use this Action to configuring required workflows in a workflow file protected
by `CODEOWNERS` in your repository instead of in your repository settings.
Use this Action to configure required workflows in a workflow file protected by
`CODEOWNERS` in your repository instead of in your repository settings.

[![Lint](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/linter.yml/badge.svg)](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/linter.yml?query=branch%3Amain)
[![CI](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/ci.yml/badge.svg)](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/ci.yml?query=branch%3Amain)
[![Bundling](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/check-dist.yml/badge.svg)](https://github.com/urcomputeringpal/optional-required-workflows/actions/workflows/check-dist.yml?query=branch%3Amain)
[![Coverage](./badges/coverage.svg)](./badges/coverage.svg)

## Problem(s)

Expand Down
174 changes: 174 additions & 0 deletions __tests__/required.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { required } from '../src/required'
import { GitHub } from '@actions/github/lib/utils'
import { Context } from '@actions/github/lib/context'
// eslint-disable-next-line import/no-unresolved
import { WorkflowRunCompletedEvent } from '@octokit/webhooks-types'

describe('required', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let mockOctokit: any
let context: Context
let event: WorkflowRunCompletedEvent

beforeEach(() => {
process.env.GITHUB_REPOSITORY = 'owner/repo' // Setting GITHUB_REPOSITORY environment variable
mockOctokit = {
rest: {
repos: {
createCommitStatus: jest.fn()
},
actions: {
// eslint-disable-next-line @typescript-eslint/promise-function-async
getWorkflowRun: jest.fn().mockImplementation(() => {
return Promise.resolve({
data: {
id: 123,
name: 'Test Workflow',
head_sha: 'abc123',
conclusion: 'success',
html_url: 'http://example.com'
}
}) // Simulating a specific workflow run object
}),
// eslint-disable-next-line @typescript-eslint/promise-function-async
listWorkflowRunsForRepo: jest.fn().mockImplementation(() => {
return Promise.resolve({
data: {
workflow_runs: [
{ id: 123, name: 'Test Workflow', conclusion: 'success' }
]
}
}) // Simulating a successful response for listWorkflowRunsForRepo
})
}
}
}
context = new Context()
event = {
workflow_run: {
id: 123,
name: 'Test Workflow',
head_sha: 'abc123',
conclusion: 'success',
html_url: 'http://example.com'
}
} as unknown as WorkflowRunCompletedEvent
})

it('should handle all required statuses completing successfully', async () => {
// Mock setup to simulate all required statuses completing successfully
mockOctokit.rest.actions.listWorkflowRunsForRepo.mockResolvedValue({
data: {
workflow_runs: [
{ id: 123, name: 'Test Workflow', conclusion: 'success' },
{ id: 124, name: 'Another Workflow', conclusion: 'success' }
]
}
})

await required({
octokit: mockOctokit as unknown as InstanceType<typeof GitHub>,
context,
event,
workflows: ['Test Workflow', 'Another Workflow'],
statusName: 'Required'
})

expect(mockOctokit.rest.repos.createCommitStatus).toHaveBeenCalledWith(
expect.objectContaining({
state: 'success',
description: 'All 2 observed required workflows have succeeded'
})
)
})

it('should handle only one of the required statuses reporting success', async () => {
// Mock setup to simulate only one of the required statuses reporting success
mockOctokit.rest.actions.listWorkflowRunsForRepo.mockResolvedValue({
data: {
workflow_runs: [
{ id: 123, name: 'Test Workflow', conclusion: 'success' },
{ id: 124, name: 'Another Workflow', conclusion: null }
]
}
})

await required({
octokit: mockOctokit as unknown as InstanceType<typeof GitHub>,
context,
event,
workflows: ['Test Workflow', 'Another Workflow'],
statusName: 'Required'
})

expect(mockOctokit.rest.repos.createCommitStatus).toHaveBeenCalledWith(
expect.objectContaining({
state: 'pending',
description: expect.stringContaining(
'required workflows are still pending...'
)
})
)
})

it('should handle one of the required statuses reporting failure', async () => {
// Mock setup to simulate one of the required statuses reporting failure
mockOctokit.rest.actions.listWorkflowRunsForRepo.mockResolvedValue({
data: {
workflow_runs: [
{ id: 123, name: 'Test Workflow', conclusion: 'success' },
{ id: 124, name: 'Another Workflow', conclusion: 'failure' }
]
}
})

await required({
octokit: mockOctokit as unknown as InstanceType<typeof GitHub>,
context,
event,
workflows: ['Test Workflow', 'Another Workflow'],
statusName: 'Required'
})

expect(mockOctokit.rest.repos.createCommitStatus).toHaveBeenCalledWith(
expect.objectContaining({
state: 'failure',
description: expect.stringContaining(
'required workflows were not successful'
)
})
)
})

it('should handle replication lag scenario', async () => {
// Mock setup to simulate replication lag scenario where "Test workflow" isn't in the results
mockOctokit.rest.actions.listWorkflowRunsForRepo.mockResolvedValue({
data: {
workflow_runs: [
{ id: 124, name: 'Another Workflow', conclusion: 'success' },
{
id: 125,
name: 'Another Not Required Workflow 2',
conclusion: 'success'
}
]
}
})

await required({
octokit: mockOctokit as unknown as InstanceType<typeof GitHub>,
context,
event,
workflows: ['Test Workflow', 'Another Workflow'],
statusName: 'Required'
})

expect(mockOctokit.rest.repos.createCommitStatus).toHaveBeenCalledWith(
expect.objectContaining({
state: 'pending',
description:
'Waiting for conclusion to be reported for Test Workflow...'
})
)
})
})
11 changes: 11 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ inputs:
A multi-line string of the names of workflows that must succeed if a run
is observed.
required: true
retries:
description: >
The number of times to query for updated WorkflowRun statues if we don't
observe the conclusion of the run we're looking for before giving up.
required: false
default: '3'
delay:
description: >
The delay in milliseconds to wait between retries.
required: false
default: '100'

runs:
using: node20
Expand Down
2 changes: 1 addition & 1 deletion badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6dbb937

Please sign in to comment.