Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/scripts/generate_release_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
import argparse
import subprocess
import sys

def get_current_date_version():
"""Returns the current date in Year.Month format (e.g., 2025.12)."""
Expand Down Expand Up @@ -70,9 +71,21 @@ def main():
help="Type of release (stable, prerelease, development)")
args = parser.parse_args()

base_ver = get_current_date_version()
tags = get_existing_tags()
next_version = calculate_next_version(base_ver, tags, args.release_type)
# Fallback version if version generation fails
FALLBACK_VERSION = "2026.1.2"

try:
base_ver = get_current_date_version()
tags = get_existing_tags()
next_version = calculate_next_version(base_ver, tags, args.release_type)

# Validate version format
if not next_version or not re.match(r'^\d+\.\d+\.\d+', next_version):
print(f"Warning: Generated version '{next_version}' is invalid, using fallback: {FALLBACK_VERSION}", file=sys.stderr)
next_version = FALLBACK_VERSION
except Exception as e:
print(f"Error generating version: {e}, using fallback: {FALLBACK_VERSION}", file=sys.stderr)
next_version = FALLBACK_VERSION

print(next_version)

Expand Down
37 changes: 21 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
name: CI

# on:
# push:
# branches: [ main ]
# paths-ignore:
# - '**.md'
# - 'docs/**'
# - 'LICENSE'
# - '.github/ISSUE_TEMPLATE/**'
# pull_request:
# branches: [ main ]
# paths-ignore:
# - '**.md'
# - 'docs/**'
# - 'LICENSE'
# - '.github/ISSUE_TEMPLATE/**'
on:
push:
branches: [ main ]
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE'
- '.github/ISSUE_TEMPLATE/**'
pull_request:
branches: [ main ]
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE'
- '.github/ISSUE_TEMPLATE/**'
workflow_dispatch:

concurrency:
Expand All @@ -26,10 +25,14 @@ jobs:
test:
name: Run Tests
runs-on: ${{ matrix.os }}
# Python 3.15 only on main branch push (not PRs) to save time
if: |
matrix.python-version == '3.14' ||
(matrix.python-version == '3.15' && github.event_name == 'push' && github.ref == 'refs/heads/main')
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.11", "3.12"]
python-version: ["3.14", "3.15"]
Comment on lines +28 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

GitHub Actions job level if condition matrix context available documentation

💡 Result:

Short answer: You cannot use the matrix context inside a job-level if because GitHub Actions evaluates jobs.<job_id>.if before applying the job's strategy.matrix; the matrix is therefore unavailable at that level. Use a step-level if (steps can see matrix), or move the conditional into the matrix definition (include/exclude) or use a preceding job to set outputs and gate the job with needs. [1][2]

Sources:

  • Workflow syntax: jobs.<job_id>.if is evaluated before strategy.matrix is applied. [1]
  • Contexts reference: table of context availability showing jobs.<job_id>.if does not include the matrix context. [2]

References:
[1] https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
[2] https://docs.github.com/en/actions/reference/accessing-contextual-information-about-workflow-runs


🌐 Web query:

actions/setup-python@v6 Python 3.15 support ubuntu windows latest

💡 Result:

Short answer: Yes — actions/setup-python@v6 can install Python 3.15 on both ubuntu-latest and windows-latest, but as of Jan 16, 2026 Python 3.15 is still a prerelease (alpha) and therefore not guaranteed to be present in the runners' tool cache. Use the action's allow-prereleases option (or specify an exact prerelease build) so the action will fall back to/download the prerelease from releases if it's not cached.

How to (example):

  • uses: actions/setup-python@v6
    with:
    python-version: '3.15'
    allow-prereleases: true

Sources:

  • actions/setup-python README (v6) — general behavior and inputs. [1]
  • setup-python advanced usage: allow-prereleases behavior (falls back to prereleases when GA not available). [2]
  • Python 3.15 release schedule / current prerelease status (3.15 is in alpha/beta phases as of Jan 2026). [3]

Fix job-level if that references matrix, and configure prerelease support for Python 3.15.

matrix context isn't available in job-level if (it's evaluated before strategy.matrix is applied), so this condition is invalid and will cause the job to be skipped or rejected. Split the 3.15 run into a separate job gated by github.*, or move the condition into step-level guards.

Additionally, Python 3.15 is currently a prerelease (alpha as of January 2026) and won't be available in the runner tool cache without explicit prerelease support. Add allow-prereleases: true to the setup-python action, or this will fail at runtime.

🔧 Minimal patch (then add a separate 3.15 job)
-    if: |
-      matrix.python-version == '3.14' ||
-      (matrix.python-version == '3.15' && github.event_name == 'push' && github.ref == 'refs/heads/main')
     strategy:
       matrix:
         os: [ubuntu-latest, windows-latest]
-        python-version: ["3.14", "3.15"]
+        python-version: ["3.14"]

For the separate 3.15 job (or when re-adding 3.15 to this matrix), use:

- uses: actions/setup-python@v6
  with:
    python-version: '3.15'
    allow-prereleases: true
🧰 Tools
🪛 actionlint (1.7.10)

29-29: context "matrix" is not allowed here. available contexts are "github", "inputs", "needs", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)


30-30: context "matrix" is not allowed here. available contexts are "github", "inputs", "needs", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
In @.github/workflows/ci.yml around lines 28 - 35, The job-level if currently
references the matrix context (matrix.python-version) which isn’t available at
job evaluation; remove that matrix-based condition from the job if and either
(a) split the Python 3.15 run into a separate job (e.g., python-3-15) with its
own job-level if guarded by github.event_name == 'push' && github.ref ==
'refs/heads/main', or (b) keep the matrix and move the 3.15-specific gating into
step-level if checks; additionally, when creating the separate 3.15 job (or when
adding 3.15 to setup-python), update the actions/setup-python@v6 usage to
include with: allow-prereleases: true so prerelease Python 3.15 is accepted.


steps:
- uses: actions/checkout@v6
Expand All @@ -49,6 +52,8 @@ jobs:
- name: Run Tests
run: |
export PYTHONPATH=$PYTHONPATH:$(pwd)/src:$(pwd)/src/switchcraft:$(pwd)/src/switchcraft_advanced:$(pwd)/src/switchcraft_ai:$(pwd)/src/switchcraft_winget:$(pwd)/src/switchcraft_debug
export CI=true
export GITHUB_ACTIONS=true
python -m pytest tests
shell: bash

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/docs_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
source-dir: docs/.vitepress/dist
preview-branch: gh-pages
umbrella-dir: pr-preview
pages-base-path: /SwitchCraft
action: auto

cleanup-preview:
Expand Down
26 changes: 23 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ jobs:

- name: Generate Version
id: version
run: python .github/scripts/generate_release_version.py --type ${{ github.event.inputs.release_type }}
run: |
VERSION=$(python .github/scripts/generate_release_version.py --type ${{ github.event.inputs.release_type }})
# Fallback to 2026.1.2 if version generation fails or returns invalid version
if [ -z "$VERSION" ] || [ "$VERSION" = "0.0.0" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
echo "Warning: Version generation failed or returned invalid version '$VERSION', using fallback: 2026.1.2"
VERSION="2026.1.2"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is_prerelease=${{ github.event.inputs.release_type != 'stable' }}" >> $GITHUB_OUTPUT
echo "Generated version: $VERSION"
Comment on lines +41 to +50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten the version regex so malformed versions don’t bypass the fallback.

The current pattern only checks a prefix, so values like 1.2.3.4 or 1.2.3foo will pass. If you want strict MAJOR.MINOR.PATCH (optionally with pre-release/build), anchor the regex.

🛠️ Suggested fix
-          if [ -z "$VERSION" ] || [ "$VERSION" = "0.0.0" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
+          if [ -z "$VERSION" ] || [ "$VERSION" = "0.0.0" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: |
VERSION=$(python .github/scripts/generate_release_version.py --type ${{ github.event.inputs.release_type }})
# Fallback to 2026.1.2 if version generation fails or returns invalid version
if [ -z "$VERSION" ] || [ "$VERSION" = "0.0.0" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
echo "Warning: Version generation failed or returned invalid version '$VERSION', using fallback: 2026.1.2"
VERSION="2026.1.2"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is_prerelease=${{ github.event.inputs.release_type != 'stable' }}" >> $GITHUB_OUTPUT
echo "Generated version: $VERSION"
run: |
VERSION=$(python .github/scripts/generate_release_version.py --type ${{ github.event.inputs.release_type }})
# Fallback to 2026.1.2 if version generation fails or returns invalid version
if [ -z "$VERSION" ] || [ "$VERSION" = "0.0.0" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'; then
echo "Warning: Version generation failed or returned invalid version '$VERSION', using fallback: 2026.1.2"
VERSION="2026.1.2"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is_prerelease=${{ github.event.inputs.release_type != 'stable' }}" >> $GITHUB_OUTPUT
echo "Generated version: $VERSION"
🤖 Prompt for AI Agents
In @.github/workflows/release.yml around lines 41 - 50, The VERSION validation
uses an unanchored grep which lets malformed strings like "1.2.3.4" or
"1.2.3foo" pass; update the grep check that references the VERSION variable in
the if condition to use a strict anchored regex that matches only
MAJOR.MINOR.PATCH and optional pre-release/build identifiers (e.g. anchor with ^
and $ and allow an optional -pre and +build suffix pattern), so the fallback to
"2026.1.2" triggers for any invalid format.


- name: Update Version in Files
run: |
Expand Down Expand Up @@ -139,8 +148,11 @@ jobs:
PATCH=$(echo $VERSION | cut -d. -f3)
NEXT_PATCH=$((PATCH + 1))
DEV_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}-dev"
# Use release version as fallback (without -dev suffix)
FALLBACK_VERSION="${MAJOR}.${MINOR}.${PATCH}"

echo "Setting development version to $DEV_VERSION"
echo "Updating fallback versions to $FALLBACK_VERSION"

# Update version files
sed -i "s/version = \".*\"/version = \"$DEV_VERSION\"/" pyproject.toml
Expand All @@ -154,9 +166,17 @@ jobs:
sed -i "s/#define MyAppVersion \".*\"/#define MyAppVersion \"$BASE_VERSION\"/" switchcraft_legacy.iss
sed -i "s/#define MyAppVersionNumeric \".*\"/#define MyAppVersionNumeric \"$BASE_VERSION\"/" switchcraft_legacy.iss

# Update fallback versions in build scripts and version generator
# Update build_release.ps1 fallback
sed -i "s/\$AppVersion = \".*\"/\$AppVersion = \"$FALLBACK_VERSION\"/" scripts/build_release.ps1
sed -i "s/\$AppVersionNumeric = \".*\"/\$AppVersionNumeric = \"$FALLBACK_VERSION\"/" scripts/build_release.ps1

# Update generate_release_version.py fallback
sed -i "s/FALLBACK_VERSION = \".*\"/FALLBACK_VERSION = \"$FALLBACK_VERSION\"/" .github/scripts/generate_release_version.py

# Commit
git add pyproject.toml src/switchcraft/__init__.py file_version_info.txt switchcraft_modern.iss switchcraft_legacy.iss
git commit -m "chore: bump version to $DEV_VERSION for development [skip ci]"
git add pyproject.toml src/switchcraft/__init__.py file_version_info.txt switchcraft_modern.iss switchcraft_legacy.iss scripts/build_release.ps1 .github/scripts/generate_release_version.py
git commit -m "chore: bump version to $DEV_VERSION and update fallback versions to $FALLBACK_VERSION [skip ci]"
git push origin main

build:
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ on:
jobs:
test-backend:
runs-on: windows-latest
if: inputs.component == 'backend'
if: |
inputs.component == 'backend' &&
(
matrix.python-version == '3.14' ||
(matrix.python-version == '3.15' && github.event_name == 'push' && github.ref == 'refs/heads/main')
)
strategy:
fail-fast: true
max-parallel: 1
matrix:
python-version: ["3.13", "3.14"]
python-version: ["3.14", "3.15"]
Comment on lines +13 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

matrix context is not available at the job-level if condition.

The matrix context can only be accessed within job steps, not in the job-level if expression. As flagged by actionlint, only github, inputs, needs, and vars contexts are available here. This will cause the workflow to fail or behave unexpectedly.

To conditionally run specific matrix combinations, use include/exclude in the matrix definition or move the version-specific condition to a step-level if.

🔧 Suggested fix using step-level conditions
   test-backend:
     runs-on: windows-latest
-    if: |
-      inputs.component == 'backend' &&
-      (
-        matrix.python-version == '3.14' ||
-        (matrix.python-version == '3.15' && github.event_name == 'push' && github.ref == 'refs/heads/main')
-      )
+    if: inputs.component == 'backend'
     strategy:
       fail-fast: true
       max-parallel: 1
       matrix:
         python-version: ["3.14", "3.15"]
+        exclude:
+          - python-version: "3.15"
+        include:
+          - python-version: "3.15"
+            run-condition: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}

Alternatively, add a step-level condition to skip steps for Python 3.15 on non-main pushes:

      - name: Run All Python Tests
        if: matrix.python-version == '3.14' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
        run: |
          pytest tests/ -v --tb=short
🧰 Tools
🪛 actionlint (1.7.10)

15-15: context "matrix" is not allowed here. available contexts are "github", "inputs", "needs", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)


16-16: context "matrix" is not allowed here. available contexts are "github", "inputs", "needs", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
In @.github/workflows/test.yml around lines 13 - 23, The job-level if currently
references matrix.python-version (and uses matrix in the job if), which is
invalid; instead either (A) move the Python-version-specific logic into
step-level conditions by keeping the matrix in the job and adding an if on the
test step (use matrix.python-version and github.event_name/github.ref inside the
step's if), or (B) encode the allowed combinations using the matrix
include/exclude feature in the matrix definition so the job-level if only uses
allowed contexts (e.g., inputs/component); update references to
matrix.python-version in the job-level if to be removed and place them on the
relevant step's if or into the matrix include/exclude block to restrict Python
3.15 runs to main push events.


steps:
- uses: actions/checkout@v6
Expand All @@ -35,6 +40,8 @@ jobs:
pytest tests/ -v --tb=short
env:
PYTHONPATH: ${{ github.workspace }}/src
CI: true
GITHUB_ACTIONS: true

test-cli-core:
runs-on: windows-latest
Expand All @@ -45,7 +52,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"

- name: Install Core (No GUI)
run: |
Expand Down
1 change: 1 addition & 0 deletions data/stacks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
3 changes: 3 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ export default defineConfig({

vite: {
publicDir: 'public',
server: {
cors: false
},
build: {
rollupOptions: {
output: {
Expand Down
4 changes: 4 additions & 0 deletions docs/INTUNE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Pro-Users can enable the **"All-in-One"** button in the Analyzer result pane to

SwitchCraft supports extensive configuration via the GUI or Registry/GPO for enterprise environments.

> [!IMPORTANT]
> **Intune OMA-URI Configuration**: For detailed instructions on configuring Intune Custom Profiles (OMA-URI), please refer to the **[Intune Configuration Guide](Intune_Configuration_Guide.md)**.
> **Critical**: Ensure you use the **String (XML)** Data Type for all ADMX-backed policies.

### Intune API Access
To enable direct uploads, you must register an App in Azure AD (Entra ID) and provide the credentials in Settings:
- **Tenant ID**
Expand Down
145 changes: 0 additions & 145 deletions docs/IntuneConfig.md

This file was deleted.

Loading
Loading