Skip to content
Draft
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
32 changes: 11 additions & 21 deletions .github/workflows/ports_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ jobs:
platform: [x86, x64]
configuration: [Debug, Release]
variant: [dev, standard]
visualstudio: ['2017', '2019', '2022']
visualstudio: ['2019', '2022']
include:
- visualstudio: '2017'
vs_version: '[15, 16)'
custom_vs_install: true
- visualstudio: '2019'
vs_version: '[16, 17)'
custom_vs_install: true
# The v142 toolset (VS 2019 compiler) is pre-installed on
# windows-2022 as a component of VS 2022. Use VS 2022's
# MSBuild and select the v142 toolset via PlatformToolset.
vs_version: '[17, 18)'
platform_toolset: v142
- visualstudio: '2022'
vs_version: '[17, 18)'
platform_toolset: v143
# trim down the number of jobs in the matrix
exclude:
- variant: standard
configuration: Debug
- visualstudio: '2019'
configuration: Debug
runs-on: windows-latest
runs-on: windows-2022
env:
CI_BUILD_CONFIGURATION: ${{ matrix.configuration }}
steps:
Expand All @@ -51,31 +52,20 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Visual Studio ${{ matrix.visualstudio }}
if: matrix.custom_vs_install
shell: bash
# Shell functions in this block are to retry intermittent corrupt
# downloads (with a clean download dir) before failing the job outright
run: |
try () { ($@) || ($@) || ($@) || ($@) }
clean_install () ( rm -rf $TEMP/chocolatey; choco install $1 )
try clean_install visualstudio${{ matrix.visualstudio }}buildtools
try clean_install visualstudio${{ matrix.visualstudio }}-workload-vctools
try clean_install windows-sdk-8.1
- uses: microsoft/setup-msbuild@v2
with:
vs-version: ${{ matrix.vs_version }}
- uses: actions/checkout@v6
- name: Build mpy-cross.exe
run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }}
run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PlatformToolset=${{ matrix.platform_toolset }}
- name: Update submodules
run: git submodule update --init lib/micropython-lib
- name: Build micropython.exe
run: msbuild ports\windows\micropython.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }}
run: msbuild ports\windows\micropython.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }} -property:PlatformToolset=${{ matrix.platform_toolset }}
- name: Get micropython.exe path
id: get_path
run: |
$exePath="$(msbuild ports\windows\micropython.vcxproj -nologo -v:m -t:ShowTargetPath -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }})"
$exePath="$(msbuild ports\windows\micropython.vcxproj -nologo -v:m -t:ShowTargetPath -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }} -property:PlatformToolset=${{ matrix.platform_toolset }})"
echo ("micropython=" + $exePath.Trim()) >> $env:GITHUB_OUTPUT
- name: Run tests
id: test
Expand Down
6 changes: 6 additions & 0 deletions tools/mpy-triage/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.egg-info/
__pycache__/
.venv/
*.pyc
data/*.db
.pytest_cache/
31 changes: 31 additions & 0 deletions tools/mpy-triage/data/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- MicroPython Issue Triage Database Schema

-- Issues and PRs
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY,
number INTEGER NOT NULL,
repo TEXT NOT NULL DEFAULT 'micropython/micropython',
type TEXT NOT NULL, -- 'issue' or 'pr'
title TEXT,
body TEXT,
author TEXT,
state TEXT, -- open, closed
labels TEXT, -- JSON array of label names
created_at TEXT,
closed_at TEXT,
updated_at TEXT,
UNIQUE(repo, number)
);

-- Sync state for incremental updates
CREATE TABLE IF NOT EXISTS sync_state (
key TEXT PRIMARY KEY,
value TEXT
);

-- Indexes
CREATE INDEX IF NOT EXISTS idx_items_repo ON items(repo);
CREATE INDEX IF NOT EXISTS idx_items_type ON items(type);
CREATE INDEX IF NOT EXISTS idx_items_state ON items(state);
CREATE INDEX IF NOT EXISTS idx_items_created ON items(created_at);
CREATE INDEX IF NOT EXISTS idx_items_repo_number ON items(repo, number);
32 changes: 32 additions & 0 deletions tools/mpy-triage/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "mpy-triage"
version = "0.1.0"
description = "CLI tool for detecting duplicate/related MicroPython issues and PRs"
requires-python = ">=3.10"
license = {text = "MIT"}

dependencies = [
"sqlite-vec>=0.1.6",
]

[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"ruff>=0.4.0",
]

[project.scripts]
mpy-triage = "mpy_triage.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

[tool.ruff]
line-length = 99

[tool.pytest.ini_options]
testpaths = ["tests"]
Empty file.
29 changes: 29 additions & 0 deletions tools/mpy-triage/src/mpy_triage/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""CLI entry point for mpy-triage."""

import argparse
import logging


def main() -> None:
"""Main entry point for the mpy-triage CLI."""
parser = argparse.ArgumentParser(
prog="mpy-triage",
description="Detect duplicate and related MicroPython issues/PRs using semantic search.",
)
parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose logging.")
parser.add_argument(
"--db",
default="data/triage.db",
help="Path to the SQLite database (default: data/triage.db).",
)

_args = parser.parse_args()

logging.basicConfig(
level=logging.DEBUG if _args.verbose else logging.INFO,
format="%(levelname)s: %(message)s",
)


if __name__ == "__main__":
main()
85 changes: 85 additions & 0 deletions tools/mpy-triage/src/mpy_triage/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""Database layer for mpy-triage.

Manages SQLite connections, schema initialization, sync state, and
sqlite-vec extension loading.
"""

import logging
import sqlite3
from pathlib import Path

log = logging.getLogger(__name__)


def get_connection(db_path: Path) -> sqlite3.Connection:
"""Open an SQLite connection with Row factory and WAL mode.

Args:
db_path: Path to the SQLite database file.

Returns:
An open sqlite3.Connection.
"""
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA journal_mode=WAL")
return conn


def init_db(conn: sqlite3.Connection, schema_path: Path) -> None:
"""Read and execute a schema SQL file against the connection.

Safe to call multiple times (uses IF NOT EXISTS in schema).

Args:
conn: An open sqlite3 connection.
schema_path: Path to the .sql schema file.
"""
schema_path = Path(schema_path)
schema_sql = schema_path.read_text()
conn.executescript(schema_sql)
conn.commit()


def get_sync_state(conn: sqlite3.Connection, key: str) -> str | None:
"""Retrieve a value from the sync_state table.

Args:
conn: An open sqlite3 connection.
key: The sync state key to look up.

Returns:
The stored value string, or None if the key is not found.
"""
cursor = conn.execute("SELECT value FROM sync_state WHERE key = ?", (key,))
row = cursor.fetchone()
return row[0] if row else None


def set_sync_state(conn: sqlite3.Connection, key: str, value: str) -> None:
"""Insert or update a value in the sync_state table.

Args:
conn: An open sqlite3 connection.
key: The sync state key.
value: The value to store.
"""
conn.execute(
"INSERT OR REPLACE INTO sync_state (key, value) VALUES (?, ?)",
(key, value),
)
conn.commit()


def load_vec_extension(conn: sqlite3.Connection) -> None:
"""Load the sqlite-vec extension into the connection.

Args:
conn: An open sqlite3 connection.
"""
import sqlite_vec

conn.enable_load_extension(True)
sqlite_vec.load(conn)
conn.enable_load_extension(False)
log.info("sqlite-vec extension loaded")
Loading
Loading