Metadata-Version: 2.4
Name: mkdocs-external-code
Version: 0.1.0
Summary: MkDocs plugin: the @code: directive fetches file content from a GitHub org via the API
License-Expression: MIT
Keywords: mkdocs,plugin,github,include,snippet
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Framework :: MkDocs
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Documentation
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mkdocs>=1.5
Dynamic: license-file

# mkdocs-external-code

[![CI](https://github.com/calmzhu/mkdocs-external-code/actions/workflows/ci.yml/badge.svg)](https://github.com/calmzhu/mkdocs-external-code/actions/workflows/ci.yml)

A MkDocs plugin: the `@code:` directive fetches a file's raw content from
a GitHub repository (via the GitHub API) at build/serve time and renders it
as a syntax-highlighted code block — so docs reference the real source instead
of maintaining a copy.

## Install

```bash
pip install mkdocs-external-code
```

## Configure

```yaml
plugins:
  - external-code:
      org: my-org          # required: GitHub org whose repos may be referenced
      default_ref: main    # optional, default "main"
      token_env: GH_READ_TOKEN  # optional, default "GH_READ_TOKEN"
```

## Usage

```markdown
@code:bash my-org/my-repo/tools/deploy.sh
@code:yaml my-org/my-repo@a1b2c3d/values.yaml   # pin a ref with @<sha>
@code:my-org/my-repo/app.py                     # language omitted -> inferred
```

Rules:

- Only the configured `org` is allowed; other orgs fail the build with a clear error.
- The language name after `@code:` is optional — it is inferred from the file
  extension (`.sh` → bash, `.hcl` → hcl, `.py` → python, `Dockerfile` →
  dockerfile, ...) and defaults to `text`. Omitting the language needs no
  space: `@code:my-org/...` and `@code: my-org/...` both work.
- `@ref` is optional: omitted uses `default_ref` (or the `EXTERNAL_DEFAULT_REF`
  env var if set). Pin an exact version with `@<commit-sha>` (refs containing
  `/` are not supported).
- Directives inside code fences or inline code are ignored (so you can document
  the syntax in a fenced block without executing it).

### Access to private repos

The plugin reads the token for `token_env` in this order:

1. the environment variable (or a `.env` file — the plugin loads it itself;
   the directory of your `mkdocs.yml` is checked first, then the current
   working directory, and existing variables are never overridden);
2. if unset, requests are anonymous (public repos only).

A GitHub Personal Access Token (prefer fine-grained) with **Contents: Read** on
each referenced repo is enough. In GitHub Actions, inject it explicitly:

```yaml
- run: mkdocs build
  env:
    GH_READ_TOKEN: ${{ secrets.REPO_READ_PAT }}
```

Note: the default `GITHUB_TOKEN` only covers the repository running the
workflow; it cannot read other private repos.

### Limitations

- Only UTF-8 **text** files are supported — binary or non-UTF-8 content fails
  the build with a clear error.
- Files are fetched through the GitHub Contents API, which caps file size at
  1 MB; larger files fail with a clear error (use a `raw.githubusercontent.com`
  URL form if you need them).
- Anonymous requests are rate-limited by GitHub (60/hour per IP); pass a token
  to raise the limit.
- Fetched content is cached for the process lifetime — during `mkdocs serve`,
  restart the server to pick up changed remote content.
- `@ref` must not contain `/` (e.g. branch names like `feature/x`); pin a
  commit SHA instead.
- Fenced code blocks and inline code are detected; indented (4-space) code
  blocks are not — use a fenced block to show the directive syntax literally.

## Development

```bash
python -m venv .venv && . .venv/bin/activate
pip install -e .
python -m unittest discover -s tests -v
ruff check . && ruff format --check .
```

## Releasing

1. Bump the version in `pyproject.toml` and `mkdocs_external_code/__init__.py`.
2. Publish a GitHub release with tag `v<version>`.
3. The `Release` workflow builds the sdist/wheel and uploads it to PyPI via
   trusted publishing. Configure the PyPI trusted publisher once (owner
   `calmzhu`, repository `mkdocs-external-code`, workflow `release.yml`,
   environment `pypi`) — no API token secret is required.

## License

MIT
