UNPKG

14.9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8require("source-map-support/register");
9
10var _publisherBase = _interopRequireDefault(require("@electron-forge/publisher-base"));
11
12var _asyncOra = require("@electron-forge/async-ora");
13
14var _debug = _interopRequireDefault(require("debug"));
15
16var _formData = _interopRequireDefault(require("form-data"));
17
18var _fs = _interopRequireDefault(require("fs"));
19
20var _nodeFetch = _interopRequireDefault(require("node-fetch"));
21
22var _path = _interopRequireDefault(require("path"));
23
24function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
26function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
27
28function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
29
30function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
31
32function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
33
34function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
35
36function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
37
38function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
39
40function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
41
42const d = (0, _debug.default)('electron-forge:publish:nucleus');
43
44class PublisherNucleus extends _publisherBase.default {
45 constructor(...args) {
46 super(...args);
47
48 _defineProperty(this, "name", 'nucleus');
49
50 _defineProperty(this, "collapseMakeResults", makeResults => {
51 const newMakeResults = [];
52 var _iteratorNormalCompletion = true;
53 var _didIteratorError = false;
54 var _iteratorError = undefined;
55
56 try {
57 for (var _iterator = makeResults[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
58 const result = _step.value;
59 const existingResult = newMakeResults.find(nResult => nResult.arch === result.arch && nResult.platform === result.platform && nResult.packageJSON.version === result.packageJSON.version);
60
61 if (existingResult) {
62 existingResult.artifacts.push(...result.artifacts);
63 } else {
64 newMakeResults.push(_objectSpread({}, result));
65 }
66 }
67 } catch (err) {
68 _didIteratorError = true;
69 _iteratorError = err;
70 } finally {
71 try {
72 if (!_iteratorNormalCompletion && _iterator.return != null) {
73 _iterator.return();
74 }
75 } finally {
76 if (_didIteratorError) {
77 throw _iteratorError;
78 }
79 }
80 }
81
82 return newMakeResults;
83 });
84 }
85
86 publish({
87 makeResults
88 }) {
89 var _this = this;
90
91 return _asyncToGenerator(function* () {
92 const config = _this.config;
93
94 const collapsedResults = _this.collapseMakeResults(makeResults);
95
96 var _iteratorNormalCompletion2 = true;
97 var _didIteratorError2 = false;
98 var _iteratorError2 = undefined;
99
100 try {
101 for (var _iterator2 = collapsedResults.entries()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
102 const _step2$value = _slicedToArray(_step2.value, 2),
103 resultIdx = _step2$value[0],
104 makeResult = _step2$value[1];
105
106 const msg = `Uploading result (${resultIdx + 1}/${collapsedResults.length})`;
107 d(msg);
108 yield (0, _asyncOra.asyncOra)(msg,
109 /*#__PURE__*/
110 _asyncToGenerator(function* () {
111 const data = new _formData.default();
112 data.append('platform', makeResult.platform);
113 data.append('arch', makeResult.arch);
114 data.append('version', makeResult.packageJSON.version);
115 let artifactIdx = 0;
116 var _iteratorNormalCompletion3 = true;
117 var _didIteratorError3 = false;
118 var _iteratorError3 = undefined;
119
120 try {
121 for (var _iterator3 = makeResult.artifacts[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
122 const artifactPath = _step3.value;
123 // Skip the RELEASES file, it is automatically generated on the server
124 // eslint-disable-next-line no-continue
125 if (_path.default.basename(artifactPath).toLowerCase() === 'releases') continue;
126 data.append(`file${artifactIdx}`, _fs.default.createReadStream(artifactPath));
127 artifactIdx += 1;
128 }
129 } catch (err) {
130 _didIteratorError3 = true;
131 _iteratorError3 = err;
132 } finally {
133 try {
134 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
135 _iterator3.return();
136 }
137 } finally {
138 if (_didIteratorError3) {
139 throw _iteratorError3;
140 }
141 }
142 }
143
144 const response = yield (0, _nodeFetch.default)(`${config.host}/rest/app/${config.appId}/channel/${config.channelId}/upload`, {
145 headers: {
146 Authorization: config.token
147 },
148 method: 'POST',
149 body: data
150 });
151
152 if (response.status !== 200) {
153 throw new Error(`Unexpected response code from Nucleus: ${response.status}\n\nBody:\n${yield response.text()}`);
154 }
155 }));
156 }
157 } catch (err) {
158 _didIteratorError2 = true;
159 _iteratorError2 = err;
160 } finally {
161 try {
162 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
163 _iterator2.return();
164 }
165 } finally {
166 if (_didIteratorError2) {
167 throw _iteratorError2;
168 }
169 }
170 }
171 })();
172 }
173
174}
175
176exports.default = PublisherNucleus;
177//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9QdWJsaXNoZXJOdWNsZXVzLnRzIl0sIm5hbWVzIjpbImQiLCJQdWJsaXNoZXJOdWNsZXVzIiwiUHVibGlzaGVyQmFzZSIsIm1ha2VSZXN1bHRzIiwibmV3TWFrZVJlc3VsdHMiLCJyZXN1bHQiLCJleGlzdGluZ1Jlc3VsdCIsImZpbmQiLCJuUmVzdWx0IiwiYXJjaCIsInBsYXRmb3JtIiwicGFja2FnZUpTT04iLCJ2ZXJzaW9uIiwiYXJ0aWZhY3RzIiwicHVzaCIsInB1Ymxpc2giLCJjb25maWciLCJjb2xsYXBzZWRSZXN1bHRzIiwiY29sbGFwc2VNYWtlUmVzdWx0cyIsImVudHJpZXMiLCJyZXN1bHRJZHgiLCJtYWtlUmVzdWx0IiwibXNnIiwibGVuZ3RoIiwiZGF0YSIsIkZvcm1EYXRhIiwiYXBwZW5kIiwiYXJ0aWZhY3RJZHgiLCJhcnRpZmFjdFBhdGgiLCJwYXRoIiwiYmFzZW5hbWUiLCJ0b0xvd2VyQ2FzZSIsImZzIiwiY3JlYXRlUmVhZFN0cmVhbSIsInJlc3BvbnNlIiwiaG9zdCIsImFwcElkIiwiY2hhbm5lbElkIiwiaGVhZGVycyIsIkF1dGhvcml6YXRpb24iLCJ0b2tlbiIsIm1ldGhvZCIsImJvZHkiLCJzdGF0dXMiLCJFcnJvciIsInRleHQiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUlBLE1BQU1BLENBQUMsR0FBRyxvQkFBTSxnQ0FBTixDQUFWOztBQUVlLE1BQU1DLGdCQUFOLFNBQStCQyxzQkFBL0IsQ0FBcUU7QUFBQTtBQUFBOztBQUFBLGtDQUMzRSxTQUQyRTs7QUFBQSxpREFHbkRDLFdBQUQsSUFBa0Q7QUFDOUUsWUFBTUMsY0FBa0MsR0FBRyxFQUEzQztBQUQ4RTtBQUFBO0FBQUE7O0FBQUE7QUFFOUUsNkJBQXFCRCxXQUFyQiw4SEFBa0M7QUFBQSxnQkFBdkJFLE1BQXVCO0FBQ2hDLGdCQUFNQyxjQUFjLEdB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UyxNQUFULEtBQW9CLEdBQXhCLEVBQTZCO0FBQzNCLG9CQUFNLElBQUlDLEtBQUosQ0FBVywwQ0FBeUNWLFFBQVEsQ0FBQ1MsTUFBTyxjQUExRCxNQUE2RVQsUUFBUSxDQUFDVyxJQUFULEVBQWdCLEVBQXZHLENBQU47QUFDRDtBQUNGLFdBMUJLLEVBQU47QUEyQkQ7QUFwQzhDO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQXFDaEQ7O0FBdkRpRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBQdWJsaXNoZXJCYXNlLCB7IFB1Ymxpc2hlck9wdGlvbnMgfSBmcm9tICdAZWxlY3Ryb24tZm9yZ2UvcHVibGlzaGVyLWJhc2UnO1xuaW1wb3J0IHsgYXN5bmNPcmEgfSBmcm9tICdAZWxlY3Ryb24tZm9yZ2UvYXN5bmMtb3JhJztcbmltcG9ydCBkZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5pbXBvcnQgRm9ybURhdGEgZnJvbSAnZm9ybS1kYXRhJztcbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgZmV0Y2ggZnJvbSAnbm9kZS1mZXRjaCc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IHsgUHVibGlzaGVyTnVjbGV1c0NvbmZpZyB9IGZyb20gJy4vQ29uZmlnJztcblxuY29uc3QgZCA9IGRlYnVnKCdlbGVjdHJvbi1mb3JnZTpwdWJsaXNoOm51Y2xldXMnKTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUHVibGlzaGVyTnVjbGV1cyBleHRlbmRzIFB1Ymxpc2hlckJhc2U8UHVibGlzaGVyTnVjbGV1c0NvbmZpZz4ge1xuICBuYW1lID0gJ251Y2xldXMnO1xuXG4gIHByaXZhdGUgY29sbGFwc2VNYWtlUmVzdWx0cyA9IChtYWtlUmVzdWx0czogUHVibGlzaGVyT3B0aW9uc1snbWFrZVJlc3VsdHMnXSkgPT4ge1xuICAgIGNvbnN0IG5ld01ha2VSZXN1bHRzOiB0eXBlb2YgbWFrZVJlc3VsdHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiBtYWtlUmVzdWx0cykge1xuICAgICAgY29uc3QgZXhpc3RpbmdSZXN1bHQgPSBuZXdNYWtlUmVzdWx0cy5maW5kKG5SZXN1bHQgPT4gblJlc3VsdC5hcmNoID09PSByZXN1bHQuYXJjaFxuICAgICAgICAgICYmIG5SZXN1bHQucGxhdGZvcm0gPT09IHJlc3VsdC5wbGF0Zm9ybVxuICAgICAgICAgICYmIG5SZXN1bHQucGFja2FnZUpTT04udmVyc2lvbiA9PT0gcmVzdWx0LnBhY2thZ2VKU09OLnZlcnNpb24pO1xuICAgICAgaWYgKGV4aXN0aW5nUmVzdWx0KSB7XG4gICAgICAgIGV4aXN0aW5nUmVzdWx0LmFydGlmYWN0cy5wdXNoKC4uLnJlc3VsdC5hcnRpZmFjdHMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmV3TWFrZVJlc3VsdHMucHVzaCh7IC4uLnJlc3VsdCB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG5ld01ha2VSZXN1bHRzO1xuICB9XG5cbiAgYXN5bmMgcHVibGlzaCh7IG1ha2VSZXN1bHRzIH06IFB1Ymxpc2hlck9wdGlvbnMpIHtcbiAgICBjb25zdCB7IGNvbmZpZyB9ID0gdGhpcztcblxuICAgIGNvbnN0IGNvbGxhcHNlZFJlc3VsdHMgPSB0aGlzLmNvbGxhcHNlTWFrZVJlc3VsdHMobWFrZVJlc3VsdHMpO1xuXG4gICAgZm9yIChjb25zdCBbcmVzdWx0SWR4LCBtYWtlUmVzdWx0XSBvZiBjb2xsYXBzZWRSZXN1bHRzLmVudHJpZXMoKSkge1xuICAgICAgY29uc3QgbXNnID0gYFVwbG9hZGluZyByZXN1bHQgKCR7cmVzdWx0SWR4ICsgMX0vJHtjb2xsYXBzZWRSZXN1bHRzLmxlbmd0aH0pYDtcbiAgICAgIGQobXNnKTtcblxuICAgICAgYXdhaXQgYXN5bmNPcmEobXNnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgZGF0YS5hcHBlbmQoJ3BsYXRmb3JtJywgbWFrZVJlc3VsdC5wbGF0Zm9ybSk7XG4gICAgICAgIGRhdGEuYXBwZW5kKCdhcmNoJywgbWFrZVJlc3VsdC5hcmNoKTtcbiAgICAgICAgZGF0YS5hcHBlbmQoJ3ZlcnNpb24nLCBtYWtlUmVzdWx0LnBhY2thZ2VKU09OLnZlcnNpb24pO1xuXG4gICAgICAgIGxldCBhcnRpZmFjdElkeCA9IDA7XG4gICAgICAgIGZvciAoY29uc3QgYXJ0aWZhY3RQYXRoIG9mIG1ha2VSZXN1bHQuYXJ0aWZhY3RzKSB7XG4gICAgICAgICAgLy8gU2tpcCB0aGUgUkVMRUFTRVMgZmlsZSwgaXQgaXMgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQgb24gdGhlIHNlcnZlclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb250aW51ZVxuICAgICAgICAgIGlmIChwYXRoLmJhc2VuYW1lKGFydGlmYWN0UGF0aCkudG9Mb3dlckNhc2UoKSA9PT0gJ3JlbGVhc2VzJykgY29udGludWU7XG4gICAgICAgICAgZGF0YS5hcHBlbmQoYGZpbGUke2FydGlmYWN0SWR4fWAsIGZzLmNyZWF0ZVJlYWRTdHJlYW0oYXJ0aWZhY3RQYXRoKSk7XG4gICAgICAgICAgYXJ0aWZhY3RJZHggKz0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7Y29uZmlnLmhvc3R9L3Jlc3QvYXBwLyR7Y29uZmlnLmFwcElkfS9jaGFubmVsLyR7Y29uZmlnLmNoYW5uZWxJZH0vdXBsb2FkYCwge1xuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGNvbmZpZy50b2tlbixcbiAgICAgICAgICB9LFxuICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgIGJvZHk6IGRhdGEsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5leHBlY3RlZCByZXNwb25zZSBjb2RlIGZyb20gTnVjbGV1czogJHtyZXNwb25zZS5zdGF0dXN9XFxuXFxuQm9keTpcXG4ke2F3YWl0IHJlc3BvbnNlLnRleHQoKX1gKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iXX0=
\No newline at end of file