feat(release): auto-update releases/updates.json in release:push using manifest.update_url and chosen XPI
This commit is contained in:
		
					parent
					
						
							
								d68603eb5e
							
						
					
				
			
			
				commit
				
					
						2083780420
					
				
			
		
					 1 changed files with 62 additions and 1 deletions
				
			
		| 
						 | 
					@ -59,6 +59,7 @@ function run(cmd, secrets = []) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pkg = require(path.join(root, 'package.json'));
 | 
					const pkg = require(path.join(root, 'package.json'));
 | 
				
			||||||
 | 
					const manifest = require(path.join(root, 'manifest.json'));
 | 
				
			||||||
const version = pkg.version;
 | 
					const version = pkg.version;
 | 
				
			||||||
if (!version) {
 | 
					if (!version) {
 | 
				
			||||||
  console.error('package.json is missing version');
 | 
					  console.error('package.json is missing version');
 | 
				
			||||||
| 
						 | 
					@ -72,6 +73,12 @@ if (!fs.existsSync(artifactsDir) || !fs.statSync(artifactsDir).isDirectory()) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const files = fs.readdirSync(artifactsDir).filter(f => fs.statSync(path.join(artifactsDir, f)).isFile());
 | 
					const files = fs.readdirSync(artifactsDir).filter(f => fs.statSync(path.join(artifactsDir, f)).isFile());
 | 
				
			||||||
 | 
					const xpis = files.filter(f => f.toLowerCase().endsWith('.xpi'));
 | 
				
			||||||
 | 
					if (xpis.length === 0) {
 | 
				
			||||||
 | 
					  console.error(`No .xpi artifacts found in ${artifactsDir}`);
 | 
				
			||||||
 | 
					  process.exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const chosenXpi = xpis.sort()[0];
 | 
				
			||||||
if (files.length === 0) {
 | 
					if (files.length === 0) {
 | 
				
			||||||
  console.error(`No files found in ${artifactsDir}`);
 | 
					  console.error(`No files found in ${artifactsDir}`);
 | 
				
			||||||
  process.exit(1);
 | 
					  process.exit(1);
 | 
				
			||||||
| 
						 | 
					@ -93,9 +100,63 @@ if (!host || !user || !pass || !remoteDir) {
 | 
				
			||||||
if (!remoteDir.startsWith('/')) remoteDir = '/' + remoteDir;
 | 
					if (!remoteDir.startsWith('/')) remoteDir = '/' + remoteDir;
 | 
				
			||||||
if (remoteDir.endsWith('/')) remoteDir = remoteDir.slice(0, -1);
 | 
					if (remoteDir.endsWith('/')) remoteDir = remoteDir.slice(0, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Construct base URL
 | 
					// Construct base URL for FTP upload target
 | 
				
			||||||
const baseUrl = `${protocol}://${host}${port ? `:${port}` : ''}${remoteDir}`;
 | 
					const baseUrl = `${protocol}://${host}${port ? `:${port}` : ''}${remoteDir}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Prepare or update self-hosted updates.json before upload
 | 
				
			||||||
 | 
					function ensureUpdatesJson() {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const updatesPath = path.join(root, 'releases', 'updates.json');
 | 
				
			||||||
 | 
					    const examplePath = path.join(root, 'releases', 'updates.example.json');
 | 
				
			||||||
 | 
					    let data;
 | 
				
			||||||
 | 
					    if (fs.existsSync(updatesPath)) {
 | 
				
			||||||
 | 
					      data = JSON.parse(fs.readFileSync(updatesPath, 'utf8'));
 | 
				
			||||||
 | 
					    } else if (fs.existsSync(examplePath)) {
 | 
				
			||||||
 | 
					      data = JSON.parse(fs.readFileSync(examplePath, 'utf8'));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      data = { addons: {} };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const addonId = manifest?.applications?.gecko?.id;
 | 
				
			||||||
 | 
					    const updateUrl = manifest?.applications?.gecko?.update_url;
 | 
				
			||||||
 | 
					    if (!addonId || !updateUrl) {
 | 
				
			||||||
 | 
					      console.warn('Missing add-on id or update_url in manifest; skipping updates.json generation');
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Derive public base directory from update_url (strip trailing filename)
 | 
				
			||||||
 | 
					    let updatesBaseDir = updateUrl.replace(/\/?[^/]*$/, '');
 | 
				
			||||||
 | 
					    // Build public link to the uploaded XPI
 | 
				
			||||||
 | 
					    const publicLink = `${updatesBaseDir}/releases/${version}/${encodeURIComponent(chosenXpi)}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!data.addons) data.addons = {};
 | 
				
			||||||
 | 
					    if (!data.addons[addonId]) data.addons[addonId] = { updates: [] };
 | 
				
			||||||
 | 
					    const entry = { version: String(version), update_link: publicLink };
 | 
				
			||||||
 | 
					    // Try to preserve existing strict_min_version if present in latest entry
 | 
				
			||||||
 | 
					    const existingUpdates = data.addons[addonId].updates || [];
 | 
				
			||||||
 | 
					    let strictMin = '91.0';
 | 
				
			||||||
 | 
					    for (const u of existingUpdates) {
 | 
				
			||||||
 | 
					      if (u?.applications?.gecko?.strict_min_version) {
 | 
				
			||||||
 | 
					        strictMin = u.applications.gecko.strict_min_version;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    entry.applications = { gecko: { strict_min_version: strictMin } };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Replace or append the entry for this version
 | 
				
			||||||
 | 
					    const idx = existingUpdates.findIndex(u => String(u.version) === String(version));
 | 
				
			||||||
 | 
					    if (idx >= 0) existingUpdates[idx] = entry; else existingUpdates.push(entry);
 | 
				
			||||||
 | 
					    data.addons[addonId].updates = existingUpdates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs.writeFileSync(updatesPath, JSON.stringify(data, null, 2) + '\n', 'utf8');
 | 
				
			||||||
 | 
					    console.log(`Prepared releases/updates.json for version ${version}`);
 | 
				
			||||||
 | 
					  } catch (e) {
 | 
				
			||||||
 | 
					    console.warn('Warning: Failed to update releases/updates.json:', e.message);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ensureUpdatesJson();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
console.log(`Uploading ${files.length} file(s) from ${artifactsDir} to ${protocol}://${host}${port ? `:${port}` : ''}${remoteDir}/`);
 | 
					console.log(`Uploading ${files.length} file(s) from ${artifactsDir} to ${protocol}://${host}${port ? `:${port}` : ''}${remoteDir}/`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for (const file of files) {
 | 
					for (const file of files) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue