Skip to content

Commit cd4fc25

Browse files
committed
update py scripts to publish in AMO/CWS
1 parent 00e62b4 commit cd4fc25

File tree

2 files changed

+223
-9
lines changed

2 files changed

+223
-9
lines changed

dist/chromium/publish-beta.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/usr/bin/env python3
2+
3+
import datetime
4+
import json
5+
import jwt
6+
import os
7+
import re
8+
import requests
9+
import shutil
10+
import subprocess
11+
import sys
12+
import tempfile
13+
import time
14+
import zipfile
15+
16+
from distutils.version import StrictVersion
17+
from string import Template
18+
19+
# - Download target (raw) uMatrix.chromium.zip from GitHub
20+
# - This is referred to as "raw" package
21+
# - This will fail if not a dev build
22+
# - Upload uMatrix.chromium.zip to Chrome store
23+
# - Publish uMatrix.chromium.zip to Chrome store
24+
25+
# Find path to project root
26+
projdir = os.path.split(os.path.abspath(__file__))[0]
27+
while not os.path.isdir(os.path.join(projdir, '.git')):
28+
projdir = os.path.normpath(os.path.join(projdir, '..'))
29+
30+
cs_extension_id = 'eckgcipdkhcfghnmincccnhpdmnbefki'
31+
tmpdir = tempfile.TemporaryDirectory()
32+
raw_zip_filename = 'uMatrix.chromium.zip'
33+
raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename)
34+
github_owner = 'gorhill'
35+
github_repo = 'uMatrix'
36+
37+
# We need a version string to work with
38+
if len(sys.argv) >= 2 and sys.argv[1]:
39+
version = sys.argv[1]
40+
else:
41+
version = input('Github release version: ')
42+
version.strip()
43+
if not re.search('^\d+\.\d+\.\d+(b|rc)\d+$', version):
44+
print('Error: Invalid version string.')
45+
exit(1)
46+
47+
# Load/save auth secrets
48+
# The build directory is excluded from git
49+
ubo_secrets = dict()
50+
ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets')
51+
if os.path.isfile(ubo_secrets_filename):
52+
with open(ubo_secrets_filename) as f:
53+
ubo_secrets = json.load(f)
54+
55+
def input_secret(prompt, token):
56+
if token in ubo_secrets:
57+
prompt += ' ✔'
58+
prompt += ': '
59+
value = input(prompt).strip()
60+
if len(value) == 0:
61+
if token not in ubo_secrets:
62+
print('Token error:', token)
63+
exit(1)
64+
value = ubo_secrets[token]
65+
elif token not in ubo_secrets or value != ubo_secrets[token]:
66+
ubo_secrets[token] = value
67+
exists = os.path.isfile(ubo_secrets_filename)
68+
with open(ubo_secrets_filename, 'w') as f:
69+
json.dump(ubo_secrets, f, indent=2)
70+
if not exists:
71+
os.chmod(ubo_secrets_filename, 0o600)
72+
return value
73+
74+
75+
# GitHub API token
76+
github_token = input_secret('Github token', 'github_token')
77+
github_auth = 'token ' + github_token
78+
79+
#
80+
# Get metadata from GitHub about the release
81+
#
82+
83+
# https://developer.github.com/v3/repos/releases/#get-a-single-release
84+
print('Downloading release info from GitHub...')
85+
release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version)
86+
headers = { 'Authorization': github_auth, }
87+
response = requests.get(release_info_url, headers=headers)
88+
if response.status_code != 200:
89+
print('Error: Release not found: {0}'.format(response.status_code))
90+
exit(1)
91+
release_info = response.json()
92+
93+
#
94+
# Extract URL to raw package from metadata
95+
#
96+
97+
# Find url for uMatrix.chromium.zip
98+
raw_zip_url = ''
99+
for asset in release_info['assets']:
100+
if asset['name'] == raw_zip_filename:
101+
raw_zip_url = asset['url']
102+
if len(raw_zip_url) == 0:
103+
print('Error: Release asset URL not found')
104+
exit(1)
105+
106+
#
107+
# Download raw package from GitHub
108+
#
109+
110+
# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
111+
print('Downloading raw zip package from GitHub...')
112+
headers = {
113+
'Authorization': github_auth,
114+
'Accept': 'application/octet-stream',
115+
}
116+
response = requests.get(raw_zip_url, headers=headers)
117+
# Redirections are transparently handled:
118+
# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history
119+
if response.status_code != 200:
120+
print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code))
121+
exit(1)
122+
with open(raw_zip_filepath, 'wb') as f:
123+
f.write(response.content)
124+
print('Downloaded raw package saved as {0}'.format(raw_zip_filepath))
125+
126+
#
127+
# Upload to Chrome store
128+
#
129+
130+
# Auth tokens
131+
cs_id = input_secret('Chrome store id', 'cs_id')
132+
cs_secret = input_secret('Chrome store secret', 'cs_secret')
133+
cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh')
134+
135+
print('Uploading to Chrome store...')
136+
with open(raw_zip_filepath, 'rb') as f:
137+
print('Generating access token...')
138+
auth_url = 'https://accounts.google.com/o/oauth2/token'
139+
auth_payload = {
140+
'client_id': cs_id,
141+
'client_secret': cs_secret,
142+
'grant_type': 'refresh_token',
143+
'refresh_token': cs_refresh,
144+
}
145+
auth_response = requests.post(auth_url, data=auth_payload)
146+
if auth_response.status_code != 200:
147+
print('Error: Auth failed -- server error {0}'.format(auth_response.status_code))
148+
print(auth_response.text)
149+
exit(1)
150+
response_dict = auth_response.json()
151+
if 'access_token' not in response_dict:
152+
print('Error: Auth failed -- no access token')
153+
exit(1)
154+
# Prepare access token
155+
cs_auth = 'Bearer ' + response_dict['access_token']
156+
headers = {
157+
'Authorization': cs_auth,
158+
'x-goog-api-version': '2',
159+
}
160+
# Upload
161+
print('Uploading package...')
162+
upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id)
163+
upload_response = requests.put(upload_url, headers=headers, data=f)
164+
f.close()
165+
if upload_response.status_code != 200:
166+
print('Upload failed -- server error {0}'.format(upload_response.status_code))
167+
print(upload_response.text)
168+
exit(1)
169+
response_dict = upload_response.json();
170+
if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS':
171+
print('Upload failed -- server error {0}'.format(response_dict['uploadState']))
172+
exit(1)
173+
print('Upload succeeded.')
174+
# Publish
175+
print('Publishing package...')
176+
publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id)
177+
headers = {
178+
'Authorization': cs_auth,
179+
'x-goog-api-version': '2',
180+
'Content-Length': '0',
181+
}
182+
publish_response = requests.post(publish_url, headers=headers)
183+
if publish_response.status_code != 200:
184+
print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code))
185+
exit(1)
186+
response_dict = publish_response.json();
187+
if 'status' not in response_dict or response_dict['status'][0] != 'OK':
188+
print('Publishing failed -- server error {0}'.format(response_dict['status']))
189+
exit(1)
190+
print('Publishing succeeded.')
191+
192+
print('All done.')

dist/firefox/publish-signed-beta.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,35 @@
6262
print('Error: Invalid version string.')
6363
exit(1)
6464

65+
# Load/save auth secrets
66+
# The build directory is excluded from git
67+
ubo_secrets = dict()
68+
ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets')
69+
if os.path.isfile(ubo_secrets_filename):
70+
with open(ubo_secrets_filename) as f:
71+
ubo_secrets = json.load(f)
72+
73+
def input_secret(prompt, token):
74+
if token in ubo_secrets:
75+
prompt += ' ✔'
76+
prompt += ': '
77+
value = input(prompt).strip()
78+
if len(value) == 0:
79+
if token not in ubo_secrets:
80+
print('Token error:', token)
81+
exit(1)
82+
value = ubo_secrets[token]
83+
elif token not in ubo_secrets or value != ubo_secrets[token]:
84+
ubo_secrets[token] = value
85+
exists = os.path.isfile(ubo_secrets_filename)
86+
with open(ubo_secrets_filename, 'w') as f:
87+
json.dump(ubo_secrets, f, indent=2)
88+
if not exists:
89+
os.chmod(ubo_secrets_filename, 0o600)
90+
return value
91+
6592
# GitHub API token
66-
# TODO: support as environment variable? (see os.environ)
67-
github_token = input("Github token: ").strip()
68-
if len(github_token) == 0:
69-
print('Error: invalid GitHub token')
70-
exit(1)
93+
github_token = input_secret('Github token', 'github_token')
7194
github_auth = 'token ' + github_token
7295

7396
#
@@ -145,9 +168,8 @@
145168

146169
print('Ask AMO to sign self-hosted xpi package...')
147170
with open(unsigned_xpi_filepath, 'rb') as f:
148-
# TODO: support use of env variables for key/secret?
149-
amo_api_key = input("AMO API key: ").strip()
150-
amo_secret = input("AMO API secret: ").strip()
171+
amo_api_key = input_secret('AMO API key', 'amo_api_key')
172+
amo_secret = input_secret('AMO API secret', 'amo_secret')
151173
amo_nonce = os.urandom(8).hex()
152174
jwt_payload = {
153175
'iss': amo_api_key,
@@ -251,7 +273,7 @@
251273
f.close()
252274
previous_version = updates_json['addons'][extension_id]['updates'][0]['version']
253275
if LooseVersion(version) > LooseVersion(previous_version):
254-
with open(os.path.join(projdir, 'platform', 'webext', 'updates.template.json')) as f:
276+
with open(os.path.join(projdir, 'dist', 'firefox', 'updates.template.json')) as f:
255277
template_json = Template(f.read())
256278
f.close()
257279
updates_json = template_json.substitute(version=version)

0 commit comments

Comments
 (0)