Skip to content

Commit 882cb43

Browse files
annab1cursoragent
andauthored
feat: add shared Product Pulse composite action [ED-24831] (#42)
* feat: Add shared Product Pulse composite action Centralizes the product-pulse logic (Cursor Agent generation, JSON parsing, Slack notification) so elementor and elementor-pro can share one implementation instead of maintaining duplicate ~300-line workflows. Callers keep their own repo-specific product-area prompt and pass it in via the prompt-file input. Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * fix: pass GitHub Action expressions via env to prevent script injection Move ${{ }} expressions (inputs.pr-number, github.action_path, steps.update.outputs.*, github.event.pull_request.html_url) out of inline run: script bodies and into env: blocks, addressing CodeQL code-injection findings in the product-pulse action. Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * feat: Unify product-pulse prompt into a shared template Moves the ~85% of the prompt that was byte-identical between elementor and elementor-pro (goal, decision criteria, type classification, writing style, output format, examples, edge cases) into prompt-template.md, owned by this action. Callers now only supply a small product-areas-file with the three things that genuinely differ per repo: PRODUCT_NAME, the PRODUCT_AREAS file-path mapping, and the PRODUCT_ENUM list. A new render-prompt.py substitutes these into the shared template before it's handed to Cursor Agent. Replaces the prompt-file/default-product inputs accordingly. Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * refactor: Drop product-area detection, just tag the caller's product name Per-repo file-path -> product-area mapping was more granularity than needed for a Slack pulse feed. The product field is now always the calling repo's name (e.g. "Elementor" or "Elementor Pro"), passed as a plain product-name input instead of a product-areas-file. This removes the whole Product Area Detection section from the shared prompt, drops the AI's product classification (and its validation), and lets callers drop their per-repo areas file entirely. Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * feat: Add build artifact link to Slack pulse footer Adds a "Get build artifact link" step that looks up the most recent successful run of the caller repo's Build workflow (build.yml) for the PR's head SHA, resolves its uploaded artifact, and appends a "Build Artifact" link to the Slack notification footer alongside the PR # and Jira ticket links. Skips gracefully if no matching run or artifact is found. Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * docs: Fix Prettier formatting in product-pulse docs Ref: ED-24831 Co-authored-by: Cursor <cursoragent@cursor.com> * fix(setup-elementor-env): activate Elementor instead of only validating it wp-env installs the Elementor plugin but does not reliably auto-activate it, causing the Performance flow CI job to fail intermittently at the "Validating elementor being activated" step. Actively activate the plugin (idempotent) instead of just checking its state. Cherry-picked from ED-24451 (5444eeb). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(test-actions): bump pinned WordPress core to 7.0.1 Elementor's latest release requires WordPress 6.8+ ("Current WordPress version (6.6) does not meet minimum requirements for Elementor"), so the Performance flow job's plugin activation was silently failing even though wp-env reported the plugin as active. Pin to the current stable core (7.0.1) instead of the outdated 6.6. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent a5fe855 commit 882cb43

8 files changed

Lines changed: 651 additions & 5 deletions

File tree

.github/workflows/test-actions.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
uses: ./actions/setup-wp-env
2121
with:
2222
php: '8.0'
23-
wp: '6.6'
23+
wp: '7.0.1'
2424
active-theme: 'hello-elementor'
2525
themes: |-
2626
https://downloads.wordpress.org/theme/hello-elementor.zip

actions/product-pulse/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Product Pulse Action
2+
3+
Uses Cursor Agent to decide whether a merged PR is product-facing, and if so, posts a
4+
user-friendly pulse update to Slack. Ported from the `elementor` and `elementor-pro`
5+
repos so both can share one implementation.
6+
7+
The full prompt (goal, decision criteria, writing style, output format, examples) lives
8+
here in `prompt-template.md` and is shared by every caller. Each consuming repo just
9+
passes its `product-name` (e.g. `"Elementor"` or `"Elementor Pro"`) plus a thin wrapper
10+
workflow that triggers on `pull_request: closed` and calls this action.
11+
12+
## Usage
13+
14+
```yaml
15+
name: Product Pulse
16+
17+
on:
18+
pull_request:
19+
types: [closed]
20+
branches: [main]
21+
22+
permissions:
23+
pull-requests: read
24+
25+
concurrency:
26+
group: product-pulse-${{ github.repository }}
27+
cancel-in-progress: false
28+
29+
jobs:
30+
product-pulse:
31+
if: github.event.pull_request.merged == true && startsWith(github.repository, 'elementor/')
32+
runs-on: ubuntu-latest
33+
steps:
34+
- uses: actions/checkout@v6
35+
36+
- uses: elementor/elementor-editor-github-actions/actions/product-pulse@main
37+
with:
38+
pr-number: ${{ github.event.pull_request.number }}
39+
product-name: 'Elementor'
40+
cursor-api-key: ${{ secrets.CURSOR_APIKEY }}
41+
slack-token: ${{ secrets.SLACK_TOKEN }}
42+
slack-channel-id: ${{ secrets.SLACK_PULSE_CHANNEL_ID }}
43+
```
44+
45+
## Inputs
46+
47+
| Input | Required | Default | Description |
48+
| ------------------ | -------- | -------------- | ------------------------------------------------ |
49+
| `pr-number` | yes | – | Merged PR number to generate the pulse for |
50+
| `product-name` | yes | – | Product name used in the prompt and Slack header |
51+
| `model` | no | `composer-2.5` | Cursor Agent model used for generation |
52+
| `cursor-api-key` | yes | – | Cursor Agent API key |
53+
| `slack-token` | yes | – | Slack bot token with `chat:write` |
54+
| `slack-channel-id` | yes | – | Slack channel ID for pulse notifications |
55+
56+
The full generic prompt lives in this action's `prompt-template.md` and is rendered
57+
with the caller's `product-name` substituted in before being sent to Cursor Agent.

0 commit comments

Comments
 (0)