-
Notifications
You must be signed in to change notification settings - Fork 57
/
update-version-and-changelog.js
156 lines (135 loc) · 4.62 KB
/
update-version-and-changelog.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* eslint-disable no-console */
/**
* External dependencies
*/
const fs = require( 'fs' );
const core = require( '@actions/core' );
const simpleGit = require( 'simple-git' );
const { promisify } = require( 'util' );
const exec = promisify( require( 'child_process' ).exec );
const git = simpleGit.default();
const releaseType = process.env.RELEASE_TYPE;
const VALID_RELEASE_TYPES = [ 'major', 'minor', 'patch' ];
// To get the merges since the last (previous) tag
async function getChangesSinceLastTag() {
try {
// Fetch all tags, sorted by creation date
const tagsResult = await git.tags( {
'--sort': '-creatordate',
} );
const tags = tagsResult.all;
if ( tags.length === 0 ) {
console.error( '❌ Error: No previous tags found.' );
return null;
}
const previousTag = tags[ 0 ]; // The most recent tag
// Now get the changes since this tag
const changes = await git.log( [ `${ previousTag }..HEAD` ] );
return changes;
} catch ( error ) {
throw error;
}
}
// To know if there are changes since the last tag.
// we are not using getChangesSinceGitTag because it returns the just the merges and not the commits.
// So for example if a hotfix was committed directly to trunk this function will detect it but getChangesSinceGitTag will not.
async function getHasChangesSinceGitTag( tag ) {
const changes = await git.log( [ `HEAD...${ tag }` ] );
return changes?.all?.length > 0;
}
async function updateVersion() {
if ( ! VALID_RELEASE_TYPES.includes( releaseType ) ) {
console.error(
'❌ Error: Release type is not valid. Valid release types are: major, minor, patch.'
);
process.exit( 1 );
}
if (
! fs.existsSync( './package.json' ) ||
! fs.existsSync( './package-lock.json' )
) {
console.error( '❌ Error: package.json or lock file not found.' );
process.exit( 1 );
}
if ( ! fs.existsSync( './readme.txt' ) ) {
console.error( '❌ Error: readme.txt file not found.' );
process.exit( 1 );
}
if ( ! fs.existsSync( './create-block-theme.php' ) ) {
console.error( '❌ Error: create-block-theme.php file not found.' );
process.exit( 1 );
}
// get changes since last tag
let changes = [];
try {
changes = await getChangesSinceLastTag();
} catch ( error ) {
console.error(
`❌ Error: failed to get changes since last tag: ${ error }`
);
process.exit( 1 );
}
const packageJson = require( './package.json' );
const currentVersion = packageJson.version;
// version bump package.json and package-lock.json using npm
const { stdout, stderr } = await exec(
`npm version --commit-hooks false --git-tag-version false ${ releaseType }`
);
if ( stderr ) {
console.error( `❌ Error: failed to bump the version."` );
process.exit( 1 );
}
const currentTag = `v${ currentVersion }`;
const newTag = stdout.trim();
const newVersion = newTag.replace( 'v', '' );
const hasChangesSinceGitTag = await getHasChangesSinceGitTag( currentTag );
// check if there are any changes
if ( ! hasChangesSinceGitTag ) {
console.error(
`❌ No changes since last tag (${ currentTag }). There is nothing new to release.`
);
// revert version update
await exec(
`npm version --commit-hooks false --git-tag-version false ${ currentVersion }`
);
process.exit( 1 );
}
console.info( '✅ Package.json version updated', currentTag, '=>', newTag );
// update readme.txt version with the new changelog
const readme = fs.readFileSync( './readme.txt', 'utf8' );
const capitalizeFirstLetter = ( string ) =>
string.charAt( 0 ).toUpperCase() + string.slice( 1 );
const changelogChanges = changes.all
.map(
( change ) =>
`* ${ capitalizeFirstLetter( change.message || change.body ) }`
)
.join( '\n' );
const newChangelog = `== Changelog ==\n\n= ${ newVersion } =\n${ changelogChanges }`;
let newReadme = readme.replace( '== Changelog ==', newChangelog );
// update version in readme.txt
newReadme = newReadme.replace(
/Stable tag: (.*)/,
`Stable tag: ${ newVersion }`
);
fs.writeFileSync( './readme.txt', newReadme );
console.info( '✅ Readme version updated', currentTag, '=>', newTag );
// update create-block-theme.php version
const pluginPhpFile = fs.readFileSync( './create-block-theme.php', 'utf8' );
const newPluginPhpFile = pluginPhpFile.replace(
/Version: (.*)/,
`Version: ${ newVersion }`
);
fs.writeFileSync( './create-block-theme.php', newPluginPhpFile );
console.info(
'✅ create-block-theme.php file version updated',
currentTag,
'=>',
newTag
);
// output data to be used by the next steps of the github action
core.setOutput( 'NEW_VERSION', newVersion );
core.setOutput( 'NEW_TAG', newTag );
core.setOutput( 'CHANGELOG', changelogChanges );
}
updateVersion();