mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-27 00:06:30 +01:00 
			
		
		
		
	feat(scripts): add script used to migrate releases
This commit is contained in:
		
							
								
								
									
										125
									
								
								scripts/migrate-releases.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								scripts/migrate-releases.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | // 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); | ||||||
|  | }); | ||||||
		Reference in New Issue
	
	Block a user