Skip to content

Commit 0aa0410

Browse files
committed
Packaging wizard fixes & general improvements
1 parent 2351e2f commit 0aa0410

File tree

12 files changed

+569
-115
lines changed

12 files changed

+569
-115
lines changed

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export default defineConfig({
114114
collapsed: true,
115115
items: [
116116
{ text: 'Building from Source', link: '/building' },
117+
{ text: 'Versioning Schema', link: '/versioning' },
117118
{ text: 'CI Architecture', link: '/CI_Architecture' },
118119
{ text: 'Debugging API', link: '/Debugging_API' }
119120
]

docs/versioning.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# SwitchCraft Versioning System
2+
3+
SwitchCraft follows a strict versioning schema to ensure compatibility, easy identification of release types, and proper upgrade paths. This document describes how version numbers are generated, how CI handles them, and how they map to different artifacts.
4+
5+
## Version Number Logic
6+
7+
### Base Format
8+
The core version number follows a calendar-based schema:
9+
10+
```
11+
Year.Month.Release
12+
```
13+
14+
* **Year**: The current year (e.g., `2026`).
15+
* **Month**: The current month (e.g., `1` for January).
16+
* **Release**: An incrementing number for releases within that month (e.g., `5`).
17+
18+
Example: `2026.1.5`
19+
20+
### Release Types (Suffixes)
21+
Depending on the build type (Stable, Beta, Development), suffixes are appended to the base version:
22+
23+
| Release Type | Suffix Example | Full Version Example | Description |
24+
| :--- | :--- | :--- | :--- |
25+
| **Stable** | *(None)* | `2026.1.5` | Production-ready official release. |
26+
| **Beta** | `b{N}` | `2026.1.5b1` | Public test build. Stable enough for testing. |
27+
| **Development** | `.dev0+{hash}` | `2026.1.5.dev0+3c4f9a` | CI/Nightly build. Contains latest commit hash. |
28+
29+
---
30+
31+
## Windows Installer Versioning
32+
33+
Windows executables and installers (`.exe`, `.msi`) require a strict 4-part numeric version format (`A.B.C.D`) in their file resources (`VS_VERSION_INFO`).
34+
35+
SwitchCraft maps the semantic version to this 4-part numeric format as follows:
36+
37+
```
38+
Year.Month.Release.BuildNumber
39+
```
40+
41+
* **Year.Month.Release**: Taken directly from the base version.
42+
* **BuildNumber**: Derived from the **GitHub Actions Run Number** (CI) or a local counter.
43+
44+
### Why this matters?
45+
Windows uses this 4-part version to decide if an installer is an "Upgrade".
46+
* `2026.1.5.105` > `2026.1.5.100` -> Windows considers this a new version.
47+
* Stable releases usually have `0` as the build number base, while Dev builds use the Run Number to ensure every CI build is "newer" than the previous one for testing, but "older" than the next Stable release if semver rules apply (though in Windows, `.100` is > `.0`, so Dev builds might appear "newer" than the *same* stable version. We handle this by bumping the `Release` number for Stable).
48+
49+
### Local Builds
50+
When building locally (using `scripts/build_release.ps1`), you can specify a custom build number to test upgrades:
51+
52+
```powershell
53+
.\scripts\build_release.ps1 -Modern -BuildNumber 999
54+
```
55+
56+
This generates `2026.1.5.999`.
57+
58+
---
59+
60+
## CI/CD Workflow
61+
62+
The release process is automated via GitHub Actions (`.github/workflows/release.yml`).
63+
64+
1. **Trigger**: Access via "Run workflow" button.
65+
2. **Input**: Select type (`stable`, `beta`, `dev`).
66+
3. **Generation**:
67+
* The script `.github/scripts/generate_release_version.py` reads `pyproject.toml`.
68+
* It calculates the Next Version based on the selected type.
69+
* It writes the version back to `pyproject.toml` and generates a `file_version_info.txt`.
70+
4. **Build**:
71+
* PyInstaller builds the app using the generated version info.
72+
* Inno Setup compiles the installer, receiving the version string and numeric components.
73+
5. **Artifacts**:
74+
* **Stable**: Uploaded to GitHub Releases.
75+
* **Dev/Beta**: Uploaded as Pre-release or Artifacts.
76+
77+
---
78+
79+
## Docker Container Tags
80+
81+
For the SwitchCraft Web/Server backend, Docker tags mimic the release version but replace `+` with `-` (as `+` is invalid in Docker tags).
82+
83+
* **Stable**: `faserf/switchcraft:2026.1.5`, `faserf/switchcraft:latest`
84+
* **Beta**: `faserf/switchcraft:2026.1.5b1`
85+
* **Dev**: `faserf/switchcraft:2026.1.5-dev0-3c4f9a`, `faserf/switchcraft:dev`
86+
87+
This ensures that `latest` always points to the last Stable release, while `dev` points to the latest CI build.

src/switchcraft/assets/lang/de.json

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,5 +1118,92 @@
11181118
"btn_browse_folder": "Serverordner durchsuchen",
11191119
"btn_add_update": "Update EXE hinzufügen",
11201120
"btn_select_logo": "Custom Logo wählen",
1121-
"btn_apply_build": "Anwenden & Paketierung erstellen"
1121+
"btn_apply_build": "Anwenden & Paketierung erstellen",
1122+
"wiz_auto_sign_status": "Signiere Skript...",
1123+
"wiz_pkg_start_status": "Schritt 3/4: Paketieren...",
1124+
"wiz_pkg_failed_msg": "Paketerstellung fehlgeschlagen",
1125+
"wiz_upload_start_status": "Schritt 4/4: Upload nach Intune...",
1126+
"wiz_new_app": "Neue App",
1127+
"wiz_autopilot_desc": "Hochgeladen via SwitchCraft Magic Mode",
1128+
"wiz_autopilot_complete": "Magie abgeschlossen! ✨",
1129+
"wiz_success": "Erfolg!",
1130+
"wiz_autopilot_failed": "Magie fehlgeschlagen 💀",
1131+
"wiz_title": "End-to-End Paketierungs-Assistent",
1132+
"wiz_step_select": "Auswahl",
1133+
"wiz_step_analyze": "Analyse",
1134+
"wiz_step_script": "Skript",
1135+
"wiz_step_package": "Paketieren",
1136+
"wiz_step_upload": "Upload",
1137+
"wiz_btn_analyze": "Analysieren >",
1138+
"wiz_btn_gen_script": "Skript Generieren >",
1139+
"wiz_btn_package": "Paketieren >",
1140+
"wiz_btn_upload": "Nach Intune Hochladen >",
1141+
"wiz_btn_finish": "Fertig",
1142+
"wiz_mode_select": "Paketierungsmodus wählen",
1143+
"wiz_mode_win32": "Win32 App (Standard)",
1144+
"wiz_mode_lob": "Direktes MSI (LOB)",
1145+
"wiz_no_file": "Keine Datei gewählt",
1146+
"wiz_select_installer": "Installer wählen",
1147+
"wiz_supported_formats": "Unterstützt: .exe, .msi",
1148+
"wiz_download_web": "Aus Web herunterladen",
1149+
"wiz_download_hint": "Direktlink zu .exe oder .msi eingeben",
1150+
"wiz_autopilot": "Auto-Pilot (Magischer Modus) 🪄",
1151+
"wiz_review_script": "Skript überprüfen & bearbeiten",
1152+
"wiz_auto_sign": "Auto-Signierung: {status}",
1153+
"wiz_enabled": "Aktiviert",
1154+
"wiz_disabled_no_cert": "Deaktiviert (Kein Cert)",
1155+
"wiz_regenerate": "Neu generieren",
1156+
"wiz_create_pkg": "Intune Paket erstellen (.intunewin)",
1157+
"wiz_source": "Quelle:",
1158+
"wiz_setup_file": "Setup Datei:",
1159+
"wiz_ready_pkg": "Bereit zum Paketieren.",
1160+
"wiz_start_pkg": "Paketierung starten",
1161+
"wiz_upload_title": "Nach Microsoft Intune hochladen",
1162+
"wiz_credentials": "Zugangsdaten",
1163+
"wiz_app_details": "App Details",
1164+
"wiz_supersedence": "Supersedence (Upgrade)",
1165+
"wiz_wait_auth": "Warte auf Anmeldung...",
1166+
"wiz_btn_upload_intune": "Nach Intune hochladen",
1167+
"wiz_btn_connect": "Verbinden",
1168+
"wiz_search_supersede": "App zum Ersetzen suchen",
1169+
"wiz_none_selected": "Keine ausgewählt",
1170+
"wiz_select_app": "App wählen",
1171+
"wiz_uninstall_prev": "Vorherige Version deinstallieren?",
1172+
"wiz_finished": "Assistent abgeschlossen!",
1173+
"wiz_pkg_failed": "Paketierung fehlgeschlagen oder nicht ausgeführt",
1174+
"wiz_lob_msi_req": "LOB Modus benötigt eine .msi Datei",
1175+
"wiz_select_file_first": "Bitte zuerst eine Datei wählen",
1176+
"wiz_large_file_warn": "Große Datei ({size} MB). Analyse dauert länger (~{eta}).",
1177+
"wiz_analyzing": "Analysiere Installer...",
1178+
"wiz_analysis_failed": "Analyse fehlgeschlagen",
1179+
"wiz_analysis_complete": "Analyse vollständig",
1180+
"wiz_install_switches": "Switches",
1181+
"wiz_pkg_start": "Starte Paketierung...",
1182+
"wiz_stage_clean": "Bereite saubere Build-Umgebung vor...",
1183+
"wiz_large_pkg": "Großes Paket ({size} MB). Dies kann einige Minuten dauern...",
1184+
"wiz_pkg_success": "Erfolg: {name}",
1185+
"wiz_pkg_err_not_found": "Fehler: .intunewin Ausgabe nicht gefunden",
1186+
"wiz_auth_progress": "Authentifiziere...",
1187+
"wiz_connected": "Verbunden! Bereit zum Upload.",
1188+
"wiz_auth_failed": "Auth fehlgeschlagen: {error}",
1189+
"wiz_select_supersede_app": "Bitte App zum Ersetzen wählen",
1190+
"wiz_upload_start": "Starte Upload...",
1191+
"wiz_upload_success": "Upload abgeschlossen!",
1192+
"wiz_upload_failed": "Upload fehlgeschlagen: {error}",
1193+
"wiz_script_signed": "Skript erfolgreich signiert!",
1194+
"wiz_sign_warn": "Signatur-Warnung: {error}",
1195+
"wiz_save_fail": "Skript konnte nicht gespeichert werden: {error}",
1196+
"wiz_download_start": "Starte Download...",
1197+
"wiz_download_success": "Heruntergeladen: {file}",
1198+
"wiz_enter_url": "Bitte URL eingeben",
1199+
"pkg_large_file_warn": "⚠️ Großer Ordner ({size} MB). Dies könnte etwas dauern.",
1200+
"pkg_eta": "Geschätzte Zeit: ~{min}m {sec}s",
1201+
"lbl_version": "App Version",
1202+
"large_file_warning": "Große Datei erkannt ({size} MB). Analyse dauert länger (~{eta}).",
1203+
"upload_complete_intune": "Upload nach Intune abgeschlossen.",
1204+
"warn_no_detection_rules": "Keine Erkennungsregeln gefunden.",
1205+
"pkg_id": "Paket ID",
1206+
"package_path": "Paket Pfad",
1207+
"config_supersedence": "Supersedence konfigurieren",
1208+
"upload_start_auth_rule": "Starte Upload..."
11221209
}

src/switchcraft/assets/lang/en.json

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,5 +1118,92 @@
11181118
"btn_browse_folder": "Browse Server Folder",
11191119
"btn_add_update": "Add Update EXE",
11201120
"btn_select_logo": "Select Custom Logo",
1121-
"btn_apply_build": "Apply & Build Packaging"
1121+
"btn_apply_build": "Apply & Build Packaging",
1122+
"wiz_auto_sign_status": "Signing Script...",
1123+
"wiz_pkg_start_status": "Step 3/4: Packaging .intunewin...",
1124+
"wiz_pkg_failed_msg": "Package creation failed",
1125+
"wiz_upload_start_status": "Step 4/4: Uploading to Intune...",
1126+
"wiz_new_app": "New App",
1127+
"wiz_autopilot_desc": "Uploaded via SwitchCraft Magic Mode",
1128+
"wiz_autopilot_complete": "Magic Complete! ✨",
1129+
"wiz_success": "Success!",
1130+
"wiz_autopilot_failed": "Magic Failed 💀",
1131+
"wiz_title": "End-to-End Packaging Wizard",
1132+
"wiz_step_select": "Select",
1133+
"wiz_step_analyze": "Analyze",
1134+
"wiz_step_script": "Script",
1135+
"wiz_step_package": "Package",
1136+
"wiz_step_upload": "Upload",
1137+
"wiz_btn_analyze": "Analyze >",
1138+
"wiz_btn_gen_script": "Generate Script >",
1139+
"wiz_btn_package": "Package >",
1140+
"wiz_btn_upload": "Upload to Intune >",
1141+
"wiz_btn_finish": "Finish",
1142+
"wiz_mode_select": "Select Packaging Mode",
1143+
"wiz_mode_win32": "Win32 App (Standard)",
1144+
"wiz_mode_lob": "Direct MSI (LOB)",
1145+
"wiz_no_file": "No file selected",
1146+
"wiz_select_installer": "Select Installer",
1147+
"wiz_supported_formats": "Supported: .exe, .msi",
1148+
"wiz_download_web": "Download from Web",
1149+
"wiz_download_hint": "Enter a direct link to an .exe or .msi file",
1150+
"wiz_autopilot": "Auto-Pilot (Magic Mode) 🪄",
1151+
"wiz_review_script": "Review & Edit Script",
1152+
"wiz_auto_sign": "Auto-Signing: {status}",
1153+
"wiz_enabled": "Enabled",
1154+
"wiz_disabled_no_cert": "Disabled (No Cert Configured)",
1155+
"wiz_regenerate": "Regenerate",
1156+
"wiz_create_pkg": "Create Intune Package (.intunewin)",
1157+
"wiz_source": "Source:",
1158+
"wiz_setup_file": "Setup File:",
1159+
"wiz_ready_pkg": "Ready to package.",
1160+
"wiz_start_pkg": "Start Packaging",
1161+
"wiz_upload_title": "Upload to Microsoft Intune",
1162+
"wiz_credentials": "Credentials",
1163+
"wiz_app_details": "App Details",
1164+
"wiz_supersedence": "Supersedence (Upgrade)",
1165+
"wiz_wait_auth": "Waiting for authentication...",
1166+
"wiz_btn_upload_intune": "Upload to Intune",
1167+
"wiz_btn_connect": "Connect",
1168+
"wiz_search_supersede": "Search App to Replace",
1169+
"wiz_none_selected": "None selected",
1170+
"wiz_select_app": "Select App",
1171+
"wiz_uninstall_prev": "Uninstall previous version?",
1172+
"wiz_finished": "Wizard Completed!",
1173+
"wiz_pkg_failed": "Package creation failed or not executed",
1174+
"wiz_lob_msi_req": "LOB Mode requires an .msi file",
1175+
"wiz_select_file_first": "Please select a file first",
1176+
"wiz_large_file_warn": "Large file detected ({size} MB). Analysis may take longer (~{eta}).",
1177+
"wiz_analyzing": "Analyzing Installer...",
1178+
"wiz_analysis_failed": "Analysis failed",
1179+
"wiz_analysis_complete": "Analysis Complete",
1180+
"wiz_install_switches": "Switches",
1181+
"wiz_pkg_start": "Starting packaging process...",
1182+
"wiz_stage_clean": "Preparing clean build environment (Staging)...",
1183+
"wiz_large_pkg": "Large package ({size} MB). This might take a few minutes...",
1184+
"wiz_pkg_success": "Success: {name}",
1185+
"wiz_pkg_err_not_found": "Failed: .intunewin output not found",
1186+
"wiz_auth_progress": "Authenticating...",
1187+
"wiz_connected": "Connected! Ready to upload.",
1188+
"wiz_auth_failed": "Auth Failed: {error}",
1189+
"wiz_select_supersede_app": "Please select an app to supersede",
1190+
"wiz_upload_start": "Starting upload...",
1191+
"wiz_upload_success": "Upload Complete!",
1192+
"wiz_upload_failed": "Upload Failed: {error}",
1193+
"wiz_script_signed": "Script Signed Successfully!",
1194+
"wiz_sign_warn": "Signing Warning: {error}",
1195+
"wiz_save_fail": "Failed to save script: {error}",
1196+
"wiz_download_start": "Starting download...",
1197+
"wiz_download_success": "Downloaded: {file}",
1198+
"wiz_enter_url": "Please enter a URL",
1199+
"pkg_large_file_warn": "⚠️ Large folder ({size} MB). This might take some time.",
1200+
"pkg_eta": "Estimated time: ~{min}m {sec}s",
1201+
"lbl_version": "App Version",
1202+
"large_file_warning": "Large file detected ({size} MB). Analysis may take longer (~{eta}).",
1203+
"upload_complete_intune": "Upload to Intune complete.",
1204+
"warn_no_detection_rules": "No detection rules found.",
1205+
"pkg_id": "Package ID",
1206+
"package_path": "Package Path",
1207+
"config_supersedence": "Configure Supersedence",
1208+
"upload_start_auth_rule": "Starting upload..."
11221209
}

src/switchcraft/gui_modern/app.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66

77
import flet as ft
8-
from switchcraft import __version__, IS_WEB
8+
from switchcraft import __version__, IS_WEB, IS_DEMO
99
from switchcraft.utils.config import SwitchCraftConfig
1010
from switchcraft.utils.i18n import i18n
1111

@@ -632,7 +632,25 @@ def setup_page(self):
632632
if hasattr(self.page, "on_drop"):
633633
self.page.on_drop = self.handle_window_drop
634634

635-
self.banner_container = ft.Container() # Placeholder
635+
self.banner_container = ft.Container()
636+
self.dev_banner_container = ft.Container()
637+
638+
# Demo Banner
639+
if IS_DEMO:
640+
self.banner_container = ft.Container(
641+
content=ft.Row(
642+
[
643+
ft.Icon(ft.Icons.INFO_OUTLINE, color="WHITE"),
644+
ft.Text(
645+
"Demo Mode: Functionality is limited. Changes are not saved persistently.",
646+
color="WHITE",
647+
),
648+
],
649+
alignment=ft.MainAxisAlignment.CENTER,
650+
),
651+
bgcolor="GREEN_900", # Dark Green
652+
padding=5,
653+
)
636654

637655
# Run Startup Update Check
638656
self._check_startup_updates()

src/switchcraft/gui_modern/views/analyzer_view.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,21 @@ def start_analysis(self, filepath, cleanup_path=None):
479479
if self.analyzing:
480480
return
481481

482+
# Check for large file size (USER REQUEST: Warning + ETA)
483+
try:
484+
path_obj = Path(filepath)
485+
if path_obj.exists():
486+
size_mb = path_obj.stat().st_size / (1024 * 1024)
487+
if size_mb > 400: # Threshold: 400MB
488+
# Estimate: ~20MB/s processing speed
489+
eta_sec = int(size_mb / 20)
490+
eta_str = f"{eta_sec // 60}min {eta_sec % 60}s" if eta_sec > 60 else f"{eta_sec}s"
491+
492+
msg = i18n.get("large_file_warning", size=int(size_mb), eta=eta_str) or f"Large file detected ({int(size_mb)} MB). Analysis may take longer (~{eta_str})."
493+
self._show_snack(msg, "ORANGE")
494+
except Exception as e:
495+
logger.warning(f"Failed to check file size: {e}")
496+
482497
self.analyzing = True
483498
self.progress_bar.visible = True
484499
self.status_text.value = f"Analyzing {Path(filepath).name}..."

src/switchcraft/gui_modern/views/home_view.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,21 @@ def _build_content(self):
128128
pass
129129

130130
# 2. Try to get display name from Windows (full name instead of login name)
131+
if not username:
132+
try:
133+
# Web Auth Check (Flet Auth)
134+
if self.app_page.auth and self.app_page.auth.user:
135+
u = self.app_page.auth.user
136+
val = None
137+
# Could be dict or object depending on provider
138+
if hasattr(u, "name"): val = u.name
139+
elif hasattr(u, "get"): val = u.get("name")
140+
141+
if isinstance(val, str) and val:
142+
username = val
143+
except Exception:
144+
pass
145+
131146
if not username:
132147
try:
133148
import ctypes

0 commit comments

Comments
 (0)