mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
Move to nodejs for publishing scripts
This commit is contained in:
parent
0e821284ab
commit
f9ee5e2a64
6 changed files with 188 additions and 422 deletions
190
dist/chromium/publish-beta.py
vendored
190
dist/chromium/publish-beta.py
vendored
|
|
@ -1,190 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from string import Template
|
|
||||||
|
|
||||||
# - Download target (raw) uBlock0.chromium.zip from GitHub
|
|
||||||
# - This is referred to as "raw" package
|
|
||||||
# - This will fail if not a dev build
|
|
||||||
# - Upload uBlock0.chromium.zip to Chrome store
|
|
||||||
# - Publish uBlock0.chromium.zip to Chrome store
|
|
||||||
|
|
||||||
# Find path to project root
|
|
||||||
projdir = os.path.split(os.path.abspath(__file__))[0]
|
|
||||||
while not os.path.isdir(os.path.join(projdir, '.git')):
|
|
||||||
projdir = os.path.normpath(os.path.join(projdir, '..'))
|
|
||||||
|
|
||||||
# We need a version string to work with
|
|
||||||
if len(sys.argv) >= 2 and sys.argv[1]:
|
|
||||||
version = sys.argv[1]
|
|
||||||
else:
|
|
||||||
version = input('Github release version: ')
|
|
||||||
version.strip()
|
|
||||||
if not re.search('^\d+\.\d+\.\d+(b|rc)\d+$', version):
|
|
||||||
print('Error: Invalid version string.')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
cs_extension_id = 'cgbcahbpdhpcegmbfconppldiemgcoii'
|
|
||||||
tmpdir = tempfile.TemporaryDirectory()
|
|
||||||
raw_zip_filename = 'uBlock0_' + version + '.chromium.zip'
|
|
||||||
raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename)
|
|
||||||
github_owner = 'gorhill'
|
|
||||||
github_repo = 'uBlock'
|
|
||||||
|
|
||||||
# Load/save auth secrets
|
|
||||||
# The tmp directory is excluded from git
|
|
||||||
ubo_secrets = dict()
|
|
||||||
ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets')
|
|
||||||
if os.path.isfile(ubo_secrets_filename):
|
|
||||||
with open(ubo_secrets_filename) as f:
|
|
||||||
ubo_secrets = json.load(f)
|
|
||||||
|
|
||||||
def input_secret(prompt, token):
|
|
||||||
if token in ubo_secrets:
|
|
||||||
prompt += ' ✔'
|
|
||||||
prompt += ': '
|
|
||||||
value = input(prompt).strip()
|
|
||||||
if len(value) == 0:
|
|
||||||
if token not in ubo_secrets:
|
|
||||||
print('Token error:', token)
|
|
||||||
exit(1)
|
|
||||||
value = ubo_secrets[token]
|
|
||||||
elif token not in ubo_secrets or value != ubo_secrets[token]:
|
|
||||||
ubo_secrets[token] = value
|
|
||||||
exists = os.path.isfile(ubo_secrets_filename)
|
|
||||||
with open(ubo_secrets_filename, 'w') as f:
|
|
||||||
json.dump(ubo_secrets, f, indent=2)
|
|
||||||
if not exists:
|
|
||||||
os.chmod(ubo_secrets_filename, 0o600)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
# GitHub API token
|
|
||||||
github_token = input_secret('Github token', 'github_token')
|
|
||||||
github_auth = 'token ' + github_token
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get metadata from GitHub about the release
|
|
||||||
#
|
|
||||||
|
|
||||||
# https://developer.github.com/v3/repos/releases/#get-a-single-release
|
|
||||||
print('Downloading release info from GitHub...')
|
|
||||||
release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version)
|
|
||||||
headers = { 'Authorization': github_auth, }
|
|
||||||
response = requests.get(release_info_url, headers=headers)
|
|
||||||
if response.status_code != 200:
|
|
||||||
print('Error: Release not found: {0}'.format(response.status_code))
|
|
||||||
exit(1)
|
|
||||||
release_info = response.json()
|
|
||||||
|
|
||||||
#
|
|
||||||
# Extract URL to raw package from metadata
|
|
||||||
#
|
|
||||||
|
|
||||||
# Find url for uBlock0.chromium.zip
|
|
||||||
raw_zip_url = ''
|
|
||||||
for asset in release_info['assets']:
|
|
||||||
if asset['name'] == raw_zip_filename:
|
|
||||||
raw_zip_url = asset['url']
|
|
||||||
if len(raw_zip_url) == 0:
|
|
||||||
print('Error: Release asset URL not found')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Download raw package from GitHub
|
|
||||||
#
|
|
||||||
|
|
||||||
# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
|
||||||
print('Downloading raw zip package from GitHub...')
|
|
||||||
headers = {
|
|
||||||
'Authorization': github_auth,
|
|
||||||
'Accept': 'application/octet-stream',
|
|
||||||
}
|
|
||||||
response = requests.get(raw_zip_url, headers=headers)
|
|
||||||
# Redirections are transparently handled:
|
|
||||||
# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history
|
|
||||||
if response.status_code != 200:
|
|
||||||
print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code))
|
|
||||||
exit(1)
|
|
||||||
with open(raw_zip_filepath, 'wb') as f:
|
|
||||||
f.write(response.content)
|
|
||||||
print('Downloaded raw package saved as {0}'.format(raw_zip_filepath))
|
|
||||||
|
|
||||||
#
|
|
||||||
# Upload to Chrome store
|
|
||||||
#
|
|
||||||
|
|
||||||
# Auth tokens
|
|
||||||
cs_id = input_secret('Chrome store id', 'cs_id')
|
|
||||||
cs_secret = input_secret('Chrome store secret', 'cs_secret')
|
|
||||||
cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh')
|
|
||||||
|
|
||||||
print('Uploading to Chrome store...')
|
|
||||||
with open(raw_zip_filepath, 'rb') as f:
|
|
||||||
print('Generating access token...')
|
|
||||||
auth_url = 'https://accounts.google.com/o/oauth2/token'
|
|
||||||
auth_payload = {
|
|
||||||
'client_id': cs_id,
|
|
||||||
'client_secret': cs_secret,
|
|
||||||
'grant_type': 'refresh_token',
|
|
||||||
'refresh_token': cs_refresh,
|
|
||||||
}
|
|
||||||
auth_response = requests.post(auth_url, data=auth_payload)
|
|
||||||
if auth_response.status_code != 200:
|
|
||||||
print('Error: Auth failed -- server error {0}'.format(auth_response.status_code))
|
|
||||||
print(auth_response.text)
|
|
||||||
exit(1)
|
|
||||||
response_dict = auth_response.json()
|
|
||||||
if 'access_token' not in response_dict:
|
|
||||||
print('Error: Auth failed -- no access token')
|
|
||||||
exit(1)
|
|
||||||
# Prepare access token
|
|
||||||
cs_auth = 'Bearer ' + response_dict['access_token']
|
|
||||||
headers = {
|
|
||||||
'Authorization': cs_auth,
|
|
||||||
'x-goog-api-version': '2',
|
|
||||||
}
|
|
||||||
# Upload
|
|
||||||
print('Uploading package...')
|
|
||||||
upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id)
|
|
||||||
upload_response = requests.put(upload_url, headers=headers, data=f)
|
|
||||||
f.close()
|
|
||||||
if upload_response.status_code != 200:
|
|
||||||
print('Upload failed -- server error {0}'.format(upload_response.status_code))
|
|
||||||
print(upload_response.text)
|
|
||||||
exit(1)
|
|
||||||
response_dict = upload_response.json();
|
|
||||||
if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS':
|
|
||||||
print('Upload failed -- server error {0}'.format(response_dict['uploadState']))
|
|
||||||
exit(1)
|
|
||||||
print('Upload succeeded.')
|
|
||||||
# Publish
|
|
||||||
print('Publishing package...')
|
|
||||||
publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id)
|
|
||||||
headers = {
|
|
||||||
'Authorization': cs_auth,
|
|
||||||
'x-goog-api-version': '2',
|
|
||||||
'Content-Length': '0',
|
|
||||||
}
|
|
||||||
publish_response = requests.post(publish_url, headers=headers)
|
|
||||||
if publish_response.status_code != 200:
|
|
||||||
print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code))
|
|
||||||
exit(1)
|
|
||||||
response_dict = publish_response.json();
|
|
||||||
if 'status' not in response_dict or response_dict['status'][0] != 'OK':
|
|
||||||
print('Publishing failed -- server error {0}'.format(response_dict['status']))
|
|
||||||
exit(1)
|
|
||||||
print('Publishing succeeded.')
|
|
||||||
|
|
||||||
print('All done.')
|
|
||||||
|
|
@ -26,8 +26,7 @@ import process from 'node:process';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const secrets = await ghapi.getSecrets();
|
const githubAuth = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||||
const githubAuth = `Bearer ${secrets.github_token}`;
|
|
||||||
const commandLineArgs = ghapi.commandLineArgs;
|
const commandLineArgs = ghapi.commandLineArgs;
|
||||||
const githubOwner = commandLineArgs.ghowner;
|
const githubOwner = commandLineArgs.ghowner;
|
||||||
const githubRepo = commandLineArgs.ghrepo;
|
const githubRepo = commandLineArgs.ghrepo;
|
||||||
|
|
@ -42,10 +41,10 @@ async function publishToCWS(filePath) {
|
||||||
const authURL = 'https://accounts.google.com/o/oauth2/token';
|
const authURL = 'https://accounts.google.com/o/oauth2/token';
|
||||||
const authRequest = new Request(authURL, {
|
const authRequest = new Request(authURL, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
client_id: secrets.cs_id,
|
client_id: process.env.CWS_ID,
|
||||||
client_secret: secrets.cs_secret,
|
client_secret: process.env.CWS_SECRET,
|
||||||
grant_type: 'refresh_token',
|
grant_type: 'refresh_token',
|
||||||
refresh_token: secrets.cs_refresh,
|
refresh_token: process.env.CWS_REFRESH,
|
||||||
}),
|
}),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
|
|
@ -61,9 +60,6 @@ async function publishToCWS(filePath) {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const cwsAuth = `Bearer ${responseDict.access_token}`;
|
const cwsAuth = `Bearer ${responseDict.access_token}`;
|
||||||
if ( responseDict.refresh_token ) {
|
|
||||||
secrets.cs_refresh = responseDict.refresh_token
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read package
|
// Read package
|
||||||
const data = await fs.readFile(filePath);
|
const data = await fs.readFile(filePath);
|
||||||
|
|
@ -86,7 +82,7 @@ async function publishToCWS(filePath) {
|
||||||
}
|
}
|
||||||
const uploadDict = await uploadResponse.json();
|
const uploadDict = await uploadResponse.json();
|
||||||
if ( uploadDict.uploadState !== 'SUCCESS' ) {
|
if ( uploadDict.uploadState !== 'SUCCESS' ) {
|
||||||
console.error(`Upload failed -- server error ${uploadDict['uploadState']}`);
|
console.error(`Upload failed -- server error ${JSON.stringify(uploadDict)}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log('Upload succeeded.')
|
console.log('Upload succeeded.')
|
||||||
|
|
@ -121,7 +117,6 @@ async function publishToCWS(filePath) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if ( secrets === undefined ) { return 'Need secrets'; }
|
|
||||||
if ( githubOwner === '' ) { return 'Need GitHub owner'; }
|
if ( githubOwner === '' ) { return 'Need GitHub owner'; }
|
||||||
if ( githubRepo === '' ) { return 'Need GitHub repo'; }
|
if ( githubRepo === '' ) { return 'Need GitHub repo'; }
|
||||||
|
|
||||||
190
dist/chromium/publish-stable.py
vendored
190
dist/chromium/publish-stable.py
vendored
|
|
@ -1,190 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from string import Template
|
|
||||||
|
|
||||||
# - Download target (raw) uBlock0.chromium.zip from GitHub
|
|
||||||
# - This is referred to as "raw" package
|
|
||||||
# - This will fail if not a dev build
|
|
||||||
# - Upload uBlock0.chromium.zip to Chrome store
|
|
||||||
# - Publish uBlock0.chromium.zip to Chrome store
|
|
||||||
|
|
||||||
# Find path to project root
|
|
||||||
projdir = os.path.split(os.path.abspath(__file__))[0]
|
|
||||||
while not os.path.isdir(os.path.join(projdir, '.git')):
|
|
||||||
projdir = os.path.normpath(os.path.join(projdir, '..'))
|
|
||||||
|
|
||||||
# We need a version string to work with
|
|
||||||
if len(sys.argv) >= 2 and sys.argv[1]:
|
|
||||||
version = sys.argv[1]
|
|
||||||
else:
|
|
||||||
version = input('Github release version: ')
|
|
||||||
version.strip()
|
|
||||||
if not re.search('^\d+\.\d+\.\d+$', version):
|
|
||||||
print('Error: Invalid version string.')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
cs_extension_id = 'cjpalhdlnbpafiamejdnhcphjbkeiagm'
|
|
||||||
tmpdir = tempfile.TemporaryDirectory()
|
|
||||||
raw_zip_filename = 'uBlock0_' + version + '.chromium.zip'
|
|
||||||
raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename)
|
|
||||||
github_owner = 'gorhill'
|
|
||||||
github_repo = 'uBlock'
|
|
||||||
|
|
||||||
# Load/save auth secrets
|
|
||||||
# The tmp directory is excluded from git
|
|
||||||
ubo_secrets = dict()
|
|
||||||
ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets')
|
|
||||||
if os.path.isfile(ubo_secrets_filename):
|
|
||||||
with open(ubo_secrets_filename) as f:
|
|
||||||
ubo_secrets = json.load(f)
|
|
||||||
|
|
||||||
def input_secret(prompt, token):
|
|
||||||
if token in ubo_secrets:
|
|
||||||
prompt += ' ✔'
|
|
||||||
prompt += ': '
|
|
||||||
value = input(prompt).strip()
|
|
||||||
if len(value) == 0:
|
|
||||||
if token not in ubo_secrets:
|
|
||||||
print('Token error:', token)
|
|
||||||
exit(1)
|
|
||||||
value = ubo_secrets[token]
|
|
||||||
elif token not in ubo_secrets or value != ubo_secrets[token]:
|
|
||||||
ubo_secrets[token] = value
|
|
||||||
exists = os.path.isfile(ubo_secrets_filename)
|
|
||||||
with open(ubo_secrets_filename, 'w') as f:
|
|
||||||
json.dump(ubo_secrets, f, indent=2)
|
|
||||||
if not exists:
|
|
||||||
os.chmod(ubo_secrets_filename, 0o600)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
# GitHub API token
|
|
||||||
github_token = input_secret('Github token', 'github_token')
|
|
||||||
github_auth = 'token ' + github_token
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get metadata from GitHub about the release
|
|
||||||
#
|
|
||||||
|
|
||||||
# https://developer.github.com/v3/repos/releases/#get-a-single-release
|
|
||||||
print('Downloading release info from GitHub...')
|
|
||||||
release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version)
|
|
||||||
headers = { 'Authorization': github_auth, }
|
|
||||||
response = requests.get(release_info_url, headers=headers)
|
|
||||||
if response.status_code != 200:
|
|
||||||
print('Error: Release not found: {0}'.format(response.status_code))
|
|
||||||
exit(1)
|
|
||||||
release_info = response.json()
|
|
||||||
|
|
||||||
#
|
|
||||||
# Extract URL to raw package from metadata
|
|
||||||
#
|
|
||||||
|
|
||||||
# Find url for uBlock0.chromium.zip
|
|
||||||
raw_zip_url = ''
|
|
||||||
for asset in release_info['assets']:
|
|
||||||
if asset['name'] == raw_zip_filename:
|
|
||||||
raw_zip_url = asset['url']
|
|
||||||
if len(raw_zip_url) == 0:
|
|
||||||
print('Error: Release asset URL not found')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Download raw package from GitHub
|
|
||||||
#
|
|
||||||
|
|
||||||
# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
|
||||||
print('Downloading raw zip package from GitHub...')
|
|
||||||
headers = {
|
|
||||||
'Authorization': github_auth,
|
|
||||||
'Accept': 'application/octet-stream',
|
|
||||||
}
|
|
||||||
response = requests.get(raw_zip_url, headers=headers)
|
|
||||||
# Redirections are transparently handled:
|
|
||||||
# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history
|
|
||||||
if response.status_code != 200:
|
|
||||||
print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code))
|
|
||||||
exit(1)
|
|
||||||
with open(raw_zip_filepath, 'wb') as f:
|
|
||||||
f.write(response.content)
|
|
||||||
print('Downloaded raw package saved as {0}'.format(raw_zip_filepath))
|
|
||||||
|
|
||||||
#
|
|
||||||
# Upload to Chrome store
|
|
||||||
#
|
|
||||||
|
|
||||||
# Auth tokens
|
|
||||||
cs_id = input_secret('Chrome store id', 'cs_id')
|
|
||||||
cs_secret = input_secret('Chrome store secret', 'cs_secret')
|
|
||||||
cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh')
|
|
||||||
|
|
||||||
print('Uploading to Chrome store...')
|
|
||||||
with open(raw_zip_filepath, 'rb') as f:
|
|
||||||
print('Generating access token...')
|
|
||||||
auth_url = 'https://accounts.google.com/o/oauth2/token'
|
|
||||||
auth_payload = {
|
|
||||||
'client_id': cs_id,
|
|
||||||
'client_secret': cs_secret,
|
|
||||||
'grant_type': 'refresh_token',
|
|
||||||
'refresh_token': cs_refresh,
|
|
||||||
}
|
|
||||||
auth_response = requests.post(auth_url, data=auth_payload)
|
|
||||||
if auth_response.status_code != 200:
|
|
||||||
print('Error: Auth failed -- server error {0}'.format(auth_response.status_code))
|
|
||||||
print(auth_response.text)
|
|
||||||
exit(1)
|
|
||||||
response_dict = auth_response.json()
|
|
||||||
if 'access_token' not in response_dict:
|
|
||||||
print('Error: Auth failed -- no access token')
|
|
||||||
exit(1)
|
|
||||||
# Prepare access token
|
|
||||||
cs_auth = 'Bearer ' + response_dict['access_token']
|
|
||||||
headers = {
|
|
||||||
'Authorization': cs_auth,
|
|
||||||
'x-goog-api-version': '2',
|
|
||||||
}
|
|
||||||
# Upload
|
|
||||||
print('Uploading package...')
|
|
||||||
upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id)
|
|
||||||
upload_response = requests.put(upload_url, headers=headers, data=f)
|
|
||||||
f.close()
|
|
||||||
if upload_response.status_code != 200:
|
|
||||||
print('Upload failed -- server error {0}'.format(upload_response.status_code))
|
|
||||||
print(upload_response.text)
|
|
||||||
exit(1)
|
|
||||||
response_dict = upload_response.json();
|
|
||||||
if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS':
|
|
||||||
print('Upload failed -- server error {0}'.format(response_dict['uploadState']))
|
|
||||||
exit(1)
|
|
||||||
print('Upload succeeded.')
|
|
||||||
# Publish
|
|
||||||
print('Publishing package...')
|
|
||||||
publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id)
|
|
||||||
headers = {
|
|
||||||
'Authorization': cs_auth,
|
|
||||||
'x-goog-api-version': '2',
|
|
||||||
'Content-Length': '0',
|
|
||||||
}
|
|
||||||
publish_response = requests.post(publish_url, headers=headers)
|
|
||||||
if publish_response.status_code != 200:
|
|
||||||
print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code))
|
|
||||||
exit(1)
|
|
||||||
response_dict = publish_response.json();
|
|
||||||
if 'status' not in response_dict or response_dict['status'][0] != 'OK':
|
|
||||||
print('Publishing failed -- server error {0}'.format(response_dict['status']))
|
|
||||||
exit(1)
|
|
||||||
print('Publishing succeeded.')
|
|
||||||
|
|
||||||
print('All done.')
|
|
||||||
175
dist/edge/publish-edge.js
vendored
Normal file
175
dist/edge/publish-edge.js
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a comprehensive, efficient content blocker
|
||||||
|
Copyright (C) 2025-present Raymond Hill
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
|
||||||
|
Home: https://github.com/gorhill/uBlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'node:fs/promises';
|
||||||
|
import * as ghapi from '../github-api.js';
|
||||||
|
import path from 'node:path';
|
||||||
|
import process from 'node:process';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const githubAuth = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||||
|
const commandLineArgs = ghapi.commandLineArgs;
|
||||||
|
const githubOwner = commandLineArgs.ghowner;
|
||||||
|
const githubRepo = commandLineArgs.ghrepo;
|
||||||
|
const githubTag = commandLineArgs.ghtag;
|
||||||
|
const edgeId = commandLineArgs.edgeid;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
async function sleep(seconds) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, seconds * 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
async function publishToEdgeStore(filePath) {
|
||||||
|
const edgeApiKey = process.env.EDGE_APIKEY;
|
||||||
|
const edgeClientId = process.env.EDGE_CLIENTID;
|
||||||
|
const uploadURL = `https://api.addons.microsoftedge.microsoft.com/v1/products/${edgeId}/submissions/draft/package`;
|
||||||
|
|
||||||
|
// Read package
|
||||||
|
const data = await fs.readFile(filePath);
|
||||||
|
|
||||||
|
// Upload
|
||||||
|
console.log(`Uploading package to ${uploadURL}`);
|
||||||
|
const uploadRequest = new Request(uploadURL, {
|
||||||
|
body: data,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `ApiKey ${edgeApiKey}`,
|
||||||
|
'X-ClientID': edgeClientId,
|
||||||
|
'Content-Type': 'application/zip'
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
const uploadResponse = await fetch(uploadRequest);
|
||||||
|
if ( uploadResponse.status !== 202 ) {
|
||||||
|
console.log(`Upload failed -- server error ${uploadResponse.status}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const operationId = uploadResponse.headers.get('Location');
|
||||||
|
if ( operationId === undefined ) {
|
||||||
|
console.log(`Upload failed -- missing Location header`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`Upload succeeded`);
|
||||||
|
|
||||||
|
// Check upload status
|
||||||
|
console.log('Checking upload status...');
|
||||||
|
const interval = 60; // check every 60 seconds
|
||||||
|
let countdown = 60 * 60 / interval; // for at most 60 minutes
|
||||||
|
for (;;) {
|
||||||
|
await sleep(interval);
|
||||||
|
countdown -= 1
|
||||||
|
if ( countdown <= 0 ) {
|
||||||
|
console.log('Error: Microsoft store timed out')
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const uploadStatusRequest = new Request(`${uploadURL}/operations/${operationId}`, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `ApiKey ${edgeApiKey}`,
|
||||||
|
'X-ClientID': edgeClientId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const uploadStatusResponse = await fetch(uploadStatusRequest);
|
||||||
|
if ( uploadStatusResponse.status !== 200 ) {
|
||||||
|
console.log(`Upload status check failed -- server error ${uploadStatusResponse.status}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const uploadStatusDict = await uploadStatusResponse.json();
|
||||||
|
const { status } = uploadStatusDict;
|
||||||
|
if ( status === undefined || status === 'Failed' ) {
|
||||||
|
console.log(`Upload status check failed -- server error ${status}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if ( status === 'InProgress' ) { continue }
|
||||||
|
console.log('Package ready to be published.')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish
|
||||||
|
// https://learn.microsoft.com/en-us/microsoft-edge/extensions-chromium/update/api/addons-api-reference?tabs=v1-1#publish-the-product-draft-submission
|
||||||
|
console.log('Publish package...')
|
||||||
|
const publishURL = `https://api.addons.microsoftedge.microsoft.com/v1/products/${edgeId}/submissions`;
|
||||||
|
const publishNotes = {
|
||||||
|
'Notes': 'See official release notes at <https://github.com/gorhill/uBlock/releases>'
|
||||||
|
}
|
||||||
|
const publishRequest = new Request(publishURL, {
|
||||||
|
body: JSON.stringify(publishNotes),
|
||||||
|
headers: {
|
||||||
|
'Authorization': `ApiKey ${edgeApiKey}`,
|
||||||
|
'X-ClientID': edgeClientId,
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
const publishResponse = await fetch(publishRequest);
|
||||||
|
if ( publishResponse.status !== 202 ) {
|
||||||
|
console.log(`Publish failed -- server error ${publishResponse.status}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if ( publishResponse.headers.get('Location') === undefined ) {
|
||||||
|
console.log(`Publish failed -- missing Location header`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log('Publish succeeded.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
if ( githubOwner === '' ) { return 'Need GitHub owner'; }
|
||||||
|
if ( githubRepo === '' ) { return 'Need GitHub repo'; }
|
||||||
|
|
||||||
|
ghapi.setGithubContext(githubOwner, githubRepo, githubTag, githubAuth);
|
||||||
|
|
||||||
|
const assetInfo = await ghapi.getAssetInfo('edge');
|
||||||
|
|
||||||
|
console.log(`GitHub owner: "${githubOwner}"`);
|
||||||
|
console.log(`GitHub repo: "${githubRepo}"`);
|
||||||
|
console.log(`Release tag: "${githubTag}"`);
|
||||||
|
console.log(`Release asset: "${assetInfo.name}"`);
|
||||||
|
|
||||||
|
// Fetch asset from GitHub repo
|
||||||
|
const filePath = await ghapi.downloadAssetFromRelease(assetInfo);
|
||||||
|
console.log('Asset saved at', filePath);
|
||||||
|
|
||||||
|
// Upload to Edge Store
|
||||||
|
await publishToEdgeStore(filePath);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
if ( commandLineArgs.keep !== true ) {
|
||||||
|
const tmpdir = path.dirname(filePath);
|
||||||
|
console.log(`Removing ${tmpdir}`);
|
||||||
|
ghapi.shellExec(`rm -rf "${tmpdir}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Done');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(result => {
|
||||||
|
if ( result !== undefined ) {
|
||||||
|
console.log(result);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
39
dist/github-api.js
vendored
39
dist/github-api.js
vendored
|
|
@ -32,6 +32,12 @@ function voidFunc() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
function reportFetchError(response) {
|
||||||
|
console.log(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
let githubOwner = '';
|
let githubOwner = '';
|
||||||
let githubRepo = '';
|
let githubRepo = '';
|
||||||
let githubTag = '';
|
let githubTag = '';
|
||||||
|
|
@ -46,37 +52,6 @@ export function setGithubContext(owner, repo, tag, auth) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
let pathToSecrets = '';
|
|
||||||
|
|
||||||
export async function getSecrets() {
|
|
||||||
const homeDir = os.homedir();
|
|
||||||
let currentDir = process.cwd();
|
|
||||||
let fileName = '';
|
|
||||||
for (;;) {
|
|
||||||
fileName = `${currentDir}/ubo_secrets`;
|
|
||||||
const stat = await fs.stat(fileName).catch(voidFunc);
|
|
||||||
if ( stat !== undefined ) { break; }
|
|
||||||
currentDir = path.resolve(currentDir, '..');
|
|
||||||
if ( currentDir.startsWith(homeDir) === false ) {
|
|
||||||
pathToSecrets = homeDir;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(`Found secrets in ${fileName}`);
|
|
||||||
const text = await fs.readFile(fileName, { encoding: 'utf8' }).catch(voidFunc);
|
|
||||||
if ( text === undefined ) { return {}; }
|
|
||||||
const secrets = JSON.parse(text);
|
|
||||||
pathToSecrets = fileName;
|
|
||||||
return secrets;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function saveSecrets(secrets) {
|
|
||||||
if ( pathToSecrets === '' ) { return; }
|
|
||||||
return fs.writeFile(pathToSecrets, JSON.stringify(secrets, null, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
export async function getRepoRoot() {
|
export async function getRepoRoot() {
|
||||||
const homeDir = os.homedir();
|
const homeDir = os.homedir();
|
||||||
let currentDir = process.cwd();
|
let currentDir = process.cwd();
|
||||||
|
|
@ -101,7 +76,7 @@ export async function getReleaseInfo() {
|
||||||
});
|
});
|
||||||
const response = await fetch(request).catch(voidFunc);
|
const response = await fetch(request).catch(voidFunc);
|
||||||
if ( response === undefined ) { return; }
|
if ( response === undefined ) { return; }
|
||||||
if ( response.ok !== true ) { return; }
|
if ( response.ok !== true ) { return reportFetchError(response); }
|
||||||
const releaseInfo = await response.json().catch(voidFunc);
|
const releaseInfo = await response.json().catch(voidFunc);
|
||||||
if ( releaseInfo === undefined ) { return; }
|
if ( releaseInfo === undefined ) { return; }
|
||||||
return releaseInfo;
|
return releaseInfo;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
"name": "uBlock",
|
"name": "uBlock",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "npm dev tools",
|
"description": "npm dev tools",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint --no-warn-ignored --ignore-pattern \"**/lib/\" --ignore-pattern \"**/npm/\" -- \"./src/js/*.js\" \"./src/js/**/*.js\" \"./**/*.json\" \"./platform/**/*.js\"",
|
"lint": "eslint --no-warn-ignored --ignore-pattern \"**/lib/\" --ignore-pattern \"**/npm/\" -- \"./src/js/*.js\" \"./src/js/**/*.js\" \"./**/*.json\" \"./platform/**/*.js\"",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue