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
6 changes: 6 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

This pull request …

### Changelog

<!-- Required when using the "Submit on merge" label. Describe user-facing changes in bullet points. -->

-

### Testing

<!-- List of steps to verify the code this pull request changed. If it is a Plugin additions, what are the core workflows to test. If it is a bug fix, what are the steps to verify it is fixed -->
Expand Down
34 changes: 29 additions & 5 deletions .github/workflows/shippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
- edited
- ready_for_review
- synchronize
- labeled
- unlabeled
workflow_dispatch:
# NOTE: To prevent GitHub from adding PRs to the merge queue before check is done,
# make sure that there is a ruleset that requires the “Shippy check to pass.
Expand All @@ -24,11 +26,33 @@ jobs:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false && github.event.pull_request.user.login != 'dependabot[bot]'
steps:
- name: Check PR description
- name: Check if Submit on merge label is present
id: check-label
uses: actions/github-script@v7
with:
script: |
const prBody = context.payload.pull_request.body?.trim()
if (!prBody) {
core.setFailed("❌ PR description is required.")
}
const labels = context.payload.pull_request.labels || []
const hasSubmitLabel = labels.some(label => label.name === 'Submit on merge')
core.setOutput('require_changelog', hasSubmitLabel ? 'true' : 'false')

- name: Checkout repository
uses: actions/checkout@v4
with:
sparse-checkout: |
scripts
package.json
yarn.lock
.yarnrc.yml
.yarn
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sparse checkout missing required .tool-versions file

High Severity

The sparse checkout configuration does not include .tool-versions, but the Setup Node.js step on line 51 requires this file via node-version-file: .tool-versions. The workflow will fail because the file won't exist after the sparse checkout completes.

Fix in Cursor Fix in Web

.tool-versions

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .tool-versions

- name: Validate PR body
run: yarn dlx tsx scripts/validate-pr-body.ts
env:
PR_BODY: ${{ github.event.pull_request.body }}
REQUIRE_CHANGELOG: ${{ steps.check-label.outputs.require_changelog }}
64 changes: 64 additions & 0 deletions .github/workflows/submit-on-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Submit on Merge

on:
pull_request:
types:
- closed
branches:
- main

jobs:
submit:
name: Submit Changed Plugins
runs-on: ubuntu-latest
# Only run if PR was merged (not just closed) and has "Submit on merge" label
if: |
github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'Submit on merge')
# FIXME: Should be production
environment: development
Copy link
Member Author

@niekert niekert Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to self to fix before merging.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Development environment hardcoded instead of production

High Severity

The workflow has environment: development and FRAMER_ENV: development hardcoded with FIXME comments. The PR notes explicitly state "note to self to fix before merging." If merged as-is, all plugins submitted via the "Submit on merge" flow would go to the development environment instead of production.

Additional Locations (1)

Fix in Cursor Fix in Web


steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git tags and diff

- name: Configure git identity
run: |
git config --global user.email "marketplace@framer.team"
git config --global user.name "Framer Marketplace"

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .tool-versions

- name: Install dependencies
run: yarn install

- name: Build framer-plugin-tools
working-directory: packages/plugin-tools
run: yarn build

- name: Write PR body to file
run: cat <<< "$PR_BODY" > /tmp/pr-body.txt
env:
PR_BODY: ${{ github.event.pull_request.body }}

- name: Submit changed plugins
run: |
export CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
yarn tsx scripts/submit-on-merge.ts
env:
DEBUG: "1"
PR_BODY_FILE: /tmp/pr-body.txt
SESSION_TOKEN: ${{ secrets.SESSION_TOKEN }}
FRAMER_ADMIN_SECRET: ${{ secrets.FRAMER_ADMIN_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_ERROR_WEBHOOK_URL: ${{ secrets.SLACK_ERROR_WEBHOOK_URL }}
RETOOL_URL: ${{ secrets.RETOOL_URL }}
# FIXME: Should be production
FRAMER_ENV: development
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should fix

GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
124 changes: 124 additions & 0 deletions .github/workflows/submit-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Submit Plugin

on:
# Manual trigger from GitHub UI
workflow_dispatch:
inputs:
plugin_path:
description: 'Plugin directory (e.g., plugins/csv-import)'
required: true
type: string
changelog:
description: 'Changelog for this release'
required: true
type: string
environment:
description: 'Environment (development/production)'
required: true
default: 'development'
type: choice
options:
- development
- production
dry_run:
description: 'Dry run (skip submission and tagging)'
required: false
default: false
type: boolean

# Reusable workflow - can be called from other repos (e.g., framer/workshop)
workflow_call:
inputs:
plugin_path:
description: 'Plugin directory (e.g., plugins/csv-import)'
required: true
type: string
changelog:
description: 'Changelog for this release'
required: true
type: string
environment:
description: 'Environment (development/production)'
required: true
default: 'development'
type: string
dry_run:
description: 'Dry run (skip submission and tagging)'
required: false
default: false
type: boolean
secrets:
SESSION_TOKEN:
description: 'Framer session cookie'
required: true
FRAMER_ADMIN_SECRET:
description: 'Framer admin API key'
required: true
SLACK_WEBHOOK_URL:
description: 'Slack webhook URL for notifications'
required: false
RETOOL_URL:
description: 'Retool dashboard URL for Slack notifications'
required: false
SLACK_ERROR_WEBHOOK_URL:
description: 'Slack webhook URL for error notifications'
required: false

jobs:
submit:
name: Submit Plugin to Marketplace
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git tags and diff

- name: Configure git identity
run: |
git config --global user.email "marketplace@framer.team"
git config --global user.name "Framer Marketplace"

- name: Validate plugin path
run: |
if [ ! -d "${{ github.workspace }}/${{ inputs.plugin_path }}" ]; then
echo "Error: Plugin path '${{ inputs.plugin_path }}' does not exist"
echo ""
echo "Available plugins:"
ls -1 plugins/
exit 1
fi
if [ ! -f "${{ github.workspace }}/${{ inputs.plugin_path }}/framer.json" ]; then
echo "Error: No framer.json found in '${{ inputs.plugin_path }}'"
exit 1
fi
echo "Plugin path validated: ${{ inputs.plugin_path }}"

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .tool-versions

- name: Install dependencies
run: yarn install

- name: Build framer-plugin-tools
run: yarn turbo run build --filter=framer-plugin-tools

- name: Submit plugin
run: yarn tsx scripts/submit-plugin.ts
env:
PLUGIN_PATH: ${{ github.workspace }}/${{ inputs.plugin_path }}
REPO_ROOT: ${{ github.workspace }}
CHANGELOG: ${{ inputs.changelog }}
SESSION_TOKEN: ${{ secrets.SESSION_TOKEN }}
FRAMER_ADMIN_SECRET: ${{ secrets.FRAMER_ADMIN_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_ERROR_WEBHOOK_URL: ${{ secrets.SLACK_ERROR_WEBHOOK_URL }}
RETOOL_URL: ${{ secrets.RETOOL_URL }}
FRAMER_ENV: ${{ inputs.environment }}
GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
DRY_RUN: ${{ inputs.dry_run }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"plugins/*"
],
"scripts": {
"test:scripts": "vitest run scripts/",
"check": "turbo run --continue check-biome check-eslint check-prettier check-svelte check-typescript check-vitest",
"dev": "turbo run dev --concurrency=40",
"fix-biome": "turbo run --continue check-biome -- --write",
Expand All @@ -29,11 +30,15 @@
"@biomejs/biome": "^2.2.4",
"@framer/eslint-config": "workspace:*",
"@framer/vite-config": "workspace:*",
"@types/node": "^22.15.21",
"eslint": "^9.35.0",
"framer-plugin-tools": "workspace:*",
"jiti": "^2.5.1",
"tsx": "^4.19.0",
"turbo": "^2.5.6",
"typescript": "^5.9.2",
"vite": "^7.1.11"
"valibot": "^1.2.0",
"vite": "^7.1.11",
"vitest": "^3.2.4"
}
}
Loading
Loading