Browse Source
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>pull/423/head
9 changed files with 656 additions and 89 deletions
@ -0,0 +1,57 @@ |
|||||||
|
name: Release Sandbox |
||||||
|
|
||||||
|
permissions: |
||||||
|
contents: read |
||||||
|
|
||||||
|
on: |
||||||
|
workflow_dispatch: |
||||||
|
inputs: |
||||||
|
app: |
||||||
|
description: The changed app |
||||||
|
type: string |
||||||
|
default: pyTermTk |
||||||
|
version: |
||||||
|
description: The app version |
||||||
|
type: string |
||||||
|
default: v0.0.0 |
||||||
|
discord-message: |
||||||
|
description: The release message |
||||||
|
type: string |
||||||
|
default: pyTermTk released |
||||||
|
workflow_call: |
||||||
|
inputs: |
||||||
|
app: |
||||||
|
description: The changed app |
||||||
|
type: string |
||||||
|
default: pyTermTk |
||||||
|
version: |
||||||
|
description: The app version |
||||||
|
type: string |
||||||
|
default: v0.0.0 |
||||||
|
discord-message: |
||||||
|
description: The release message |
||||||
|
type: string |
||||||
|
default: pyTermTk released |
||||||
|
|
||||||
|
jobs: |
||||||
|
notify-discord: |
||||||
|
# runs-on: ubuntu-latest |
||||||
|
runs-on: self-hosted |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
with: |
||||||
|
ref: ${{ github.sha }} |
||||||
|
- uses: actions/setup-python@v5 |
||||||
|
with: |
||||||
|
python-version: "3.x" |
||||||
|
- name: Instrall deps |
||||||
|
run: | |
||||||
|
python -m pip install discord.py |
||||||
|
- name: Deploy Discord message |
||||||
|
env: |
||||||
|
MESSAGE: ${{ inputs.discord-message }} |
||||||
|
run: | |
||||||
|
python tools/ci/social/notify_discord.py ${{ inputs.app }} ${{ inputs.version }} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,229 @@ |
|||||||
|
#!/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() |
||||||
@ -0,0 +1,85 @@ |
|||||||
|
#!/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. |
||||||
|
|
||||||
|
|
||||||
|
from .release_helper import * |
||||||
|
|
||||||
|
rp_pr_1 = '''{ |
||||||
|
"releases_created": "false", |
||||||
|
"paths_released": "[]", |
||||||
|
"prs_created": "true", |
||||||
|
"pr": "{\"headBranchName\":\"release-please--branches--main\",\"baseBranchName\":\"main\",\"number\":397,\"title\":\"chore: release main\",\"body\":\":robot: I have created a release *beep* *boop*\\n---\\n\\n\\n<details><summary>pyTermTk: 0.43.0-a.0</summary>\\n\\n## [0.43.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/pyTermTk-v0.42.1-a.0...pyTermTk-v0.43.0-a.0) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **kodeTab:** reworked iterWidget in iterItems\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Fixes\\n\\n* **spinbox:** better check for float, empty strings and negative numbers ([4909bf6](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/4909bf6756000f9450249b28f8c8379a2160415c))\\n\\n\\n### Chores\\n\\n* **kodeTab:** reworked iterWidget in iterItems ([47f73fc](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/47f73fc03a5a049ac3e6073dcadc09018b509328))\\n* **ttk:** workaround timer disconnect in case of error ([d70b2c1](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/d70b2c1c3cf25f7ffb479bc2850b3c9a3ca0fe0c))\\n\\n\\n### Refactors\\n\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n* **TTkColor:** improved typings ([711d611](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/711d611a73be0d0a6fce37e4624b5ae30847dd9c))\\n</details>\\n\\n<details><summary>ttkode: 0.4.0-a.2</summary>\\n\\n## [0.4.0-a.2](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/ttkode-v0.3.2-a.2...ttkode-v0.4.0-a.2) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Refactors\\n\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n</details>\\n\\n<details><summary>tlogg: 0.7.0-a.0</summary>\\n\\n## [0.7.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/tlogg-v0.6.0-a.0...tlogg-v0.7.0-a.0) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Refactors\\n\\n* move the main routine outside the a folder ([#400](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/400)) ([b1bb71f](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/b1bb71fd1ecd9c41a4cb016de15f1d695ea58ba5))\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n</details>\\n\\n---\\nThis PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).\",\"files\":[],\"labels\":[\"autorelease: pending\"]}", |
||||||
|
"prs": "[{\"headBranchName\":\"release-please--branches--main\",\"baseBranchName\":\"main\",\"number\":397,\"title\":\"chore: release main\",\"body\":\":robot: I have created a release *beep* *boop*\\n---\\n\\n\\n<details><summary>pyTermTk: 0.43.0-a.0</summary>\\n\\n## [0.43.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/pyTermTk-v0.42.1-a.0...pyTermTk-v0.43.0-a.0) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **kodeTab:** reworked iterWidget in iterItems\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Fixes\\n\\n* **spinbox:** better check for float, empty strings and negative numbers ([4909bf6](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/4909bf6756000f9450249b28f8c8379a2160415c))\\n\\n\\n### Chores\\n\\n* **kodeTab:** reworked iterWidget in iterItems ([47f73fc](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/47f73fc03a5a049ac3e6073dcadc09018b509328))\\n* **ttk:** workaround timer disconnect in case of error ([d70b2c1](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/d70b2c1c3cf25f7ffb479bc2850b3c9a3ca0fe0c))\\n\\n\\n### Refactors\\n\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n* **TTkColor:** improved typings ([711d611](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/711d611a73be0d0a6fce37e4624b5ae30847dd9c))\\n</details>\\n\\n<details><summary>ttkode: 0.4.0-a.2</summary>\\n\\n## [0.4.0-a.2](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/ttkode-v0.3.2-a.2...ttkode-v0.4.0-a.2) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Refactors\\n\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n</details>\\n\\n<details><summary>tlogg: 0.7.0-a.0</summary>\\n\\n## [0.7.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/tlogg-v0.6.0-a.0...tlogg-v0.7.0-a.0) (2025-05-28)\\n\\n\\n### ⚠ BREAKING CHANGES\\n\\n* **TabWidget:** tab request close event need to be handled inside the app\\n\\n### Refactors\\n\\n* move the main routine outside the a folder ([#400](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/400)) ([b1bb71f](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/b1bb71fd1ecd9c41a4cb016de15f1d695ea58ba5))\\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\\n</details>\\n\\n---\\nThis PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).\",\"files\":[],\"labels\":[\"autorelease: pending\"]}]" |
||||||
|
} |
||||||
|
''' |
||||||
|
|
||||||
|
rp_release_1 = '''{ |
||||||
|
"releases_created": "true", |
||||||
|
"libs/pyTermTk--release_created": "true", |
||||||
|
"libs/pyTermTk--id": "222844982", |
||||||
|
"libs/pyTermTk--name": "pyTermTk: v0.43.0-a.0", |
||||||
|
"libs/pyTermTk--tag_name": "pyTermTk-v0.43.0-a.0", |
||||||
|
"libs/pyTermTk--sha": "edce717e527f2fe93a8a0c7f17e08a6b5fecd7bd", |
||||||
|
"libs/pyTermTk--body": "## [0.43.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/pyTermTk-v0.42.1-a.0...pyTermTk-v0.43.0-a.0) (2025-06-03)\n\n\n### ⚠ BREAKING CHANGES\n\n* **kodeTab:** reworked iterWidget in iterItems\n* **TabWidget:** tab request close event need to be handled inside the app\n\n### Fixes\n\n* **spinbox:** better check for float, empty strings and negative numbers ([4909bf6](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/4909bf6756000f9450249b28f8c8379a2160415c))\n\n\n### Chores\n\n* autogen code for scrollarea classes ([#406](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/406)) ([fef1b0e](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/fef1b0ea5bd6ddc8f3e8f93a23ea156071e77493))\n* **Input:** add support for ctrl and other key comination ([#404](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/404)) ([5c2bb92](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/5c2bb9202cd819aa573e9f0d9ea966a4d0e5c485))\n* **kodeTab:** reworked iterWidget in iterItems ([47f73fc](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/47f73fc03a5a049ac3e6073dcadc09018b509328))\n* **spinbox:** fix return type ([ddc53a0](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/ddc53a07653a6f3aa958509d7d400cc6c6264d91))\n* **spinbox:** handle left/right wheel event ([ce961a6](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/ce961a657573ee520b73fca7d4ae721a8837a1d0))\n* **ttk:** workaround timer disconnect in case of error ([d70b2c1](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/d70b2c1c3cf25f7ffb479bc2850b3c9a3ca0fe0c))\n\n\n### Refactors\n\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))\n* **TTkColor:** improved typings ([711d611](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/711d611a73be0d0a6fce37e4624b5ae30847dd9c))", |
||||||
|
"libs/pyTermTk--html_url": "https://github.com/ceccopierangiolieugenio/pyTermTk/releases/tag/pyTermTk-v0.43.0-a.0", |
||||||
|
"libs/pyTermTk--draft": "false", |
||||||
|
"libs/pyTermTk--upload_url": "https://uploads.github.com/repos/ceccopierangiolieugenio/pyTermTk/releases/222844982/assets{?name,label}", |
||||||
|
"libs/pyTermTk--path": "libs/pyTermTk", |
||||||
|
"libs/pyTermTk--version": "0.43.0-a.0", |
||||||
|
"libs/pyTermTk--major": "0", |
||||||
|
"libs/pyTermTk--minor": "43", |
||||||
|
"libs/pyTermTk--patch": "0", |
||||||
|
"libs/pyTermTk--prNumber": "397", |
||||||
|
"apps/ttkode--release_created": "true", |
||||||
|
"apps/ttkode--id": "222844984", |
||||||
|
"apps/ttkode--name": "ttkode: v0.4.0-a.2", |
||||||
|
"apps/ttkode--tag_name": "ttkode-v0.4.0-a.2", |
||||||
|
"apps/ttkode--sha": "edce717e527f2fe93a8a0c7f17e08a6b5fecd7bd", |
||||||
|
"apps/ttkode--body": "## [0.4.0-a.2](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/ttkode-v0.3.2-a.2...ttkode-v0.4.0-a.2) (2025-06-03)\n\n\n### ⚠ BREAKING CHANGES\n\n* **TabWidget:** tab request close event need to be handled inside the app\n\n### Features\n\n* add save feature ([#407](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/407)) ([26ff9b2](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/26ff9b2f0a81bddadeb6849d5d560ae67406f973))\n\n\n### Refactors\n\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))", |
||||||
|
"apps/ttkode--html_url": "https://github.com/ceccopierangiolieugenio/pyTermTk/releases/tag/ttkode-v0.4.0-a.2", |
||||||
|
"apps/ttkode--draft": "false", |
||||||
|
"apps/ttkode--upload_url": "https://uploads.github.com/repos/ceccopierangiolieugenio/pyTermTk/releases/222844984/assets{?name,label}", |
||||||
|
"apps/ttkode--path": "apps/ttkode", |
||||||
|
"apps/ttkode--version": "0.4.0-a.2", |
||||||
|
"apps/ttkode--major": "0", |
||||||
|
"apps/ttkode--minor": "4", |
||||||
|
"apps/ttkode--patch": "0", |
||||||
|
"apps/ttkode--prNumber": "397", |
||||||
|
"apps/tlogg--release_created": "true", |
||||||
|
"apps/tlogg--id": "222844986", |
||||||
|
"apps/tlogg--name": "tlogg: v0.7.0-a.0", |
||||||
|
"apps/tlogg--tag_name": "tlogg-v0.7.0-a.0", |
||||||
|
"apps/tlogg--sha": "edce717e527f2fe93a8a0c7f17e08a6b5fecd7bd", |
||||||
|
"apps/tlogg--body": "## [0.7.0-a.0](https://github.com/ceccopierangiolieugenio/pyTermTk/compare/tlogg-v0.6.0-a.0...tlogg-v0.7.0-a.0) (2025-06-03)\n\n\n### ⚠ BREAKING CHANGES\n\n* **TabWidget:** tab request close event need to be handled inside the app\n\n### Refactors\n\n* move the main routine outside the a folder ([#400](https://github.com/ceccopierangiolieugenio/pyTermTk/issues/400)) ([b1bb71f](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/b1bb71fd1ecd9c41a4cb016de15f1d695ea58ba5))\n* **TabWidget:** tab request close event need to be handled inside the app ([9420adf](https://github.com/ceccopierangiolieugenio/pyTermTk/commit/9420adf68e2184482cd71266f280c560ea911f45))", |
||||||
|
"apps/tlogg--html_url": "https://github.com/ceccopierangiolieugenio/pyTermTk/releases/tag/tlogg-v0.7.0-a.0", |
||||||
|
"apps/tlogg--draft": "false", |
||||||
|
"apps/tlogg--upload_url": "https://uploads.github.com/repos/ceccopierangiolieugenio/pyTermTk/releases/222844986/assets{?name,label}", |
||||||
|
"apps/tlogg--path": "apps/tlogg", |
||||||
|
"apps/tlogg--version": "0.7.0-a.0", |
||||||
|
"apps/tlogg--major": "0", |
||||||
|
"apps/tlogg--minor": "7", |
||||||
|
"apps/tlogg--patch": "0", |
||||||
|
"apps/tlogg--prNumber": "397", |
||||||
|
"paths_released": "[\"libs/pyTermTk\",\"apps/ttkode\",\"apps/tlogg\"]", |
||||||
|
"prs_created": "false" |
||||||
|
}''' |
||||||
@ -0,0 +1,82 @@ |
|||||||
|
#!/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 os, sys |
||||||
|
import re |
||||||
|
import asyncio |
||||||
|
import argparse |
||||||
|
from typing import Dict,List,Any |
||||||
|
|
||||||
|
import discord |
||||||
|
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__)) |
||||||
|
sys.path.append(current_dir) |
||||||
|
from ci_tools.social.social_common import get_social_data, SocialData, get_env_var |
||||||
|
|
||||||
|
async def send_discord_message(version: str, data:SocialData): |
||||||
|
token = get_env_var("DISCORD_TOKEN") |
||||||
|
message = get_env_var("MESSAGE") |
||||||
|
|
||||||
|
intents = discord.Intents.default() |
||||||
|
client = discord.Client(intents=intents) |
||||||
|
|
||||||
|
embed = discord.Embed( |
||||||
|
title=f"{data.name} Released!!!", |
||||||
|
url=data.link, |
||||||
|
# description="Here's a new feature we added.", |
||||||
|
color=0x00ff00, |
||||||
|
) |
||||||
|
embed.add_field(name="Version", value=version, inline=True) |
||||||
|
# embed.add_field(name="What's New:", value=message, inline=False) |
||||||
|
|
||||||
|
# embed.set_image(url="https://example.com/image.png") |
||||||
|
# embed.add_field(name="Feature", value="Auto-messaging", inline=False) |
||||||
|
embed.set_footer(text="Bot by Pier...") |
||||||
|
message = re.sub(r'\((https?://[^\)]+)\)', r'(<\1>)', message).replace('\\n','\n')[:2000] |
||||||
|
# print(message) |
||||||
|
# exit(1) |
||||||
|
|
||||||
|
@client.event |
||||||
|
async def on_ready(): |
||||||
|
print(f'Logged in as {client.user}') |
||||||
|
channel = client.get_channel(data.discord_channel_id) |
||||||
|
await channel.send(embed=embed) |
||||||
|
await channel.send(message) |
||||||
|
await client.close() # Optional: close after sending |
||||||
|
|
||||||
|
await client.start(token) |
||||||
|
|
||||||
|
def main(): |
||||||
|
parser = argparse.ArgumentParser(description="Send a Discord notification.") |
||||||
|
parser.add_argument("app", type=str, help="The application name.") |
||||||
|
parser.add_argument("version", type=str, help="The application version.") |
||||||
|
args = parser.parse_args() |
||||||
|
|
||||||
|
data = get_social_data(args.app) |
||||||
|
if not data: |
||||||
|
raise ValueError(f"app: {args.app} is not recognised") |
||||||
|
|
||||||
|
asyncio.run(send_discord_message(args.version, data)) |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
# 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.from dataclasses import dataclass |
||||||
|
|
||||||
|
__all__ = ['get_social_data','SocialData','get_env_var'] |
||||||
|
|
||||||
|
import os |
||||||
|
from dataclasses import dataclass |
||||||
|
from typing import List |
||||||
|
|
||||||
|
@dataclass |
||||||
|
class SocialData(): |
||||||
|
name: str |
||||||
|
link: str |
||||||
|
discord_channel_id: int |
||||||
|
|
||||||
|
_all_data:List[SocialData] = [ |
||||||
|
SocialData( |
||||||
|
name='pytermtk', |
||||||
|
link='https://github.com/ceccopierangiolieugenio/pyTermTk', |
||||||
|
discord_channel_id=1379381341145268305, |
||||||
|
), |
||||||
|
SocialData( |
||||||
|
name='ttkode', |
||||||
|
link='https://github.com/ceccopierangiolieugenio/pyTermTk/tree/main/apps/ttkode', |
||||||
|
discord_channel_id=1379381474783924295, |
||||||
|
), |
||||||
|
SocialData( |
||||||
|
name='dumbpainttool', |
||||||
|
link='https://github.com/ceccopierangiolieugenio/pyTermTk/tree/main/apps/dumbPaintTool', |
||||||
|
discord_channel_id=1379381571412430931, |
||||||
|
), |
||||||
|
SocialData( |
||||||
|
name='tlogg', |
||||||
|
link='https://github.com/ceccopierangiolieugenio/pyTermTk/tree/main/apps/tlogg', |
||||||
|
discord_channel_id=1379381593378000916, |
||||||
|
), |
||||||
|
] |
||||||
|
|
||||||
|
def get_social_data(app:str) -> SocialData: |
||||||
|
for _sd in _all_data: |
||||||
|
if _sd.name.lower() == app.lower(): |
||||||
|
return _sd |
||||||
|
raise ValueError(f"app: {app} is not recognised") |
||||||
|
|
||||||
|
def get_env_var(name:str) -> str: |
||||||
|
value = os.environ.get(name) |
||||||
|
if value is None: |
||||||
|
raise EnvironmentError(f"{name} environment variable is not available") |
||||||
|
return value |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
[build-system] |
||||||
|
requires = ["setuptools>=45", "wheel"] |
||||||
|
build-backend = "setuptools.build_meta" |
||||||
|
|
||||||
|
[project] |
||||||
|
name = "ci_tools" |
||||||
|
version = "0.1.0" |
||||||
|
description = "ci helpers" |
||||||
|
authors = [ |
||||||
|
{name = "Eugenio Parodi", email = "ceccopierangiolieugenio@googlemail.com"}, |
||||||
|
] |
||||||
|
requires-python = ">=3.9" |
||||||
|
dependencies = [ |
||||||
|
'GitPython==3.1.44' |
||||||
|
] |
||||||
|
|
||||||
|
[project.optional-dependencies] |
||||||
|
social = [ |
||||||
|
'discord.py==2.5.2' |
||||||
|
] |
||||||
|
|
||||||
|
[project.scripts] |
||||||
|
release-helper = "ci_tools.release_helper:main" |
||||||
|
notify-discord = "ci_tools.social.notify_discord:main" |
||||||
|
|
||||||
|
[tool.setuptools] |
||||||
|
packages = ["ci_tools"] |
||||||
Loading…
Reference in new issue