backend-infra-engineer: Release v0.3.0 snapshot
This commit is contained in:
369
scripts/agent.sh
Executable file
369
scripts/agent.sh
Executable file
@@ -0,0 +1,369 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Unified background agent script for YAZE (macOS launchd, Linux systemd)
|
||||
# Subcommands:
|
||||
# install [--build-type X] [--use-inotify] [--ubuntu-bootstrap] [--enable-linger]
|
||||
# uninstall
|
||||
# run-once # one-shot build & test
|
||||
# watch # linux: inotify-based watch loop
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
BUILD_DIR_DEFAULT="${PROJECT_ROOT}/build"
|
||||
BUILD_TYPE_DEFAULT="Debug"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 <subcommand> [options]
|
||||
|
||||
Subcommands:
|
||||
install Install background agent
|
||||
--build-type X CMake build type (default: ${BUILD_TYPE_DEFAULT})
|
||||
--use-inotify Linux: use long-lived inotify watcher
|
||||
--ubuntu-bootstrap Install Ubuntu deps via apt (sudo)
|
||||
--enable-linger Enable user lingering (Linux)
|
||||
|
||||
uninstall Remove installed background agent
|
||||
|
||||
run-once One-shot build and test
|
||||
env: BUILD_DIR, BUILD_TYPE
|
||||
|
||||
watch Linux: inotify-based watch loop
|
||||
env: BUILD_DIR, BUILD_TYPE, INTERVAL_SECONDS (fallback)
|
||||
|
||||
Environment:
|
||||
BUILD_DIR Build directory (default: ${BUILD_DIR_DEFAULT})
|
||||
BUILD_TYPE CMake build type (default: ${BUILD_TYPE_DEFAULT})
|
||||
EOF
|
||||
}
|
||||
|
||||
build_and_test() {
|
||||
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
|
||||
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
|
||||
local log_file="${LOG_FILE:-"${build_dir}/yaze_agent.log"}"
|
||||
|
||||
mkdir -p "${build_dir}"
|
||||
{
|
||||
echo "==== $(date '+%Y-%m-%d %H:%M:%S') | yaze agent run (type=${build_type}) ===="
|
||||
echo "Project: ${PROJECT_ROOT}"
|
||||
|
||||
cmake -S "${PROJECT_ROOT}" -B "${build_dir}" -DCMAKE_BUILD_TYPE="${build_type}"
|
||||
cmake --build "${build_dir}" --config "${build_type}" -j
|
||||
|
||||
if [[ -x "${build_dir}/bin/yaze_test" ]]; then
|
||||
"${build_dir}/bin/yaze_test"
|
||||
else
|
||||
if command -v ctest >/dev/null 2>&1; then
|
||||
ctest --test-dir "${build_dir}" --output-on-failure
|
||||
else
|
||||
echo "ctest not found and test binary missing. Skipping tests." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
} >>"${log_file}" 2>&1
|
||||
}
|
||||
|
||||
sub_run_once() {
|
||||
build_and_test
|
||||
}
|
||||
|
||||
sub_watch() {
|
||||
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
|
||||
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
|
||||
local interval="${INTERVAL_SECONDS:-5}"
|
||||
mkdir -p "${build_dir}"
|
||||
if command -v inotifywait >/dev/null 2>&1; then
|
||||
echo "[agent] using inotifywait watcher"
|
||||
while true; do
|
||||
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
|
||||
inotifywait -r -e modify,create,delete,move \
|
||||
"${PROJECT_ROOT}/src" \
|
||||
"${PROJECT_ROOT}/test" \
|
||||
"${PROJECT_ROOT}/CMakeLists.txt" \
|
||||
"${PROJECT_ROOT}/src/CMakeLists.txt" >/dev/null 2>&1 || true
|
||||
done
|
||||
else
|
||||
echo "[agent] inotifywait not found; running periodic loop (${interval}s)"
|
||||
while true; do
|
||||
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
|
||||
sleep "${interval}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_exec() {
|
||||
if [[ ! -x "$1" ]]; then
|
||||
chmod +x "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
ubuntu_bootstrap() {
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y inotify-tools build-essential cmake ninja-build pkg-config \
|
||||
libsdl2-dev libpng-dev libglew-dev libwavpack-dev libabsl-dev \
|
||||
libboost-all-dev libboost-python-dev python3-dev libpython3-dev
|
||||
else
|
||||
echo "apt-get not found; skipping Ubuntu bootstrap" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
enable_linger_linux() {
|
||||
if command -v loginctl >/dev/null 2>&1; then
|
||||
if sudo -n true 2>/dev/null; then
|
||||
sudo loginctl enable-linger "$USER" || true
|
||||
else
|
||||
echo "Note: enabling linger may require sudo: sudo loginctl enable-linger $USER" >&2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Wrapper to run systemctl --user with a session bus in headless shells
|
||||
systemctl_user() {
|
||||
# Only apply on Linux
|
||||
if [[ "$(uname -s)" != "Linux" ]]; then
|
||||
systemctl "$@"
|
||||
return
|
||||
fi
|
||||
local uid
|
||||
uid="$(id -u)"
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/${uid}}"
|
||||
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=${XDG_RUNTIME_DIR}/bus}"
|
||||
if [[ ! -S "${XDG_RUNTIME_DIR}/bus" ]]; then
|
||||
echo "[agent] Warning: user bus not found at ${XDG_RUNTIME_DIR}/bus. If this fails, run: sudo loginctl enable-linger $USER" >&2
|
||||
fi
|
||||
systemctl --user "$@"
|
||||
}
|
||||
|
||||
is_systemd_available() {
|
||||
# True if systemd is PID 1 and systemctl exists and a user bus likely available
|
||||
if [[ ! -d /run/systemd/system ]]; then
|
||||
return 1
|
||||
fi
|
||||
if ! command -v systemctl >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
start_userland_agent() {
|
||||
local build_type="${1}"
|
||||
local build_dir="${2}"
|
||||
local agent_home="$HOME/.local/share/yaze-agent"
|
||||
mkdir -p "${agent_home}"
|
||||
local log_file="${agent_home}/agent.log"
|
||||
nohup env BUILD_TYPE="${build_type}" BUILD_DIR="${build_dir}" "${SCRIPT_DIR}/agent.sh" watch >>"${log_file}" 2>&1 & echo $! > "${agent_home}/agent.pid"
|
||||
echo "Userland agent started (PID $(cat "${agent_home}/agent.pid")) - logs: ${log_file}"
|
||||
}
|
||||
|
||||
stop_userland_agent() {
|
||||
local agent_home="$HOME/.local/share/yaze-agent"
|
||||
local pid_file="${agent_home}/agent.pid"
|
||||
if [[ -f "${pid_file}" ]]; then
|
||||
local pid
|
||||
pid="$(cat "${pid_file}")"
|
||||
if kill -0 "${pid}" >/dev/null 2>&1; then
|
||||
kill "${pid}" || true
|
||||
fi
|
||||
rm -f "${pid_file}"
|
||||
echo "Stopped userland agent"
|
||||
fi
|
||||
}
|
||||
|
||||
install_macos() {
|
||||
local build_type="${1}"
|
||||
local build_dir="${2}"
|
||||
local label="com.yaze.watchtest"
|
||||
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
|
||||
|
||||
mkdir -p "${build_dir}"
|
||||
|
||||
cat >"$plist_path" <<PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>${label}</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/zsh</string>
|
||||
<string>-lc</string>
|
||||
<string>"${SCRIPT_DIR}/agent.sh" run-once</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${PROJECT_ROOT}</string>
|
||||
<key>WatchPaths</key>
|
||||
<array>
|
||||
<string>${PROJECT_ROOT}/src</string>
|
||||
<string>${PROJECT_ROOT}/test</string>
|
||||
<string>${PROJECT_ROOT}/CMakeLists.txt</string>
|
||||
<string>${PROJECT_ROOT}/src/CMakeLists.txt</string>
|
||||
</array>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${build_dir}/yaze_agent.out.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${build_dir}/yaze_agent.err.log</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>BUILD_TYPE</key><string>${build_type}</string>
|
||||
<key>BUILD_DIR</key><string>${build_dir}</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
launchctl unload -w "$plist_path" 2>/dev/null || true
|
||||
launchctl load -w "$plist_path"
|
||||
echo "LaunchAgent installed and loaded: ${plist_path}"
|
||||
}
|
||||
|
||||
install_linux() {
|
||||
local build_type="${1}"
|
||||
local build_dir="${2}"
|
||||
local use_inotify="${3}"
|
||||
local systemd_dir="$HOME/.config/systemd/user"
|
||||
local service_name="yaze-watchtest.service"
|
||||
local path_name="yaze-watchtest.path"
|
||||
|
||||
mkdir -p "${systemd_dir}" "${build_dir}"
|
||||
|
||||
if ! is_systemd_available; then
|
||||
echo "[agent] systemd not available; installing userland background agent"
|
||||
start_userland_agent "${build_type}" "${build_dir}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "${use_inotify}" == "1" ]]; then
|
||||
cat >"${systemd_dir}/yaze-watchtest-inotify.service" <<UNIT
|
||||
[Unit]
|
||||
Description=Yaze inotify watcher build-and-test
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=BUILD_TYPE=${build_type}
|
||||
Environment=BUILD_DIR=${build_dir}
|
||||
WorkingDirectory=${PROJECT_ROOT}
|
||||
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" watch'
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
UNIT
|
||||
|
||||
systemctl_user daemon-reload
|
||||
systemctl_user enable --now yaze-watchtest-inotify.service
|
||||
echo "systemd user service enabled: yaze-watchtest-inotify.service"
|
||||
return
|
||||
fi
|
||||
|
||||
cat >"${systemd_dir}/${service_name}" <<UNIT
|
||||
[Unit]
|
||||
Description=Yaze build-and-test (one-shot)
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=BUILD_TYPE=${build_type}
|
||||
Environment=BUILD_DIR=${build_dir}
|
||||
WorkingDirectory=${PROJECT_ROOT}
|
||||
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" run-once'
|
||||
UNIT
|
||||
|
||||
cat >"${systemd_dir}/${path_name}" <<UNIT
|
||||
[Unit]
|
||||
Description=Watch Yaze src/test for changes
|
||||
|
||||
[Path]
|
||||
PathModified=${PROJECT_ROOT}/src
|
||||
PathModified=${PROJECT_ROOT}/test
|
||||
PathModified=${PROJECT_ROOT}/CMakeLists.txt
|
||||
PathModified=${PROJECT_ROOT}/src/CMakeLists.txt
|
||||
Unit=${service_name}
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
UNIT
|
||||
|
||||
systemctl_user daemon-reload
|
||||
systemctl_user enable --now "$path_name"
|
||||
echo "systemd user path unit enabled: ${path_name}"
|
||||
systemctl_user start "$service_name" || true
|
||||
}
|
||||
|
||||
sub_install() {
|
||||
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
|
||||
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
|
||||
local use_inotify=0
|
||||
local do_bootstrap=0
|
||||
local do_linger=0
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--build-type) build_type="$2"; shift 2 ;;
|
||||
--use-inotify) use_inotify=1; shift ;;
|
||||
--ubuntu-bootstrap) do_bootstrap=1; shift ;;
|
||||
--enable-linger) do_linger=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown option for install: $1" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$(uname -s)" in
|
||||
Darwin)
|
||||
install_macos "${build_type}" "${build_dir}" ;;
|
||||
Linux)
|
||||
if (( do_bootstrap == 1 )); then ubuntu_bootstrap; fi
|
||||
if (( do_linger == 1 )); then enable_linger_linux; fi
|
||||
install_linux "${build_type}" "${build_dir}" "${use_inotify}" ;;
|
||||
*)
|
||||
echo "Unsupported platform" >&2; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
sub_uninstall() {
|
||||
case "$(uname -s)" in
|
||||
Darwin)
|
||||
local label="com.yaze.watchtest"
|
||||
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
|
||||
launchctl unload -w "$plist_path" 2>/dev/null || true
|
||||
rm -f "$plist_path"
|
||||
echo "Removed LaunchAgent ${label}"
|
||||
;;
|
||||
Linux)
|
||||
local systemd_dir="$HOME/.config/systemd/user"
|
||||
if is_systemd_available; then
|
||||
systemctl_user stop yaze-watchtest.path 2>/dev/null || true
|
||||
systemctl_user disable yaze-watchtest.path 2>/dev/null || true
|
||||
systemctl_user stop yaze-watchtest.service 2>/dev/null || true
|
||||
systemctl_user stop yaze-watchtest-inotify.service 2>/dev/null || true
|
||||
systemctl_user disable yaze-watchtest-inotify.service 2>/dev/null || true
|
||||
rm -f "${systemd_dir}/yaze-watchtest.service" "${systemd_dir}/yaze-watchtest.path" "${systemd_dir}/yaze-watchtest-inotify.service"
|
||||
systemctl_user daemon-reload || true
|
||||
echo "Removed systemd user units"
|
||||
fi
|
||||
stop_userland_agent
|
||||
;;
|
||||
*) echo "Unsupported platform" >&2; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
ensure_exec "$0"
|
||||
local subcmd="${1:-}"; shift || true
|
||||
case "${subcmd}" in
|
||||
install) sub_install "$@" ;;
|
||||
uninstall) sub_uninstall ;;
|
||||
run-once) sub_run_once ;;
|
||||
watch) sub_watch ;;
|
||||
-h|--help|help|"") usage ;;
|
||||
*) echo "Unknown subcommand: ${subcmd}" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
|
||||
138
scripts/create_release.sh
Executable file
138
scripts/create_release.sh
Executable file
@@ -0,0 +1,138 @@
|
||||
#!/bin/bash
|
||||
# Script to create a proper release tag for YAZE
|
||||
# Usage: ./scripts/create_release.sh [version]
|
||||
# Example: ./scripts/create_release.sh 0.3.0
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# Check if we're in a git repository
|
||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
print_error "Not in a git repository!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if we're on master branch
|
||||
current_branch=$(git branch --show-current)
|
||||
if [ "$current_branch" != "master" ]; then
|
||||
print_warning "You're on branch '$current_branch', not 'master'"
|
||||
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_info "Switching to master branch..."
|
||||
git checkout master
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get version argument or prompt for it
|
||||
if [ $# -eq 0 ]; then
|
||||
echo
|
||||
print_info "Enter the version number (e.g., 0.3.0, 1.0.0-beta, 2.1.0-rc1):"
|
||||
read -p "Version: " version
|
||||
else
|
||||
version=$1
|
||||
fi
|
||||
|
||||
# Validate version format
|
||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
|
||||
print_error "Invalid version format: '$version'"
|
||||
print_info "Version must follow semantic versioning (e.g., 1.2.3 or 1.2.3-beta)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create tag with v prefix
|
||||
tag="v$version"
|
||||
|
||||
# Check if tag already exists
|
||||
if git tag -l | grep -q "^$tag$"; then
|
||||
print_error "Tag '$tag' already exists!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show current status
|
||||
echo
|
||||
print_info "Current repository status:"
|
||||
git status --short
|
||||
|
||||
# Check for uncommitted changes
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
print_warning "You have uncommitted changes!"
|
||||
read -p "Continue with creating release? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_info "Please commit your changes first, then run this script again."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Show what will happen
|
||||
echo
|
||||
print_info "Creating release for YAZE:"
|
||||
echo " 📦 Version: $version"
|
||||
echo " 🏷️ Tag: $tag"
|
||||
echo " 🌿 Branch: $current_branch"
|
||||
echo " 📝 Changelog: docs/C1-changelog.md"
|
||||
echo
|
||||
|
||||
# Confirm
|
||||
read -p "Create this release? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_info "Release creation cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create and push tag
|
||||
print_info "Creating tag '$tag'..."
|
||||
if git tag -a "$tag" -m "Release $tag"; then
|
||||
print_success "Tag '$tag' created successfully!"
|
||||
else
|
||||
print_error "Failed to create tag!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Pushing tag to origin..."
|
||||
if git push origin "$tag"; then
|
||||
print_success "Tag pushed successfully!"
|
||||
else
|
||||
print_error "Failed to push tag!"
|
||||
print_info "You can manually push with: git push origin $tag"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
print_success "🎉 Release $tag created successfully!"
|
||||
print_info "The GitHub Actions release workflow will now:"
|
||||
echo " • Build packages for Windows, macOS, and Linux"
|
||||
echo " • Extract changelog from docs/C1-changelog.md"
|
||||
echo " • Create GitHub release with all assets"
|
||||
echo " • Include themes, fonts, layouts, and documentation"
|
||||
echo
|
||||
print_info "Check the release progress at:"
|
||||
echo " https://github.com/scawful/yaze/actions"
|
||||
echo
|
||||
print_info "The release will be available at:"
|
||||
echo " https://github.com/scawful/yaze/releases/tag/$tag"
|
||||
94
scripts/extract_changelog.py
Executable file
94
scripts/extract_changelog.py
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Extract changelog section for a specific version from docs/C1-changelog.md
|
||||
Usage: python3 extract_changelog.py <version>
|
||||
Example: python3 extract_changelog.py 0.3.0
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
def extract_version_changelog(version_num, changelog_file):
|
||||
"""Extract changelog section for specific version"""
|
||||
try:
|
||||
with open(changelog_file, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Find the section for this version
|
||||
version_pattern = rf"## {re.escape(version_num)}\s*\([^)]+\)"
|
||||
next_version_pattern = r"## \d+\.\d+\.\d+\s*\([^)]+\)"
|
||||
|
||||
# Find start of current version section
|
||||
version_match = re.search(version_pattern, content)
|
||||
if not version_match:
|
||||
return f"Changelog section not found for version {version_num}."
|
||||
|
||||
start_pos = version_match.end()
|
||||
|
||||
# Find start of next version section
|
||||
remaining_content = content[start_pos:]
|
||||
next_match = re.search(next_version_pattern, remaining_content)
|
||||
|
||||
if next_match:
|
||||
end_pos = start_pos + next_match.start()
|
||||
section_content = content[start_pos:end_pos].strip()
|
||||
else:
|
||||
section_content = remaining_content.strip()
|
||||
|
||||
return section_content
|
||||
|
||||
except Exception as e:
|
||||
return f"Error reading changelog: {str(e)}"
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python3 extract_changelog.py <version>")
|
||||
sys.exit(1)
|
||||
|
||||
version_num = sys.argv[1]
|
||||
changelog_file = "docs/C1-changelog.md"
|
||||
|
||||
# Check if changelog file exists
|
||||
if not os.path.exists(changelog_file):
|
||||
print(f"Error: Changelog file {changelog_file} not found")
|
||||
sys.exit(1)
|
||||
|
||||
# Extract changelog content
|
||||
changelog_content = extract_version_changelog(version_num, changelog_file)
|
||||
|
||||
# Generate full release notes
|
||||
release_notes = f"""# Yaze v{version_num} Release Notes
|
||||
|
||||
{changelog_content}
|
||||
|
||||
## Download Instructions
|
||||
|
||||
### Windows
|
||||
- Download `yaze-windows-x64.zip` for 64-bit Windows
|
||||
- Download `yaze-windows-x86.zip` for 32-bit Windows
|
||||
- Extract and run `yaze.exe`
|
||||
|
||||
### macOS
|
||||
- Download `yaze-macos.dmg`
|
||||
- Mount the DMG and drag Yaze to Applications
|
||||
- You may need to allow the app in System Preferences > Security & Privacy
|
||||
|
||||
### Linux
|
||||
- Download `yaze-linux-x64.tar.gz`
|
||||
- Extract: `tar -xzf yaze-linux-x64.tar.gz`
|
||||
- Run: `./yaze`
|
||||
|
||||
## System Requirements
|
||||
- **Windows**: Windows 10 or later (64-bit recommended)
|
||||
- **macOS**: macOS 10.15 (Catalina) or later
|
||||
- **Linux**: Ubuntu 20.04 or equivalent, with X11 or Wayland
|
||||
|
||||
## Support
|
||||
For issues and questions, please visit our [GitHub Issues](https://github.com/scawful/yaze/issues) page.
|
||||
"""
|
||||
|
||||
print(release_notes)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
54
scripts/quality_check.sh
Executable file
54
scripts/quality_check.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Quality check script for YAZE codebase
|
||||
# This script runs various code quality checks to ensure CI/CD pipeline passes
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
echo "🔍 Running code quality checks for YAZE..."
|
||||
|
||||
# Check if required tools are available
|
||||
command -v clang-format >/dev/null 2>&1 || { echo "❌ clang-format not found. Please install it."; exit 1; }
|
||||
command -v cppcheck >/dev/null 2>&1 || { echo "❌ cppcheck not found. Please install it."; exit 1; }
|
||||
|
||||
# Create .clang-format config if it doesn't exist
|
||||
if [ ! -f .clang-format ]; then
|
||||
echo "📝 Creating .clang-format configuration..."
|
||||
clang-format --style=Google --dump-config > .clang-format
|
||||
fi
|
||||
|
||||
echo "✅ Code formatting check..."
|
||||
# Check formatting without modifying files
|
||||
FORMATTING_ISSUES=$(find src test -name "*.cc" -o -name "*.h" | head -50 | xargs clang-format --dry-run --Werror --style=Google 2>&1 || true)
|
||||
if [ -n "$FORMATTING_ISSUES" ]; then
|
||||
echo "⚠️ Formatting issues found. Run 'make format' to fix them."
|
||||
echo "$FORMATTING_ISSUES" | head -20
|
||||
else
|
||||
echo "✅ All files are properly formatted"
|
||||
fi
|
||||
|
||||
echo "🔍 Running static analysis..."
|
||||
# Run cppcheck on main source directories
|
||||
cppcheck --enable=all --error-exitcode=0 \
|
||||
--suppress=missingIncludeSystem \
|
||||
--suppress=unusedFunction \
|
||||
--suppress=unmatchedSuppression \
|
||||
--suppress=unreadVariable \
|
||||
--suppress=cstyleCast \
|
||||
--suppress=variableScope \
|
||||
src/ 2>&1 | head -30
|
||||
|
||||
echo "✅ Quality checks completed!"
|
||||
echo ""
|
||||
echo "💡 To fix formatting issues automatically, run:"
|
||||
echo " find src test -name '*.cc' -o -name '*.h' | xargs clang-format -i --style=Google"
|
||||
echo ""
|
||||
echo "💡 For CI/CD pipeline compatibility, ensure:"
|
||||
echo " - All formatting issues are resolved"
|
||||
echo " - absl::Status return values are handled with RETURN_IF_ERROR() or PRINT_IF_ERROR()"
|
||||
echo " - Use Google C++ style for consistency"
|
||||
150
scripts/test_asar_integration.py
Executable file
150
scripts/test_asar_integration.py
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Asar Integration Test Script for Yaze
|
||||
Tests the Asar 65816 assembler integration with real ROM files
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
def find_project_root():
|
||||
"""Find the yaze project root directory"""
|
||||
current = Path(__file__).parent
|
||||
while current != current.parent:
|
||||
if (current / "CMakeLists.txt").exists():
|
||||
return current
|
||||
current = current.parent
|
||||
raise FileNotFoundError("Could not find yaze project root")
|
||||
|
||||
def main():
|
||||
print("🧪 Yaze Asar Integration Test")
|
||||
print("=" * 50)
|
||||
|
||||
project_root = find_project_root()
|
||||
build_dir = project_root / "build_test"
|
||||
rom_path = build_dir / "bin" / "zelda3.sfc"
|
||||
test_patch = project_root / "test" / "assets" / "test_patch.asm"
|
||||
|
||||
# Check if ROM file exists
|
||||
if not rom_path.exists():
|
||||
print(f"❌ ROM file not found: {rom_path}")
|
||||
print(" Please ensure you have a test ROM at the expected location")
|
||||
return 1
|
||||
|
||||
print(f"✅ Found ROM file: {rom_path}")
|
||||
print(f" Size: {rom_path.stat().st_size:,} bytes")
|
||||
|
||||
# Check if test patch exists
|
||||
if not test_patch.exists():
|
||||
print(f"❌ Test patch not found: {test_patch}")
|
||||
return 1
|
||||
|
||||
print(f"✅ Found test patch: {test_patch}")
|
||||
|
||||
# Check if z3ed tool exists
|
||||
z3ed_path = build_dir / "bin" / "z3ed"
|
||||
if not z3ed_path.exists():
|
||||
print(f"❌ z3ed CLI tool not found: {z3ed_path}")
|
||||
print(" Run: cmake --build build_test --target z3ed")
|
||||
return 1
|
||||
|
||||
print(f"✅ Found z3ed CLI tool: {z3ed_path}")
|
||||
|
||||
# Create temporary directory for testing
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
test_rom_path = temp_path / "test_rom.sfc"
|
||||
patched_rom_path = temp_path / "patched_rom.sfc"
|
||||
|
||||
# Copy ROM to temporary location
|
||||
shutil.copy2(rom_path, test_rom_path)
|
||||
print(f"📋 Copied ROM to: {test_rom_path}")
|
||||
|
||||
# Test 1: Apply patch using z3ed CLI
|
||||
print("\n🔧 Test 1: Applying patch with z3ed CLI")
|
||||
try:
|
||||
cmd = [str(z3ed_path), "asar", str(test_patch), str(test_rom_path)]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ Patch applied successfully!")
|
||||
if result.stdout:
|
||||
print(f" Output: {result.stdout.strip()}")
|
||||
else:
|
||||
print(f"❌ Patch failed with return code: {result.returncode}")
|
||||
if result.stderr:
|
||||
print(f" Error: {result.stderr.strip()}")
|
||||
return 1
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("❌ Patch operation timed out")
|
||||
return 1
|
||||
except Exception as e:
|
||||
print(f"❌ Error running patch: {e}")
|
||||
return 1
|
||||
|
||||
# Test 2: Verify ROM was modified
|
||||
print("\n🔍 Test 2: Verifying ROM modification")
|
||||
original_size = rom_path.stat().st_size
|
||||
modified_size = test_rom_path.stat().st_size
|
||||
|
||||
print(f" Original ROM size: {original_size:,} bytes")
|
||||
print(f" Modified ROM size: {modified_size:,} bytes")
|
||||
|
||||
# Read first few bytes to check for changes
|
||||
with open(rom_path, 'rb') as orig_file, open(test_rom_path, 'rb') as mod_file:
|
||||
orig_bytes = orig_file.read(1024)
|
||||
mod_bytes = mod_file.read(1024)
|
||||
|
||||
if orig_bytes != mod_bytes:
|
||||
print("✅ ROM was successfully modified!")
|
||||
# Count different bytes
|
||||
diff_count = sum(1 for a, b in zip(orig_bytes, mod_bytes) if a != b)
|
||||
print(f" {diff_count} bytes differ in first 1KB")
|
||||
else:
|
||||
print("⚠️ No differences detected in first 1KB")
|
||||
print(" (Patch may have been applied to a different region)")
|
||||
|
||||
# Test 3: Run unit tests if available
|
||||
yaze_test_path = build_dir / "bin" / "yaze_test"
|
||||
if yaze_test_path.exists():
|
||||
print("\n🧪 Test 3: Running Asar unit tests")
|
||||
try:
|
||||
# Run only the Asar-related tests
|
||||
cmd = [str(yaze_test_path), "--gtest_filter=*Asar*", "--gtest_brief=1"]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
||||
|
||||
print(f" Exit code: {result.returncode}")
|
||||
if result.stdout:
|
||||
# Extract test results
|
||||
lines = result.stdout.split('\n')
|
||||
for line in lines:
|
||||
if 'PASSED' in line or 'FAILED' in line or 'RUN' in line:
|
||||
print(f" {line}")
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ Unit tests passed!")
|
||||
else:
|
||||
print("⚠️ Some unit tests failed (this may be expected)")
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("❌ Unit tests timed out")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error running unit tests: {e}")
|
||||
else:
|
||||
print("\n⚠️ Test 3: yaze_test executable not found")
|
||||
|
||||
print("\n🎉 Asar integration test completed!")
|
||||
print("\nNext steps:")
|
||||
print("- Run full test suite with: ctest --test-dir build_test")
|
||||
print("- Test Asar functionality in the main yaze application")
|
||||
print("- Create custom assembly patches for your ROM hacking projects")
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user