Skip to content

Releases: Joomla-Bible-Study/cwm-build-tools

v1.5.1 — opt-in verifyAssets check

16 Jun 15:07

Choose a tag to compare

Additive, opt-in, fully backward-compatible.

Added

  • cwm-build asset-reference verification (build.verifyAssets). With build.verifyAssets: true in cwm-build.config.json, cwm-build fails — after the pre-build step, before zipping — if any file referenced by a joomla.asset.json (type: script/style with a local uri) is absent from the source tree.

    This closes the silent-skip gap introduced alongside v1.5.0's ESM support: if a *.es6.mjs module didn't compile (the JS build was skipped, or an older toolchain ignored the .es6.mjs suffix), the asset would 404 at runtime and any dependent JS would break for end users. Now it's a loud build failure with the offending file named.

    • Resolution is by basename under the manifest's media directory (a uri like com_proclaim/foo.min.js is served from a media root that doesn't mirror the repo's media/js/ layout).
    • CDN / absolute / protocol-relative URLs are skipped.
    • Only joomla.asset.json files that would actually ship (per the package's include/exclude rules) are checked.
    • Defaults to false — existing consumers are unaffected until they opt in.

Fixed (tests)

  • Latent fclose(STDIN) bug in the child-process gate test helper that surfaced under random execution order; the two gate tests now share a runBuildInChild() helper.

v1.5.0 — ESM rollup output + cwm-lint-deprecations

15 Jun 22:34

Choose a tag to compare

Additive, fully backward-compatible.

Added

  • ESM output from the shared Rollup config — unblocks first-class JoomlaDialog. templates/rollup.config.js now picks output format by source suffix: *.es6.js still emits an IIFE bundle (every existing consumer builds exactly as before), while a new *.es6.mjs source emits an ES module (format: 'es'). In module builds, bare joomla.* specifiers (e.g. import JoomlaDialog from 'joomla.dialog') are marked external, so the import survives to the browser and Joomla's import-map resolves it at runtime. An IIFE bundle inlines everything and structurally cannot carry a live external ESM import — which is why consuming JoomlaDialog (or any Joomla JS module API) was previously impossible without hand-writing an unbundled module. Register the built file as a type="module" asset in joomla.asset.json. Extra externals (e.g. vue) via the MODULE_EXTERNALS env var.

  • cwm-lint-deprecations — flags Joomla 6/7 upgrade blockers in source. New CI-gating scanner (composer lint-deprecations) reporting file:line for bootstrap.modal assets, data-bs-toggle="modal" markup, legacy {handler: 'iframe'} modal links, the removed Joomla.Modal JS API, and jQuery globals. Exits non-zero on any finding (or --warn to report without failing). Skips vendor/, node_modules/, build/, dist/, *.min.js. cwm-init now offers to wire it into consumers.

Migration

No action required for existing builds (the old template ignores *.es6.mjs, so adopting it is safe to stage ahead of upgrading). To use JoomlaDialog: name the source <thing>.es6.mjs, import JoomlaDialog from 'joomla.dialog', and register the built <thing>.js as "type": "module". Note JoomlaDialog.confirm()/alert() are Promise-based, not synchronous like native confirm(). Run composer lint-deprecations to find Bootstrap-modal usages to migrate.

v1.4.1 — component media-link namespaced-source fix

04 Jun 17:58

Choose a tag to compare

Fixed

Component media now links from media/<name> when assets are namespaced. The dev linker always sourced a component's media from <root>/media, which only fits the <media folder="media"> layout (Proclaim). For the <media folder="media/com_x"> layout (e.g. com_cwmconnect, com_livingword), cwm-link pointed the install's media/<name> symlink one level too high — CSS/JS 404'd and cwm-verify flagged the correct symlink as a conflict. The resolver now prefers media/<name> when that subdir exists, else falls back to media/. Targets unchanged; only the source path is corrected.

Consumers on the namespaced layout should composer update cwm/build-tools to pick this up (within ^1.4).

Full PR: #27

v1.4.0 — flat-key build.properties (IDE-friendly)

15 May 20:36

Choose a tag to compare

Changed (non-breaking — both formats still parse)

  • build.properties switched from INI sections to flat keys. Every
    field is now a globally unique key (e.g. builder.j5.role,
    paths.cwm/sibling) so Java-properties-aware IDEs (PhpStorm,
    IntelliJ) don't flag "duplicate property key" warnings on role,
    path, db_host, etc. across sections. Same content, same semantics,
    zero IDE noise.

    New canonical shape:

    joomla.version = 5.4.2
    builder.installs = j5, j6, j5-test
    
    builder.j5.role        = dev
    builder.j5.path        = /path/to/joomla5
    builder.j5.url         = https://j5-dev.local
    builder.j5.version     = 5.4.2
    builder.j5.db_host     = localhost
    builder.j5.admin_email = admin@example.com
    # ... etc
    
    builder.j5-test.role = test
    builder.j5-test.path = /path/to/joomla5-test
    
    paths.joomla-bible-study/lib-cwmscripture = /Users/you/GitHub/lib_cwmscripture
  • Comment marker switched from ; to # to satisfy Java-properties
    parsers too. PHP's parse_ini_string accepts both via
    PropertiesReader's pre-strip step.

Internal

  • PropertiesReader::fromLegacyFlat() renamed to fromFlat() (with the
    old name retained as a private alias for any external caller still
    using it). The "flat" format is the canonical v1.4 shape, not legacy.
    • Extended to honor explicit builder.installs = ... lists.
    • Auto-discovers ids from builder.<id>.path keys (preferred) before
      falling back to builder.<id>.url (Proclaim legacy).
    • Parses builder.<id>.role, builder.<id>.version, and modern
      admin_user/pass/email key names alongside Proclaim's legacy
      username/password/email.
  • PropertiesReader::paths() now reads flat paths.<package> keys
    (preferred). Still falls back to the [paths] INI section for any
    existing v1.2/v1.3 files.
  • PropertiesReader::write() and writePaths() now emit flat keys.
  • PropertiesReader::fromSections() retained as a reader-only path for
    backward compatibility with any developer's existing INI-style
    build.properties from v1.0–v1.3. Next composer setup rewrites
    the file in the new flat shape.

Migration

Per consumer:

  1. composer require --dev cwm/build-tools:^1.4
  2. composer cwm-sync-configs refreshes build.dist.properties to
    the new flat-key template.
  3. Developers with an existing INI build.properties keep working
    thanks to fromSections() backward-compat. Running composer setup will migrate the file to the flat shape on next save.

v1.3.0 — manifest_cache staleness check + build.dist.properties sync

15 May 20:08

Choose a tag to compare

Added

  • cwm-verify detects and rebuilds stale manifest_cache. Each row in
    #__extensions carries a manifest_cache JSON column that Joomla
    populates on install and update. When an extension's install
    scriptfile update() doesn't run cleanly, that column drifts away
    from the source manifest XML — visible to users as
    mb_strtolower(null) deprecation warnings in Joomla 6's manage view.
    • ExtensionVerifier::parseManifestXml() reproduces Joomla's
      Installer::parseXMLInstallFile() shape so cwm-verify can build
      the canonical cache JSON.
    • ExtensionVerifier::compareManifestCache() checks the four fields
      the manage view actually reads (name, version, description,
      author) — other fields are informational and not worth surfacing
      as drift.
    • cwm-verify --target test now reports STALE: <name> manifest_cache — version: 'old' → 'new' per drifted extension.
    • cwm-verify --target test --fix UPDATEs the row with rebuilt JSON
      directly — no extension reinstall required.
    • Applies to self extensions AND CWM dep extensions installed via
      path repositories (expectedFromPackages() resolves the source
      manifest from each dep's joomlaLinks tuple).
  • cwm-sync-configs distributes build.dist.properties to consumers.
    Each consuming project gets an auto-managed copy of cwm-build-tools'
    templates/build.properties.tmpl, headed by a marker comment telling
    developers to edit the upstream template rather than the local file.
    Schema changes to build.properties (the role field added in
    v1.1.0, the [paths] block added in v1.2.0) now propagate to every
    consumer on the next composer cwm-sync-configs run rather than
    silently drifting.

Migration

Per-repo:

  1. composer require --dev cwm/build-tools:^1.3
  2. composer cwm-sync-configs — refreshes build.dist.properties
    from the upstream template (committed change, review the diff).
  3. Optionally composer cwm-verify --target test --fix against a
    live install with stale extension caches.

v1.2.2 — constraint satisfaction for stability qualifiers

15 May 19:40

Choose a tag to compare

Fixed

  • DevTargetVerifier::satisfies() now understands Composer stability
    qualifiers.
    Constraints like @dev, *@dev, and bare * are stability
    / wildcard expressions, not semver ranges; the previous implementation
    fell through to literal-match and reported out of range for every
    path-repo dep pinned with @dev (which is the common shape for CWM
    sibling deps). Now treats * / @dev / *@dev as any-version,
    strips trailing @<stability> qualifiers from caret/tilde constraints,
    and matches dev-<branch> literally against the installed version.

v1.2.1 — honor config.vendor-dir

15 May 19:34

Choose a tag to compare

Fixed

  • InstalledPackageReader now honors composer.json's
    config.vendor-dir override.
    Consumers with a non-default vendor
    directory (e.g. CWMLivingWord and Proclaim both ship with
    "vendor-dir": "libraries/vendor") had the cross-package machinery
    silently degrade to zero deps — installed.json was being looked up
    at <project>/vendor/composer/installed.json regardless of the
    configured location. cwm-link and cwm-verify --target dev now
    resolve installed.json against the actual vendor dir, so the CWM
    dependencies section appears as designed.

v1.2.0 — two-level cwmSiblings config

15 May 19:17

Choose a tag to compare

Added

  • dev.cwmSiblings declaration in cwm-build.config.json — a project
    now declares the list of CWM sibling packages it expects to find as
    Composer path repositories:

    {
      "dev": {
        "cwmSiblings": [
          "joomla-bible-study/lib-cwmscripture",
          "cwm/scripture-links"
        ]
      }
    }

    This is the project-level "I depend on these siblings via local
    checkouts" declaration — committed, shared across all developers.

  • [paths] block in build.properties — per-developer mapping
    from each declared CWM sibling to its absolute path on the local
    machine:

    [paths]
    joomla-bible-study/lib-cwmscripture = /Users/brent/GitHub/lib_cwmscripture
    cwm/scripture-links                 = /Users/brent/GitHub/CWMScriptureLinks

    Gitignored (per-developer). Companion to the existing per-install
    configuration sections.

    • PropertiesReader::paths(): array<string, string> reads the block.
    • PropertiesReader::writePaths(array $paths) rewrites it while
      preserving every install section.
    • PropertiesReader::write() reciprocally preserves any existing
      [paths] block when re-emitting installs — neither path can
      accidentally drop the other's state.
  • cwm-setup CWM-siblings flow — after the Joomla install
    configuration step, the wizard now:

    1. Reads dev.cwmSiblings from cwm-build.config.json.
    2. For each sibling, surfaces the existing [paths] entry,
      or auto-detects a sibling checkout at ../<name> next to
      the project root.
    3. Prompts to confirm or change the path per sibling.
    4. Writes the resulting paths to build.properties [paths].
    5. Synchronises composer.json's repositories[] block so each
      declared sibling has a matching {"type":"path","url":"..."}
      entry pointing at the developer's local checkout.

    Subsequent composer install / composer update picks up the
    configured paths automatically — no hand-editing of composer.json.

Changed (non-breaking)

  • PropertiesReader::fromSections() now excludes [paths] from the
    install auto-discovery branch (when installs = is omitted), so
    a paths-only or paths-plus-sections file parses correctly.

Migration

Consumers using v1.1.0 path repositories (e.g. CWMLivingWord) can
adopt the new schema by:

  1. Adding dev.cwmSiblings to cwm-build.config.json listing each
    Composer package consumed via a local path repo.
  2. Running composer setup — the wizard prompts for each sibling's
    local path, writes them to build.properties, and rewrites
    composer.json's repositories[] block accordingly.
  3. Re-running composer install.

v1.1.0 — cross-component link awareness + --target test

15 May 18:17

Choose a tag to compare

Added

  • Cross-component link awareness via extra.cwm-build-tools.joomlaLinks.
    Each CWM Composer package can now declare its Joomla install footprint
    in its own composer.json:
    {
      "extra": {
        "cwm-build-tools": {
          "joomlaLinks": [
            { "type": "library",  "name": "cwmscripturelinks" },
            { "type": "plugin",   "group": "content", "element": "cwmsl_autolink" },
            { "type": "module",   "name": "mod_cwm_widget", "client": "site" },
            { "type": "component","name": "com_cwmthing" }
          ]
        }
      }
    }
    Consumers' cwm-link and cwm-verify discover these declarations via
    vendor/composer/installed.json and operate on them automatically —
    no per-consumer wiring required.
    • New CWM\BuildTools\Config\InstalledPackageReader parses
      installed.json directly (Laravel-style — \Composer\InstalledVersions
      strips extra from its accessors), surfacing each CWM dep's version,
      install path, path-repo source path (if installed via a path
      repository), and validated joomlaLinks tuples.
    • New value object CWM\BuildTools\Config\CwmPackage.
  • cwm-link walks CWM Composer deps in addition to the consumer's own
    extensions. Per-dep links land at the same canonical Joomla paths
    (libraries/<name>, plugins/<group>/<element>, etc.) — re-running
    cwm-link from a different consuming repo is idempotent on shared
    targets.
    • Conflict detection: when a symlink already exists at the expected
      target but points somewhere other than this run's source, the
      conflict is reported and skipped (exit 1) rather than silently
      overwritten. New --force flag reinstates overwrite for the rare
      case where a developer actually wants to replace someone else's
      link.
    • Linker::check() return shape gains existingRealpath for ok/wrong/
      broken statuses so callers can compare without re-reading the link.
  • build.properties install role. Each install can now declare
    role = dev (the default — symlink-style working install where
    cwm-link deploys) or role = test (artifact-style install for the
    new cwm-install-zip command). Multiple installs may share a role
    (e.g. j5 and j6 both as dev). Legacy flat Proclaim-style
    build.properties files default every install to role = dev.
    • New PropertiesReader::installsFor(string $role) filters by role.
    • InstallConfig gains a role constructor argument and
      ROLE_DEV / ROLE_TEST constants.
  • cwm-install-zip command. New companion to cwm-link: builds nothing
    itself, but takes the most recent dist zip produced by cwm-build
    (matched via build.outputGlob) and installs it into every Joomla
    install with role = test by invoking the bundled Joomla CLI:
    php <joomlaRoot>/cli/joomla.php extension:install --path=<zip>
    
    Re-running on an existing extension triggers Joomla's upgrade path —
    install scriptfile update() runs, manifest update.sql migrations
    apply. Use this to exercise the SHIPPED artifact end-to-end (install
    scriptfile, dist exclusions, schema migrations) before a release,
    separately from the symlink-style dev workflow.
    • Implementation: new src/Dev/ExtensionInstaller.php and
      src/Dev/InstallResult.php; thin bin wrapper at
      bin/cwm-install-zip.
    • --zip <path> flag to override the outputGlob resolution.
    • proc_open is invoked array-form (no shell) per CLAUDE.md guardrails.
  • cwm-verify --target <role> flag. Filters which installs are
    verified. Without --target, every install is verified per its
    declared role.
    • For role = dev installs, the new
      CWM\BuildTools\Dev\DevTargetVerifier checks: every expected
      symlink is in place (self + every CWM dep); each installed dep
      version satisfies the constraint in the consuming project's
      composer.json; each path-repo dep has a clean working tree
      (git -C <source> status --porcelain).
    • For role = test installs, the existing ExtensionVerifier now
      also walks each CWM dep's declared joomlaLinks and confirms each
      one is registered in #__extensions at the right (type, element, folder, client_id) tuple.
    • New public method ExtensionVerifier::expectedFromPackages(list<CwmPackage>): list<array>
      folds dep declarations into the existing expected-extension shape.
    • lookup() now filters by client_id when supplied, so two modules
      with the same element in different clients (site vs administrator)
      resolve unambiguously.

Changed (non-breaking)

  • Linker::check() return shape now includes an existingRealpath key
    for ok, wrong, and broken statuses. Existing callers reading
    only status and message are unaffected.
  • ExtensionVerifier::verify() signature gains an optional
    array $packages = [] parameter. Existing callers passing
    (InstallConfig, bool) continue to work unchanged.
  • templates/build.properties.tmpl documents the role field and ships
    with a commented-out [j5-test] block for the new artifact-target
    install.

Migration

Consumers pin to ^1.1. Per-repo migration:

  1. composer require --dev cwm/build-tools:^1.1
  2. Add extra.cwm-build-tools.joomlaLinks to your composer.json,
    derived from your manifests.extensions[] in
    cwm-build.config.json (one tuple per declared extension).
  3. (Optional) Add a [j5-test] block with role = test to your
    build.properties to enable cwm-install-zip and
    cwm-verify --target test.
  4. Re-run composer cwm-link — output now shows the deps section;
    existing links are reported as idempotent.
  5. Re-run composer cwm-verify — output now shows per-dep version,
    link state, and (for path-repo deps) working-tree cleanliness.

v1.0.2

14 May 23:35
v1.0.2
53ce471

Choose a tag to compare

Added

versionTracking profiles — consumers can now declare "profile": "component" | "library" | "package-wrapper" in cwm-build.config.json instead of hand-authoring the entire versionTracking block.

  • Profile defaults live in templates/profiles/<name>.json and resolve through CWM\BuildTools\Config\ProfileResolver at every read site (cwm-bump, cwm-release, substitute-tokens, and release.sh's gate check).
  • The consumer's versionTracking key is still honored as an override layer: maps deep-merge, lists replace wholesale.
  • cwm-init detects the right profile from extension.type and pre-fills the prompt.
  • cwm-sync-configs prints a migration hint when an inline block exists without a profile, and a "safe to delete" hint when an inline block exactly matches the profile defaults. Never auto-rewrites JSON.

Migration

Existing consumers can keep their inline versionTracking block (no breaking change) or migrate to the profile pattern:

{
  "extension": { "type": "library", "name": "lib_x" },
  "profile":   "library"
  // Optional: add "versionTracking": { ... } to override per-repo bits.
}