stitch#

Walks the per-source detail rows for each tracked app and projects them into the canonical apps table. Inputs are heterogeneous (Installomator labels, Homebrew Cask JSON, AutoPkg recipes, Jamf App Installers metadata); outputs are normalized fields the public catalog serves. For the conceptual overview see Stitching.

async stitch_catalog(session: AsyncSession) tuple[int, int, int, int, int, int][source]#

Run the stitch process. Builds unified apps rows from ingested Installomator labels, Homebrew Cask records, AutoPkg recipe-index entries, and Jamf App Installers catalog rows.

Phases:

  1. Installomator-led. For each label, try to match a Cask (token or artifact app-name), any AutoPkg recipes (by normalized display name), and any JAI catalog row (by normalized display name). Upsert one apps row per label. Sources land in canonical ordering [installomator, homebrew_cask, autopkg, jamf_app_installer] regardless of which combination is present.

  2. Cask-only. Walk Casks not claimed in phase 1, with AutoPkg + JAI name matching still attempted.

AutoPkg and JAI never create new apps. Both are coverage indicators attached to existing apps when their normalized name matches the app’s display name.

Parameters:

session (sqlalchemy.ext.asyncio.AsyncSession) – Async SQLAlchemy session bound to the target DB.

Returns:

(installomator_apps, cask_only_apps, both_sources, autopkg_attached_apps, jai_attached_apps, failed).

  • installomator_apps is the count of apps with an Installomator source

  • cask_only_apps is the count of apps with only a Cask source

  • both_sources is the subset of installomator_apps that also matched a Cask

  • autopkg_attached_apps is the count of apps with one or more AutoPkg recipes attached (across all phases)

  • jai_attached_apps is the count of apps with a JAI catalog row attached (across all phases)

  • failed is the count of records whose upsert hit a database error

Return type:

tuple[int, int, int, int, int, int]