Skip to content

Commit 98dce7f

Browse files
committed
[TASK] Release workflow and scripts
1 parent 2a3d8be commit 98dce7f

File tree

8 files changed

+635
-0
lines changed

8 files changed

+635
-0
lines changed

.ddev/config.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ omit_containers: [db, dba]
2020
use_dns_when_possible: true
2121
composer_version: "2"
2222
web_environment:
23+
- COMPOSER_ROOT_VERSION=0.6.0
2324
- XDEBUG_MODE=debug,develop,coverage
2425
nodejs_version: "16"
2526

.github/actions/dist/release.js

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/**
2+
* Core synchronization action.
3+
*
4+
* @param {@actions/github/GitHub} github
5+
* @param {@actions/github/Context} context
6+
* @param {@actions/core} core
7+
* @param {@actions/exec} exec
8+
* @param {string} version
9+
* @param {string} step
10+
* @returns {void}
11+
*/
12+
module.exports = async ({github, context, core, exec}, version, step) => {
13+
/**
14+
* Log a debug message.
15+
*
16+
* core.debug does not recursively resolve all objects so instead we use the
17+
* console.log which behalfs like expected.
18+
*
19+
* @param {...any} data
20+
* @returns {void}
21+
*/
22+
async function debug(
23+
...data
24+
) {
25+
if (!core.isDebug()) {
26+
return
27+
}
28+
29+
console.log(...data)
30+
}
31+
32+
/**
33+
* Executes a command and throws in case of a failure.
34+
*
35+
* @param {string} commandLine
36+
* @param {string[]} args
37+
* @param {ExecOptions} options
38+
* @returns {void}
39+
*/
40+
async function safeExec(
41+
commandLine,
42+
args,
43+
options
44+
) {
45+
const exitCode = await exec.exec(commandLine, args, options)
46+
47+
if (exitCode > 0) {
48+
throw new Error(`"${commandLine}" terminated with exit code ${exitCode}.`)
49+
}
50+
}
51+
52+
/**
53+
* Commits all changes with the given message.
54+
*
55+
* @param {string} message
56+
* @returns {void}
57+
*/
58+
async function commitChange(
59+
message
60+
) {
61+
await safeExec(`git commit -a -m "${message}"`)
62+
}
63+
64+
/**
65+
* Lookups a pending pull request and returns its number or 0 if
66+
* not found.
67+
*
68+
* @param {string} branch
69+
* @returns {number}
70+
*/
71+
async function getPendingPullRequest(
72+
branch
73+
) {
74+
const response = await github.rest.pulls.list({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
head: `${context.repo.owner}:${branch}`,
78+
})
79+
80+
debug(response)
81+
82+
if (response.status !== 200) {
83+
throw new Error(`List pull requests failed (${response.status}).`)
84+
}
85+
86+
var pullRequestNo = 0
87+
88+
if (response.data.length > 0) {
89+
pullRequestNo = response.data[0].number
90+
core.notice(`Pending pull request ${pullRequestNo} found.`)
91+
}
92+
93+
return pullRequestNo
94+
}
95+
96+
/**
97+
* Returns the default branch of the repository.
98+
*
99+
* @returns {string}
100+
*/
101+
async function getDefaultBranch() {
102+
if (context.payload.repository.default_branch !== undefined) {
103+
return context.payload.repository.default_branch
104+
}
105+
106+
const response = await github.rest.repos.get({
107+
owner: context.repo.owner,
108+
repo: context.repo.repo,
109+
})
110+
111+
debug(response)
112+
113+
if (response.status !== 200) {
114+
throw new Error(`Get repository failed (${response.status}).`)
115+
}
116+
117+
return response.data.default_branch
118+
}
119+
120+
/**
121+
* Creates a pull request for the given branch and returns its number.
122+
*
123+
* @param {string} branch
124+
* @param {string} title
125+
* @returns {number}
126+
*/
127+
async function createPullRequest(
128+
branch,
129+
title
130+
) {
131+
const defaultBranch = await getDefaultBranch()
132+
133+
debug(context.repo.owner)
134+
debug(context.repo.repo)
135+
debug(branch)
136+
debug(version)
137+
debug(step)
138+
debug(defaultBranch)
139+
140+
const response = await github.rest.pulls.create({
141+
owner: context.repo.owner,
142+
repo: context.repo.repo,
143+
title: title,
144+
head: branch,
145+
base: defaultBranch,
146+
body: ``,
147+
maintainer_can_modify: true,
148+
draft: true,
149+
})
150+
151+
debug(response)
152+
153+
if (response.status !== 201) {
154+
throw new Error(`Create pull request failed (${response.status}).`)
155+
}
156+
157+
core.notice(`Pull request ${response.data.number} created.`)
158+
159+
return response.data.number
160+
}
161+
162+
/**
163+
* Dumps the context if debug mode is enabled.
164+
*
165+
* @returns {void}
166+
*/
167+
async function dumpContext() {
168+
if (!core.isDebug()) {
169+
return
170+
}
171+
172+
core.startGroup(`Dump context attributes`)
173+
174+
try {
175+
console.log(context)
176+
} finally {
177+
core.endGroup()
178+
}
179+
}
180+
181+
/**
182+
* Setups the repository to be able to commit and switches to the
183+
* given branch.
184+
*
185+
* @param {string} branch
186+
* @returns {void}
187+
*/
188+
async function setupRepository(
189+
branch
190+
) {
191+
core.startGroup(`Setup repository`)
192+
193+
try {
194+
await safeExec(`git config user.name github-actions`)
195+
await safeExec(`git config user.email [email protected]`)
196+
await safeExec(`git branch ${branch}`)
197+
await safeExec(`git switch ${branch}`)
198+
} finally {
199+
core.endGroup()
200+
}
201+
}
202+
203+
/**
204+
* Create release or version commit.
205+
*
206+
* @param {string} version
207+
* @param {string} step
208+
* @returns {string}
209+
*/
210+
async function createCommit(
211+
version,
212+
step
213+
) {
214+
core.startGroup('Create release commit')
215+
216+
try {
217+
await safeExec(`composer set-version ${version}`)
218+
219+
let commitMessage = ''
220+
if (step === 'version') {
221+
commitMessage = `[TASK] Set TYPO3 Coding Standards version to ${version}`
222+
} else {
223+
commitMessage = `[RELEASE] Release of TYPO3 Coding Standards ${version}`
224+
}
225+
226+
await commitChange(commitMessage)
227+
228+
return commitMessage
229+
} finally {
230+
core.endGroup()
231+
}
232+
}
233+
234+
/**
235+
* Push changes to the provided branch.
236+
*
237+
* @param {string} branch
238+
* @returns {void}
239+
*/
240+
async function pushChanges(
241+
branch
242+
) {
243+
core.startGroup(`Push changes`)
244+
245+
try {
246+
await safeExec(`git push -f origin ${branch}`)
247+
} finally {
248+
core.endGroup()
249+
}
250+
}
251+
252+
/**
253+
* Create a pull request or update an existing one.
254+
*
255+
* @param {string} branch
256+
* @param {string} title
257+
* @returns {number}
258+
*/
259+
async function createOrUpdatePullRequest(
260+
branch,
261+
title
262+
) {
263+
core.startGroup(`Create pull request`)
264+
265+
try {
266+
let pullRequestNo = await getPendingPullRequest(branch)
267+
268+
if (pullRequestNo !== 0) {
269+
return pullRequestNo
270+
}
271+
272+
pullRequestNo = await createPullRequest(branch, title)
273+
274+
return pullRequestNo
275+
} finally {
276+
core.endGroup()
277+
}
278+
}
279+
280+
try {
281+
dumpContext()
282+
283+
let pullRequestBranch = ''
284+
if (step === 'version') {
285+
pullRequestBranch = 'release/version'
286+
} else {
287+
pullRequestBranch = 'release/release'
288+
}
289+
290+
await setupRepository(pullRequestBranch)
291+
292+
const commitMessage = await createCommit(version, step)
293+
294+
let pullRequestNo = 0
295+
await pushChanges(pullRequestBranch)
296+
pullRequestNo = await createOrUpdatePullRequest(pullRequestBranch, commitMessage)
297+
298+
core.setOutput('pull-request', pullRequestNo)
299+
} catch (err) {
300+
core.setFailed(`Action failed with error ${err}`)
301+
}
302+
}

.github/release-drafter-dev.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name-template: 'TYPO3 Coding Standards Package $RESOLVED_VERSION'
2+
tag-template: '$RESOLVED_VERSION'
3+
version-template: '$MAJOR.$MINOR.$PATCH-dev'
4+
prerelease: true
5+
version-resolver:
6+
default: minor
7+
filter-by-commitish: true
8+
template: _⚠⚠⚠ Draft to calculate next release. Will be overwritten with the next release and can be deleted at any time ⚠⚠⚠_

.github/release-drafter.yml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
template: |
2+
## What's Changed Since $PREVIOUS_TAG
3+
4+
$CHANGES
5+
6+
**Full Changelog**: <https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION>
7+
category-template: '### $TITLE'
8+
name-template: 'TYPO3 Coding Standards Package $RESOLVED_VERSION'
9+
tag-template: 'v$RESOLVED_VERSION'
10+
tag-prefix: 'v'
11+
version-template: '$COMPLETE'
12+
change-template: '- $TITLE by @$AUTHOR in <$URL>'
13+
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
14+
categories:
15+
- title: '🚀 Features'
16+
label: 'enhancement'
17+
- title: '🐞 Bug Fixes'
18+
label: 'bug'
19+
- title: '🧰 Maintenance'
20+
label: 'maintenance'
21+
- title: '📖 Documentation'
22+
label: 'documentation'
23+
- title: '🔓 Security'
24+
label: 'security'
25+
- title: '⚠ Breaking'
26+
label: 'breaking'
27+
exclude-labels:
28+
- 'skip-changelog'
29+
version-resolver:
30+
major:
31+
labels:
32+
- 'breaking'
33+
minor:
34+
labels:
35+
- 'enhancement'
36+
patch:
37+
labels:
38+
- 'bug'
39+
- 'documentation'
40+
- 'maintenance'
41+
- 'security'
42+
default: patch
43+
filter-by-commitish: true

0 commit comments

Comments
 (0)