Skip to content

Commit 363a116

Browse files
authored
Add release immutability support to repository plugin
1 parent 2bb8d13 commit 363a116

4 files changed

Lines changed: 113 additions & 4 deletions

File tree

docs/github-settings/1. repository-settings.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ repository:
4444
security:
4545
enableVulnerabilityAlerts: true
4646
enableAutomatedSecurityFixes: true
47+
releases:
48+
immutable: true
4749
```
4850
4951
## Repository API Spec
@@ -414,5 +416,27 @@ repository:
414416
...
415417
```
416418

419+
</td></tr>
420+
<tr><td>
421+
<p><code>releases</code><span style="color:gray;">&emsp;<i>object</i>&emsp;</span></p>
422+
<p>Settings for releases in this repository.</p>
423+
424+
<details><summary>Properties of <code>releases</code></summary>
425+
426+
<br>
427+
<p>&emsp;<code>immutable</code><span style="color:gray;">&emsp;<i>boolean</i>&emsp;</span></p>
428+
<p>&emsp;&emsp;Either <code>true</code> to enable release immutability (disallow assets and tags from being modified once a release is published), or <code>false</code> to disable it.</p>
429+
<p>&emsp;&emsp;See <a href="https://docs.github.com/en/rest/repos/repos#enable-immutable-releases">Enable immutable releases</a> for more information.</p>
430+
</details>
431+
432+
</td><td style="vertical-align:top">
433+
434+
```yaml
435+
repository:
436+
releases:
437+
immutable: true
438+
...
439+
```
440+
417441
</td></tr>
418442
</table>

docs/sample-settings/settings.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ repository:
2424
enableVulnerabilityAlerts: true
2525
enableAutomatedSecurityFixes: true
2626

27+
# Settings for release immutability
28+
# See https://docs.github.com/en/rest/repos/repos#enable-immutable-releases
29+
releases:
30+
immutable: true
31+
2732
# Either `true` to make the repository private, or `false` to make it public.
2833
# If this value is changed and if org members cannot change the visibility of repos
2934
# it would result in an error when updating a repo

lib/plugins/repository.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const ignorableFields = [
3737
'force_create',
3838
'auto_init',
3939
'repo',
40-
'archived'
40+
'archived',
41+
'releases'
4142
]
4243

4344
module.exports = class Repository extends ErrorStash {
@@ -48,6 +49,7 @@ module.exports = class Repository extends ErrorStash {
4849
this.settings = Object.assign({ mediaType: { previews: ['nebula-preview'] } }, settings, repo)
4950
this.topics = this.settings.topics
5051
this.security = this.settings.security
52+
this.releases = this.settings.releases
5153
this.repo = repo
5254
this.log = log
5355
this.nop = nop
@@ -56,6 +58,7 @@ module.exports = class Repository extends ErrorStash {
5658
delete this.settings.topics
5759
delete this.settings.force
5860
delete this.settings.template
61+
delete this.settings.releases
5962
}
6063

6164
sync () {
@@ -109,8 +112,12 @@ module.exports = class Repository extends ErrorStash {
109112
promises.push(updateRepoPromise.then(() => {
110113
return this.updateAutomatedSecurityFixes(resp.data, resArray)
111114
}))
115+
promises.push(updateRepoPromise.then(() => {
116+
return this.updateReleaseImmutability(resp.data, resArray)
117+
}))
112118
} else {
113119
promises.push(this.updateSecurity(resp.data, resArray))
120+
promises.push(this.updateReleaseImmutability(resp.data, resArray))
114121
}
115122
if (this.nop) {
116123
return Promise.resolve(resArray)
@@ -315,4 +322,34 @@ module.exports = class Repository extends ErrorStash {
315322
}
316323
}
317324
}
325+
326+
updateReleaseImmutability (repoData, resArray) {
327+
if (this.releases?.immutable === true || this.releases?.immutable === false) {
328+
const parms = {
329+
owner: repoData.owner.login,
330+
repo: repoData.name
331+
}
332+
if (this.releases.immutable === true) {
333+
this.log.debug(`Enabling release immutability for owner: ${repoData.owner.login} and repo ${repoData.name}`)
334+
if (this.nop) {
335+
resArray.push(new NopCommand(this.constructor.name, this.repo, this.github.request.endpoint('PUT /repos/{owner}/{repo}/releases/immutability', parms), 'Enabling release immutability'))
336+
return Promise.resolve(resArray)
337+
}
338+
return this.github.request('PUT /repos/{owner}/{repo}/releases/immutability', parms)
339+
} else {
340+
this.log.debug(`Disabling release immutability for owner: ${repoData.owner.login} and repo ${repoData.name}`)
341+
if (this.nop) {
342+
resArray.push(new NopCommand(this.constructor.name, this.repo, this.github.request.endpoint('DELETE /repos/{owner}/{repo}/releases/immutability', parms), 'Disabling release immutability'))
343+
return Promise.resolve(resArray)
344+
}
345+
return this.github.request('DELETE /repos/{owner}/{repo}/releases/immutability', parms)
346+
}
347+
} else {
348+
this.log.debug(`no need to update release immutability for ${repoData.name}`)
349+
if (this.nop) {
350+
return Promise.resolve([])
351+
}
352+
return Promise.resolve()
353+
}
354+
}
318355
}

test/unit/lib/plugins/repository.test.js

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ describe('Repository', () => {
66
repos: {
77
get: jest.fn().mockResolvedValue({
88
data: {
9-
topics: []
9+
topics: [],
10+
owner: { login: 'bkeepers' },
11+
name: 'test'
1012
}
1113
}),
1214
update: jest.fn().mockResolvedValue(),
1315
replaceAllTopics: jest.fn().mockResolvedValue()
1416
}
15-
}
17+
},
18+
request: jest.fn().mockResolvedValue()
1619
}
20+
github.request.endpoint = jest.fn().mockReturnValue({})
1721
const log = jest.fn()
1822
log.debug = jest.fn()
1923
log.error = jest.fn()
@@ -60,7 +64,7 @@ describe('Repository', () => {
6064
})
6165
})
6266

63-
it.only('syncs topics', () => {
67+
it('syncs topics', () => {
6468
const plugin = configure({
6569
topics: ['foo', 'bar']
6670
})
@@ -76,5 +80,44 @@ describe('Repository', () => {
7680
})
7781
})
7882
})
83+
84+
it('enables release immutability', () => {
85+
const plugin = configure({
86+
releases: { immutable: true }
87+
})
88+
89+
return plugin.sync().then(() => {
90+
expect(github.request).toHaveBeenCalledWith(
91+
'PUT /repos/{owner}/{repo}/releases/immutability',
92+
{ owner: 'bkeepers', repo: 'test' }
93+
)
94+
})
95+
})
96+
97+
it('disables release immutability', () => {
98+
const plugin = configure({
99+
releases: { immutable: false }
100+
})
101+
102+
return plugin.sync().then(() => {
103+
expect(github.request).toHaveBeenCalledWith(
104+
'DELETE /repos/{owner}/{repo}/releases/immutability',
105+
{ owner: 'bkeepers', repo: 'test' }
106+
)
107+
})
108+
})
109+
110+
it('does not call release immutability API when releases setting is absent', () => {
111+
const plugin = configure({
112+
name: 'test'
113+
})
114+
115+
return plugin.sync().then(() => {
116+
expect(github.request).not.toHaveBeenCalledWith(
117+
expect.stringMatching(/releases\/immutability/),
118+
expect.anything()
119+
)
120+
})
121+
})
79122
})
80123
})

0 commit comments

Comments
 (0)