Skip to content
Merged
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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Validate Composer metadata strictly
run: docker run --rm -v "$GITHUB_WORKSPACE:/app" -w /app composer:2.10 validate --strict --no-check-publish
run: docker run --rm -v "$GITHUB_WORKSPACE:/app" -w /app composer:2.10 validate --strict

- name: Validate VCS imports before and after the package rename
run: docker run --rm --network none -v "$GITHUB_WORKSPACE:/app:ro" -w /app composer:2.10 php tests/php/check-composer-import.php /usr/bin/composer

- name: Check optimized production classmap
run: |
Expand Down
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

Notable changes to the Basicrum Analytics module are recorded here.
Notable changes to Basicrum Analytics are recorded here.

## [Unreleased]

Expand Down Expand Up @@ -28,6 +28,15 @@ Notable changes to the Basicrum Analytics module are recorded here.

### Changed

- **Breaking packaging change:** the Composer name is now
`basicrum/basicrum-magento-2`, retaining the public title "Basicrum Analytics"
and distribution filename `basicrum-magento-2.zip`. No compatibility
replacement is declared. The old-name conflict is omitted during the rename
because VCS imports under the old default-branch name reject it as a self-conflict.
Remove the old package explicitly; Composer does not prevent co-installation.
Magento module/namespace/ACL identifiers and configuration paths are unchanged
by this packaging change. Packagist registration and release publication are
separate, pending maintainer steps; historical tags are not rewritten.
- **Breaking:** Magento 2 `p_type` now uses Magento 1's exact 27 named labels
for equivalent native pages, including `Checkout Success`, account/address,
wishlist, guest-order, and PayPal billing-agreement pages. HTTP 404 takes
Expand Down Expand Up @@ -65,6 +74,12 @@ Notable changes to the Basicrum Analytics module are recorded here.

### Fixed

- The Admin integration test opens Magento's native Basicrum navigation group
before selecting the exact settings link, which is hidden when collapsed.
- Validate rename branches through Composer's validating VCS importer in CI,
including the pre-merge old-name default branch that root validation misses.
- Rebuild the disposable Magento catalog search index before native browser
checks, including when retained application/database volumes outlive OpenSearch data.
- Fresh disposable Magento provisioning no longer writes the Admin Usage setting
after disabling its owning module. Configuration failures still stop the job.
- Release ZIPs and expected hashes now come from committed files; ignored local
Expand Down
39 changes: 33 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Basicrum Analytics for Magento 2
# Basicrum Analytics

Basicrum adds Boomerang real user monitoring (RUM) to a Magento 2 storefront.
Monitoring is fail-closed: no Basicrum storefront scripts are emitted unless
Expand All @@ -24,12 +24,21 @@ verification scope, skips, and remaining release requirements.

## Installation

Install a published package with Composer:
The Composer package is being renamed to `basicrum/basicrum-magento-2`.
This source change does not register the new Packagist listing or publish a
release. After the new package's `0.1.0` release is published, install it with:

```sh
composer require basicrum/basicrum-analytics
composer require 'basicrum/basicrum-magento-2:^0.1'
```

The version constraint deliberately excludes the historical `0.0.x` releases,
which may also appear under the new name when Packagist imports the repository.
Do not drop the constraint to make an unpublished release install. Until
`0.1.0` is available, use a reviewed source checkout for development only.
See the [package migration checklist](https://github.com/basicrum/basicrum-magento-2/blob/main/docs/PACKAGE-NAMING-MIGRATION.md)
for the separate maintainer steps and existing-installation considerations.

For a manual source installation, place this module at the exact path below.
The casing is required on case-sensitive filesystems:

Expand All @@ -53,7 +62,7 @@ static content using the store's normal deployment process as well.

## Configuration

Open **Stores > Configuration > Basicrum Analytics**. Every setting supports
Open **Stores > Configuration > Basicrum > Basicrum Analytics**. Every setting supports
Magento default, website, and store inheritance. Display-only status, version,
and callback instructions have no inheritance controls or stored values.
Visitor Consent and Privacy open expanded each time you visit the page. You
Expand Down Expand Up @@ -155,6 +164,14 @@ Automatic consent-provider adapters are not part of Phase 1.
No data migration renames, deletes, or heuristically rewrites stored settings.
Review the following before enabling the upgraded module:

- The Composer package name changes from `basicrum/basicrum-analytics` to
`basicrum/basicrum-magento-2`. The two packages must not be installed together;
Composer does not prevent that combination during the naming transition.
Remove the old requirement and check the resolved lock file for old-name
transitive dependencies when the new release is available; this is not an
automatic or backward-compatible replacement. A manual `app/code` copy must not coexist
with a Composer installation either. No stored configuration is deleted.

- Magento 2 `p_type` labels now match Magento 1, including capitalization and
spaces. This intentionally changes existing report groupings; historical
beacons are not migrated and no legacy-label mode is provided. Update any
Expand Down Expand Up @@ -240,8 +257,18 @@ blocked unnonced inline negative control. The fixture is never packaged with
the extension. This is separate from the report-only homepage FPC checks; it
does not certify nonce handling on cacheable pages or custom strict-dynamic
policies. See the integration README for fixture installation and scope.
The regular CI workflow runs strict Composer 2.10 validation and optimized
production classmap checks plus the fast PHP and Chromium checks. The Chromium
The regular CI workflow runs strict Composer 2.10 validation, a validating VCS
import regression before and after the default-branch rename, and optimized
production classmap checks plus the fast PHP and Chromium checks. The VCS test
uses the real Composer importer on a temporary local Git repository containing
the candidate metadata and a synthetic historical tag; it needs no network or
Packagist account. Run it with:

```sh
docker run --rm --network none -v "$PWD:/app:ro" -w /app composer:2.10 php tests/php/check-composer-import.php /usr/bin/composer
```

This is not a live Packagist update or a Magento Composer installation. The Chromium
job uploads an HTML report with traces from failed test attempts, retained for
seven days. A flaky pass still fails the job; retries do not hide failures.
Additional CI checks run Magento-aware PHPStan level 8 and Magento coding
Expand Down
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{
"name": "basicrum/basicrum-analytics",
"description": "Basicrum real user monitoring for Magento 2",
"name": "basicrum/basicrum-magento-2",
"description": "Basicrum real user monitoring (RUM) for Magento 2",
"type": "magento2-module",
"homepage": "https://github.com/basicrum/basicrum-magento-2",
"support": {
"issues": "https://github.com/basicrum/basicrum-magento-2/issues",
"docs": "https://github.com/basicrum/basicrum-magento-2#readme"
},
"authors": [
{
"name": "Tsvetan Stoychev",
Expand Down
119 changes: 119 additions & 0 deletions docs/PACKAGE-NAMING-MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Composer and Packagist naming migration

## Scope and identity

This repository prepares the rename; it does not register, abandon, publish or
delete any Packagist package, create a release tag, or approve a module license.

| Surface | Canonical value |
| --- | --- |
| Composer / Packagist | `basicrum/basicrum-magento-2` |
| Public title and Admin section | Basicrum Analytics |
| Description | Basicrum real user monitoring (RUM) for Magento 2 |
| Distribution ZIP | `basicrum-magento-2.zip` |
| Magento module (unchanged) | `Basicrum_Analytics` |
| PHP namespace (unchanged) | `Basicrum\Analytics` |
| Configuration paths (unchanged) | `basicrum/*` |

The ACL resource, layout aliases, JavaScript identifiers, Beacon Endpoint and
Brum Site ID names also stay unchanged. Historical tags, the existing MIT
declaration and third-party notices are preserved.

## Composer decision

The rename does not declare a conflict with `basicrum/basicrum-analytics`.
While `main` still uses that old name, Composer's VCS importer assigns it to
the rename branch too. An old-name conflict then becomes a self-conflict and
Packagist rejects the branch, even though standalone `composer validate` passes.
The initial PR declared that conflict; the Packagist update failure exposed this
import-stage gap. CI now exercises Composer's validating VCS importer with both
old-name and new-name default branches, the real candidate metadata, and a
synthetic historical tag in a disposable local Git repository.

Both packages must not be installed together, but **Composer does not enforce
that restriction during this transition**. Remove the old requirement explicitly
and inspect the resolved lock file for transitive old-name dependencies.
Any later conflict declaration requires a separately verified migration step,
including successful imports for the affected Packagist listings; it is not
automatically safe merely because this PR was merged. There is no `replace`, `provide`,
compatibility metapackage, class alias or automatic upgrade: this is an
intentional package-name break, not a promise to satisfy old dependencies.
Composer cannot detect a duplicate manually installed `app/code` copy.

Package names come from the default branch during VCS import. Composer can
therefore expose historical tags under the new name without changing those
tags. An unversioned `composer require` could select the old `0.0.2` code before
the new release exists. The README uses `basicrum/basicrum-magento-2:^0.1`
and explicitly makes installation conditional on publication of `0.1.0`.
Do not present `dev-main` or an imported `0.0.x` tag as the new stable release.

## Maintainer checklist — not executed by this change

1. Merge the naming change into the repository's default branch, `main`.
A feature branch alone does not establish the new Packagist identity.
After the corrected branch is pushed, verify that the old listing's next
update no longer rejects it for a self-conflict. If the hook has not retried,
an authorized maintainer can trigger an update. Repeat the import check after
merging; a local test does not certify the hosted updater's state.
2. Before publishing `0.1.0`, obtain the owner's approval for the missing root
LICENSE text and run the release gate against the exact clean commit to be
tagged. CI success is not license approval. Keep the Composer `version`
field absent. Do not move, delete or reuse `0.0.1` or `0.0.2`.
3. Publish the approved new `0.1.0` tag as a separate release action, **before
submitting the new Packagist listing**. Packagist's generated install command
has no version constraint and could otherwise select old `0.0.2` code.
4. As an authorized `basicrum` maintainer, submit the same repository URL to
Packagist under `basicrum/basicrum-magento-2`. Configure/verify its GitHub
update hook and trigger an update if needed. Do not assume updating the old
listing renames it. Verify `0.1.0` is the newest stable version, with the
intended source commit, description, support links and README.
Inspect imported historical versions; their appearance is not evidence that
`0.0.x` contains the new implementation. Verify a clean disposable Magento
Composer install using `^0.1`, including `Basicrum_Analytics` registration.
5. Once the new stable package is available and verified, mark
`basicrum/basicrum-analytics` abandoned in the **old listing's Packagist UI**,
with `basicrum/basicrum-magento-2` as the suggested alternative. Do not add an
`abandoned` field to the renamed package's `composer.json`. Keep the old
listing and historical versions; do not delete them or expect download
statistics to transfer. Abandonment is a notice, not a lock-file migration.

## Existing development installations

After the new release is available, review the project's dependency graph and
change the old requirement explicitly. For a project that directly requires
the old package, the intended Composer transaction is:

```sh
composer remove basicrum/basicrum-analytics --no-update
composer require 'basicrum/basicrum-magento-2:^0.1'
```

Back up and review the resulting `composer.json` / `composer.lock` diff. If a
different package still requires the old name, stop and update that dependency
deliberately. Do not deploy a lock file containing both names; there is no
solver-level conflict guard in this rename. This transaction only changes Composer
packages. It does not migrate the historical module-name capitalization,
Magento's enabled-module configuration, or third-party customizations. Review
the README's upgrade notes and Magento deployment steps. Remove any duplicate
manual installation through the project's normal deployment process, preserve
stored settings, and rebuild compiled DI/static assets and caches as documented.

## Review and sources

CLI consultations used `grok-4.7` at high reasoning effort (reported
`grok-4.7-build`) and `claude-opus-5-5` at maximum effort. Both initially recommended an explicit
conflict without `replace` / `provide`. We removed that conflict
after the Packagist failure and a local reproduction using Composer's validating
VCS importer; the no-alias decision remains. Opus also identified the old-tag install trap
and recommended publishing the new stable tag before submitting the listing.
An initial Grok claim that old tags stay confined to the old name was corrected
against Composer source. A fixed `support.source` URL is deliberately omitted:
Composer's GitHub driver supplies a version-specific source link instead.
Tests guard package identity and dependency semantics; the native Admin test
opens Magento's native collapsible navigation before checking the exact rendered
section name and logo caption rather than adding a repository-wide branding scan.

- [Packagist maintainer rename procedure](https://github.com/composer/packagist/issues/47)
- [Composer conflict semantics](https://getcomposer.org/doc/04-schema.md#conflict)
- [Composer VCS name normalization, including historical tags](https://github.com/composer/composer/blob/2.10.3/src/Composer/Repository/VcsRepository.php#L432-L438)
- [Packagist publication and update hooks](https://packagist.org/about)
5 changes: 4 additions & 1 deletion tests/integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ For subsequent runs after `down`, first recreate the containers with
`docker compose -f tests/integration/docker/compose.yaml up -d`.
Application/database volumes are retained; do not reprovision them. Git's
`safe.directory` is baked into the PHP image and survives container recreation.
OpenSearch data is not persisted by this test stack. The release gate rebuilds
`catalogsearch_fulltext` through Magento's standard indexer before browser checks,
so a reused installation does not depend on an old search index or background cron.
After harness Dockerfile changes, run `docker compose -f tests/integration/docker/compose.yaml build php`
before `up -d`. First-time `start.sh` installs npm dependencies using the caller's
UID/GID so the bind-mounted checkout does not acquire root-owned `node_modules`.
Expand Down Expand Up @@ -306,7 +309,7 @@ CAPTCHA must be disabled for this isolated test account.
The gate requires Git and a clean, committed module checkout, including no
untracked files. First build the Git-commit ZIP using `build-artifact.sh` and
install its contents. `BASICRUM_ARTIFACT` can select a ZIP path; the default is
`.test-results/package/basicrum-analytics.zip`. The gate hashes every ZIP entry
`.test-results/package/basicrum-magento-2.zip`. The gate hashes every ZIP entry
against the candidate's production manifest. Before any upgrade/configuration
write it also resolves `Basicrum_Analytics` through
Magento's actual `ComponentRegistrar` and compares SHA-256 hashes of package
Expand Down
26 changes: 20 additions & 6 deletions tests/integration/admin.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,25 @@ test("Basicrum configuration renders in Magento Admin", async ({ page }) => {
expect(configurationUrl).toBeTruthy();
await page.goto(configurationUrl, { waitUntil: "domcontentloaded" });

const basicrumSection = page
.locator("#system_config_tabs a")
.filter({ hasText: "Basicrum Analytics" });
const basicrumUrl = await basicrumSection.getAttribute("href");
expect(basicrumUrl).toBeTruthy();
const response = await page.goto(basicrumUrl, { waitUntil: "networkidle" });
const configTabs = page.locator("#system_config_tabs");
// Magento initializes this group as a collapsible. Hidden links are not
// accessible by role until the group is opened through its native control.
// The tab's accessible name also contains Magento's expand/collapse icon.
const basicrumTab = configTabs.getByRole("tab").filter({
has: page.getByText("Basicrum", { exact: true })
});
await expect(basicrumTab).toBeVisible();
if ((await basicrumTab.getAttribute("aria-expanded")) !== "true") {
await basicrumTab.click();
}
await expect(basicrumTab).toHaveAttribute("aria-expanded", "true");
const basicrumSection = configTabs.getByRole("link", { name: "Basicrum Analytics", exact: true });
await expect(basicrumSection).toBeVisible();
const [response] = await Promise.all([
page.waitForNavigation({ waitUntil: "networkidle" }),
basicrumSection.click()
]);
expect(response).toBeTruthy();
expectAdminCsp(response.headers());

const generalSettings = page.locator('a[href="#basicrum_general-link"]');
Expand All @@ -52,6 +65,7 @@ test("Basicrum configuration renders in Magento Admin", async ({ page }) => {
return logo.isVisible();
})
.toBe(true);
await expect(logo.locator("span")).toHaveText("Basicrum Analytics");
await expect(page.getByText("Monitoring Status", { exact: true })).toBeVisible();
await expect(page.getByText("Beacon Endpoint", { exact: true })).toBeVisible();
await expect(page.getByText("Brum Site ID", { exact: true })).toBeVisible();
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/build-artifact.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ module_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
cd "$module_root"
mkdir -p .test-results/package
candidate_commit=$(sh tests/integration/check-candidate.sh)
git archive --format=zip --output=.test-results/package/basicrum-analytics.zip "$candidate_commit"
php tests/integration/check-artifact.php .test-results/package/basicrum-analytics.zip
git archive --format=zip --output=.test-results/package/basicrum-magento-2.zip "$candidate_commit"
php tests/integration/check-artifact.php .test-results/package/basicrum-magento-2.zip
2 changes: 1 addition & 1 deletion tests/integration/docker/install-artifact.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -eu
test "${BASICRUM_DISPOSABLE_MAGENTO:-}" = 1
test "${MAGENTO_ROOT:-}" = /var/www/html
module_root=$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)
artifact="$module_root/.test-results/package/basicrum-analytics.zip"
artifact="$module_root/.test-results/package/basicrum-magento-2.zip"
php "$module_root/tests/integration/check-artifact.php" "$artifact"
cd "$MAGENTO_ROOT"
# Exact destination inside this disposable stack. Do not delete stale files:
Expand Down
Loading
Loading