# Contributing

## Workspace-specific guides

- [Injected coding guidelines](./injected/docs/coding-guidelines.md)
- [Injected testing guide](./injected/docs/testing-guide.md)
- [Special Pages README](./special-pages/README.md)
- [Messaging docs](./messaging/docs/messaging.md)

## Development

Consider using [nvm](https://github.com/nvm-sh/nvm) to manage node versions, after installing in the project directory run:

```
nvm use
```

From the top-level root folder of this npm workspace, you can run the following npm commands:

**Install dependencies**:

Will install all the dependencies we need to build and run the project:
```
npm install
```

**Build all workspaces**:

Use this to produce the same output as a release. The `build` directory will be populated with
various artifacts.

```sh
npm run build
```

> [!TIP]
> You can run the `build` command from within any sub-project too, the artifacts will always be
> lifted out to the root-level `build` folder.

**Run unit tests for all workspaces**:

```sh
npm run test-unit
```

**Run integration tests for all workspaces**:
```sh
npm run test-int
```

**Run extended integration tests for all workspaces**:
```sh
npm run test-int-x
```

**Clean tree and check for changes**:
```sh
npm run test-clean-tree
```

**Generate documentation using TypeDoc**:
```sh
npm run docs
```

**Generate and watch documentation using TypeDoc**:
```sh
npm run docs-watch
```

**Compile TypeScript files**:
```sh
npm run tsc
```

**Watch and compile TypeScript files**:
```sh
npm run tsc-watch
```

**Lint the codebase using ESLint**:
```sh
npm run lint
```

**Lint and automatically fix issues**:
```sh
npm run lint-fix
```

**Serve integration test pages on port 3220**:
```sh
npm run serve
```

**Serve special pages on port 3221**:
```sh
npm run serve-special-pages
```

## Release Process

Releases are created via GitHub Actions: [Release workflow](https://github.com/duckduckgo/content-scope-scripts/actions/workflows/build.yml)

### Why release branches exist

C-S-S is consumed by native apps (Android, iOS, macOS, Windows) that each use a different dependency mechanism (npm, Swift Package Manager, git submodules). These consumers need **built artifacts** (`build/`, `Sources/ContentScopeScripts/dist/`) — not source code they'd have to compile themselves.

On `main` and feature branches, `build/` and `Sources/ContentScopeScripts/dist/*.js` are **gitignored**. This keeps diffs clean: PRs show only source changes, not thousands of lines of generated JavaScript.

Built artifacts live on dedicated branches:

| Branch | Purpose | How it's created |
|--------|---------|-----------------|
| `releases` | Production releases. Tags (e.g. `12.38.0`) point here. | Manual `workflow_dispatch` on `build.yml` |
| `pr-releases/<branch>` | Per-PR build artifacts for cross-repo testing. | Automatic via `build-branch.yml` on every PR push |

The `releases` branch is the long-lived equivalent of "what `main` would look like if we checked in build output". The `pr-releases/` branches are ephemeral — created when a PR is opened/updated, deleted when it's closed.

**Why not check build output into `main` directly?**

- Rebasing becomes painful: every commit in a rebase would require rebuilding and re-staging `build/` and `Sources/`.
- PRs become unreadable: generated diffs dwarf the actual source changes.
- Merge conflicts in generated files are meaningless noise.

The separate-branch approach was adopted via [Tech Design: Build automation for content-scope-scripts](https://app.asana.com/0/1201614831475344/1203979567756832/f).

### Creating a release

1. Go to [Actions → Release](https://github.com/duckduckgo/content-scope-scripts/actions/workflows/build.yml)
2. Click "Run workflow"
3. Select version bump type
4. Click "Run workflow"

The workflow creates a tag and GitHub release automatically. Build artifacts on the `releases` branch are consumed by native app repos.

### PR build branches

When you push to any branch (except `main`, `releases`, `pr-releases/*`, or `dependabot/*`), the `build-branch.yml` workflow automatically:

1. Builds all workspaces (`npm run build`)
2. Pushes the source + build artifacts to `pr-releases/<your-branch-name>`
3. If an open PR exists for the branch, updates the PR description and posts a comment with:
   - Static preview entry points (docs, static pages, integration pages)
   - Integration commands for each platform

The build branch is created on the first push and updated on every subsequent push. It's deleted automatically when the source branch is deleted.

Dependabot branches are deliberately excluded: the workflow's publish job holds a `contents: write` token, and dependency-bump branches are the one place third-party code enters the repo. Test a Dependabot bump via the regular CI checks or a local build instead.

**Using a PR build branch in a native client:**

```sh
# Android / Extension (npm)
npm i github:duckduckgo/content-scope-scripts#pr-releases/my-feature-branch

# Apple (Swift Package Manager) — in Package.swift
.package(url: "https://github.com/duckduckgo/content-scope-scripts.git",
         branch: "pr-releases/my-feature-branch")

# Windows (git submodule)
git -C submodules/content-scope-scripts fetch origin pr-releases/my-feature-branch
git -C submodules/content-scope-scripts checkout origin/pr-releases/my-feature-branch
```

Use `<build-commit-hash>` from the PR build comment for cache-safe preview links.

**Static preview entry points for that build commit:**

```text
https://rawcdn.githack.com/duckduckgo/content-scope-scripts/<build-commit-hash>/docs/index.html
```

```text
https://rawcdn.githack.com/duckduckgo/content-scope-scripts/<build-commit-hash>/injected/integration-test/test-pages/index.html
```

```text
https://rawcdn.githack.com/duckduckgo/content-scope-scripts/<build-commit-hash>/build/integration/pages/index.html
```

### Breaking Changes Protocol

**When making breaking changes:**

1. Ensure you land a **major release** version bump.
2. **Test and complete the native application side first** before merging the C-S-S repo change.
3. Only merge the C-S-S change after native app support is complete.

**Why This Matters**

This prevents any engineer from having a breaking change and broken workflow. The native application must be tested and complete before the C-S-S repo change is merged.
