Skip to content
Open
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
22 changes: 22 additions & 0 deletions .github/workflows/support-ownership-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: Support ownership check

on:
pull_request:
branches: [master, main]
paths:
- 'apps/**'
- 'SUPPORT_OWNERSHIP.md'
- '.github/workflows/support-ownership-check.yml'

permissions:
contents: read

jobs:
check:
name: All apps listed in SUPPORT_OWNERSHIP.md
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify support ownership manifest
run: node scripts/check-support-ownership.mjs
59 changes: 59 additions & 0 deletions SUPPORT_OWNERSHIP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Marketplace app support ownership

This file lists who provides support for each app in this repository. When adding a new app under `apps/`, you **must** add a row to the table below—CI will fail otherwise.

**App id** must match the app directory name under `apps/` (e.g. `apps/jira` → App id `jira`).

| App id | App name | Support owner | Support link |
|--------|----------|---------------|--------------|
| ai-content-generator | AI Content Generator powered by OpenAI | Contentful | |
| ai-image-generator | AI Image Generator powered by OpenAI | Contentful | |
| ai-image-tagging | AI Image Tagging | Contentful | |
| auto-prefix | Auto-prefix | Contentful | |
| aws-amplify | AWS Amplify | Contentful | |
| bedrock-content-generator | AI Content Generator powered by Amazon Bedrock | Amazon Web Services | |
| brandfolder | Brandfolder App | Contentful | |
| braze | Braze | Contentful | |
| bulk-edit | Bulk Edit | Contentful | |
| bynder | Bynder App | Contentful | |
| closest-preview | Closest Preview | Contentful | |
| cloudinary | Cloudinary | Contentful | |
| color-picker | Color Picker | Contentful | |
| commercetools | Commercetools | Commercetools | |
| commercetools-without-search | Commercetools (no search) | Commercetools | |
| content-insights | Content Insights | Contentful | |
| deep-clone | Deep Clone | Contentful | |
| dropbox | Dropbox | Contentful | |
| frontify | Frontify | Frontify | |
| gatsby | Gatsby | Contentful | |
| google-analytics | Google Analytics Legacy | Contentful | |
| google-analytics-4 | Google Analytics 4 | Contentful | |
| google-docs | Google Docs | Contentful | |
| google-drive-ner-app | Google Drive NER App | Contentful | |
| graphql-playground | GraphQL Playground | Contentful | |
| graphql-playground-v2 | GraphQL Playground v2 | Contentful | |
| homebase | Homebase | Contentful | |
| hubspot | Hubspot | Contentful | |
| image-focal-point | Image Focal Point | Contentful | |
| iterable | Iterable | Contentful | |
| jira | Jira | Contentful | |
| json-viewer | JSON Viewer | Contentful | |
| klaviyo | Klaviyo | Contentful | |
| locale-field-populator | Locale Field Populator | Contentful | |
| microsoft-teams | Microsoft Teams | Contentful | |
| mux | Mux | Contentful | |
| marketo | Marketo | Contentful | |
| netlify | Netlify | Contentful | |
| optimizely | Optimizely | Contentful | |
| remote-mcp | Remote MCP | Contentful | |
| rich-text-versioning | Rich Text Versioning | Contentful | |
| saleor | Saleor | Saleor | |
| salesforce-commerce-cloud | Salesforce Commerce Cloud | Contentful | |
| sap-commerce-cloud | SAP Commerce Cloud | Contentful | |
| shopify | Shopify | Contentful | |
| side-notes-app | Compose / Studio | Contentful | |
| slack | Slack | Contentful | |
| smartling | Smartling | Contentful | |
| typeform | Typeform | Contentful | |
| vercel | Vercel | Vercel | |
| wistia-videos | Wistia | Contentful | |
64 changes: 64 additions & 0 deletions scripts/check-support-ownership.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env node
/**
* Verifies every app under apps/ is listed in SUPPORT_OWNERSHIP.md.
* Run from repo root. Exits 1 if any app is missing.
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '..');
const manifestPath = path.join(repoRoot, 'SUPPORT_OWNERSHIP.md');
const appsDir = path.join(repoRoot, 'apps');

function parseSupportOwnershipManifest(content) {
const appIds = new Set();
const lines = content.split(/\r?\n/);

for (const line of lines) {
const trimmed = line.trim();
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) continue;

const cells = trimmed
.slice(1, -1)
.split('|')
.map((c) => c.trim());

if (cells[0]?.replace(/-/g, '') === '') continue; // separator row
if (cells[0]?.toLowerCase() === 'app id') continue; // header row
if (cells[0]) appIds.add(cells[0]);
}
return appIds;
}

function getAppDirectories() {
if (!fs.existsSync(appsDir)) return [];
return fs.readdirSync(appsDir, { withFileTypes: true })
.filter((d) => d.isDirectory())
.map((d) => d.name);
}

const appDirs = getAppDirectories();
if (appDirs.length === 0) {
console.log('No apps directory or no app subdirectories found.');
process.exit(0);
}

if (!fs.existsSync(manifestPath)) {
console.error('SUPPORT_OWNERSHIP.md is missing at repo root. Add it with a table: | App id | App name | Support owner | Support link |');
console.error('Required app ids:', appDirs.join(', '));
process.exit(1);
}

const content = fs.readFileSync(manifestPath, 'utf-8');
const listedIds = parseSupportOwnershipManifest(content);
const missing = appDirs.filter((id) => !listedIds.has(id));

if (missing.length > 0) {
console.error('SUPPORT_OWNERSHIP.md is missing entries for these app ids:', missing.join(', '));
console.error('Add a row for each with App id (directory name), App name, Support owner, and Support link.');
process.exit(1);
}

console.log('Support ownership check passed: all', appDirs.length, 'apps are listed.');