Skip to main content

development

Ground rules for working in the Tika codebase — git policy, Maven wrapper/repo conventions, building and testing specific modules, code and test conventions, pre-commit checks. Load at session start for any Tika development task.

Informações da origem

Repositório
apache/tika
Última atividade na origem
6 de outubro de 2026 às 23:38
Idioma detectado do SKILL.md
inglês
Estrelas
4.096
Forks
1.030

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
development
description
Ground rules for working in the Tika codebase — git policy, Maven wrapper/repo conventions, building and testing specific modules, code and test conventions, pre-commit checks. Load at session start for any Tika development task.
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> Local override: `$TIKA_SKILLS_LOCAL/development/LOCAL.md` (default `~/.tika-skills`), read after this file, wins on conflict. # Tika Development Skill Guidelines and checklist for developing against the Apache Tika codebase. ## Question the direction, not just the code Before optimizing a change — yours or a PR's — ask whether it should exist: does it belong in Tika, is the complexity proportional to the need, would config, an existing mechanism, a plugin, or documentation serve the use case more cheaply? Every merged feature is surface the project maintains for decades. Steelman the use case first and question the vehicle, not the goal; pushback must name a concrete cost or a simpler path — never taste alone, and never no for the sake of no. "The direction is right" is a valid conclusion. Feature whose shape isn't known yet: spike first, cut PRs after (`.skills/devs/feature-workflow/SKILL.md`). ## Git Policy (default — personally overridable) Never run `git commit` or `git push` — no commits of any kind, including merge commits. If a merge is needed, use `git merge --no-commit --no-ff` and hand back. Stage files and provide the suggested commit message for the user to run. Never write to GitHub (PR comments, reviews, issues, labels, merges). Read-only `gh` is fine. **Precedence**: these are conservative defaults for *workflow* — actions on the contributor's own machine and accounts. A contributor's personal agent configuration (their own skills, CLAUDE.md/AGENTS.md, settings, or a `LOCAL.md` overlay — see `AGENTS.md`) may override them. Everything else in this file — code and comment conventions, test discipline, hygiene, pre-commit checks — governs what lands in the repo and is project policy: personal configuration does not override it. ## Session Start Checklist 1. **Local Maven repo** — Default to an in-repo `.local_m2_repo` (via `-Dmaven.repo.local=$(pwd)/.local_m2_repo`) unless the user says otherwise. This isolates builds from the shared `~/.m2/repository` and avoids polluting or being affected by other projects. 2. **Maven wrapper** — Use `./mvnw`; fall back to a system Maven (3.9+) only if the wrapper is absent. 3. **Merge conflicts** — Check `git status` for `UU` files and resolve before building. ## Maven Rules - **Always include `clean`** in every `./mvnw` invocation. Stale classes in `target/` cause hard-to-debug failures. ```bash ./mvnw clean compile -pl <module> ... # not just: mvnw compile ./mvnw clean test -pl <module> ... # not just: mvnw test ./mvnw clean install -pl <module> ... # not just: mvnw install ``` - **Always use absolute path for local repo**: ```bash -Dmaven.repo.local=$(pwd)/.local_m2_repo ``` - **Fast builds with `-Pfast`** — use the `fast` profile to skip tests, checkstyle, spotless, and rat in one flag. Prefer this over individual `-D` skip flags when you want a quick build (e.g., installing for downstream consumers or eval runs): ```bash ./mvnw clean install -pl <module> -am -Pfast \ -Dmaven.repo.local=$(pwd)/.local_m2_repo ``` Run **without** `-Pfast` before final commit to catch formatting and style issues. License (rat) checks run only under `-Ppedantic` (or explicit `apache-rat:check`), not in default builds. **`-Pfast` skips test *execution*** (by design): a green `-Pfast` build — including `-Pfast test` — has run zero tests, and stale `target/surefire-reports/*` will look current. Verify with a plain (non-`-Pfast`) `test` run. - **Plugin zips resolve only after `package`** — a reactor `clean test` fails on modules that depend on pipes plugin zips (`tika-server-core`, `tika-app`, ...) unless the zips are already in the local repo. Use `clean install` (or `-Pfast install` first). - **Forked JVM tests** — Integration tests in `tika-pipes` fork new JVMs that load classes from the local Maven repo, not from `target/classes`. You must `./mvnw clean install -Pfast` the changed modules before running integration tests that fork. ## Building Specific Modules ```bash # Single module (with dependencies) ./mvnw clean compile -pl <module> -am \ -Dmaven.repo.local=$(pwd)/.local_m2_repo # Run a single test class ./mvnw clean test -pl <module> -Dtest=<TestClass> \ -Dmaven.repo.local=$(pwd)/.local_m2_repo -Dcheckstyle.skip=true # Install for downstream consumers (tika-app, integration tests) ./mvnw clean install -pl <module> -am -Pfast \ -Dmaven.repo.local=$(pwd)/.local_m2_repo ``` ## Common Module Paths | Module | Path | |--------|------| | tika-core | `tika-core` | | tika-app | `tika-app` | | tika-server | `tika-server/tika-server-core` | | tika-eval | `tika-eval/tika-eval-app` | | Pipes core | `tika-pipes/tika-pipes-core` | | Pipes API | `tika-pipes/tika-pipes-api` | | Async CLI | `tika-pipes/tika-async-cli` | ## Code Conventions - ASF License 2.0 header on all Java files - Spotless formatter runs during build — don't fight it - Tests use `@TempDir Path tmp` for temp directories - No emojis in code or comments - **Comments**: every comment must earn its place — one short line by default; multi-line only for a genuinely non-obvious WHY (subtle invariant, workaround, spec quirk). Never restate the code, narrate the next line, justify the change to a reviewer, or describe past states of the code. - **XML is parsed only through `XMLReaderUtils.parseSAX` / `buildDOM`** (forbidden-apis rejects the JAXP and Commons Secure XML factories and the raw `getSAXParser` / `getXMLReader` / `getDocumentBuilder` in main code). Never install an `EntityResolver`; a resolver that returns null or a stream-less `InputSource` makes the parser fetch the id itself (CVE-2025-66516). A new XML-bearing format gets a fixture in `TestXXEInXML`; a third-party library that parses XML with its own parser gets its own oracle test (see `GeographicInformationXxeTest`) before it ships. - **Input files are hostile**: bound anything derived from document content (loop counts, allocations, timeouts); release external processes, temp files, and pool slots on every failure path. - **No local/machine-specific paths** in committed code, tests, docs, or config — never `/home/<user>`, `/Users/<user>`, `C:\Users\<user>`, or a personal `~/data/...`. Use a placeholder (`<workdir>/`, `<corpus>`), `@TempDir`, or an in-repo `src/test/resources` fixture instead. *Only* legitimate exception: a path that is the data under test (e.g. an expected metadata value extracted from a test document) — leave those untouched. ## NEVER: two mistakes that ship as vulnerabilities **Never trust a length that came from user input or from inside a file.** `Content-Length` on a request, a zip or 7z entry's declared size, an OLE/OOXML part size, a PDF embedded file's `/Size`, an ISO box length, a count line in a mail file: every one of them is an untrusted number. Never allocate, reserve, `mark()`, `skip()` or bound a loop by it as if it were true. A lie small truncates content silently; a lie large lets one document allocate the heap or a budget, or spin a reader waiting for bytes that never come. Use a declared length only to *decline* work (a size the budget cannot cover is not attempted) or as a hint that the actual read corrects; grow from a floor and reserve what was actually read; treat the measured end of the stream as the only ground truth (`hasReliableLength()`), and overwrite the claim with it. See TIKA-4908 and the 2026-09-19 stream audit for what this cost. **Never call `InputStream.skip()` on a stream that could be a `FileInputStream` (or a `BufferedInputStream` over one) and trust the answer.** `FileInputStream.skip(n)` seeks past EOF and returns `n` even when no bytes exist, so a reader that skips a payload and then reads the next header believes it is somewhere it is not, and loops or mis-parses forever; `BufferedInputStream.skip` can return 0 before EOF, which spins any `while (remaining > 0) remaining -= skip(remaining)` loop. Skip by reading (`IOUtils.skip` / `IOUtils.skipFully`) or seek on a channel or an in-memory buffer whose size you own; `TikaInputStream.skip`, `BoundedInputStream.skip` and every source's `seekTo` read for this reason. Do not "optimize" them back. Anything hot enough to need a real seek gets a channel from `getSeekableByteChannel()`, never a raw `skip`. ## Test Discipline - A behavioral change gets a regression test that fails without it. Where impractical (timing, native binaries, external services, kill paths), say so explicitly and name the next-best check. - Prove a negative by reverting the fix: an "X does not happen" test that still passes is not a test. Assert on what the consumer is handed, not an ambient side effect (a `@TempDir` watch misses `TemporaryResources` not bound to it). - Cover error paths and the configuration/mode matrix — a behavior verified in only one parse mode or config shape is a gap (RMETA-only tests miss CONCATENATE-only bugs). - Keep tests non-duplicative: don't add a test whose failure another test already guarantees. - `-Dtika.test.locale=random` runs every test JVM under a random default locale (`RandomLocaleListener` in `tika-test-support`, wired through tika-parent); run it before touching anything that formats or parses text. The PR jobs leave it off until `nightly-locale-build` (one full build per priority locale, plus a random draw) has been green several nights running (TIKA-4920). A plain build keeps the JVM's own locale. A failure's stack trace and the fork's stderr name the locale; reproduce with `-Dtika.test.locale=<tag>`. A test that fails only in some locales is a bug in the code under test (use `Locale.ROOT`), not a reason to pin `Locale.US` in the test. - Where there's bang for the buck, prefer parameterized tests over copy-pasted cases, randomized inputs over hand-picked ones (log the seed so failures reproduce), and fuzzing for parsers and format/boundary arithmetic. Don't force it on code a couple of fixed cases fully cover. ## Metadata Keys & Schema Registry Adding/renaming a metadata key touches the committed, build-gated registry in `tika-metadata-schema` — regeneration has real traps. See `.skills/devs/metadata-schema/SKILL.md`. ## Testing an End-to-End Change When a change affects parsing output (e.g., new parser behavior, encoding fix), run a before/after comparison using tika-eval. See `.skills/devs/tika-eval-compare/SKILL.md` for the full procedure. ## Pre-Commit Checks ```bash # Full compile with checkstyle (catches formatting issues) ./mvnw clean compile -pl <module> -am \ -Dmaven.repo.local=$(pwd)/.local_m2_repo # Run module tests ./mvnw clean test -pl <module> \ -Dmaven.repo.local=$(pwd)/.local_m2_repo ``` Also before commit: - Commit message / PR title references a JIRA ticket (`TIKA-XXXX`). - CHANGES entry for user-visible changes. - New dependencies: ASF-compatible license; LICENSE/NOTICE updated. Scan the staged diff for machine-specific local paths before committing (see Code Conventions). Added lines only; review any hit by hand — a test fixture's expected value is allowed, a real config/doc/code path is not: ```bash git diff --cached -U0 | grep -E '^\+' \ | grep -nE '/home/[A-Za-z0-9._-]+|/Users/[A-Za-z0-9._-]+|[A-Za-z]:\\+Users|~/data/' \ && echo "^ local path in staged diff — replace with a placeholder/fixture" ```
Ver no GitHub