mirror of
https://github.com/tauri-apps/tauri-action.git
synced 2026-01-31 00:35:20 +01:00
Generate updater JSON file (#287)
Co-authored-by: wangxianqiao <wangxianqiao@cloudfine.com> Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
450
packages/action/dist/918.index.js
vendored
Normal file
450
packages/action/dist/918.index.js
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
export const id = 918;
|
||||
export const ids = [918];
|
||||
export const modules = {
|
||||
|
||||
/***/ 918:
|
||||
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
|
||||
/* harmony export */ });
|
||||
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7445);
|
||||
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9457);
|
||||
|
||||
|
||||
|
||||
let s = 0;
|
||||
const S = {
|
||||
START_BOUNDARY: s++,
|
||||
HEADER_FIELD_START: s++,
|
||||
HEADER_FIELD: s++,
|
||||
HEADER_VALUE_START: s++,
|
||||
HEADER_VALUE: s++,
|
||||
HEADER_VALUE_ALMOST_DONE: s++,
|
||||
HEADERS_ALMOST_DONE: s++,
|
||||
PART_DATA_START: s++,
|
||||
PART_DATA: s++,
|
||||
END: s++
|
||||
};
|
||||
|
||||
let f = 1;
|
||||
const F = {
|
||||
PART_BOUNDARY: f,
|
||||
LAST_BOUNDARY: f *= 2
|
||||
};
|
||||
|
||||
const LF = 10;
|
||||
const CR = 13;
|
||||
const SPACE = 32;
|
||||
const HYPHEN = 45;
|
||||
const COLON = 58;
|
||||
const A = 97;
|
||||
const Z = 122;
|
||||
|
||||
const lower = c => c | 0x20;
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
class MultipartParser {
|
||||
/**
|
||||
* @param {string} boundary
|
||||
*/
|
||||
constructor(boundary) {
|
||||
this.index = 0;
|
||||
this.flags = 0;
|
||||
|
||||
this.onHeaderEnd = noop;
|
||||
this.onHeaderField = noop;
|
||||
this.onHeadersEnd = noop;
|
||||
this.onHeaderValue = noop;
|
||||
this.onPartBegin = noop;
|
||||
this.onPartData = noop;
|
||||
this.onPartEnd = noop;
|
||||
|
||||
this.boundaryChars = {};
|
||||
|
||||
boundary = '\r\n--' + boundary;
|
||||
const ui8a = new Uint8Array(boundary.length);
|
||||
for (let i = 0; i < boundary.length; i++) {
|
||||
ui8a[i] = boundary.charCodeAt(i);
|
||||
this.boundaryChars[ui8a[i]] = true;
|
||||
}
|
||||
|
||||
this.boundary = ui8a;
|
||||
this.lookbehind = new Uint8Array(this.boundary.length + 8);
|
||||
this.state = S.START_BOUNDARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} data
|
||||
*/
|
||||
write(data) {
|
||||
let i = 0;
|
||||
const length_ = data.length;
|
||||
let previousIndex = this.index;
|
||||
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
|
||||
const boundaryLength = this.boundary.length;
|
||||
const boundaryEnd = boundaryLength - 1;
|
||||
const bufferLength = data.length;
|
||||
let c;
|
||||
let cl;
|
||||
|
||||
const mark = name => {
|
||||
this[name + 'Mark'] = i;
|
||||
};
|
||||
|
||||
const clear = name => {
|
||||
delete this[name + 'Mark'];
|
||||
};
|
||||
|
||||
const callback = (callbackSymbol, start, end, ui8a) => {
|
||||
if (start === undefined || start !== end) {
|
||||
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
|
||||
}
|
||||
};
|
||||
|
||||
const dataCallback = (name, clear) => {
|
||||
const markSymbol = name + 'Mark';
|
||||
if (!(markSymbol in this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
callback(name, this[markSymbol], i, data);
|
||||
delete this[markSymbol];
|
||||
} else {
|
||||
callback(name, this[markSymbol], data.length, data);
|
||||
this[markSymbol] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
for (i = 0; i < length_; i++) {
|
||||
c = data[i];
|
||||
|
||||
switch (state) {
|
||||
case S.START_BOUNDARY:
|
||||
if (index === boundary.length - 2) {
|
||||
if (c === HYPHEN) {
|
||||
flags |= F.LAST_BOUNDARY;
|
||||
} else if (c !== CR) {
|
||||
return;
|
||||
}
|
||||
|
||||
index++;
|
||||
break;
|
||||
} else if (index - 1 === boundary.length - 2) {
|
||||
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
|
||||
state = S.END;
|
||||
flags = 0;
|
||||
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
|
||||
index = 0;
|
||||
callback('onPartBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c !== boundary[index + 2]) {
|
||||
index = -2;
|
||||
}
|
||||
|
||||
if (c === boundary[index + 2]) {
|
||||
index++;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_FIELD_START:
|
||||
state = S.HEADER_FIELD;
|
||||
mark('onHeaderField');
|
||||
index = 0;
|
||||
// falls through
|
||||
case S.HEADER_FIELD:
|
||||
if (c === CR) {
|
||||
clear('onHeaderField');
|
||||
state = S.HEADERS_ALMOST_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (c === HYPHEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c === COLON) {
|
||||
if (index === 1) {
|
||||
// empty header field
|
||||
return;
|
||||
}
|
||||
|
||||
dataCallback('onHeaderField', true);
|
||||
state = S.HEADER_VALUE_START;
|
||||
break;
|
||||
}
|
||||
|
||||
cl = lower(c);
|
||||
if (cl < A || cl > Z) {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_VALUE_START:
|
||||
if (c === SPACE) {
|
||||
break;
|
||||
}
|
||||
|
||||
mark('onHeaderValue');
|
||||
state = S.HEADER_VALUE;
|
||||
// falls through
|
||||
case S.HEADER_VALUE:
|
||||
if (c === CR) {
|
||||
dataCallback('onHeaderValue', true);
|
||||
callback('onHeaderEnd');
|
||||
state = S.HEADER_VALUE_ALMOST_DONE;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_VALUE_ALMOST_DONE:
|
||||
if (c !== LF) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
case S.HEADERS_ALMOST_DONE:
|
||||
if (c !== LF) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback('onHeadersEnd');
|
||||
state = S.PART_DATA_START;
|
||||
break;
|
||||
case S.PART_DATA_START:
|
||||
state = S.PART_DATA;
|
||||
mark('onPartData');
|
||||
// falls through
|
||||
case S.PART_DATA:
|
||||
previousIndex = index;
|
||||
|
||||
if (index === 0) {
|
||||
// boyer-moore derrived algorithm to safely skip non-boundary data
|
||||
i += boundaryEnd;
|
||||
while (i < bufferLength && !(data[i] in boundaryChars)) {
|
||||
i += boundaryLength;
|
||||
}
|
||||
|
||||
i -= boundaryEnd;
|
||||
c = data[i];
|
||||
}
|
||||
|
||||
if (index < boundary.length) {
|
||||
if (boundary[index] === c) {
|
||||
if (index === 0) {
|
||||
dataCallback('onPartData', true);
|
||||
}
|
||||
|
||||
index++;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index === boundary.length) {
|
||||
index++;
|
||||
if (c === CR) {
|
||||
// CR = part boundary
|
||||
flags |= F.PART_BOUNDARY;
|
||||
} else if (c === HYPHEN) {
|
||||
// HYPHEN = end boundary
|
||||
flags |= F.LAST_BOUNDARY;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index - 1 === boundary.length) {
|
||||
if (flags & F.PART_BOUNDARY) {
|
||||
index = 0;
|
||||
if (c === LF) {
|
||||
// unset the PART_BOUNDARY flag
|
||||
flags &= ~F.PART_BOUNDARY;
|
||||
callback('onPartEnd');
|
||||
callback('onPartBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
}
|
||||
} else if (flags & F.LAST_BOUNDARY) {
|
||||
if (c === HYPHEN) {
|
||||
callback('onPartEnd');
|
||||
state = S.END;
|
||||
flags = 0;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
// when matching a possible boundary, keep a lookbehind reference
|
||||
// in case it turns out to be a false lead
|
||||
lookbehind[index - 1] = c;
|
||||
} else if (previousIndex > 0) {
|
||||
// if our boundary turned out to be rubbish, the captured lookbehind
|
||||
// belongs to partData
|
||||
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
|
||||
callback('onPartData', 0, previousIndex, _lookbehind);
|
||||
previousIndex = 0;
|
||||
mark('onPartData');
|
||||
|
||||
// reconsider the current character even so it interrupted the sequence
|
||||
// it could be the beginning of a new sequence
|
||||
i--;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.END:
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected state entered: ${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
dataCallback('onHeaderField');
|
||||
dataCallback('onHeaderValue');
|
||||
dataCallback('onPartData');
|
||||
|
||||
// Update properties for the next call
|
||||
this.index = index;
|
||||
this.state = state;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
end() {
|
||||
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
|
||||
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
|
||||
this.onPartEnd();
|
||||
} else if (this.state !== S.END) {
|
||||
throw new Error('MultipartParser.end(): stream ended unexpectedly');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _fileName(headerValue) {
|
||||
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
const match = m[2] || m[3] || '';
|
||||
let filename = match.slice(match.lastIndexOf('\\') + 1);
|
||||
filename = filename.replace(/%22/g, '"');
|
||||
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
|
||||
return String.fromCharCode(code);
|
||||
});
|
||||
return filename;
|
||||
}
|
||||
|
||||
async function toFormData(Body, ct) {
|
||||
if (!/multipart/i.test(ct)) {
|
||||
throw new TypeError('Failed to fetch');
|
||||
}
|
||||
|
||||
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
|
||||
|
||||
if (!m) {
|
||||
throw new TypeError('no or bad content-type header, no multipart boundary');
|
||||
}
|
||||
|
||||
const parser = new MultipartParser(m[1] || m[2]);
|
||||
|
||||
let headerField;
|
||||
let headerValue;
|
||||
let entryValue;
|
||||
let entryName;
|
||||
let contentType;
|
||||
let filename;
|
||||
const entryChunks = [];
|
||||
const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
|
||||
|
||||
const onPartData = ui8a => {
|
||||
entryValue += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
const appendToFile = ui8a => {
|
||||
entryChunks.push(ui8a);
|
||||
};
|
||||
|
||||
const appendFileToFormData = () => {
|
||||
const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
|
||||
formData.append(entryName, file);
|
||||
};
|
||||
|
||||
const appendEntryToFormData = () => {
|
||||
formData.append(entryName, entryValue);
|
||||
};
|
||||
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
decoder.decode();
|
||||
|
||||
parser.onPartBegin = function () {
|
||||
parser.onPartData = onPartData;
|
||||
parser.onPartEnd = appendEntryToFormData;
|
||||
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
entryValue = '';
|
||||
entryName = '';
|
||||
contentType = '';
|
||||
filename = null;
|
||||
entryChunks.length = 0;
|
||||
};
|
||||
|
||||
parser.onHeaderField = function (ui8a) {
|
||||
headerField += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
parser.onHeaderValue = function (ui8a) {
|
||||
headerValue += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
parser.onHeaderEnd = function () {
|
||||
headerValue += decoder.decode();
|
||||
headerField = headerField.toLowerCase();
|
||||
|
||||
if (headerField === 'content-disposition') {
|
||||
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
|
||||
|
||||
if (m) {
|
||||
entryName = m[2] || m[3] || '';
|
||||
}
|
||||
|
||||
filename = _fileName(headerValue);
|
||||
|
||||
if (filename) {
|
||||
parser.onPartData = appendToFile;
|
||||
parser.onPartEnd = appendFileToFormData;
|
||||
}
|
||||
} else if (headerField === 'content-type') {
|
||||
contentType = headerValue;
|
||||
}
|
||||
|
||||
headerValue = '';
|
||||
headerField = '';
|
||||
};
|
||||
|
||||
for await (const chunk of Body) {
|
||||
parser.write(chunk);
|
||||
}
|
||||
|
||||
parser.end();
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
};
|
||||
8
packages/action/dist/index.js
vendored
8
packages/action/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -21,6 +21,7 @@
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/github": "5.1.1",
|
||||
"@tauri-apps/action-core": "0.3.1",
|
||||
"node-fetch": "3.2.6",
|
||||
"string-argv": "0.3.1",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as core from '@actions/core'
|
||||
import { join, resolve, dirname, basename } from 'path'
|
||||
import { existsSync } from 'fs'
|
||||
import uploadReleaseAssets from './upload-release-assets'
|
||||
import uploadVersionJSON from './upload-version-json'
|
||||
import createRelease from './create-release'
|
||||
import { getPackageJson, buildProject, getInfo, execCommand } from '@tauri-apps/action-core'
|
||||
import type { BuildOptions } from '@tauri-apps/action-core'
|
||||
@@ -57,7 +58,7 @@ async function run(): Promise<void> {
|
||||
throw new Error('No artifacts were found.')
|
||||
}
|
||||
|
||||
console.log(`Artifacts: ${artifacts}.`)
|
||||
console.log(`Artifacts: ${artifacts.map(a => a.path)}.`)
|
||||
|
||||
let releaseId: number
|
||||
if (tagName) {
|
||||
@@ -65,7 +66,7 @@ async function run(): Promise<void> {
|
||||
const templates = [
|
||||
{
|
||||
key: '__VERSION__',
|
||||
value: info.version
|
||||
value: info.version || packageJson.version
|
||||
}
|
||||
]
|
||||
|
||||
@@ -98,10 +99,10 @@ async function run(): Promise<void> {
|
||||
for (const artifact of artifacts) {
|
||||
// updater provide a .tar.gz, this will prevent duplicate and overwriting of
|
||||
// signed archive
|
||||
if (artifact.endsWith('.app') && !existsSync(`${artifact}.tar.gz`)) {
|
||||
await execCommand('tar', ['czf', `${artifact}.tar.gz`, '-C', dirname(artifact), basename(artifact)])
|
||||
artifacts[i] += '.tar.gz'
|
||||
} else if (artifact.endsWith('.app')) {
|
||||
if (artifact.path.endsWith('.app') && !existsSync(`${artifact.path}.tar.gz`)) {
|
||||
await execCommand('tar', ['czf', `${artifact}.tar.gz`, '-C', dirname(artifact.path), basename(artifact.path)])
|
||||
artifact[i].path += '.tar.gz'
|
||||
} else if (artifact.path.endsWith('.app')) {
|
||||
// we can't upload a directory
|
||||
artifacts.splice(i, 1);
|
||||
}
|
||||
@@ -109,6 +110,7 @@ async function run(): Promise<void> {
|
||||
}
|
||||
}
|
||||
await uploadReleaseAssets(releaseId, artifacts)
|
||||
await uploadVersionJSON({ version: info.version, notes: body, releaseId, artifacts });
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message)
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
import { getOctokit, context } from '@actions/github'
|
||||
import { Artifact } from '@tauri-apps/action-core'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getAssetName } from './utils'
|
||||
|
||||
export default async function uploadAssets(
|
||||
releaseId: number,
|
||||
assets: string[]
|
||||
assets: Artifact[]
|
||||
) {
|
||||
if (process.env.GITHUB_TOKEN === undefined) {
|
||||
throw new Error('GITHUB_TOKEN is required')
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
'.app.tar.gz.sig',
|
||||
'.app.tar.gz',
|
||||
'.dmg',
|
||||
'.AppImage.tar.gz.sig',
|
||||
'.AppImage.tar.gz',
|
||||
'.AppImage',
|
||||
'.deb',
|
||||
'.msi.zip.sig',
|
||||
'.msi.zip',
|
||||
'.msi'
|
||||
]
|
||||
|
||||
|
||||
const github = getOctokit(process.env.GITHUB_TOKEN)
|
||||
|
||||
@@ -36,29 +26,13 @@ export default async function uploadAssets(
|
||||
// Determine content-length for header to upload asset
|
||||
const contentLength = (filePath: string) => fs.statSync(filePath).size
|
||||
|
||||
for (const assetPath of assets) {
|
||||
for (const asset of assets) {
|
||||
const headers = {
|
||||
'content-type': 'application/zip',
|
||||
'content-length': contentLength(assetPath)
|
||||
'content-length': contentLength(asset.path)
|
||||
}
|
||||
|
||||
const basename = path.basename(assetPath)
|
||||
const exts = extensions.filter((s) => basename.includes(s))
|
||||
const ext = exts[0] || path.extname(assetPath)
|
||||
const filename = basename.replace(ext, '')
|
||||
|
||||
let arch = ''
|
||||
if (ext === '.app.tar.gz.sig' || ext === '.app.tar.gz') {
|
||||
arch = assetPath.includes('universal-apple-darwin')
|
||||
? '_universal'
|
||||
: assetPath.includes('aarch64-apple-darwin')
|
||||
? '_aarch64'
|
||||
: '_x64'
|
||||
}
|
||||
|
||||
const assetName = assetPath.includes(`${path.sep}debug${path.sep}`)
|
||||
? `${filename}-debug${arch}${ext}`
|
||||
: `${filename}${arch}${ext}`
|
||||
const assetName = getAssetName(asset.path)
|
||||
|
||||
const existingAsset = existingAssets.find((a) => a.name === assetName)
|
||||
if (existingAsset) {
|
||||
|
||||
94
packages/action/src/upload-version-json.ts
Normal file
94
packages/action/src/upload-version-json.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { getOctokit, context } from "@actions/github";
|
||||
import { resolve } from "path";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import uploadAssets from "./upload-release-assets";
|
||||
import fetch from "node-fetch";
|
||||
import { arch, platform } from "os";
|
||||
import { getAssetName } from "./utils";
|
||||
import { Artifact } from "@tauri-apps/action-core";
|
||||
|
||||
export default async function uploadVersionJSON({
|
||||
version,
|
||||
notes,
|
||||
releaseId,
|
||||
artifacts,
|
||||
}: {
|
||||
version: string;
|
||||
notes: string;
|
||||
releaseId: number;
|
||||
artifacts: Artifact[];
|
||||
}) {
|
||||
if (process.env.GITHUB_TOKEN === undefined) {
|
||||
throw new Error("GITHUB_TOKEN is required");
|
||||
}
|
||||
|
||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||
|
||||
const versionFilename = "latest.json";
|
||||
const versionFile = resolve(process.cwd(), versionFilename);
|
||||
const versionContent = {
|
||||
version,
|
||||
notes,
|
||||
pub_date: new Date().toISOString(),
|
||||
platforms: {},
|
||||
};
|
||||
|
||||
const assets = await github.rest.repos.listReleaseAssets({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
release_id: releaseId,
|
||||
});
|
||||
const asset = assets.data.find((e) => e.name === versionFilename);
|
||||
|
||||
if (asset) {
|
||||
versionContent.platforms = (
|
||||
(await (await fetch(asset.browser_download_url)).json()) as any
|
||||
).platforms;
|
||||
|
||||
// https://docs.github.com/en/rest/releases/assets#update-a-release-asset
|
||||
await github.rest.repos.deleteReleaseAsset({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
release_id: releaseId,
|
||||
asset_id: asset.id,
|
||||
});
|
||||
}
|
||||
|
||||
const sigFile = artifacts.find((s) => s.path.endsWith(".sig"));
|
||||
const assetNames = new Set(artifacts.map((p) => getAssetName(p.path)));
|
||||
const downloadUrl = assets.data
|
||||
.filter((e) => assetNames.has(e.name))
|
||||
.find(
|
||||
(s) => s.name.endsWith(".tar.gz") || s.name.endsWith(".zip")
|
||||
)?.browser_download_url;
|
||||
|
||||
let os = platform() as string;
|
||||
if (os === "win32") os = "windows";
|
||||
|
||||
if (downloadUrl && sigFile) {
|
||||
let arch = sigFile.arch;
|
||||
arch === 'amd64' || arch === 'x86_64' || arch === 'x64'
|
||||
? 'x86_64'
|
||||
: arch === 'x86' || arch === 'i386'
|
||||
? 'i686'
|
||||
: arch === 'arm'
|
||||
? 'armv7'
|
||||
: arch === 'arm64'
|
||||
? 'aarch64'
|
||||
: arch
|
||||
|
||||
// https://github.com/tauri-apps/tauri/blob/fd125f76d768099dc3d4b2d4114349ffc31ffac9/core/tauri/src/updater/core.rs#L856
|
||||
versionContent.platforms[`${os}-${arch}`] = {
|
||||
signature: readFileSync(sigFile.path).toString(),
|
||||
url: downloadUrl,
|
||||
};
|
||||
} else {
|
||||
const missing = downloadUrl ? 'Signature' : sigFile ? 'Asset' : 'Asset and signature'
|
||||
console.warn(`${missing} not found for the updater JSON.`)
|
||||
}
|
||||
|
||||
writeFileSync(versionFile, JSON.stringify(versionContent, null, 2));
|
||||
|
||||
console.log(`Uploading ${versionFile}...`);
|
||||
await uploadAssets(releaseId, [{ path: versionFile, arch: '' }]);
|
||||
}
|
||||
34
packages/action/src/utils.ts
Normal file
34
packages/action/src/utils.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import path from 'path';
|
||||
|
||||
const extensions = [
|
||||
'.app.tar.gz.sig',
|
||||
'.app.tar.gz',
|
||||
'.dmg',
|
||||
'.AppImage.tar.gz.sig',
|
||||
'.AppImage.tar.gz',
|
||||
'.AppImage',
|
||||
'.deb',
|
||||
'.msi.zip.sig',
|
||||
'.msi.zip',
|
||||
'.msi'
|
||||
]
|
||||
|
||||
export function getAssetName(assetPath: string) {
|
||||
const basename = path.basename(assetPath)
|
||||
const exts = extensions.filter((s) => basename.includes(s))
|
||||
const ext = exts[0] || path.extname(assetPath)
|
||||
const filename = basename.replace(ext, '')
|
||||
|
||||
let arch = ''
|
||||
if (ext === '.app.tar.gz.sig' || ext === '.app.tar.gz') {
|
||||
arch = assetPath.includes('universal-apple-darwin')
|
||||
? '_universal'
|
||||
: assetPath.includes('aarch64-apple-darwin')
|
||||
? '_aarch64'
|
||||
: '_x64'
|
||||
}
|
||||
|
||||
return assetPath.includes(`${path.sep}debug${path.sep}`)
|
||||
? `${filename}-debug${arch}${ext}`
|
||||
: `${filename}${arch}${ext}`
|
||||
}
|
||||
@@ -161,6 +161,11 @@ interface Info {
|
||||
wixLanguage: string | string[] | { [language: string]: unknown }
|
||||
}
|
||||
|
||||
export interface Artifact {
|
||||
path: string
|
||||
arch: string
|
||||
}
|
||||
|
||||
function _getJson5Config(contents: string): TauriConfig | null {
|
||||
try {
|
||||
const config = JSON5.parse(contents) as TauriConfig
|
||||
@@ -248,7 +253,7 @@ export async function buildProject(
|
||||
root: string,
|
||||
debug: boolean,
|
||||
{ configPath, distPath, iconPath, tauriScript, args, bundleIdentifier }: BuildOptions
|
||||
): Promise<string[]> {
|
||||
): Promise<Artifact[]> {
|
||||
return new Promise<Runner>((resolve, reject) => {
|
||||
if (tauriScript) {
|
||||
const [runnerCommand, ...runnerArgs] = tauriScript.split(' ')
|
||||
@@ -422,7 +427,7 @@ export async function buildProject(
|
||||
join(artifactsPath, `bundle/macos/${fileAppName}.app`),
|
||||
join(artifactsPath, `bundle/macos/${fileAppName}.app.tar.gz`),
|
||||
join(artifactsPath, `bundle/macos/${fileAppName}.app.tar.gz.sig`)
|
||||
]
|
||||
].map(path => ({ path, arch }))
|
||||
} else if (platform() === 'win32') {
|
||||
arch = arch.startsWith('i') ? 'x86' : 'x64'
|
||||
|
||||
@@ -457,7 +462,7 @@ export async function buildProject(
|
||||
)
|
||||
)
|
||||
})
|
||||
return artifacts
|
||||
return artifacts.map(path => ({ path, arch }))
|
||||
} else {
|
||||
const debianArch =
|
||||
arch === 'x64' || arch === 'x86_64'
|
||||
@@ -477,28 +482,40 @@ export async function buildProject(
|
||||
: arch
|
||||
|
||||
return [
|
||||
join(
|
||||
artifactsPath,
|
||||
`bundle/deb/${fileAppName}_${app.version}_${debianArch}.deb`
|
||||
),
|
||||
join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage`
|
||||
),
|
||||
join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz`
|
||||
),
|
||||
join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz.sig`
|
||||
)
|
||||
{
|
||||
path: join(
|
||||
artifactsPath,
|
||||
`bundle/deb/${fileAppName}_${app.version}_${debianArch}.deb`
|
||||
),
|
||||
arch: debianArch
|
||||
},
|
||||
{
|
||||
path: join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage`
|
||||
),
|
||||
arch: appImageArch
|
||||
},
|
||||
{
|
||||
path: join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz`
|
||||
),
|
||||
arch: appImageArch
|
||||
},
|
||||
{
|
||||
path: join(
|
||||
artifactsPath,
|
||||
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz.sig`
|
||||
),
|
||||
arch: appImageArch
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
.then((paths) => {
|
||||
console.log(`Expected artifacts paths:\n${paths.join('\n')}`)
|
||||
return paths.filter((p) => existsSync(p))
|
||||
.then((artifacts) => {
|
||||
console.log(`Expected artifacts paths:\n${artifacts.map(a => a.path).join('\n')}`)
|
||||
return artifacts.filter((p) => existsSync(p.path))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
39
yarn.lock
39
yarn.lock
@@ -639,6 +639,11 @@ ctrlc-windows@^2.0.0:
|
||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||
neon-cli "^0.8.1"
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
||||
|
||||
debug@4:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
@@ -790,6 +795,14 @@ fault@^1.0.0:
|
||||
dependencies:
|
||||
format "^0.2.0"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.5.tgz#0077bf5f3fcdbd9d75a0b5362f77dbb743489863"
|
||||
integrity sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||
@@ -824,6 +837,13 @@ format@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
|
||||
integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
@@ -1350,6 +1370,20 @@ neon-cli@^0.8.1:
|
||||
validate-npm-package-license "^3.0.4"
|
||||
validate-npm-package-name "^3.0.0"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.6.tgz#6d4627181697a9d9674aae0d61548e0d629b31b9"
|
||||
integrity sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
@@ -1968,6 +2002,11 @@ vfile@^4.0.0:
|
||||
unist-util-stringify-position "^2.0.0"
|
||||
vfile-message "^2.0.0"
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
||||
Reference in New Issue
Block a user