Skip to content
Merged
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
44 changes: 41 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand All @@ -28,7 +28,7 @@ jobs:

- name: Install dependencies with uv
run: |
uv sync --all-extras --dev --python ${{ matrix.python-version }}
uv sync --locked --all-extras --dev --python ${{ matrix.python-version }}

- name: Lint with flake8
run: |
Expand Down Expand Up @@ -62,6 +62,44 @@ jobs:
echo "- ✅ CLI installation: Passed" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Doctor JSON smoke test: Passed" >> $GITHUB_STEP_SUMMARY

compiler-integration:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v8.1.0
with:
version: "latest"
enable-cache: true

- name: Set up Python
run: uv python install 3.11

- name: Install dependencies with uv
run: uv sync --locked --all-extras --dev --python 3.11

- name: Set up Typst
uses: typst-community/setup-typst@v4
with:
typst-version: "0.15.1"

- name: Install LaTeX and PDF tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
latexmk texlive-latex-extra texlive-fonts-recommended \
texlive-bibtex-extra biber poppler-utils

- name: Check bibliography tools
run: |
kpsewhich biblatex.sty
biber --version

- name: Verify archives and versioned PDFs with real compilers
run: uv run --locked pytest tests/test_bundle.py tests/test_bundle_typst.py tests/test_paper_version.py

build:
needs: test
runs-on: ubuntu-latest
Expand All @@ -79,7 +117,7 @@ jobs:
run: uv python install 3.11

- name: Install dependencies with uv
run: uv sync --all-extras --dev --python 3.11
run: uv sync --locked --all-extras --dev --python 3.11

- name: Build package
run: uv build
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ article.cli/
### Updating Dependencies

1. Update `pyproject.toml` dependencies section
2. Test with different Python versions (3.8-3.12)
2. Test with different Python versions (3.11-3.13)
3. Update CI if needed
4. Document any breaking changes

Expand All @@ -120,7 +120,7 @@ article.cli/

1. **Build and Test** (`ci.yml`):
- Triggered on: push to main/develop, pull requests
- Tests: Python 3.8, 3.9, 3.10, 3.11, 3.12
- Tests: Python 3.11, 3.12, 3.13
- Checks: Black, flake8, mypy, CLI functionality
- Artifacts: Built package for distribution

Expand Down Expand Up @@ -191,7 +191,7 @@ uv pip install black flake8 mypy types-requests pytest
- **Default Zotero Group ID**: `4678293` (for article.template)
- **Default Output File**: `references.bib`
- **Default Branch**: `main`
- **Python Support**: 3.8 - 3.12
- **Python Support**: 3.11+

## 🔗 Important Links

Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.1.0] - 2026-10-30

### Added
- `article-cli bundle` creates reproducible LaTeX and Typst source ZIPs through a shared service and injectable compiler strategies. LaTeX uses TeX recorder dependencies; Typst uses native JSON dependency reporting.
- Project include/exclude policy in `[tool.article-cli.bundle]`, repeatable CLI overrides, optional main PDF, dry-run file listing, and clean compilation verification.
- Typst bundle support includes imports, dynamic data, bibliography/styles, configured local fonts, and vendored external packages.
- Portable Typst Git snapshots with version/commit/branch/date/dirty state, integrated with `version`, `compile`, templates, and paper release workflows. LaTeX templates use local `gitinfo2` snapshots for archive portability.
- Adjacent JSON manifests record source hashes and the archive checksum; existing archives require `--force` to replace.

### Changed
- Require Python 3.11+ for article-cli and generated projects; remove the TOML backport and use the standard-library parser.
- Use Twine 7 to validate modern package metadata and run package validation on pull requests.
- Exercise source bundles and versioned PDFs in CI with real LaTeX, Biber and Typst compilers.

### Fixed
- Broad bundle include patterns respect the main-PDF policy and do not add stale PDFs or duplicate generated bibliography files.

## [1.4.0] - 2026-01-18

### Added
Expand Down Expand Up @@ -220,6 +237,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `article-cli config show` - Show current configuration
- `article-cli config create` - Create sample configuration

[2.1.0]: https://github.com/feelpp/article.cli/compare/v2.0.1...v2.1.0
[1.4.0]: https://github.com/feelpp/article.cli/releases/tag/v1.4.0
[1.3.2]: https://github.com/feelpp/article.cli/releases/tag/v1.3.2
[1.3.1]: https://github.com/feelpp/article.cli/releases/tag/v1.3.1
Expand Down
47 changes: 47 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Article CLI Development Setup

This guide helps you set up the article-cli package for development and distribution.
Python 3.11 or newer is required.

CI runs archive and paper-version tests in a dedicated compiler integration job with
LaTeX, Biber, Typst 0.15.1 and Poppler installed. To run the same checks locally:

```bash
uv run pytest tests/test_bundle.py tests/test_bundle_typst.py tests/test_paper_version.py
```

These tests skip compiler-specific cases when the corresponding tools are unavailable locally.

## Development Setup

Expand Down Expand Up @@ -217,3 +227,40 @@ When you need to update the tool:
2. Update version in `pyproject.toml`
3. Build and publish new version
4. Users update with: `uv tool upgrade article-cli`


## Source bundle API and compiler strategies

`BundleService` orchestrates a shared workflow: resolve the document, select a
backend, build, collect required files, apply policy, optionally verify in a
clean directory, and publish a deterministic ZIP plus a manifest.

```python
from article_cli.config import Config
from article_cli.services import BundleOptions, BundleService

service = BundleService(Config("pyproject.toml"))
plan = service.plan(BundleOptions(document="main.typ", verify=True))
archive = service.write(plan)
```

`BundleBackend` is a structural `Protocol` (Strategy pattern) with a source suffix
and two operations: `compile(BundleBuild)` and `dependencies(BundleBuild)`.
`LatexBundleBackend` and `TypstBundleBackend` encapsulate native compiler behavior;
the archive service has no source parser. `BundleBuild` and `BundleDependency`
are immutable data objects. A dependency carries its source, portable archive
name, and allowed source root; shared policy checks containment, exclusions,
collisions, and required-file availability for both backends.

Callers can inject `BundleService(..., backends={engine: backend})` or a
`CommandRunner` for testing. The default registry maps the existing LaTeX engines
and `typst` to their strategies. Dependencies are collected from `.fls`/`.aux` (and Biber `.bcf`)
or Typst 0.14+ `--deps --deps-format json`; no regex-based Typst parser is used.
Typst package sources are vendored under `.article-cli/typst-packages` without
rewriting imports, and verification resolves fonts and packages from the staged
archive contents. System fonts and TeX distributions remain environment inputs.

`GitSnapshot` in `paper_version.py` separates Git reads from document rendering.
Typst consumes safely serialized JSON; LaTeX uses the existing `gitinfo2` adapter.
`version` and `release` select the appropriate output format. Compiler services
pass absolute paths so the API works without changing the process directory.
99 changes: 97 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ The `init` command sets up:
### Git Release Management

```bash
# Refresh gitinfo2 version metadata
# Refresh paper version metadata (LaTeX or Typst)
article-cli version

# Refresh metadata, compile, and check the PDF version text
Expand Down Expand Up @@ -307,6 +307,97 @@ article-cli compile --clean-first --clean-after
article-cli compile --output-dir build/
```

### Paper Version Metadata

`article-cli version` writes LaTeX's `gitHeadLocal.gin` for `gitinfo2`, or a
portable `gitHeadLocal.json` snapshot beside a Typst main document. The Typst
snapshot contains the commit, short hash, branch, description, nearest tag,
commit date, and dirty flag. Generated metadata is excluded from dirty detection;
tracked source changes count as dirty, matching the existing LaTeX behavior.
`--dry-run` reports planned changes without writing files.

```latex
\usepackage[local]{gitinfo2}
% In the document body:
Version: \gitDescribe{} / \gitAbbrevHash{}
```

```typst
#let git = json("gitHeadLocal.json")
#set page(footer: align(center)[Version: #git.description])
```

New built-in templates include a version stamp. Typst compilation refreshes its
snapshot when Git is available; extracted source archives keep their frozen
snapshot. Typst reads JSON directly, so no extra Typst package is needed.

```bash
article-cli version --document main.typ --compile --check-pdf --checksum
article-cli version --document main.tex --compile --check-pdf
```

### Submission Source Bundles (LaTeX and Typst)

```bash
# Build and package the main document and its recorded dependencies
article-cli bundle main.tex --verify
article-cli bundle main.typ --verify

# Preview an existing build without changing any files
article-cli bundle main.tex --dry-run

# Extend project policy for one archive
article-cli bundle main.tex --include 'supplement/**' --exclude 'reviews/**' -o dist/preprint.zip
```

`bundle` automatically selects a LaTeX or Typst backend. LaTeX uses `latexmk`
and TeX recorder data; Typst 0.14+ uses native JSON dependency reporting, including
dynamically loaded data, imports, figures, and bibliography styles. The command
writes a reproducible ZIP and an adjacent JSON manifest with file hashes.
`--verify` recompiles only the selected files in a temporary directory before
publishing the archive. Both formats share the same selection and output policy.

```toml
[tool.article-cli.bundle]
output = "dist/preprint.zip"
include = ["supplement/**"]
exclude = ["reviews/**", "local-only/**"]
include_pdf = false
verify = true
```

Paths and globs are relative to the main document's directory, which becomes the
ZIP root. Include patterns add files to detected dependencies; CLI patterns extend
those in configuration. Exclusions take precedence, and excluding a required
source fails with an explanation. `**` matches any number of directories.

Git repository internals, virtual environments, `local-only`, `.env` files, and build logs are
excluded by default. The main PDF is excluded unless `--include-pdf` is set; figure
PDFs remain included. Keep all local dependencies and the build directory under
the main document's directory. System TeX packages are supplied by the receiving
service. LaTeX shell escape is disabled.

Typst imports from external versioned packages are copied, with their manifests
and license files, under `.article-cli/typst-packages`. Configured local
`[tool.article-cli.typst].font_paths` must be under the document directory; font
files are included and their relative search paths recorded in the manifest.
System fonts remain environment dependencies. To compile an extracted Typst bundle:

```bash
typst compile --root . --package-path .article-cli/typst-packages main.typ
# Add --font-path fonts when the bundle uses a configured local font directory.
```

Use `--build-dir build --no-build` to reuse existing LaTeX `.fls`/`.aux`/`.bbl`
data or Typst `<document>.typst-deps.json` metadata, or `--force` to replace an
existing ZIP and manifest. Typst dependency metadata is generated by `bundle`;
a previous plain `compile` does not create it. Dry runs require existing metadata. `--no-verify` and `--no-include-pdf` override project policy.
Verification checks local compilability; HAL/arXiv still apply their own submission
and supported-format requirements. This command prepares files without uploading them.

Run `article-cli version` before bundling when you need an up-to-date provenance
stamp. Bundling preserves the selected snapshot during compilation and verification.

### Typst Compilation

```bash
Expand Down Expand Up @@ -442,7 +533,7 @@ Use `[tool.article-cli.release] tag_policy = "semver"` when a repository must re

## Requirements

- Python 3.9+
- Python 3.11+
- Git repository with gitinfo2 package (for LaTeX integration)
- Zotero account with API access (for bibliography features)
- Typst CLI (for Typst compilation) - install from https://typst.app/
Expand All @@ -462,6 +553,10 @@ MIT License - see LICENSE file for details.

## Changelog

### v2.1.0
- Require Python 3.11+ and use its built-in TOML parser
- Add LaTeX and Typst submission bundles and portable paper version metadata

### v2.0.1
- Keep Python package, generated-template minimum version, Antora component version, docs package version, and lockfiles synchronized
- Add a release-version bump script and CI test to prevent stale documentation version labels
Expand Down
9 changes: 0 additions & 9 deletions build-and-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,6 @@ run_command() {
echo -e "${YELLOW}📦 Installing dependencies...${NC}"
run_command "pip install -e ."

# Check if optional dependencies are available
echo -e "${YELLOW}🧪 Checking optional dependencies...${NC}"
if python -c "import tomli" 2>/dev/null; then
echo -e "${GREEN}✅ tomli available for Python < 3.11${NC}"
else
echo -e "${YELLOW}⚠️ Installing tomli for TOML support${NC}"
run_command "pip install tomli"
fi

# Build the package
echo -e "${YELLOW}🏗️ Building package...${NC}"
if ! command -v build &> /dev/null; then
Expand Down
6 changes: 3 additions & 3 deletions docs/antora.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: article-cli
title: Article CLI
version: '2.0'
version: '2.1'
start_page: ROOT:index.adoc
nav:
- modules/ROOT/nav.adoc
Expand All @@ -9,8 +9,8 @@ asciidoc:
attributes:
project-name: article-cli
cli-command: article-cli
python-supported: '3.9, 3.10, 3.11, 3.12, 3.13'
article-cli-version: '2.0.1'
python-supported: '3.11, 3.12, 3.13'
article-cli-version: '2.1.0'
template-version: '1'
zotero-group-example: '4709047'
page-pagination: ''
Expand Down
30 changes: 30 additions & 0 deletions docs/modules/ROOT/pages/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ build_dir = "build"
font_paths = ["fonts"]
----

== Submission Source Bundles

[source,toml]
----
[tool.article-cli.bundle]
output = "dist/preprint.zip"
include = ["supplement/**"]
exclude = ["reviews/**", "local-only/**"]
include_pdf = false
verify = true
----

The ZIP root and all patterns are relative to the main document directory.
`include` adds files to automatically detected dependencies.
Command-line `--include` and `--exclude` patterns extend configured lists.
Exclusions take precedence; excluding a required dependency is an error.
Globs support `*`, `?`, character classes, and recursive `**` (including zero directories).
Patterns cannot contain absolute paths or `..` components.

The default policy excludes Git metadata, virtual environments, Python caches,
`local-only` directories, `.env` files, and build logs.
`include_pdf` controls the generated main PDF; required figure PDFs remain included.
`verify` recompiles the selected sources in isolation before writing output.
The same policy applies to `.tex` and `.typ` documents.
For Typst, `[tool.article-cli.typst].font_paths` directories must be under the
main document directory. Font files are included and search paths are recorded
in the manifest. Imported external packages are copied into the source archive.
Use `--no-verify` or `--no-include-pdf` for one-off overrides.
The same keys work in a standalone `.article-cli.toml` under `[bundle]`.

== Workflow

[source,toml]
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/install.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ uv run mypy src/
uv build
----

The GitHub Actions workflow runs the test suite across Python 3.9 through 3.13.
The GitHub Actions workflow runs the test suite across Python 3.11 through 3.13.

== Documentation Site

Expand Down
Loading
Loading