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
76 changes: 76 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/ew_pr_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<!-- EW_PR_TEMPLATE -->
# [EW] Experience Builder — PR

## Summary

<!-- One sentence: what does this PR do and why? -->

## Related issue / RFC

Fixes # <!-- GitHub issue or RFC link -->

## Test URLs

| | URL |
|---|---|
| Before | `https://main--da-nx--<owner>.hlx.live/` |
| After | `https://<branch>--da-nx--<owner>.hlx.live/` |

---

## Definition of Done checklist

> Fill this out. CI will fail if required items are unchecked.

### Functional

- [ ] Feature behaves as specified (manual smoke-test on After URL above)
- [ ] No regressions in adjacent features (browse, canvas, chat, quick-edit, loc)
- [ ] Dark / light theme renders correctly (if visual change)

### Quality

- [ ] `npm test` passes locally (or unit failures are pre-existing and noted below)
- [ ] No new lint errors (`npm run lint`)
- [ ] No new `console.error` / `console.warn` in the browser at runtime
- [ ] JS added/changed is plain ESM — no CommonJS, no bundler churn without buy-in

### Architecture & contracts

- [ ] Client code does **not** contain orchestration / session logic (belongs in backend repo)
- [ ] Any new wire shapes are documented (inline JSDoc or `aem-agent-contracts` entry)
- [ ] No `any` / untyped casts on contract boundaries
- [ ] CSS uses block-scoped selectors; no accidental global overrides
- [ ] Lazy-loading used for non-critical paths (or absence is justified)

### Skills Lab (check if Skills Lab changed in this PR)

- [ ] Skills Lab changed in this PR
- [ ] All 13 Playwright E2E tests pass: `cd da-live/test/e2e && npx playwright test tests/skills-lab.spec.js --project=chromium`
- [ ] Data model `{ id, body, status }` preserved
- [ ] Dual storage preserved: `/.da/skills/{id}.md` **and** config sheet row
- [ ] `.md` file-content-wins merge rule preserved
- [ ] Public CSS selectors unchanged (or tests updated in same PR): `.skills-lab-card-skill`, `.skills-lab-card-title`, `.skills-lab-skill-edit`, `.skills-lab-save-row`, `.skills-lab-cat-tab`, `.skills-lab-tools-col`, `.skills-lab-loading`, `.skills-lab-section-h`
- [ ] DA admin API surface unchanged: `/source`, `/config`, `/list`

### E2E / integration

- [ ] Ran Playwright smoke suite locally **or** confirmed not applicable (no routing / API changes)

### Security

- [ ] No secrets, tokens, or credentials in source or test files
- [ ] AuthN/AuthZ ordering respected: authenticate → authorize → capabilities → resolve
- [ ] No capability resolution before policy check

### Branch hygiene

- [ ] Branch is up to date with `origin/ew` (rebased, not merged)
- [ ] Commits are logical and message follows `type(scope): subject` convention
- [ ] PR targets `ew` (not `main` / `exp-workspace`)

---

## Notes for reviewer

<!-- Anything non-obvious, trade-offs, follow-ups, known issues -->
4 changes: 4 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<!-- Default PR template -->
> **Experience Builder / `ew` work?** Use the dedicated EW template instead:
> append `?template=ew_pr_template.md` to the PR creation URL, or select it from the template picker.

Please always provide the [GitHub issue(s)](../issues) your PR is for, as well as test URLs where your change can be observed (before and after):

Fix #<gh-issue-id>
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/ew-pr-checklist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: EW PR checklist

on:
pull_request_target:
types: [opened, edited, synchronize, reopened]
branches:
- ew

permissions:
pull-requests: read

jobs:
checklist:
name: Validate EW Definition of Done
runs-on: ubuntu-latest
steps:
- name: Check EW PR template checklist
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || '';

// Only enforce when the EW template marker is present
if (!body.includes('<!-- EW_PR_TEMPLATE -->')) {
core.info('EW PR template not used — skipping checklist enforcement.');
return;
}

// Items that must be checked in every EW PR
const required = [
'Feature behaves as specified',
'No new lint errors',
'No new `console.error`',
'Client code does **not** contain orchestration / session logic',
'No secrets, tokens, or credentials',
'AuthN/AuthZ ordering respected',
'No capability resolution before policy check',
'Branch is up to date with `origin/ew`',
'PR targets `ew`',
];

const missing = required.filter(item => {
// Look for an unchecked checkbox line containing the item text
const pattern = new RegExp(`- \\[ \\].*${item.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`);
return pattern.test(body);
});

if (missing.length > 0) {
core.setFailed(
`EW DoD: the following required items are unchecked:\n${missing.map(i => ` • ${i}`).join('\n')}`
);
}

// Conditional: if Skills Lab checkbox is checked, enforce Skills Lab items
const skillsLabChanged = /- \[x\].*Skills Lab changed in this PR/i.test(body);
if (skillsLabChanged) {
const skillsLabRequired = [
'All 13 Playwright E2E tests pass',
'Data model `{ id, body, status }` preserved',
'Dual storage preserved',
'`.md` file-content-wins merge rule preserved',
'Public CSS selectors unchanged',
'DA admin API surface unchanged',
];

const skillsMissing = skillsLabRequired.filter(item => {
const pattern = new RegExp(`- \\[ \\].*${item.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`);
return pattern.test(body);
});

if (skillsMissing.length > 0) {
core.setFailed(
`EW DoD (Skills Lab): the following items are unchecked:\n${skillsMissing.map(i => ` • ${i}`).join('\n')}`
);
}
}

core.info('EW PR checklist passed.');
102 changes: 102 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/sh
# Husky pre-push hook
# Maps changed source paths to their Playwright E2E spec(s) in ../da-live.
# Only the specs relevant to what changed are run — fast by default,
# comprehensive when many areas are touched.
#
# To add a new mapping when a spec lands:
# 1. Add a pattern block below (copy an existing one)
# 2. Uncomment the corresponding spec in SPECS_TO_RUN
#
# Bypass (emergency only): git push --no-verify

DA_LIVE_TEST_DIR="$(git rev-parse --show-toplevel)/../da-live/test/e2e"
SPECS_TO_RUN=""

# Collect changed files in the push range
remote="$1"
while read local_ref local_sha remote_ref remote_sha; do
[ "$local_sha" = "0000000000000000000000000000000000000000" ] && continue
if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then
range="$local_sha"
else
range="$remote_sha..$local_sha"
fi

changed=$(git diff --name-only "$range" 2>/dev/null)

# ── Skills Lab ────────────────────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/(skills-lab|skills-editor|browse/skills|browse/da-skills)"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/skills-lab.spec.js"
fi

# ── Browse ────────────────────────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/browse"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/browse.spec.js"
fi

# ── Edit / Canvas ─────────────────────────────────────────────────────────
# Uncomment when canvas.spec.js lands in da-live
# if echo "$changed" | grep -qE "nx2?/blocks/(canvas|chat|quick-edit-portal)"; then
# SPECS_TO_RUN="$SPECS_TO_RUN tests/canvas.spec.js"
# fi

# ── Edit (prose / formatting) ─────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/(canvas|form|quick-edit-portal)"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/edit.spec.js tests/formatting.spec.js"
fi

# ── Sheet ─────────────────────────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/(form|loc)"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/sheet.spec.js"
fi

# ── Copy / rename / delete ────────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/(browse|shared)"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/copy_rename.spec.js tests/delete.spec.js"
fi

# ── Versions ─────────────────────────────────────────────────────────────
if echo "$changed" | grep -qE "nx2?/blocks/(snapshot-admin|canvas)"; then
SPECS_TO_RUN="$SPECS_TO_RUN tests/versions.spec.js"
fi

# ── Nav / sidenav ─────────────────────────────────────────────────────────
# Uncomment when nav.spec.js lands in da-live
# if echo "$changed" | grep -qE "nx2?/blocks/(nav|sidenav|profile)"; then
# SPECS_TO_RUN="$SPECS_TO_RUN tests/nav.spec.js"
# fi

done

# Deduplicate spec list
SPECS_TO_RUN=$(echo "$SPECS_TO_RUN" | tr ' ' '\n' | sort -u | tr '\n' ' ' | xargs)

if [ -z "$SPECS_TO_RUN" ]; then
exit 0
fi

if [ ! -d "$DA_LIVE_TEST_DIR" ]; then
echo ""
echo "ERROR: da-live test directory not found at: $DA_LIVE_TEST_DIR"
echo " Clone da-live as a sibling of da-nx, or skip with: git push --no-verify"
exit 1
fi

echo ""
echo "Changed paths trigger E2E specs: $SPECS_TO_RUN"
echo ""

cd "$DA_LIVE_TEST_DIR" || exit 1

# shellcheck disable=SC2086
if ! npx playwright test $SPECS_TO_RUN --project=chromium; then
echo ""
echo "ERROR: E2E tests failed. Fix failures before pushing."
echo " To bypass (not recommended): git push --no-verify"
exit 1
fi

echo ""
echo "All triggered E2E tests passed."
exit 0
Loading