You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
8.4 KiB
229 lines
8.4 KiB
#!/usr/bin/env python3 |
|
# MIT License |
|
# |
|
# Copyright (c) 2025 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
|
# |
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
|
# of this software and associated documentation files (the "Software"), to deal |
|
# in the Software without restriction, including without limitation the rights |
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
# copies of the Software, and to permit persons to whom the Software is |
|
# furnished to do so, subject to the following conditions: |
|
# |
|
# The above copyright notice and this permission notice shall be included in all |
|
# copies or substantial portions of the Software. |
|
# |
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
# SOFTWARE. |
|
|
|
import re |
|
import sys |
|
import glob |
|
import json |
|
import argparse |
|
import fileinput |
|
from dataclasses import dataclass |
|
from enum import Enum |
|
|
|
from typing import List, Dict, Union |
|
|
|
class MatrixType(Enum): |
|
ALL = "all" |
|
PYPI = "pypi" |
|
ITCH = "itch" |
|
|
|
@dataclass |
|
class _AppData(): |
|
name: str |
|
path: str |
|
version: str |
|
pypi: bool = False |
|
itch: bool = False |
|
tag: str = "" |
|
release_notes: str = "" |
|
|
|
def to_dict(self) -> Dict[str, Union[str,bool]]: |
|
return { |
|
"name" : self.name, |
|
"path" : self.path, |
|
"version" : self.version, |
|
"pypi" : self.pypi, |
|
"itch" : self.itch, |
|
"tag" : self.tag, |
|
"release-notes" : self.release_notes |
|
} |
|
|
|
def _print_info(apps_data:List[_AppData]) -> None: |
|
for _a in apps_data: |
|
print(f"{_a.name} : {_a.version}") |
|
|
|
# for item in $(jq -r '.[].path' <<< ${APPS_ARRAY}) ; do; do |
|
# # Update version in the project |
|
# _VERSION=$(_get_version ${item}) |
|
# _NAME=$(_get_name ${item}) |
|
# if grep -q "${_NAME}: ${_VERSION}" <<< ' ${{ steps.release-please.outputs.pr }}' ; then |
|
# sed -i \ |
|
# "s|__version__:str.*|__version__:str = '${_VERSION}'|" \ |
|
# ${item}/*/__init__.py |
|
# sed "s|'pyTermTk *>=[^']*'|'pyTermTk>=${_VERSION_TTK}'|" -i ${item}/pyproject.toml |
|
# echo ✅ Bumped ${_NAME} to ${_VERSION} |
|
# else |
|
# echo 🆗 No new release found for ${_NAME} |
|
# fi |
|
# done |
|
def _upgrade_files(apps_data:List[_AppData], rp_data:Dict, dry_run:bool) -> None: |
|
_ttk = [_a for _a in apps_data if _a.name=='pyTermTk'][0] |
|
for _a in apps_data: |
|
print(f"{_a.name} : {_a.version}") |
|
if f"{_a.name}: {_a.version}" not in rp_data.get('pr',''): |
|
print(f"🆗 No new release found for ${_a.name}") |
|
else: |
|
print(f"✅ Bumped ${_a.name} to ${_a.version}") |
|
print(f"sed {_a.path}/*/__init__.py <<< {_a.version}") |
|
|
|
pattern = re.compile(r"__version__:str.*") |
|
replacement=f"__version__:str = '{_a.version}'" |
|
files = glob.glob(f"{_a.path}/*/__init__.py") |
|
if dry_run: |
|
print(files, replacement) |
|
else: |
|
for line in fileinput.input(files, inplace=True): |
|
print(pattern.sub(replacement, line), end="") |
|
|
|
pattern = re.compile(r"'pyTermTk *>=[^']*'") |
|
replacement = f"'pyTermTk>={_ttk.version}'" |
|
|
|
files = glob.glob(f"{_a.path}/pyproject.toml") |
|
if dry_run: |
|
print(files, replacement) |
|
else: |
|
for line in fileinput.input(files, inplace=True): |
|
print(pattern.sub(replacement, line), end="") |
|
|
|
|
|
def _gen_matrix(matrix_type: MatrixType, rp_data:Dict, apps_data:List[_AppData]) -> List[_AppData]: |
|
if matrix_type == MatrixType.PYPI: |
|
apps = [app for app in apps_data if app.pypi] |
|
elif matrix_type == MatrixType.ITCH: |
|
apps = [app for app in apps_data if app.itch] |
|
elif matrix_type == MatrixType.ALL: |
|
apps = apps_data |
|
else: |
|
raise ValueError(f"Invalid matrix type: {matrix_type}") |
|
|
|
# if 'pr' not in rp_data: |
|
# return []# |
|
|
|
# pr = json.loads(rp_data['pr']) |
|
|
|
# print(rp_data) |
|
# for app in apps: |
|
# print(f"{app.name}: [{app.path}--release_created]: ", rp_data.get(f"{app.path}--release_created",False)) |
|
|
|
apps = [app for app in apps if rp_data.get(f"{app.path}--release_created",False) in ('true',True)] |
|
for app in apps: |
|
app.tag = rp_data.get(f"{app.path}--tag_name",'') |
|
app.release_notes = rp_data.get(f"{app.path}--body",'') |
|
|
|
return apps |
|
|
|
def main(): |
|
parser = argparse.ArgumentParser(description="Release Helper Script") |
|
# Configuration File Argument |
|
parser.add_argument("--config", metavar="config_file", type=argparse.FileType("r"), help="Path to the configuration file") |
|
parser.add_argument("--manifest", metavar="config_file", type=argparse.FileType("r"), help="Path to the configuration file") |
|
|
|
subparsers = parser.add_subparsers(title="Features", dest="feature") |
|
|
|
# Apps Feature |
|
info_parser = subparsers.add_parser("info", help="Print release info") |
|
|
|
upgrade_parser = subparsers.add_parser("upgrade", help="update the app versions") |
|
upgrade_parser.add_argument("--dry-run", action="store_true", help="Do not apply thw changes") |
|
|
|
# Apps Feature |
|
apps_parser = subparsers.add_parser("apps", help="Apps related operations") |
|
apps_parser.add_argument("--list", action="store_true", help="List available apps") |
|
apps_parser.add_argument("--build", metavar="app_name", type=str, help="Build a specific app") |
|
|
|
# Matrix Feature |
|
matrix_parser = subparsers.add_parser("matrix", help="Matrix related operations") |
|
matrix_parser.add_argument("type", metavar="matrix_type", type=str, choices=[e.value for e in MatrixType], help="Specify the type of matrix to generate") |
|
|
|
args = parser.parse_args() |
|
|
|
# Load and parse configuration file if provided |
|
config = {} |
|
if args.config: |
|
try: |
|
config = json.load(args.config) # Parse the JSON file |
|
# print(f"Loaded configuration: {json.dumps(config, indent=2)}") |
|
except json.JSONDecodeError: |
|
print(f"Error: Configuration file '{args.config.name}' is not valid JSON.") |
|
sys.exit(1) |
|
|
|
# Load and parse configuration file if provided |
|
manifest = {} |
|
if args.manifest: |
|
try: |
|
manifest = json.load(args.manifest) # Parse the JSON file |
|
# print(f"Loaded manifesturation: {json.dumps(manifest, indent=2)}") |
|
except json.JSONDecodeError: |
|
print(f"Error: Configuration file '{args.manifest.name}' is not valid JSON.") |
|
sys.exit(1) |
|
|
|
input_data = {} |
|
if not sys.stdin.isatty(): # or sys.stdin.peek(1): |
|
try: |
|
read = sys.stdin.read() |
|
input_data = json.loads(read) |
|
except json.JSONDecodeError: |
|
print("Error: Invalid JSON input.") |
|
sys.exit(1) |
|
|
|
apps_data = [ |
|
_AppData( |
|
name=_v.get('package-name',''), |
|
path=_a, |
|
version=manifest.get(_a,"0.0.0"), |
|
itch=_v.get('itch',False), |
|
pypi=_v.get('pypi',False)) |
|
for _a,_v in config.get('packages',{}).items()] |
|
|
|
# print(apps_data) |
|
|
|
if args.feature == "info": |
|
_print_info(apps_data) |
|
elif args.feature == "upgrade": |
|
print(args) |
|
_upgrade_files(apps_data, input_data, args.dry_run) |
|
elif args.feature == "apps": |
|
if args.list: |
|
print("Available Apps:") |
|
for app in apps_data: |
|
print(f" - {app.name}") |
|
elif args.build: |
|
print(f"Building app: {args.build}") |
|
# Implement build logic here |
|
else: |
|
apps_parser.print_help() |
|
elif args.feature == "matrix": |
|
matrix_type = MatrixType(args.type) |
|
matrix = _gen_matrix(matrix_type, input_data, apps_data) |
|
# print(json.dumps( |
|
# { |
|
# 'has_matrix': bool(matrix), |
|
# 'matrix':[app.to_dict() for app in matrix] |
|
# } |
|
# , indent=2)) |
|
print(json.dumps([app.to_dict() for app in matrix], indent=2)) |
|
else: |
|
parser.print_help() |
|
|
|
if __name__ == "__main__": |
|
main() |