Skip to content

Commit b9af66c

Browse files
committed
Added a release workflow and a release number script
1 parent 4d686bd commit b9af66c

2 files changed

Lines changed: 246 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Build and Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'R[0-9]+.[0-9]+.[0-9]+'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
runs-on: windows-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: '3.x'
23+
cache: 'pip'
24+
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install -r requirements.txt
29+
30+
- name: Build tools
31+
run: |
32+
cd buildspec
33+
python build_tools.py all
34+
35+
- name: Extract version from tag
36+
id: version
37+
run: |
38+
$tag = '${{ github.ref_name }}'
39+
$version = $tag -replace '^R', ''
40+
echo "version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
41+
42+
- name: Create Release
43+
uses: softprops/action-gh-release@v2
44+
with:
45+
files: buildspec/dist/*.exe
46+
tag_name: ${{ github.ref_name }}
47+
name: 'JMF-Python ${{ steps.version.outputs.version }}'
48+
draft: false
49+
prerelease: false

buildspec/CreateRelease.py

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Release management script for JMF-Python tools.
5+
Extracts version from README.md and updates all version-related files.
6+
"""
7+
8+
import re
9+
import sys
10+
import argparse
11+
from pathlib import Path
12+
13+
14+
def get_version():
15+
"""Read the version string from README.md and return (tag, (major, minor, patch))."""
16+
readme = Path(__file__).resolve().parent.parent / 'README.md'
17+
try:
18+
first_line = readme.read_text(encoding='utf-8').splitlines()[0]
19+
match = re.search(r'R(\d+)\.(\d+)\.(\d+)', first_line)
20+
if match:
21+
return match.group(0), tuple(int(x) for x in match.groups())
22+
except Exception as e:
23+
print(f"[ERROR] Failed to read README.md: {e}")
24+
return None, None
25+
26+
print("[ERROR] Could not find version in README.md (expected format: R#.#.#)")
27+
return None, None
28+
29+
30+
def get_version_files(buildspec_dir):
31+
"""Get list of all version-related files in buildspec."""
32+
version_files = []
33+
34+
# Find all *_version_info.txt files
35+
for txt_file in buildspec_dir.glob('*_version_info.txt'):
36+
version_files.append(txt_file)
37+
38+
return sorted(version_files)
39+
40+
41+
def generate_version_info(tool, version_str, version_tuple):
42+
"""Generate content for a PyInstaller version resource file."""
43+
major, minor, patch = version_tuple
44+
content = (
45+
'VSVersionInfo(\n'
46+
' ffi=FixedFileInfo(\n'
47+
f' filevers=({major}, {minor}, {patch}, 0),\n'
48+
f' prodvers=({major}, {minor}, {patch}, 0),\n'
49+
' mask=0x3f,\n'
50+
' flags=0x0,\n'
51+
' OS=0x4,\n'
52+
' fileType=0x1,\n'
53+
' subtype=0x0,\n'
54+
' date=(0, 0)\n'
55+
' ),\n'
56+
' kids=[\n'
57+
' StringFileInfo(\n'
58+
' [\n'
59+
' StringTable(\n'
60+
" u'040904B0',\n"
61+
" [StringStruct(u'CompanyName', u'Canon Production Printing'),\n"
62+
f" StringStruct(u'FileDescription', u'{tool}'),\n"
63+
f" StringStruct(u'FileVersion', u'{major}.{minor}.{patch}.0'),\n"
64+
f" StringStruct(u'InternalName', u'{tool}'),\n"
65+
f" StringStruct(u'OriginalFilename', u'{tool}.exe'),\n"
66+
" StringStruct(u'ProductName', u'JMF Python Tools'),\n"
67+
f" StringStruct(u'ProductVersion', u'{major}.{minor}.{patch}.0')])\n"
68+
' ]),\n'
69+
" VarFileInfo([VarStruct(u'Translation', [1033, 1200])])\n"
70+
' ]\n'
71+
')\n'
72+
)
73+
return content
74+
75+
76+
def update_version_files(buildspec_dir, version_str, version_tuple, dry_run=False):
77+
"""Update all version files with the new version."""
78+
version_files = get_version_files(buildspec_dir)
79+
80+
if not version_files:
81+
print("[WARN] No version files found")
82+
return 0
83+
84+
updated = 0
85+
86+
for ver_file in version_files:
87+
# Extract tool name from filename (e.g., "CreateMimePackage_version_info.txt" -> "CreateMimePackage")
88+
tool = ver_file.stem.replace('_version_info', '')
89+
90+
new_content = generate_version_info(tool, version_str, version_tuple)
91+
92+
if dry_run:
93+
print(f"[DRY-RUN] Would update: {ver_file.name}")
94+
updated += 1
95+
else:
96+
try:
97+
ver_file.write_text(new_content, encoding='utf-8')
98+
print(f"[OK] Updated: {ver_file.name} ({version_str})")
99+
updated += 1
100+
except Exception as e:
101+
print(f"[ERROR] Failed to update {ver_file.name}: {e}")
102+
103+
return updated
104+
105+
106+
def list_version_files(buildspec_dir):
107+
"""List all version files and their current content."""
108+
version_files = get_version_files(buildspec_dir)
109+
110+
if not version_files:
111+
print("[WARN] No version files found")
112+
return
113+
114+
print("\nVersion files in buildspec:")
115+
print("=" * 60)
116+
117+
for ver_file in version_files:
118+
tool = ver_file.stem.replace('_version_info', '')
119+
print(f"\n File: {ver_file.name}")
120+
print(f" Tool: {tool}")
121+
122+
# Extract version from file content
123+
try:
124+
content = ver_file.read_text(encoding='utf-8')
125+
match = re.search(r"FileVersion', u'(\d+\.\d+\.\d+)", content)
126+
if match:
127+
print(f" Current Version: {match.group(1)}")
128+
except Exception as e:
129+
print(f" Error reading: {e}")
130+
131+
print("\n" + "=" * 60)
132+
133+
134+
def main():
135+
"""Parse arguments and execute version update operations."""
136+
parser = argparse.ArgumentParser(
137+
description="Release management for JMF-Python tools. Updates all version information from README.md."
138+
)
139+
parser.add_argument(
140+
'--list',
141+
action='store_true',
142+
help='List all version files and their current versions'
143+
)
144+
parser.add_argument(
145+
'--dry-run',
146+
action='store_true',
147+
help='Show what would be updated without making changes'
148+
)
149+
parser.add_argument(
150+
'--update',
151+
action='store_true',
152+
help='Update all version files with version from README.md'
153+
)
154+
155+
args = parser.parse_args()
156+
157+
buildspec_dir = Path(__file__).resolve().parent
158+
159+
# If no arguments provided, show help and list current versions
160+
if not any([args.list, args.dry_run, args.update]):
161+
parser.print_help()
162+
print("\n")
163+
list_version_files(buildspec_dir)
164+
return 0
165+
166+
# Read version from README.md
167+
version_str, version_tuple = get_version()
168+
if not version_str:
169+
return 1
170+
171+
print(f"\nVersion from README.md: {version_str}")
172+
print(f"Version tuple: {version_tuple}")
173+
print()
174+
175+
if args.list:
176+
list_version_files(buildspec_dir)
177+
return 0
178+
179+
if args.dry_run or args.update:
180+
updated = update_version_files(buildspec_dir, version_str, version_tuple, dry_run=args.dry_run)
181+
182+
print()
183+
print("=" * 60)
184+
if args.dry_run:
185+
print(f"[DRY-RUN] Would update {updated} version file(s)")
186+
print("Run with --update to apply changes")
187+
else:
188+
print(f"[OK] Updated {updated} version file(s)")
189+
print("=" * 60)
190+
191+
return 0
192+
193+
return 0
194+
195+
196+
if __name__ == '__main__':
197+
sys.exit(main())

0 commit comments

Comments
 (0)