0
# Lifecycle Hooks
1
2
Standard Version provides comprehensive lifecycle hook support, allowing custom scripts to run at specific stages of the release process. This enables integration with build systems, testing frameworks, deployment pipelines, and custom validation workflows.
3
4
## Capabilities
5
6
### Lifecycle Script Execution
7
8
Core function for executing lifecycle hook scripts.
9
10
```javascript { .api }
11
/**
12
* Execute lifecycle script for specified hook name
13
* @param {Object} args - Configuration object containing scripts definition
14
* @param {string} hookName - Name of the lifecycle hook to execute
15
* @returns {Promise<string>} Promise resolving to script output (stdout)
16
* @throws {Error} If script execution fails or returns non-zero exit code
17
*/
18
async function runLifecycleScript(args, hookName);
19
```
20
21
**Usage Examples:**
22
23
```javascript
24
const runLifecycleScript = require('standard-version/lib/run-lifecycle-script');
25
26
const config = {
27
scripts: {
28
prebump: 'npm run test',
29
postbump: 'npm run build',
30
posttag: 'npm publish'
31
},
32
silent: false
33
};
34
35
try {
36
// Execute prebump hook
37
const output = await runLifecycleScript(config, 'prebump');
38
console.log('Prebump output:', output);
39
40
// Execute hook that doesn't exist (returns resolved promise)
41
await runLifecycleScript(config, 'nonexistent'); // No-op
42
43
} catch (error) {
44
console.error('Script failed:', error.message);
45
}
46
```
47
48
### Available Lifecycle Hooks
49
50
Standard Version supports hooks at eight key stages of the release process.
51
52
```javascript { .api }
53
/**
54
* Lifecycle hook execution order and timing:
55
*
56
* 1. prerelease - Before any release processing begins
57
* 2. prebump - Before version calculation and file updates
58
* 3. postbump - After version bump, before changelog generation
59
* 4. prechangelog- Before changelog generation
60
* 5. postchangelog - After changelog generation, before commit
61
* 6. precommit - Before git commit creation
62
* 7. postcommit - After git commit, before tag creation
63
* 8. pretag - Before git tag creation
64
* 9. posttag - After git tag creation (final step)
65
*/
66
```
67
68
**Hook Execution Flow:**
69
70
```javascript
71
// Standard Version execution flow with hooks:
72
73
await runLifecycleScript(args, 'prerelease');
74
// → Validate environment, prepare workspace
75
76
await runLifecycleScript(args, 'prebump');
77
// → Run tests, lint code, validate dependencies
78
79
const newVersion = await bump(args, currentVersion);
80
81
await runLifecycleScript(args, 'postbump');
82
// → Build artifacts, update documentation
83
84
await runLifecycleScript(args, 'prechangelog');
85
// → Generate additional release notes, validate commits
86
87
await changelog(args, newVersion);
88
89
await runLifecycleScript(args, 'postchangelog');
90
// → Format changelog, add custom sections
91
92
await runLifecycleScript(args, 'precommit');
93
// → Final validation, security checks
94
95
await commit(args, newVersion);
96
97
await runLifecycleScript(args, 'postcommit');
98
// → Notify systems, prepare for tagging
99
100
await runLifecycleScript(args, 'pretag');
101
// → Final pre-tag validation
102
103
await tag(newVersion, isPrivate, args);
104
105
await runLifecycleScript(args, 'posttag');
106
// → Publish packages, deploy, notify stakeholders
107
```
108
109
### Hook Configuration
110
111
Configure lifecycle hooks through the scripts configuration object.
112
113
```javascript { .api }
114
interface LifecycleScripts {
115
prerelease?: string; // Before any release processing
116
prebump?: string; // Before version calculation
117
postbump?: string; // After version bump
118
prechangelog?: string; // Before changelog generation
119
postchangelog?: string; // After changelog generation
120
precommit?: string; // Before git commit
121
postcommit?: string; // After git commit
122
pretag?: string; // Before git tag
123
posttag?: string; // After git tag (final)
124
}
125
```
126
127
**Usage Examples:**
128
129
```json
130
{
131
"scripts": {
132
"prerelease": "echo 'Starting release process'",
133
"prebump": "npm run lint && npm run test",
134
"postbump": "npm run build:prod",
135
"prechangelog": "node scripts/gather-contributors.js",
136
"postchangelog": "node scripts/format-changelog.js",
137
"precommit": "npm run security-audit",
138
"postcommit": "echo 'Changes committed successfully'",
139
"pretag": "npm run validate-build",
140
"posttag": "npm publish && npm run deploy"
141
}
142
}
143
```
144
145
### Common Hook Patterns
146
147
Typical use cases and patterns for each lifecycle hook.
148
149
**Development and Testing Hooks:**
150
151
```json { .api }
152
{
153
"scripts": {
154
"prerelease": "git status --porcelain | grep -q . && exit 1 || echo 'Working directory clean'",
155
"prebump": "npm run lint && npm run test && npm run test:integration",
156
"postbump": "npm run build && npm run test:build"
157
}
158
}
159
```
160
161
**Build and Deployment Hooks:**
162
163
```json { .api }
164
{
165
"scripts": {
166
"postbump": "npm run build:prod && npm run compress-assets",
167
"postchangelog": "node scripts/update-docs.js",
168
"precommit": "npm run validate-bundle-size",
169
"posttag": "npm publish && docker build -t myapp:$npm_package_version ."
170
}
171
}
172
```
173
174
**Notification and Integration Hooks:**
175
176
```json { .api }
177
{
178
"scripts": {
179
"prerelease": "slack-notify 'Starting release for $npm_package_name'",
180
"postcommit": "git push origin main",
181
"posttag": "github-release create --tag $npm_package_version && slack-notify 'Released $npm_package_version'"
182
}
183
}
184
```
185
186
### Environment Variables in Hooks
187
188
Hooks have access to npm environment variables and can use them for dynamic behavior.
189
190
```javascript { .api }
191
/**
192
* Available environment variables in hook scripts:
193
* - npm_package_name - Package name from package.json
194
* - npm_package_version - Current version from package.json
195
* - npm_config_* - npm configuration values
196
* - Standard shell environment variables
197
*/
198
```
199
200
**Usage Examples:**
201
202
```json
203
{
204
"scripts": {
205
"postbump": "echo 'Building $npm_package_name version $npm_package_version'",
206
"posttag": "docker tag myapp:latest myapp:$npm_package_version",
207
"precommit": "echo 'Committing version $npm_package_version' >> release.log"
208
}
209
}
210
```
211
212
### Complex Hook Examples
213
214
Advanced hook configurations for sophisticated workflows.
215
216
**Multi-step Hook with Error Handling:**
217
218
```json { .api }
219
{
220
"scripts": {
221
"prebump": "npm run lint && npm run test && npm run security-check || (echo 'Pre-bump validation failed' && exit 1)",
222
"postbump": "npm run build && npm run package && npm run verify-package",
223
"posttag": "npm publish && npm run deploy-docs && npm run notify-slack"
224
}
225
}
226
```
227
228
**Conditional Hook Execution:**
229
230
```json { .api }
231
{
232
"scripts": {
233
"prebump": "[ \"$CI\" = \"true\" ] && npm run test:ci || npm run test",
234
"posttag": "[ \"$NODE_ENV\" = \"production\" ] && npm publish || echo 'Skipping publish in non-production'",
235
"postcommit": "[ -f \"deploy.sh\" ] && ./deploy.sh || echo 'No deploy script found'"
236
}
237
}
238
```
239
240
**Hook with Custom Script Files:**
241
242
```json { .api }
243
{
244
"scripts": {
245
"prebump": "./scripts/pre-release-check.sh",
246
"postbump": "node scripts/build-and-test.js",
247
"postchangelog": "python scripts/update-changelog.py",
248
"posttag": "./scripts/deploy-release.sh $npm_package_version"
249
}
250
}
251
```
252
253
### Hook Script Output Handling
254
255
Hook scripts can influence standard-version behavior through their output.
256
257
```javascript { .api }
258
/**
259
* Special hook output behaviors:
260
*
261
* prebump hook output:
262
* - If prebump script outputs text, it overrides --release-as option
263
* - Output should be: major, minor, patch, or specific version number
264
*
265
* All hooks:
266
* - stdout is captured and can be logged
267
* - stderr is displayed immediately
268
* - Non-zero exit code stops release process
269
*/
270
```
271
272
**Usage Examples:**
273
274
```bash
275
#!/bin/bash
276
# prebump hook that determines release type based on commit analysis
277
if git log --oneline -1 | grep -q "BREAKING CHANGE"; then
278
echo "major"
279
elif git log --oneline -1 | grep -q "feat:"; then
280
echo "minor"
281
else
282
echo "patch"
283
fi
284
```
285
286
```javascript
287
// Node.js prebump script
288
const { execSync } = require('child_process');
289
290
// Analyze commits to determine version bump
291
const commits = execSync('git log --oneline --since="1 week ago"', { encoding: 'utf8' });
292
293
if (commits.includes('BREAKING CHANGE') || commits.includes('!:')) {
294
console.log('major');
295
} else if (commits.includes('feat:')) {
296
console.log('minor');
297
} else {
298
console.log('patch');
299
}
300
```
301
302
### Error Handling in Hooks
303
304
Proper error handling patterns for lifecycle hooks.
305
306
```javascript { .api }
307
/**
308
* Hook error handling:
309
* - Script exit code 0: Success, continue release process
310
* - Script exit code non-zero: Failure, abort release process
311
* - Uncaught exceptions in Node.js hooks: Abort release process
312
* - Empty or missing script: No-op, continue release process
313
*/
314
```
315
316
**Usage Examples:**
317
318
```bash
319
#!/bin/bash
320
# Robust prebump hook with error handling
321
set -e # Exit on any error
322
323
echo "Running pre-bump validations..."
324
325
# Run tests with proper error handling
326
if ! npm run test; then
327
echo "Tests failed, aborting release"
328
exit 1
329
fi
330
331
# Check for uncommitted changes
332
if [ -n "$(git status --porcelain)" ]; then
333
echo "Working directory not clean, aborting release"
334
exit 1
335
fi
336
337
echo "All validations passed"
338
exit 0
339
```
340
341
```javascript
342
// Node.js hook with error handling
343
const { execSync } = require('child_process');
344
345
try {
346
console.log('Running build and validation...');
347
348
execSync('npm run build', { stdio: 'inherit' });
349
execSync('npm run test:build', { stdio: 'inherit' });
350
351
console.log('Build and validation successful');
352
process.exit(0);
353
354
} catch (error) {
355
console.error('Build or validation failed:', error.message);
356
process.exit(1);
357
}
358
```
359
360
### Hook Integration with CI/CD
361
362
Patterns for using hooks effectively in continuous integration environments.
363
364
```json { .api }
365
{
366
"scripts": {
367
"prerelease": "[ \"$CI\" != \"true\" ] && echo 'Running in development mode' || echo 'Running in CI mode'",
368
"prebump": "[ \"$CI\" = \"true\" ] && npm ci || npm install",
369
"postbump": "[ \"$CI\" = \"true\" ] && npm run build:ci || npm run build:dev",
370
"posttag": "[ \"$CI\" = \"true\" ] && [ \"$BRANCH\" = \"main\" ] && npm publish || echo 'Skipping publish'"
371
}
372
}
373
```