Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,19 @@ class Settings {
})
})

// A nop run triggered outside the webhook flow (e.g. the full-sync entrypoint)
// can be missing the check run and repository webhook fields in its payload.
// If either is absent there is no check run to report to, so put the plan in
// the log instead. The full diff can contain config values (e.g. Actions
// variables), so it goes to debug; info gets a summary without them.
if (!payload?.check_run || !payload?.repository) {
// Passed as an object so the logger only serializes it when debug is emitted
this.log.debug({ results: this.results }, 'Dry-run results')
const summary = this.results.map(res => `${res.type} ${res.plugin} ${res.repo}: ${res.action?.msg ?? ''}`).join('\n')
this.log.info(`Dry-run finished with ${this.results.length} planned change(s); the full diff is logged at debug level.\n${summary}`)
return
}

let error = false
// Different logic
const stats = {
Expand Down
57 changes: 57 additions & 0 deletions test/unit/lib/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -549,4 +549,61 @@ repository:
expect(mockRepoSync).toHaveBeenCalledTimes(1)
})
}) // updateRepos - archived repo skipping

describe('handleResults', () => {
let settings

beforeEach(() => {
stubContext.octokit.rest.checks = { update: jest.fn().mockResolvedValue({}) }
stubContext.octokit.rest.issues = { createComment: jest.fn().mockResolvedValue({}) }
settings = new Settings(true, stubContext, mockRepo, {}, mockRef)
settings.results = [
{
type: 'INFO',
plugin: 'Branches',
repo: 'test/test-repo',
endpoint: '',
body: '',
action: { msg: 'Changes found', additions: {}, modifications: { MY_VAR: { value: 'plain-value' } }, deletions: {} }
}
]
})

describe('in nop mode without a check run in the payload (full sync)', () => {
it('logs a summary instead of updating a check run, keeping config values out of info', async () => {
// stubContext.payload only contains `installation`, like a full-sync context
await settings.handleResults()

expect(stubContext.log.info).toHaveBeenCalledWith(expect.stringContaining('Changes found'))
expect(stubContext.log.info).not.toHaveBeenCalledWith(expect.stringContaining('plain-value'))
expect(stubContext.log.debug).toHaveBeenCalledWith({ results: settings.results }, 'Dry-run results')
expect(stubContext.octokit.rest.checks.update).not.toHaveBeenCalled()
})
})

describe('in nop mode with a check run but no repository in the payload', () => {
it('logs the results instead of updating a check run', async () => {
stubContext.payload.check_run = { id: 42, check_suite: { pull_requests: [{ number: 1 }] } }

await settings.handleResults()

expect(stubContext.log.info).toHaveBeenCalledWith(expect.stringContaining('Changes found'))
expect(stubContext.octokit.rest.checks.update).not.toHaveBeenCalled()
})
})

describe('in nop mode with a check run in the payload (webhook flow)', () => {
it('completes the check run', async () => {
stubContext.payload.check_run = { id: 42, check_suite: { pull_requests: [{ number: 1 }] } }
stubContext.payload.repository = { owner: { login: 'test' }, name: 'test-repo' }

await settings.handleResults()

expect(stubContext.octokit.rest.checks.update).toHaveBeenCalledWith(expect.objectContaining({
check_run_id: 42,
status: 'completed'
}))
})
})
}) // handleResults
}) // Settings Tests