mirror of
https://github.com/zadam/trilium.git
synced 2025-10-06 05:25:37 +08:00
125 lines
3.6 KiB
JavaScript
125 lines
3.6 KiB
JavaScript
// migrate-releases.js
|
|
const fetch = require('node-fetch').default;
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const TOKEN = process.env.GITHUB_TOKEN;
|
|
const SOURCE_REPO = 'TriliumNext/Notes';
|
|
const DEST_REPO = 'TriliumNext/trilium';
|
|
|
|
if (!TOKEN) {
|
|
console.error('Error: Please set your GITHUB_TOKEN environment variable');
|
|
process.exit(1);
|
|
}
|
|
|
|
const headers = {
|
|
Authorization: `token ${TOKEN}`,
|
|
Accept: 'application/vnd.github.v3+json',
|
|
};
|
|
|
|
async function getReleases(repo) {
|
|
let releases = [];
|
|
let page = 1;
|
|
|
|
while (true) {
|
|
console.log("Got fetch", fetch);
|
|
const res = await fetch(
|
|
`https://api.github.com/repos/${repo}/releases?per_page=100&page=${page}`,
|
|
{ headers }
|
|
);
|
|
if (!res.ok) throw new Error(`Failed to get releases: ${res.status} ${res.statusText}`);
|
|
|
|
const data = await res.json();
|
|
if (data.length === 0) break;
|
|
|
|
releases = releases.concat(data);
|
|
page++;
|
|
}
|
|
return releases;
|
|
}
|
|
|
|
async function createRelease(repo, release) {
|
|
// Strip id, url etc. fields to prepare payload
|
|
const payload = {
|
|
tag_name: release.tag_name,
|
|
target_commitish: "main",
|
|
name: release.name,
|
|
body: release.body,
|
|
draft: release.draft,
|
|
prerelease: release.prerelease,
|
|
};
|
|
|
|
const res = await fetch(`https://api.github.com/repos/${repo}/releases`, {
|
|
method: 'POST',
|
|
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
console.log(`POST to https://api.github.com/repos/${repo}/releases with payload:`, payload);
|
|
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(`Failed to create release: ${res.status} ${res.statusText} - ${text}`);
|
|
}
|
|
|
|
return await res.json();
|
|
}
|
|
|
|
async function downloadAsset(assetUrl, filename) {
|
|
const res = await fetch(assetUrl, { headers: { ...headers, Accept: 'application/octet-stream' } });
|
|
if (!res.ok) throw new Error(`Failed to download asset: ${res.status} ${res.statusText}`);
|
|
const buffer = await res.buffer();
|
|
fs.writeFileSync(filename, buffer);
|
|
}
|
|
|
|
async function uploadAsset(uploadUrl, filepath) {
|
|
const filename = path.basename(filepath);
|
|
const stats = fs.statSync(filepath);
|
|
const res = await fetch(`${uploadUrl}?name=${encodeURIComponent(filename)}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `token ${TOKEN}`,
|
|
'Content-Type': 'application/octet-stream',
|
|
'Content-Length': stats.size,
|
|
},
|
|
body: fs.createReadStream(filepath),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(`Failed to upload asset: ${res.status} ${res.statusText} - ${text}`);
|
|
}
|
|
|
|
return await res.json();
|
|
}
|
|
|
|
async function migrate() {
|
|
console.log(`Fetching releases from ${SOURCE_REPO}...`);
|
|
const releases = await getReleases(SOURCE_REPO);
|
|
console.log(`Found ${releases.length} releases.`);
|
|
|
|
releases.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
|
|
|
|
for (const release of releases) {
|
|
console.log(`Migrating release: ${release.name} (${release.tag_name})`);
|
|
const newRelease = await createRelease(DEST_REPO, release);
|
|
|
|
// Download and upload assets if any
|
|
for (const asset of release.assets) {
|
|
const tempFile = path.join(__dirname, asset.name);
|
|
console.log(`Downloading asset ${asset.name}...`);
|
|
await downloadAsset(asset.url, tempFile);
|
|
|
|
console.log(`Uploading asset ${asset.name}...`);
|
|
await uploadAsset(newRelease.upload_url.replace('{?name,label}', ''), tempFile);
|
|
|
|
fs.unlinkSync(tempFile); // Clean up temp file
|
|
}
|
|
}
|
|
console.log('Migration complete!');
|
|
}
|
|
|
|
migrate().catch((err) => {
|
|
console.error('Migration failed:', err);
|
|
process.exit(1);
|
|
});
|