1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-30 10:36:35 +02:00
joplin/packages/app-desktop/tools/githubReleasesUtils.ts

119 lines
3.6 KiB
TypeScript
Raw Normal View History

import * as fs from 'fs';
import { createWriteStream } from 'fs';
import * as path from 'path';
import { pipeline } from 'stream/promises';
import axios from 'axios';
import { GitHubRelease, GitHubReleaseAsset } from '../utils/checkForUpdatesUtils';
export interface Context {
repo: string; // {owner}/{repo}
githubToken: string;
targetTag: string;
}
const apiBaseUrl = 'https://api.github.com/repos/';
const defaultApiHeaders = (context: Context) => ({
'User-Agent': 'Joplin',
'Authorization': `token ${context.githubToken}`,
'X-GitHub-Api-Version': '2022-11-28',
'Accept': 'application/vnd.github+json',
});
export const getTargetRelease = async (context: Context, targetTag: string): Promise<GitHubRelease> => {
console.log('Fetching releases...');
// Note: We need to fetch all releases, not just /releases/tag/tag-name-here.
// The latter doesn't include draft releases.
const result = await fetch(`${apiBaseUrl}${context.repo}/releases`, {
method: 'GET',
headers: defaultApiHeaders(context),
});
const releases = await result.json();
if (!result.ok) {
throw new Error(`Error fetching release: ${JSON.stringify(releases)}`);
}
for (const release of releases) {
if (release.tag_name === targetTag) {
return release;
}
}
throw new Error(`No release with tag ${targetTag} found!`);
};
// Download a file from Joplin Desktop releases
export const downloadFileFromGitHub = async (context: Context, asset: GitHubReleaseAsset, destinationDir: string) => {
const downloadPath = path.join(destinationDir, asset.name);
if (!fs.existsSync(destinationDir)) {
fs.mkdirSync(destinationDir);
}
/* eslint-disable no-console */
console.log(`Downloading ${asset.name} from ${asset.url} to ${downloadPath}`);
try {
const response = await axios({
method: 'get',
url: asset.url,
responseType: 'stream',
headers: {
...defaultApiHeaders(context),
'Accept': 'application/octet-stream',
},
});
if (response.status < 200 || response.status >= 300) {
throw new Error(`Failed to download file: Status Code ${response.status}`);
}
await pipeline(response.data, createWriteStream(downloadPath));
console.log('Download successful!');
/* eslint-enable no-console */
return downloadPath;
} catch (error) {
throw new Error('Download not successful.');
}
};
export const updateReleaseAsset = async (context: Context, assetUrl: string, newName: string) => {
console.log('Updating asset with URL', assetUrl, 'to have name, ', newName);
// See https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28#update-a-release-asset
const result = await fetch(assetUrl, {
method: 'PATCH',
headers: defaultApiHeaders(context),
body: JSON.stringify({
name: newName,
}),
});
if (!result.ok) {
throw new Error(`Unable to update release asset: ${await result.text()}`);
}
};
export const uploadReleaseAsset = async (context: Context, release: GitHubRelease, filePath: string): Promise<void> => {
console.log(`Uploading file from ${filePath} to release ${release.tag_name}`);
const fileContent = fs.readFileSync(filePath);
const fileName = path.basename(filePath);
const uploadUrl = `https://uploads.github.com/repos/${context.repo}/releases/${release.id}/assets?name=${encodeURIComponent(fileName)}`;
const response = await fetch(uploadUrl, {
method: 'POST',
headers: {
...defaultApiHeaders(context),
'Content-Type': 'application/octet-stream',
},
body: fileContent,
});
if (!response.ok) {
throw new Error(`Failed to upload asset: ${await response.text()}`);
} else {
console.log(`${fileName} uploaded successfully.`);
}
};