Skip to content
7 changes: 6 additions & 1 deletion lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,19 @@ ${this.results.reduce((x, y) => {
const RepoPlugin = Settings.PLUGINS.repository

const archivePlugin = new Archive(this.nop, this.github, repo, repoConfig, this.log)
const { shouldArchive, shouldUnarchive } = await archivePlugin.getState()
const { isArchived, shouldArchive, shouldUnarchive } = await archivePlugin.getState()

if (shouldUnarchive) {
this.log.debug(`Unarchiving repo ${repo.repo}`)
const unArchiveResults = await archivePlugin.sync()
this.appendToResults(unArchiveResults)
}

if (isArchived && !shouldUnarchive) {
this.log.debug(`Skipping repo/child plugin updates for archived repo ${repo.repo}`)
return
}

const repoResults = await new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log, this.errors).sync()
this.appendToResults(repoResults)

Expand Down
21 changes: 21 additions & 0 deletions schema/dereferenced/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
}
}
},
"code_security": {
"type": "object",
"description": "Use the `status` property to enable or disable GitHub Code Security for this repository.",
"description": "Use the `status` property to enable or disable GitHub Advanced Security for this repository.\nFor more information, see \"[About GitHub Advanced\nSecurity](/github/getting-started-with-github/learning-about-github/about-github-advanced-security).\"\n\nFor standalone Code Scanning or Secret Protection products, this parameter cannot be used.",
"properties": {
"status": {
"type": "string",
"description": "Can be `enabled` or `disabled`."
}
Comment thread
decyjphr marked this conversation as resolved.
}
},
"code_security": {
"type": "object",
"description": "Use the `status` property to enable or disable GitHub Code Security for this repository.",
Comment thread
decyjphr marked this conversation as resolved.
Expand Down Expand Up @@ -90,6 +101,16 @@
}
}
},
"secret_scanning_ai_detection": {
"type": "object",
"description": "Use the `status` property to enable or disable secret scanning AI detection for this repository. For more information, see \"[Responsible detection of generic secrets with AI](https://docs.github.com/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/generic-secret-detection/responsible-ai-generic-secrets).\"",
"properties": {
"status": {
"type": "string",
"description": "Can be `enabled` or `disabled`."
}
}
},
"secret_scanning_non_provider_patterns": {
"type": "object",
"description": "Use the `status` property to enable or disable secret scanning non-provider patterns for this repository. For more information, see \"[Supported secret scanning patterns](/code-security/secret-scanning/introduction/supported-secret-scanning-patterns#supported-secrets).\"",
Expand Down
50 changes: 50 additions & 0 deletions test/unit/lib/plugins/archive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,56 @@ describe('Archive Plugin', () => {
})
})

describe('getState', () => {
it('getState when repo is already archived and desired state is not set returns isArchived true shouldArchive false shouldUnarchive false', async () => {
// Arrange
github.rest.repos.get.mockResolvedValue({ data: { archived: true } })
archive = new Archive(false, github, repo, {}, log)

// Act
const result = await archive.getState()

// Assert
expect(result).toEqual({
isArchived: true,
shouldArchive: false,
shouldUnarchive: false
})
})

it('getState when repo is not archived and desired state is not set returns isArchived false shouldArchive false shouldUnarchive false', async () => {
// Arrange
github.rest.repos.get.mockResolvedValue({ data: { archived: false } })
archive = new Archive(false, github, repo, {}, log)

// Act
const result = await archive.getState()

// Assert
expect(result).toEqual({
isArchived: false,
shouldArchive: false,
shouldUnarchive: false
})
})

it('getState when repo is archived and desired state is false returns isArchived true shouldArchive false shouldUnarchive true', async () => {
// Arrange
github.rest.repos.get.mockResolvedValue({ data: { archived: true } })
archive = new Archive(false, github, repo, { archived: false }, log)

// Act
const result = await archive.getState()

// Assert
expect(result).toEqual({
isArchived: true,
shouldArchive: false,
shouldUnarchive: true
})
})
})

describe('sync', () => {
beforeEach(() => {
archive = new Archive(false, github, repo, settings, log)
Expand Down
87 changes: 87 additions & 0 deletions test/unit/lib/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,4 +462,91 @@ repository:
);
});
});

describe('updateRepos - archived repo skipping', () => {
const Archive = require('../../../lib/plugins/archive')

let settings
let mockRepoSync
let originalRepoPlugin

beforeEach(() => {
// Preserve the original RepoPlugin so it can be restored after each test
originalRepoPlugin = Settings.PLUGINS.repository

// Replace RepoPlugin with a mock constructor whose sync() we can assert on
mockRepoSync = jest.fn().mockResolvedValue([])
Settings.PLUGINS.repository = jest.fn().mockImplementation(() => ({
sync: mockRepoSync
}))

// Build a Settings instance that will enter the `if (repoConfig)` branch:
// config.repository must be defined so repoConfig is truthy
settings = new Settings(
false,
stubContext,
{ owner: 'test-org', repo: 'test-repo' },
{ repository: { name: 'test-repo' } },
'main'
)

// Pre-set subOrgConfigs so updateRepos() does not call the async getSubOrgConfigs()
settings.subOrgConfigs = {}

// Pre-set repoConfigs so getRepoOverrideConfig() does not throw on undefined
settings.repoConfigs = {}
})

afterEach(() => {
// Restore the real RepoPlugin and all prototype spies
Settings.PLUGINS.repository = originalRepoPlugin
jest.restoreAllMocks()
})

it('updateRepos when repo is already archived and not being unarchived does not call RepoPlugin sync', async () => {
// Arrange
jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({
isArchived: true,
shouldArchive: false,
shouldUnarchive: false
})

// Act
await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' })

// Assert
expect(mockRepoSync).not.toHaveBeenCalled()
})

it('updateRepos when repo is archived but is being unarchived calls RepoPlugin sync', async () => {
// Arrange
jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({
isArchived: true,
shouldArchive: false,
shouldUnarchive: true
})
jest.spyOn(Archive.prototype, 'sync').mockResolvedValue([])

// Act
await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' })

// Assert
expect(mockRepoSync).toHaveBeenCalledTimes(1)
})

it('updateRepos when repo is not archived calls RepoPlugin sync', async () => {
// Arrange
jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({
isArchived: false,
shouldArchive: false,
shouldUnarchive: false
})

// Act
await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' })

// Assert
expect(mockRepoSync).toHaveBeenCalledTimes(1)
})
}) // updateRepos - archived repo skipping
}) // Settings Tests
Loading