Change release - don't publish the XPI but a readme instead
This commit is contained in:
@@ -9,61 +9,66 @@ from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
MANIFEST_PATH = ROOT / 'webextension' / 'manifest.json'
|
||||
FRONTEND_VERSION_PATH = ROOT / 'frontend' / 'version.json'
|
||||
SETTINGS_PATH = ROOT / 'backend' / 'app' / 'core' / 'config.py'
|
||||
UPDATES_PATH = ROOT / 'webextension' / 'updates.json'
|
||||
SIGNED_DIR = ROOT / 'XPI' / 'signed'
|
||||
VERSION_RE = re.compile(r'\d+\.\d+\.\d+')
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
raise SystemExit(f'release validation failed: {message}')
|
||||
|
||||
|
||||
def version_key(version: str) -> tuple[int, int, int]:
|
||||
return tuple(int(part) for part in version.split('.'))
|
||||
|
||||
|
||||
def find_latest_signed_xpi() -> tuple[str, Path]:
|
||||
candidates = []
|
||||
for xpi_path in SIGNED_DIR.glob('LinkLog-*.xpi'):
|
||||
match = re.fullmatch(r'LinkLog-(\d+\.\d+\.\d+)\.xpi', xpi_path.name)
|
||||
if match:
|
||||
candidates.append((match.group(1), xpi_path))
|
||||
if not candidates:
|
||||
fail(f'no signed plugin artifacts found in {SIGNED_DIR.relative_to(ROOT)}')
|
||||
return max(candidates, key=lambda candidate: version_key(candidate[0]))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
manifest = json.loads(MANIFEST_PATH.read_text())
|
||||
extension_version = manifest.get('version')
|
||||
if not isinstance(extension_version, str) or not re.fullmatch(r'\d+\.\d+\.\d+', extension_version):
|
||||
fail('webextension/manifest.json has no valid three-part version')
|
||||
|
||||
frontend_version = json.loads(FRONTEND_VERSION_PATH.read_text()).get('version')
|
||||
if frontend_version != extension_version:
|
||||
fail(f'frontend version {frontend_version} does not match extension version {extension_version}')
|
||||
|
||||
gecko_settings = manifest.get('browser_specific_settings', {}).get('gecko', {})
|
||||
data_permissions = gecko_settings.get('data_collection_permissions')
|
||||
if data_permissions != {'required': ['websiteActivity'], 'optional': []}:
|
||||
fail('Firefox data_collection_permissions must require websiteActivity and have no optional categories')
|
||||
|
||||
settings = SETTINGS_PATH.read_text()
|
||||
match = re.search(r"version: str = os\.getenv\('LINKLOG_VERSION', '([^']+)'\)", settings)
|
||||
if not match:
|
||||
fail('backend version default could not be found')
|
||||
backend_version = match.group(1)
|
||||
if backend_version != extension_version:
|
||||
fail(f'backend version {backend_version} does not match extension version {extension_version}')
|
||||
if not VERSION_RE.fullmatch(backend_version):
|
||||
fail(f'backend version {backend_version} is not a valid three-part version')
|
||||
|
||||
xpi_path = SIGNED_DIR / f'LinkLog-{extension_version}.xpi'
|
||||
if not xpi_path.is_file():
|
||||
fail(f'missing manually signed artifact: {xpi_path.relative_to(ROOT)}')
|
||||
extension_version, xpi_path = find_latest_signed_xpi()
|
||||
with zipfile.ZipFile(xpi_path) as archive:
|
||||
try:
|
||||
packaged_manifest = json.loads(archive.read('manifest.json'))
|
||||
except KeyError:
|
||||
fail('signed XPI does not contain manifest.json')
|
||||
if packaged_manifest.get('version') != extension_version:
|
||||
fail('signed XPI manifest version does not match webextension/manifest.json')
|
||||
fail('signed XPI manifest version does not match its filename')
|
||||
gecko_settings = packaged_manifest.get('browser_specific_settings', {}).get('gecko', {})
|
||||
data_permissions = gecko_settings.get('data_collection_permissions')
|
||||
if data_permissions != {'required': ['websiteActivity'], 'optional': []}:
|
||||
fail('Firefox data_collection_permissions must require websiteActivity and have no optional categories')
|
||||
if archive.testzip() is not None:
|
||||
fail('signed XPI contains a corrupt member')
|
||||
|
||||
updates = json.loads(UPDATES_PATH.read_text())
|
||||
addon_id = gecko_settings['id']
|
||||
update_entries = updates.get('addons', {}).get(addon_id, {}).get('updates', [])
|
||||
if not any(entry.get('version') == extension_version for entry in update_entries):
|
||||
fail(f'webextension/updates.json has no update entry for {extension_version}')
|
||||
signed_xpi = xpi_path.relative_to(ROOT)
|
||||
if len(sys.argv) == 3 and sys.argv[1] == '--github-output':
|
||||
with Path(sys.argv[2]).open('a') as output:
|
||||
print(f'backend_version={backend_version}', file=output)
|
||||
print(f'plugin_version={extension_version}', file=output)
|
||||
print(f'signed_xpi={signed_xpi}', file=output)
|
||||
elif len(sys.argv) != 1:
|
||||
fail('usage: validate_release.py [--github-output <path>]')
|
||||
|
||||
print(f'validated LinkLog release {frontend_version}')
|
||||
print(f'xpi={xpi_path.relative_to(ROOT)}')
|
||||
print(f'validated LinkLog backend release {backend_version}')
|
||||
print(f'plugin_version={extension_version}')
|
||||
print(f'signed_xpi={signed_xpi}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user