0
# Asset Management
1
2
File asset handling system supporting glob patterns, metadata, and upload management for GitHub releases. The asset management system provides flexible file selection with powerful globbing capabilities and customizable metadata.
3
4
## Capabilities
5
6
### Asset Globbing
7
8
Resolves glob patterns and file paths into concrete asset objects ready for upload to GitHub releases.
9
10
```javascript { .api }
11
/**
12
* Resolves glob patterns for asset files
13
* @param context - Context object containing current working directory
14
* @param assets - Array of asset configurations with paths/globs
15
* @returns Promise resolving to array of concrete asset file paths
16
*/
17
async function globAssets(
18
context: { cwd: string },
19
assets: AssetConfig[]
20
): Promise<ResolvedAsset[]>;
21
22
type AssetConfig = string | {
23
path: string | string[];
24
name?: string;
25
label?: string;
26
};
27
28
interface ResolvedAsset {
29
path: string;
30
name?: string;
31
label?: string;
32
}
33
```
34
35
**Glob Pattern Support:**
36
- Standard glob patterns (`*.js`, `**/*.json`)
37
- Multiple patterns per asset (`["dist/*.js", "docs/*.pdf"]`)
38
- Negation patterns (`!**/*.test.js`)
39
- Directory expansion with automatic recursion
40
- Unique file deduplication across patterns
41
42
**Usage Examples:**
43
44
```javascript
45
import globAssets from "@semantic-release/github/lib/glob-assets.js";
46
47
// Simple glob patterns
48
const assets1 = await globAssets(
49
{ cwd: "/project" },
50
[
51
"dist/*.js",
52
"docs/*.pdf",
53
"build/assets/*.css"
54
]
55
);
56
// Returns: [{ path: "dist/app.js" }, { path: "docs/guide.pdf" }, ...]
57
58
// Complex asset configurations
59
const assets2 = await globAssets(
60
{ cwd: "/project" },
61
[
62
{
63
path: ["dist/*.js", "dist/*.js.map"],
64
label: "JavaScript Distribution"
65
},
66
{
67
path: "docs/**/*.pdf",
68
name: "documentation-${nextRelease.version}.pdf", // Template support
69
label: "Documentation Bundle"
70
}
71
]
72
);
73
74
// Mixed string and object configurations
75
const assets3 = await globAssets(
76
{ cwd: "/project" },
77
[
78
"README.md", // Simple file
79
"dist/*.zip", // Glob pattern
80
{
81
path: "build/**/*.{js,css}", // Complex glob with metadata
82
label: "Built Assets"
83
}
84
]
85
);
86
```
87
88
### Asset Configuration Types
89
90
Different ways to configure assets for release uploads.
91
92
```javascript { .api }
93
// String configuration - simple file path or glob
94
type StringAsset = string;
95
96
// Object configuration - path with metadata
97
interface ObjectAsset {
98
/** File path or glob pattern(s) */
99
path: string | string[];
100
101
/** Custom filename for uploaded asset (supports templates) */
102
name?: string;
103
104
/** Human-readable label shown in GitHub release UI */
105
label?: string;
106
}
107
108
// Combined asset configuration type
109
type AssetConfig = StringAsset | ObjectAsset;
110
```
111
112
**Configuration Examples:**
113
114
```javascript
115
// String configurations
116
const stringAssets = [
117
"dist/app.js", // Single file
118
"build/*.zip", // Glob pattern
119
"docs/api.pdf" // Documentation file
120
];
121
122
// Object configurations with metadata
123
const objectAssets = [
124
{
125
path: "dist/app.min.js",
126
name: "app-${nextRelease.version}.min.js",
127
label: "Minified Application Bundle"
128
},
129
{
130
path: ["src/**/*.ts", "!src/**/*.test.ts"],
131
name: "source-code.zip",
132
label: "TypeScript Source Code"
133
},
134
{
135
path: "coverage/lcov-report/**/*",
136
label: "Test Coverage Report"
137
}
138
];
139
140
// Mixed configurations
141
const mixedAssets = [
142
"LICENSE", // Simple file
143
"CHANGELOG.md", // Another simple file
144
{
145
path: "dist/*.{js,css,map}",
146
label: "Distribution Files"
147
}
148
];
149
```
150
151
### Asset Processing Pipeline
152
153
The asset processing pipeline handles glob resolution, file validation, and metadata preparation.
154
155
```javascript { .api }
156
/**
157
* Asset processing pipeline stages:
158
* 1. Glob expansion - Convert patterns to file lists
159
* 2. Directory handling - Expand directories to files
160
* 3. File validation - Check existence and accessibility
161
* 4. Deduplication - Remove duplicate file paths
162
* 5. Metadata preparation - Apply names and labels
163
* 6. Template processing - Resolve template variables
164
*/
165
166
interface ProcessingStages {
167
/** Expand glob patterns using globby library */
168
expandGlobs(patterns: string[], options: GlobOptions): Promise<string[]>;
169
170
/** Validate files exist and are readable */
171
validateFiles(paths: string[]): Promise<string[]>;
172
173
/** Remove duplicate file paths */
174
deduplicateFiles(paths: string[]): string[];
175
176
/** Apply asset metadata and templates */
177
prepareMetadata(assets: AssetConfig[], files: string[]): ResolvedAsset[];
178
}
179
```
180
181
**Processing Example:**
182
183
```javascript
184
// Input configuration
185
const assetConfig = {
186
path: ["dist/**/*.js", "!dist/**/*.test.js"],
187
name: "${basename}-${nextRelease.version}${extname}",
188
label: "JavaScript Distribution"
189
};
190
191
// Processing stages:
192
// 1. Glob expansion: ["dist/app.js", "dist/utils.js", "dist/app.test.js"]
193
// 2. Negation filtering: ["dist/app.js", "dist/utils.js"]
194
// 3. File validation: Check files exist and are readable
195
// 4. Metadata application: Add name templates and labels
196
// 5. Result: [
197
// { path: "dist/app.js", name: "app-1.0.0.js", label: "JavaScript Distribution" },
198
// { path: "dist/utils.js", name: "utils-1.0.0.js", label: "JavaScript Distribution" }
199
// ]
200
```
201
202
### Upload Process
203
204
Asset upload handling within the publish lifecycle function.
205
206
```javascript { .api }
207
/**
208
* Asset upload process during release publication:
209
* 1. Create draft release
210
* 2. Resolve asset globs
211
* 3. Upload assets in parallel
212
* 4. Publish release (if not draft mode)
213
*/
214
215
interface UploadProcess {
216
/** File stat checking and validation */
217
validateAssetFile(filePath: string): Promise<FileStats>;
218
219
/** MIME type detection for proper Content-Type headers */
220
detectMimeType(filePath: string): string;
221
222
/** Asset upload with retry logic */
223
uploadAsset(asset: ResolvedAsset, uploadUrl: string): Promise<AssetResponse>;
224
225
/** Parallel upload coordination */
226
uploadAllAssets(assets: ResolvedAsset[]): Promise<AssetResponse[]>;
227
}
228
229
interface FileStats {
230
size: number;
231
isFile: boolean;
232
isDirectory: boolean;
233
}
234
235
interface AssetResponse {
236
id: number;
237
name: string;
238
size: number;
239
download_count: number;
240
browser_download_url: string;
241
}
242
```
243
244
**Upload Error Handling:**
245
246
```javascript
247
// The upload process includes comprehensive error handling:
248
249
try {
250
await uploadAsset(asset, uploadUrl);
251
} catch (error) {
252
if (error.code === 'ENOENT') {
253
logger.error(`Asset file not found: ${asset.path}`);
254
// File is skipped, upload continues
255
} else if (error.status === 422) {
256
logger.error(`Asset already exists: ${asset.name}`);
257
// GitHub rejects duplicate asset names
258
} else if (error.status === 413) {
259
logger.error(`Asset too large: ${asset.path}`);
260
// GitHub has file size limits
261
} else {
262
// Other errors are retried or escalated
263
throw error;
264
}
265
}
266
```
267
268
### Template Support
269
270
Asset names and labels support Lodash templates for dynamic content generation.
271
272
```javascript { .api }
273
// Available template variables in asset configurations:
274
interface AssetTemplateContext {
275
nextRelease: {
276
version: string; // "1.0.0"
277
gitTag: string; // "v1.0.0"
278
name: string; // "1.0.0"
279
channel?: string; // Release channel
280
};
281
branch: {
282
name: string; // "main"
283
};
284
// File path utilities (for name templates)
285
basename: string; // "app.js" from "dist/app.js"
286
extname: string; // ".js" from "dist/app.js"
287
dirname: string; // "dist" from "dist/app.js"
288
filename: string; // "app" from "dist/app.js"
289
}
290
```
291
292
**Template Examples:**
293
294
```javascript
295
{
296
// Version-based naming
297
name: "${basename}-v${nextRelease.version}${extname}",
298
// "app.js" becomes "app-v1.0.0.js"
299
300
// Channel-aware naming
301
name: "${filename}-${nextRelease.channel || 'stable'}${extname}",
302
// "app.js" becomes "app-stable.js" or "app-beta.js"
303
304
// Complex naming with metadata
305
name: "${dirname}-${filename}-${nextRelease.version}-${branch.name}${extname}",
306
// "dist/app.js" becomes "dist-app-1.0.0-main.js"
307
308
// Dynamic labels
309
label: "${basename} (${nextRelease.version}${nextRelease.channel ? ` - ${nextRelease.channel}` : ''})"
310
// "App Bundle (1.0.0)" or "App Bundle (1.0.0 - beta)"
311
}
312
```
313
314
### Advanced Patterns
315
316
Complex asset management patterns for sophisticated release workflows.
317
318
**Conditional Assets:**
319
```javascript
320
// Assets based on build configuration
321
const assets = [
322
// Always include core files
323
"LICENSE",
324
"README.md",
325
326
// Conditional inclusion based on environment
327
...(process.env.NODE_ENV === 'production' ? [
328
"dist/app.min.js",
329
"dist/app.min.css"
330
] : [
331
"dist/app.js",
332
"dist/app.css"
333
]),
334
335
// Platform-specific assets
336
{
337
path: "build/darwin/**/*",
338
label: "macOS Distribution"
339
},
340
{
341
path: "build/win32/**/*",
342
label: "Windows Distribution"
343
}
344
];
345
```
346
347
**Multi-Architecture Builds:**
348
```javascript
349
const architectures = ['x64', 'arm64', 'x86'];
350
351
const assets = architectures.flatMap(arch => [
352
{
353
path: `dist/${arch}/app`,
354
name: `app-${arch}-${nextRelease.version}`,
355
label: `Application (${arch.toUpperCase()})`
356
},
357
{
358
path: `dist/${arch}/app.exe`,
359
name: `app-${arch}-${nextRelease.version}.exe`,
360
label: `Application (${arch.toUpperCase()} Windows)`
361
}
362
]);
363
```
364
365
**Documentation Bundles:**
366
```javascript
367
const assets = [
368
// Individual documentation files
369
{
370
path: "docs/**/*.md",
371
label: "Individual Documentation Files"
372
},
373
374
// Generated documentation bundle
375
{
376
path: "docs-build/api-docs.zip",
377
name: "api-documentation-${nextRelease.version}.zip",
378
label: "Complete API Documentation"
379
},
380
381
// Coverage reports
382
{
383
path: "coverage/lcov.info",
384
name: "test-coverage-${nextRelease.version}.lcov",
385
label: "Test Coverage Data"
386
}
387
];
388
```
389
390
### Performance Considerations
391
392
Asset management includes several performance optimizations:
393
394
- **Parallel Uploads**: Multiple assets uploaded simultaneously
395
- **Glob Caching**: File system scans cached within single run
396
- **File Streaming**: Large files streamed rather than loaded into memory
397
- **Resume Support**: Failed uploads can be resumed (GitHub API dependent)
398
- **Progress Reporting**: Upload progress logged for large files
399
- **Size Validation**: File size checked before upload attempt