UNPKG

3.42 kBJavaScriptView Raw
1const path = require('path');
2const {stat, readFile} = require('fs-extra');
3const {isPlainObject, template} = require('lodash');
4const mime = require('mime');
5const debug = require('debug')('semantic-release:github');
6const {RELEASE_NAME} = require('./definitions/constants');
7const parseGithubUrl = require('./parse-github-url');
8const globAssets = require('./glob-assets.js');
9const resolveConfig = require('./resolve-config');
10const getClient = require('./get-client');
11const isPrerelease = require('./is-prerelease');
12
13module.exports = async (pluginConfig, context) => {
14 const {
15 cwd,
16 options: {repositoryUrl},
17 branch,
18 nextRelease: {name, gitTag, notes},
19 logger,
20 } = context;
21 const {githubToken, githubUrl, githubApiPathPrefix, proxy, assets} = resolveConfig(pluginConfig, context);
22 const {owner, repo} = parseGithubUrl(repositoryUrl);
23 const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy});
24 const release = {
25 owner,
26 repo,
27 tag_name: gitTag,
28 target_commitish: branch.name,
29 name,
30 body: notes,
31 prerelease: isPrerelease(branch),
32 };
33
34 debug('release object: %O', release);
35
36 // When there are no assets, we publish a release directly
37 if (!assets || assets.length === 0) {
38 const {
39 data: {html_url: url, id: releaseId},
40 } = await github.repos.createRelease(release);
41
42 logger.log('Published GitHub release: %s', url);
43 return {url, name: RELEASE_NAME, id: releaseId};
44 }
45
46 // We'll create a draft release, append the assets to it, and then publish it.
47 // This is so that the assets are available when we get a Github release event.
48 const draftRelease = {...release, draft: true};
49
50 const {
51 data: {upload_url: uploadUrl, id: releaseId},
52 } = await github.repos.createRelease(draftRelease);
53
54 // Append assets to the release
55 const globbedAssets = await globAssets(context, assets);
56 debug('globed assets: %o', globbedAssets);
57
58 await Promise.all(
59 globbedAssets.map(async (asset) => {
60 const filePath = isPlainObject(asset) ? asset.path : asset;
61 let file;
62
63 try {
64 file = await stat(path.resolve(cwd, filePath));
65 } catch {
66 logger.error('The asset %s cannot be read, and will be ignored.', filePath);
67 return;
68 }
69
70 if (!file || !file.isFile()) {
71 logger.error('The asset %s is not a file, and will be ignored.', filePath);
72 return;
73 }
74
75 const fileName = template(asset.name || path.basename(filePath))(context);
76 const upload = {
77 url: uploadUrl,
78 data: await readFile(path.resolve(cwd, filePath)),
79 name: fileName,
80 headers: {
81 'content-type': mime.getType(path.extname(fileName)) || 'text/plain',
82 'content-length': file.size,
83 },
84 };
85
86 debug('file path: %o', filePath);
87 debug('file name: %o', fileName);
88
89 if (isPlainObject(asset) && asset.label) {
90 upload.label = template(asset.label)(context);
91 }
92
93 const {
94 data: {browser_download_url: downloadUrl},
95 } = await github.repos.uploadReleaseAsset(upload);
96 logger.log('Published file %s', downloadUrl);
97 })
98 );
99
100 const {
101 data: {html_url: url},
102 } = await github.repos.updateRelease({owner, repo, release_id: releaseId, draft: false});
103
104 logger.log('Published GitHub release: %s', url);
105 return {url, name: RELEASE_NAME, id: releaseId};
106};