Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd637a7
docs(sdk): Add CONTRIBUTING.md template and contributing-md skill
dingsdax Mar 10, 2026
05a29bc
docs(sdk): Fix contributing-md skill path to sentry-sdk-skills plugin
dingsdax Mar 10, 2026
38fc763
docs(sdk): Clarify contributing-md skill creates and updates
dingsdax Mar 10, 2026
17ca698
docs(sdk): Align contributing-md template with develop-docs conventions
dingsdax Mar 10, 2026
7274ae9
docs(sdk): Fix bugs found in SDK engineer review
dingsdax Mar 10, 2026
1798216
docs(sdk): Simplify Getting Help — Discord + GH issues only
dingsdax Mar 10, 2026
87c7906
docs(sdk): Remove ready-for-merge label reference
dingsdax Mar 10, 2026
3f9cf8d
docs(sdk): Tighten template copy
dingsdax Mar 10, 2026
440c50c
docs(sdk): Remove placeholder GitHub issues link to fix link checker
dingsdax Mar 10, 2026
29cb1b9
docs(sdk): Replace smoke test placeholder with generic test command
dingsdax Mar 10, 2026
88b5cb1
Merge branch 'master' into docs/contributing-md-template
dingsdax Mar 10, 2026
563593e
docs(sdk): Fix redirect warnings from link checker
dingsdax Mar 10, 2026
1170de8
Merge branch 'master' into docs/contributing-md-template
dingsdax Mar 10, 2026
87581a1
Update develop-docs/sdk/getting-started/templates/contributing-md-tem…
dingsdax Mar 16, 2026
fff00de
Update develop-docs/sdk/getting-started/templates/contributing-md-tem…
dingsdax Mar 16, 2026
f19bdb3
Update develop-docs/sdk/getting-started/templates/contributing-md-tem…
dingsdax Mar 16, 2026
f21ab97
Merge branch 'master' into docs/contributing-md-template
dingsdax Mar 16, 2026
e418189
Merge branch 'master' into docs/contributing-md-template
stephanie-anderson Mar 16, 2026
9ada569
Merge branch 'master' into docs/contributing-md-template
dingsdax Mar 16, 2026
9db1e1d
fix(copyableCard): Handle heading tags in domToMarkdown
dingsdax Mar 16, 2026
7761924
docs(contributing-md-template): Remove internal playbook links from t…
dingsdax Mar 16, 2026
06cdbd2
ref(contributing-md-template): Rename to contributing-md, add redirect
dingsdax Mar 16, 2026
bb4c29e
fix(contributing-md): Fix skill link URL
dingsdax Mar 17, 2026
89289e4
[getsentry/action-github-commit] Auto commit
getsantry[bot] Mar 17, 2026
0929665
Merge branch 'master' into docs/contributing-md-template
dingsdax Mar 17, 2026
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

This file was deleted.

101 changes: 101 additions & 0 deletions develop-docs/sdk/getting-started/templates/contributing-md.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: CONTRIBUTING.md
sidebar_order: 20
description: Boilerplate CONTRIBUTING.md template for Sentry SDK repositories. Tells contributors how to set up, develop, test, and submit changes.
---

`CONTRIBUTING.md` is a Markdown file at the root of your repository that orients both external contributors and Sentry engineers before they open their first PR. GitHub surfaces it automatically on the Issues and Pull Requests tabs.

**Keep it short.** Detailed process lives on [develop.sentry.dev](https://develop.sentry.dev/sdk/) — link there, don't duplicate it. Target 100–200 lines.

## What Belongs in CONTRIBUTING.md

- **Welcome + issue-first policy** — ask contributors to open an issue before a non-trivial PR. Link to the [handling external contributor PRs playbook](https://develop.sentry.dev/sdk/getting-started/playbooks/development/handling-external-contributor-pr/).
- **Getting started** — environment setup steps specific to this repo. Refer readers to the README for general project overview; CONTRIBUTING.md covers what's extra.
- **Development workflow** — commit format, branch naming, and changelog requirement. Link to the [code submission standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/) rather than restating it.
- **Testing** — exact commands to run the test suite, a subset, and lint. Include platform-specific notes (tox environments, Gradle tasks, Xcode schemes, etc.).
- **Submitting a PR** — open as draft until ready; fill out the PR template. Link to the [opening a PR playbook](https://develop.sentry.dev/sdk/getting-started/playbooks/development/opening-a-pr/).
- **Code review** — LOGAF scale (`h:`/`m:`/`l:`), expected SLAs (1 business day internal / 2 business days external). Link to the [reviewing a PR playbook](https://develop.sentry.dev/sdk/getting-started/playbooks/development/reviewing-a-pr/).
- **AI-assisted contributions** — `Co-Authored-By` attribution required per the [AI attribution standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#ai-attribution). Point maintainers to the [reviewing AI-generated code playbook](https://develop.sentry.dev/sdk/getting-started/playbooks/development/reviewing-ai-generated-code/).
- **Getting help** — Discord server link, `#sdk-[language]` support channel.
- **Code of conduct** — link to [Sentry's Code of Conduct](https://open.sentry.io/code-of-conduct/).

**Do NOT include:**

- Full environment setup (belongs in README)
- Release / publish process (internal; link to sdk-lifecycle playbooks instead)
- Architecture or API design decisions (belongs in AGENTS.md)
- Verbatim copies of content already on develop.sentry.dev

## Good Examples in SDK Repositories

Check if the repository already has one before starting from scratch. The following repos have well-structured examples worth referencing:

- [`getsentry/sentry-python`](https://github.com/getsentry/sentry-python/blob/master/CONTRIBUTING.md) — clear integration development principles; good separation between user and contributor setup
- [`getsentry/sentry-javascript`](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md) — Volta pin for Node/yarn, concise monorepo workflow, explicit PR draft rule
- [`getsentry/sentry-go`](https://github.com/getsentry/sentry-go/blob/master/CONTRIBUTING.md) — explicit LOGAF scale usage, craft release-notes requirement called out
- [`getsentry/sentry-cocoa`](https://github.com/getsentry/sentry-cocoa/blob/main/CONTRIBUTING.md) — LOGAF examples with descriptions, copyright header rule
- [`getsentry/sentry-java`](https://github.com/getsentry/sentry-java/blob/main/CONTRIBUTING.md) — API compatibility validation workflow, clear step-by-step setup

## Template

Use the [`sentry-sdk-skills:contributing-md`](https://github.com/getsentry/sdk-skills/tree/main/plugins/sentry-sdk-skills/skills/contributing-md) skill to create or update your `CONTRIBUTING.md` — it detects commands, CI config, and ecosystem from the repo, fills in the placeholders below, and preserves any SDK-specific sections already present.

Remove sections that don't apply and replace all `[placeholder]` values with real content.

<CopyableCard title="CONTRIBUTING.md">

# Contributing to \[SDK name\]

We welcome contributions! Before submitting a non-trivial change, please open an issue
so we can align on scope and approach. Want to understand how we work? Our
[SDK development docs](https://develop.sentry.dev/sdk/) cover our engineering process
in detail.

## Getting Started

1. Fork the repository and clone your fork.
2. \[SDK-specific setup steps — e.g. install language runtime, create virtualenv, etc.\]
3. Install dependencies: `[install command]`

## Development Workflow

See our [principles](https://develop.sentry.dev/sdk/getting-started/principles/) and [standards](https://develop.sentry.dev/sdk/getting-started/standards/) for SDK development.

## Testing

Run the full test suite: `[full test command]`

Run a single test / test file: `[single test command]`

Lint and format: `[lint command]` / `[format command]`

\[Optional: platform-specific notes, e.g. tox environments, Gradle tasks, Xcode schemes,
required env vars, or native dependency setup for React Native (sentry-cocoa, sentry-java).\]

## Submitting a Pull Request

Open as a **draft**, fill in the PR description, and ensure CI passes before marking ready.

## Code Review

We use the **LOGAF scale** to signal comment weight:

- `h:` (high) — must fix: bugs, security, breakage
- `m:` (medium) — should fix: design, missing tests, clarity
- `l:` (low) — optional nit: style, minor suggestions


## AI-Assisted Contributions

AI-generated code is welcome — include a `Co-Authored-By` trailer per the [AI attribution standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#ai-attribution).

## Getting Help

Have a question? Join the [Sentry Discord](https://discord.com/invite/sentry) in **#sdk-\[language\]** or open a GitHub issue.

## Code of Conduct

This project follows the [Sentry Code of Conduct](https://open.sentry.io/code-of-conduct/).

</CopyableCard>
4 changes: 4 additions & 0 deletions redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ const isDeveloperDocs = !!process.env.NEXT_PUBLIC_DEVELOPER_DOCS;

/** @type {import('next/dist/lib/load-custom-routes').Redirect[]} */
const developerDocsRedirects = [
{
source: '/sdk/getting-started/templates/contributing-md-template/',
destination: '/sdk/getting-started/templates/contributing-md/',
},
// Spotlight and MCP moved from expected-features to foundations/client/integrations
{
source: '/sdk/expected-features/spotlight/',
Expand Down
77 changes: 77 additions & 0 deletions src/components/copyableCard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// @vitest-environment jsdom
import {describe, expect, it} from 'vitest';

import {domToMarkdown} from './copyableCard';

function parse(html: string): HTMLElement {
const div = document.createElement('div');
div.innerHTML = html;
return div;
}

describe('domToMarkdown', () => {
describe('headings', () => {
it.each([
['h1', '# text\n\n'],
['h2', '## text\n\n'],
['h3', '### text\n\n'],
['h4', '#### text\n\n'],
['h5', '##### text\n\n'],
['h6', '###### text\n\n'],
])('converts %s', (tag, expected) => {
expect(domToMarkdown(parse(`<${tag}>text</${tag}>`))).toBe(expected);
});
});

describe('inline formatting', () => {
it.each([
['<strong>bold</strong>', '**bold**'],
['<b>bold</b>', '**bold**'],
['<em>italic</em>', '*italic*'],
['<i>italic</i>', '*italic*'],
['<code>foo()</code>', '`foo()`'],
])('converts %s', (html, expected) => {
expect(domToMarkdown(parse(html))).toBe(expected);
});

it('converts a', () => {
expect(domToMarkdown(parse('<a href="https://example.com">link</a>'))).toBe(
'[link](https://example.com)'
);
});
});

describe('block elements', () => {
it('converts p', () => {
expect(domToMarkdown(parse('<p>hello</p>'))).toBe('hello\n\n');
});
it('converts ul with li', () => {
expect(domToMarkdown(parse('<ul><li>a</li><li>b</li></ul>'))).toBe('- a\n- b\n\n');
});
it('converts ol with li', () => {
expect(domToMarkdown(parse('<ol><li>first</li><li>second</li></ol>'))).toBe(
'1. first\n2. second\n\n'
);
});
});

describe('checkboxes', () => {
it('converts unchecked checkbox', () => {
expect(domToMarkdown(parse('<input type="checkbox" />'))).toBe('[ ] ');
});
it('converts checked checkbox', () => {
const div = parse('<input type="checkbox" />');
(div.querySelector('input') as HTMLInputElement).checked = true;
expect(domToMarkdown(div)).toBe('[x] ');
});
});

describe('document structure', () => {
it('preserves heading prefixes in a full document', () => {
const result = domToMarkdown(
parse('<h1>Title</h1><h2>Section</h2><p>Body text.</p>')
);
expect(result).toBe('# Title\n\n## Section\n\nBody text.\n\n');
});
});
});
14 changes: 13 additions & 1 deletion src/components/copyableCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Chevron from 'sentry-docs/icons/Chevron';
* preserve formatting (checkboxes, bold, links, lists) when pasted
* into GitHub's markdown editor.
*/
function domToMarkdown(node: Node): string {
export function domToMarkdown(node: Node): string {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent ?? '';
}
Expand All @@ -34,6 +34,18 @@ function domToMarkdown(node: Node): string {
const childText = Array.from(el.childNodes).map(domToMarkdown).join('');

switch (tag) {
case 'h1':
return `# ${childText}\n\n`;
case 'h2':
return `## ${childText}\n\n`;
case 'h3':
return `### ${childText}\n\n`;
case 'h4':
return `#### ${childText}\n\n`;
case 'h5':
return `##### ${childText}\n\n`;
case 'h6':
return `###### ${childText}\n\n`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Auto-linked headings produce malformed copied markdown

Medium Severity

The new heading cases in domToMarkdown don't account for rehype-autolink-headings (configured with behavior: 'wrap' in mdx.ts), which wraps heading content in <a> tags. This is the first CopyableCard containing headings. When copied, each heading's inner <a> is converted to a markdown link, producing output like ## [Getting Started](#getting-started) instead of ## Getting Started. For the h1, nested brackets (# [Contributing to [SDK name]](#…)) break markdown parsing entirely.

Additional Locations (1)
Fix in Cursor Fix in Web

case 'strong':
case 'b':
return `**${childText}**`;
Expand Down
Loading