-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Python release-tool #10114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Python release-tool #10114
Conversation
b460067
to
c423ae6
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #10114 +/- ##
========================================
Coverage 64.35% 64.35%
========================================
Files 378 378
Lines 39719 39719
========================================
Hits 25561 25561
Misses 14158 14158 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a56d67e
to
0732119
Compare
f52c79c
to
d741087
Compare
7fd7a73
to
85038ad
Compare
Fix argparse handling when no subcommand given Implement check command Implement i18n command Add Ctrl+F TOC Implement merge command Implement source tarball creation Implement macOS builds Implement Linux builds Support building for multiple platforms Disable test building Debug-log executed commands Allow cross-compilation without Docker when using vcpkg Implement macOS codesigning and notarization Remove obsolete globals Check xcode setup Implement GPG signing Re-enable Git branch checkout Show key selection for merge commit signing Check for git and merge basic and tool checks Remove redundant checkout message Update headline formatting
* Move pre-build installer signing to cmake to streamline the operation and avoid signing hundreds of unnecessary files. * Enable building both amd64 and arm64 builds with visual studio
* Incorporate shell=True directly into _run when on windows and modifying path/env * Fix _get_bin_path to resolve the build_dir to absolute path * Fix _git_branches_related to ignore non-zero return code * Fix double naming of transifex resource
e728c4d
to
419de58
Compare
@phoerious this is ready for prime time. I tested all functions except for merge on windows. Made several improvements and fixes. Will test merge soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a comprehensive Python rewrite of the KeePassXC release tool, replacing the existing Bash and PowerShell versions with a unified Python implementation. The new tool consolidates functionality for checking, merging, building, signing, and internationalization tasks while adding improved cross-platform support.
- Python-based unified release tool replacing separate Bash and PowerShell scripts
- Enhanced Windows build system with integrated code signing capabilities
- Updated Transifex configuration for modern API endpoints
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
File | Description |
---|---|
release-tool.py | New comprehensive Python release tool with all functionality from previous scripts |
release-tool.ps1 | Removed PowerShell version (replaced by Python tool) |
release-tool | Removed Bash version (replaced by Python tool) |
share/linux/appimage-apprun.sh | New AppImage launcher script for Linux distributions |
src/CMakeLists.txt | Updated Windows packaging to use new post-install script |
cmake/WindowsPostInstall.cmake.in | New Windows post-install script template for signing and portable zip creation |
cmake/MakePortableZip.cmake | Removed old portable zip creation script |
.tx/config | Updated Transifex configuration for new API endpoints |
raise Error('No secret keys found!') | ||
|
||
if not user_choice and len(keys) == 1: | ||
logger.info('Using secret key %s %s.', keys[0][0]. keys[0][2]) |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing comma operator between tuple elements. Should be keys[0][0], keys[0][2]
instead of keys[0][0]. keys[0][2]
.
logger.info('Using secret key %s %s.', keys[0][0]. keys[0][2]) | |
logger.info('Using secret key %s %s.', keys[0][0], keys[0][2]) |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wtf
changelog = 'Release ' + changelog.group(1) | ||
|
||
tag_name = tag_name or version | ||
logger.info('Creating "%s%" tag...', tag_name) |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect string formatting with mismatched quotes. Should be 'Creating \"%s\" tag...'
or use a different quote style to avoid the %s% pattern.
logger.info('Creating "%s%" tag...', tag_name) | |
logger.info('Creating "%s" tag...', tag_name) |
Copilot uses AI. Check for mistakes.
yes_no = input().strip().lower() | ||
if default_no: | ||
return yes_no == 'y' | ||
return yes_no == 'n' |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic error in _yes_no_prompt function. When default_no=False (meaning default is 'yes'), the function should return yes_no != 'n'
to return True unless user explicitly says 'n'.
return yes_no == 'n' | |
return yes_no != 'n' |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, this is a logic error
signtool_args += ['/sha1', identity] | ||
signtool_args += ['/d', file.name, str(file.resolve())] | ||
|
||
_run(signtool_args, cwd=src_dir, capture_output=False, shell=True) |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using shell=True with user-controlled input (identity parameter) poses a command injection risk. The signtool_args list should be executed directly without shell=True.
_run(signtool_args, cwd=src_dir, capture_output=False, shell=True) | |
_run(signtool_args, cwd=src_dir, capture_output=False) |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is run locally, no risk for command injection unless you do it to yourself 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shell should still be set to false. I don't see why this needs to be run in a shell wrapper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it literally didn't work otherwise. The sign tool will invoke a pin prompt and that will fail to show with an error if not done in a shell
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, perhaps add a comment then.
inst = subprocess.check_output([vswhere, '-latest', '-products', '*', | ||
'-requires', 'Microsoft.Component.MSBuild', | ||
'-property', 'installationPath'], text=True).strip() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use _run(...).stdout
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote this before I understood all the functions in this file, good point
out = subprocess.run(f'cmd /c "{vs_cmd}" -arch={arch} -no_logo && set', capture_output=True, text=True) | ||
except subprocess.CalledProcessError as e: | ||
raise Error('Failed to run Visual Studio dev script: %s', e.output or str(e)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. I would also separate the cmd call and the actual shell command like this:
_run(['cmd', '/c', f'"{vs_cmd}" -arch={arch} -no_logo && set']), text=True)
Also, maybe escaping spaces vs_cmd.replace(' ', r'\ ')
is safer than quotes?
You should probably also call _find_vs_dev_cmd
from here directly. There's only a single usage of both these functions, so no need to take vs_cmd
as a parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried so many ways to get all this to work.... out of 100 possible permutations only 2 work because windows command prompt is trash
for line in out.stdout.splitlines(): | ||
k, v = line.split('=', 1) | ||
if v is not None: | ||
env[k] = v |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v
will never be None
. This will just error out if there's no =
.
Maybe a better solution than Copilot's would be not to use expansion at all:
for line in out.stdout.splitlines(): | |
k, v = line.split('=', 1) | |
if v is not None: | |
env[k] = v | |
for line in out.stdout.splitlines(): | |
if len(kv := line.split('=', 1)) == 2: | |
env[kv[0]] = kv[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my testing it didn't error out, only k had a value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For 'abc='
yes (but then it'll be ''
, not None
). For 'abc'
you will get a ValueError
.
vs_cmd = _find_vs_dev_cmd() | ||
vs_env = _capture_vs_env(vs_cmd, arch=platform_target) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge (see above)
Work-in-progress PR for rewriting out release-tool in Python and merging the Bash and PS1 versions.
Type of change