mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-20 05:18:08 +00:00
feat(common): create release script
This commit is contained in:
parent
8dd7ad3c3e
commit
2173f6cec7
common/tools
27
common/tools/release.sh
Executable file
27
common/tools/release.sh
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
HERE=$(dirname $0)
|
||||||
|
|
||||||
|
CHECK_OUTPUT=$(mktemp -d)
|
||||||
|
trap "rm -r $CHECK_OUTPUT" EXIT
|
||||||
|
|
||||||
|
$HERE/cointool.py check > $CHECK_OUTPUT/pre.txt
|
||||||
|
|
||||||
|
ETH_DIR=$HERE/../defs/ethereum
|
||||||
|
ETH_REPOS="chains tokens"
|
||||||
|
|
||||||
|
for dir in $ETH_REPOS; do
|
||||||
|
(
|
||||||
|
cd $ETH_DIR/$dir; \
|
||||||
|
git checkout master; \
|
||||||
|
git pull origin master
|
||||||
|
)
|
||||||
|
done
|
||||||
|
|
||||||
|
$HERE/support.py release
|
||||||
|
|
||||||
|
$HERE/cointool.py check > $CHECK_OUTPUT/post.txt
|
||||||
|
|
||||||
|
make -C $HERE/../.. gen
|
||||||
|
|
||||||
|
diff $CHECK_OUTPUT/pre.txt $CHECK_OUTPUT/post.txt
|
@ -2,7 +2,6 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@ -37,6 +36,19 @@ def clear_support(device, key):
|
|||||||
unsupported.pop(key, None)
|
unsupported.pop(key, None)
|
||||||
|
|
||||||
|
|
||||||
|
def support_setdefault(device, key, value, reason=None):
|
||||||
|
"""Set value only if no other value is set"""
|
||||||
|
supported, unsupported = support_dicts(device)
|
||||||
|
if value is not False and key not in unsupported:
|
||||||
|
supported.setdefault(key, value)
|
||||||
|
|
||||||
|
if value is False:
|
||||||
|
if reason is None:
|
||||||
|
raise ValueError("reason must be given for unsupported keys")
|
||||||
|
if key not in supported:
|
||||||
|
unsupported[key] = reason
|
||||||
|
|
||||||
|
|
||||||
def set_supported(device, key, value):
|
def set_supported(device, key, value):
|
||||||
clear_support(device, key)
|
clear_support(device, key)
|
||||||
supported, _ = support_dicts(device)
|
supported, _ = support_dicts(device)
|
||||||
@ -291,94 +303,56 @@ def check(check_tokens, ignore_missing):
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
# fmt: off
|
# fmt: off
|
||||||
@click.argument("device")
|
@click.option("--v1", help="Version for T1 release (default: guess from latest)")
|
||||||
@click.option("-r", "--version", help="Set explicit version string (default: guess from latest release)")
|
@click.option("--v2", help="Version for TT release (default: guess from latest)")
|
||||||
@click.option("--git-tag/--no-git-tag", "-g", default=False, help="Create a corresponding Git tag")
|
|
||||||
@click.option("--release-missing/--no-release-missing", default=True, help="Release coins with missing support info")
|
|
||||||
@click.option("-n", "--dry-run", is_flag=True, help="Do not write changes")
|
@click.option("-n", "--dry-run", is_flag=True, help="Do not write changes")
|
||||||
@click.option("-s", "--soon", is_flag=True, help="Only set missing support-infos to be released 'soon'")
|
|
||||||
@click.option("-f", "--force", is_flag=True, help="Proceed even with bad version/device info")
|
@click.option("-f", "--force", is_flag=True, help="Proceed even with bad version/device info")
|
||||||
@click.option("-y", "--add-all", is_flag=True, help="Do not ask for confirmation, add all selected coins")
|
|
||||||
@click.option("-v", "--verbose", is_flag=True, help="Be more verbose")
|
@click.option("-v", "--verbose", is_flag=True, help="Be more verbose")
|
||||||
|
@click.option("--skip-testnets/--no-skip-testnets", default=True, help="Automatically exclude testnets")
|
||||||
# fmt: on
|
# fmt: on
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def release(
|
def release(
|
||||||
ctx,
|
ctx,
|
||||||
device: str,
|
v1,
|
||||||
version,
|
v2,
|
||||||
git_tag,
|
|
||||||
release_missing,
|
|
||||||
dry_run,
|
dry_run,
|
||||||
soon,
|
|
||||||
force,
|
force,
|
||||||
add_all,
|
|
||||||
verbose,
|
verbose,
|
||||||
|
skip_testnets,
|
||||||
):
|
):
|
||||||
"""Release a new Trezor firmware.
|
"""Release a new Trezor firmware.
|
||||||
|
|
||||||
Update support infos so that all coins have a clear support status.
|
Update support infos so that all coins have a clear support status.
|
||||||
By default, marks duplicate tokens as unsupported, and all coins that either
|
By default, marks duplicate tokens and testnets as unsupported, and all coins that
|
||||||
don't have support info, or they are supported "soon", are set to the
|
don't have support info are set to the released firmware version.
|
||||||
released firmware version.
|
|
||||||
|
|
||||||
Optionally tags the repository with the given version.
|
The tool will ask you to confirm each added coin. ERC20 tokens are added
|
||||||
|
automatically. Use `--verbose` to see them.
|
||||||
`device` can be "1", "2", or a string matching `support.json` key. Version
|
|
||||||
is autodetected by downloading a list of latest releases and incrementing
|
|
||||||
micro version by one, or you can specify `--version` explicitly.
|
|
||||||
|
|
||||||
Unless `--add-all` is specified, the tool will ask you to confirm each added
|
|
||||||
coin. ERC20 tokens are added automatically. Use `--verbose` to see them.
|
|
||||||
"""
|
"""
|
||||||
# check condition(s)
|
latest_releases = coin_info.latest_releases()
|
||||||
if soon and git_tag:
|
|
||||||
raise click.ClickException("Cannot git-tag a 'soon' revision")
|
|
||||||
|
|
||||||
# process `device`
|
def bump_version(version_tuple):
|
||||||
if device.isnumeric():
|
version_list = list(version_tuple)
|
||||||
device = f"trezor{device}"
|
version_list[-1] += 1
|
||||||
|
return ".".join(str(n) for n in version_list)
|
||||||
|
|
||||||
if not force and device not in coin_info.VERSIONED_SUPPORT_INFO:
|
# guess `version` if not given
|
||||||
raise click.ClickException(
|
if not v1:
|
||||||
f"Non-releasable device {device} (support info is not versioned). "
|
v1 = bump_version(latest_releases["trezor1"])
|
||||||
"Use --force to proceed anyway."
|
if not v2:
|
||||||
)
|
v2 = bump_version(latest_releases["trezor2"])
|
||||||
|
|
||||||
if not soon:
|
versions = {"trezor1": v1, "trezor2": v2}
|
||||||
# guess `version` if not given
|
|
||||||
if not version:
|
|
||||||
versions = coin_info.latest_releases()
|
|
||||||
latest_version = versions.get(device)
|
|
||||||
if latest_version is None:
|
|
||||||
raise click.ClickException(
|
|
||||||
"Failed to guess version. "
|
|
||||||
"Please use --version to specify it explicitly."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
latest_version = list(latest_version)
|
|
||||||
latest_version[-1] += 1
|
|
||||||
version = ".".join(str(n) for n in latest_version)
|
|
||||||
|
|
||||||
# process `version`
|
for number in "1", "2":
|
||||||
try:
|
device = f"trezor{number}"
|
||||||
version_numbers = list(map(int, version.split(".")))
|
version = versions[device]
|
||||||
expected_device = f"trezor{version_numbers[0]}"
|
if not force and not version.startswith(number + "."):
|
||||||
if not force and device != expected_device:
|
raise click.ClickException(
|
||||||
raise click.ClickException(
|
f"Device trezor{device} should not be version {version}. "
|
||||||
f"Device {device} should not be version {version}. "
|
"Use --force to proceed anyway."
|
||||||
"Use --force to proceed anyway."
|
)
|
||||||
)
|
|
||||||
except ValueError as e:
|
|
||||||
if not force:
|
|
||||||
raise click.ClickException(
|
|
||||||
f"Failed to parse '{version}' as a version. "
|
|
||||||
"Use --force to proceed anyway."
|
|
||||||
) from e
|
|
||||||
|
|
||||||
if soon:
|
|
||||||
version = "soon"
|
|
||||||
print(f"Moving {device} missing infos to 'soon'")
|
|
||||||
else:
|
|
||||||
print(f"Releasing {device} firmware version {version}")
|
print(f"Releasing {device} firmware version {version}")
|
||||||
|
|
||||||
defs, _ = coin_info.coin_info_with_duplicates()
|
defs, _ = coin_info.coin_info_with_duplicates()
|
||||||
@ -389,50 +363,49 @@ def release(
|
|||||||
print("Fixing up data...")
|
print("Fixing up data...")
|
||||||
ctx.invoke(fix, dry_run=True)
|
ctx.invoke(fix, dry_run=True)
|
||||||
|
|
||||||
def maybe_add(coin, label):
|
def maybe_add(coin):
|
||||||
add = False
|
add = click.confirm(
|
||||||
if add_all:
|
f"Add missing coin {coin['key']} ({coin['name']})?", default=True
|
||||||
add = True
|
)
|
||||||
else:
|
if not add:
|
||||||
text = f"Add {label} coin {coin['key']} ({coin['name']})?"
|
unsupport_reason = click.prompt(
|
||||||
add = click.confirm(text, default=True)
|
"Enter reason for not supporting (blank to skip)",
|
||||||
if add:
|
default="",
|
||||||
set_supported(device, coin["key"], version)
|
show_default=False,
|
||||||
|
)
|
||||||
|
if not unsupport_reason:
|
||||||
|
return
|
||||||
|
|
||||||
# if we're releasing, process coins marked "soon"
|
for device, version in versions.items():
|
||||||
if not soon:
|
if add:
|
||||||
supported, _ = support_dicts(device)
|
support_setdefault(device, coin["key"], version)
|
||||||
soon_list = [
|
else:
|
||||||
coins_dict[key]
|
support_setdefault(device, coin["key"], False, unsupport_reason)
|
||||||
for key, val in supported.items()
|
|
||||||
if val == "soon" and key in coins_dict
|
|
||||||
]
|
|
||||||
for coin in soon_list:
|
|
||||||
key = coin["key"]
|
|
||||||
maybe_add(coin, "soon")
|
|
||||||
|
|
||||||
# process missing (not listed) supportinfos
|
# process missing (not listed) supportinfos
|
||||||
if release_missing:
|
missing_list = []
|
||||||
missing_list = find_unsupported_coins(coins_dict)[device]
|
unsupported = find_unsupported_coins(coins_dict)
|
||||||
tokens = [coin for coin in missing_list if coin_info.is_token(coin)]
|
for val in unsupported.values():
|
||||||
nontokens = [coin for coin in missing_list if not coin_info.is_token(coin)]
|
for coin in val:
|
||||||
for coin in tokens:
|
if coin not in missing_list:
|
||||||
key = coin["key"]
|
missing_list.append(coin)
|
||||||
# assert not coin.get("duplicate"), key
|
|
||||||
if verbose:
|
|
||||||
print(f"Adding missing {key} ({coin['name']})")
|
|
||||||
set_supported(device, key, version)
|
|
||||||
|
|
||||||
for coin in nontokens:
|
tokens = [coin for coin in missing_list if coin_info.is_token(coin)]
|
||||||
maybe_add(coin, "missing")
|
nontokens = [coin for coin in missing_list if not coin_info.is_token(coin)]
|
||||||
|
for coin in tokens:
|
||||||
|
key = coin["key"]
|
||||||
|
# assert not coin.get("duplicate"), key
|
||||||
|
if verbose:
|
||||||
|
print(f"Adding missing {key} ({coin['name']})")
|
||||||
|
for device, version in versions.items():
|
||||||
|
support_setdefault(device, key, version)
|
||||||
|
|
||||||
tagname = f"{device}-{version}"
|
for coin in nontokens:
|
||||||
if git_tag:
|
if skip_testnets and "testnet" in coin["name"].lower():
|
||||||
if dry_run:
|
for device, version in versions.items():
|
||||||
print(f"Would tag current commit with {tagname}")
|
support_setdefault(device, coin["key"], False, "(AUTO) exclude testnet")
|
||||||
else:
|
else:
|
||||||
print(f"Tagging current commit with {tagname}")
|
maybe_add(coin)
|
||||||
subprocess.check_call(["git", "tag", tagname])
|
|
||||||
|
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
write_support_info()
|
write_support_info()
|
||||||
|
Loading…
Reference in New Issue
Block a user