Skip to content

Commit 0b65830

Browse files
authored
TIKA-4725 - updates to docker release workflow (#2807)
1 parent cf1a656 commit 0b65830

31 files changed

Lines changed: 1348 additions & 431 deletions

.github/workflows/docker-release.yml

Lines changed: 142 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,118 @@
1717

1818
name: Docker release - tika-server and tika-grpc
1919

20+
# Auto-trigger on tag push for GA-style version tags only. The convention is:
21+
# release:prepare creates `X.Y.Z-rcN` for the vote (workflow stays silent),
22+
# vote passes, the release manager pushes a separate `X.Y.Z` tag pointing
23+
# at the same commit, and *that* push triggers this workflow.
24+
# Manual rebuilds (CVE in base image, plugin refresh) use workflow_dispatch
25+
# with an explicit build_number.
26+
#
27+
# GH Actions doesn't allow combining `tags` (include) and `tags-ignore` on
28+
# a single event, so the filter is expressed as `tags-ignore` only. Any tag
29+
# without a hyphen or underscore fires the workflow; this rejects prerelease
30+
# tags (`4.0.0-rc1`, `4.0.0-alpha-1`, `4.0.0-BETA`) and branch-style tags
31+
# (`branch_4x`). The `Compute tags` step has a separate prerelease check
32+
# (`*-*`) that gates `:latest` defense-in-depth for the workflow_dispatch
33+
# path where the auto-trigger filter isn't in play.
2034
on:
2135
push:
22-
tags:
23-
- '[0-9]+.[0-9]+.[0-9]+*'
36+
tags-ignore:
37+
- '*-*' # anything with a hyphen is a prerelease/non-GA tag
38+
- '*_*' # anything with an underscore is a branch/non-version tag
39+
workflow_dispatch:
40+
inputs:
41+
tag:
42+
description: 'Tika release tag (e.g. 4.0.0-alpha-1). Must already exist as a git tag.'
43+
required: true
44+
build_number:
45+
description: 'Docker build number for this Tika tag (1 for first build, increment on rebuilds).'
46+
required: true
47+
default: '1'
48+
source_ref:
49+
description: 'Git ref to build from. Defaults to `tag`. Override only for Dockerfile-update rebuilds where the source has changed since the original tag was cut.'
50+
required: false
51+
52+
# Resolve the effective tag and build number from either trigger source.
53+
# `inputs.*` is populated only by workflow_dispatch; on a tag push, fall
54+
# back to the tag's short name (e.g. `4.0.0`) and build_number=1.
55+
env:
56+
TAG: ${{ inputs.tag || github.ref_name }}
57+
BUILD: ${{ inputs.build_number || '1' }}
2458

2559
jobs:
60+
# Gating job for push triggers: refuse to publish if the tag isn't shaped
61+
# like a GA version (digit+ . digit+ . digit+). The `tags-ignore` filter at
62+
# the `on:` level already blocks anything with `-` or `_`, but it doesn't
63+
# reject other oddities like `wip`, `foo`, or `test`. This job is the
64+
# belt-and-suspenders to those (which were the suspenders).
65+
#
66+
# workflow_dispatch trigger is permissive — humans pick the tag (which can
67+
# be alpha/beta/RC) — so the strict check is push-only.
68+
validate-tag:
69+
runs-on: ubuntu-latest
70+
steps:
71+
- name: Reject non-GA-style tags on push triggers
72+
run: |
73+
if [[ "${{ github.event_name }}" != "push" ]]; then
74+
echo "workflow_dispatch trigger — skipping strict tag-shape validation."
75+
exit 0
76+
fi
77+
tag='${{ github.ref_name }}'
78+
if [[ ! "$tag" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
79+
echo "::error title=Non-GA tag::Refusing to publish: tag '$tag' is not a GA-style X.Y.Z."
80+
echo "::error::For prerelease publishes (alpha/BETA/RC), use workflow_dispatch with an explicit tag and build_number."
81+
exit 1
82+
fi
83+
echo "Tag '$tag' is GA-style. Proceeding."
84+
2685
release-tika-server:
86+
needs: validate-tag
2787
runs-on: ubuntu-latest
2888
timeout-minutes: 60
2989

3090
steps:
3191
- uses: actions/checkout@v6
92+
with:
93+
ref: ${{ inputs.source_ref || env.TAG }}
94+
fetch-depth: 0 # full history so we can push a provenance tag at the end
3295

33-
- name: Extract version from tag
34-
id: version
96+
# Compute the tag set for each image. Three tags per image at minimum:
97+
# apache/tika:<tag> (mutable; moves on each rebuild)
98+
# apache/tika:<tag>-<build> (immutable; one per rebuild)
99+
# apache/tika:latest (only for non-prerelease tags)
100+
# The grpc image always pushes :latest (no 3.x incumbent to protect).
101+
- name: Compute tags
102+
id: tags
35103
run: |
36-
TAG_NAME="${GITHUB_REF#refs/tags/}"
37-
echo "tag=${TAG_NAME}" >> "$GITHUB_OUTPUT"
104+
tag='${{ env.TAG }}'
105+
build='${{ env.BUILD }}'
106+
minimal="apache/tika:${tag}
107+
apache/tika:${tag}-${build}"
108+
full="apache/tika:${tag}-full
109+
apache/tika:${tag}-${build}-full"
110+
grpc="apache/tika-grpc:${tag}
111+
apache/tika-grpc:${tag}-${build}
112+
apache/tika-grpc:latest"
113+
# Any hyphen in the tag = prerelease (alpha/beta/rc/SNAPSHOT/etc.,
114+
# in any case). Mirrors the `tags-ignore: ['*-*']` rule on the
115+
# auto-trigger so manual workflow_dispatch behaves the same way.
116+
case "$tag" in
117+
*-*)
118+
echo "Prerelease tag $tag — skipping :latest for apache/tika."
119+
;;
120+
*)
121+
minimal="${minimal}
122+
apache/tika:latest"
123+
full="${full}
124+
apache/tika:latest-full"
125+
;;
126+
esac
127+
{
128+
echo "minimal<<EOF"; echo "$minimal"; echo "EOF"
129+
echo "full<<EOF"; echo "$full"; echo "EOF"
130+
echo "grpc<<EOF"; echo "$grpc"; echo "EOF"
131+
} >> "$GITHUB_OUTPUT"
38132
39133
- name: Set up Docker Buildx
40134
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
@@ -52,38 +146,45 @@ jobs:
52146
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
53147
with:
54148
file: tika-server/docker-build/minimal/Dockerfile
55-
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/s390x
149+
platforms: linux/amd64,linux/arm64,linux/s390x
56150
push: true
57151
build-args: |
58-
TIKA_VERSION=${{ steps.version.outputs.tag }}
59-
tags: |
60-
apache/tika:${{ steps.version.outputs.tag }}
61-
apache/tika:latest
152+
TIKA_VERSION=${{ env.TAG }}
153+
tags: ${{ steps.tags.outputs.minimal }}
62154

63155
- name: Build and push tika-server full
64156
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
65157
with:
66158
file: tika-server/docker-build/full/Dockerfile
67-
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/s390x
159+
platforms: linux/amd64,linux/arm64,linux/s390x
68160
push: true
69161
build-args: |
70-
TIKA_VERSION=${{ steps.version.outputs.tag }}
71-
tags: |
72-
apache/tika:${{ steps.version.outputs.tag }}-full
73-
apache/tika:latest-full
162+
TIKA_VERSION=${{ env.TAG }}
163+
tags: ${{ steps.tags.outputs.full }}
164+
165+
# After a successful publish, push a `<tag>-<build_number>` git tag for
166+
# provenance. Skipped on build_number=1 because the original `<tag>` already
167+
# marks the source state of build 1. Lives in the server job (not the grpc
168+
# job) to avoid both jobs racing to push the same tag.
169+
- name: Push provenance git tag
170+
if: ${{ env.BUILD != '1' }}
171+
env:
172+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
173+
run: |
174+
git config user.name "github-actions[bot]"
175+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
176+
git tag "${TAG}-${BUILD}"
177+
git push origin "${TAG}-${BUILD}"
74178
75179
release-tika-grpc:
180+
needs: validate-tag
76181
runs-on: ubuntu-latest
77182
timeout-minutes: 120
78183

79184
steps:
80185
- uses: actions/checkout@v6
81-
82-
- name: Extract version from tag
83-
id: version
84-
run: |
85-
TAG_NAME="${GITHUB_REF#refs/tags/}"
86-
echo "tag=${TAG_NAME}" >> "$GITHUB_OUTPUT"
186+
with:
187+
ref: ${{ inputs.source_ref || env.TAG }}
87188

88189
- name: Set up JDK 17
89190
uses: actions/setup-java@v5
@@ -107,9 +208,22 @@ jobs:
107208
username: ${{ secrets.DOCKERHUB_USER }}
108209
password: ${{ secrets.DOCKERHUB_TOKEN }}
109210

211+
- name: Compute grpc tags
212+
id: grpc_tags
213+
run: |
214+
tag='${{ env.TAG }}'
215+
build='${{ env.BUILD }}'
216+
{
217+
echo "tags<<EOF"
218+
echo "apache/tika-grpc:${tag}"
219+
echo "apache/tika-grpc:${tag}-${build}"
220+
echo "apache/tika-grpc:latest"
221+
echo "EOF"
222+
} >> "$GITHUB_OUTPUT"
223+
110224
- name: Prepare tika-grpc Docker build context
111225
run: |
112-
TIKA_VERSION="${{ steps.version.outputs.tag }}"
226+
TIKA_VERSION='${{ env.TAG }}'
113227
OUT_DIR=target/tika-grpc-docker
114228
115229
mkdir -p "${OUT_DIR}/libs/tika-grpc" "${OUT_DIR}/plugins" "${OUT_DIR}/config" "${OUT_DIR}/bin"
@@ -151,7 +265,8 @@ jobs:
151265
platforms: linux/amd64,linux/arm64
152266
push: true
153267
build-args: |
154-
VERSION=${{ steps.version.outputs.tag }}
155-
tags: |
156-
apache/tika-grpc:${{ steps.version.outputs.tag }}
157-
apache/tika-grpc:latest
268+
VERSION=${{ env.TAG }}
269+
# apache/tika-grpc is new in 4.x with no prior `:latest` to protect, so
270+
# we track latest from the start (unlike apache/tika the server image,
271+
# whose :latest stays on 3.x until 4.0.0 GA).
272+
tags: ${{ steps.grpc_tags.outputs.tags }}

.github/workflows/docker-snapshot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ jobs:
105105
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
106106
with:
107107
context: target/tika-server-minimal-docker
108-
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/s390x
108+
platforms: linux/amd64,linux/arm64,linux/s390x
109109
push: true
110110
build-args: |
111111
TIKA_VERSION=${{ steps.version.outputs.tika_version }}
@@ -157,7 +157,7 @@ jobs:
157157
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
158158
with:
159159
context: target/tika-server-full-docker
160-
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/s390x
160+
platforms: linux/amd64,linux/arm64,linux/s390x
161161
push: true
162162
build-args: |
163163
TIKA_VERSION=${{ steps.version.outputs.tika_version }}

docs/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
** xref:advanced/spooling.adoc[Spooling]
7272
** xref:advanced/embedded-documents.adoc[Embedded Document Metadata]
7373
** xref:advanced/local-vlm-server.adoc[Running a Local VLM Server]
74+
** xref:advanced/integration-testing/run-uat-script.adoc[Tika-Server REST UAT Script]
7475
* xref:developers/index.adoc[Developers]
7576
** xref:developers/serialization.adoc[Serialization and Configuration]
7677
* xref:faq.adoc[FAQ]
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one or more
3+
// contributor license agreements. See the NOTICE file distributed with
4+
// this work for additional information regarding copyright ownership.
5+
// The ASF licenses this file to You under the Apache License, Version 2.0
6+
// (the "License"); you may not use this file except in compliance with
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
18+
= Tika-Server REST UAT Script
19+
20+
A portable shell script that exercises the tika-server REST surface against an
21+
already-running server. The same script is used as the docker image smoke
22+
test, the e2e integration test, and as part of the source-release
23+
verification.
24+
25+
== Where it lives
26+
27+
[source]
28+
----
29+
release-tools/uat/
30+
├── run-uat.sh # the script
31+
└── test-files/
32+
├── testPDF.pdf
33+
├── testHTML.html
34+
└── test_recursive_embedded.docx
35+
----
36+
37+
== What it covers
38+
39+
Roughly 25 REST endpoint checks across the default-mode endpoints, header
40+
behavior, and error handling — the same surface enumerated in the manual
41+
walkthrough at xref:advanced/integration-testing/tika-server.adoc[Tika-Server
42+
Integration Testing], translated to bash + curl assertions.
43+
44+
Coverage includes:
45+
46+
* `/version`, `/parsers`, `/detectors`, `/mime-types` (introspection)
47+
* `/detect/stream` (mime detection)
48+
* `/tika`, `/tika/text`, `/tika/xml`, `/tika/json` (parse)
49+
* `/meta`, `/meta/{field}` (metadata)
50+
* `/rmeta`, `/rmeta/text` (recursive metadata)
51+
* `/unpack/all` (embedded extraction; verifies the response is a valid zip)
52+
* `/language/stream`
53+
* `/meta/form`, `/rmeta/form` (multipart variants)
54+
* `enableUnsecureFeatures=false` gating: `/meta/config`, `/rmeta/config`,
55+
`/tika/config` all return 403
56+
* `X-Tika-OCRskipOcr` header, `Content-Disposition` filename
57+
* 404 / 405 error handling
58+
59+
Two checks (T18d, T27) are currently disabled with inline comments pointing
60+
at tika-core behavior anomalies that need fixing — re-enable them when those
61+
land.
62+
63+
== Running it
64+
65+
The script takes a URL pointing at a running tika-server. It does *not* start
66+
or stop the server itself.
67+
68+
[source,bash]
69+
----
70+
release-tools/uat/run-uat.sh [host]
71+
# default host: http://localhost:9998
72+
----
73+
74+
Exit code: `0` on all-pass, `1` on any failure. Failed checks print the
75+
expected pattern and a truncated response body.
76+
77+
=== Against the unpacked bin.zip distribution
78+
79+
[source,bash]
80+
----
81+
unzip tika-server-standard-<VERSION>-bin.zip -d /tmp/tika-server-dist
82+
cd /tmp/tika-server-dist
83+
java -jar tika-server.jar -p 9998 -h localhost &
84+
sleep 12
85+
~/path/to/tika/release-tools/uat/run-uat.sh
86+
----
87+
88+
=== Against the Docker image
89+
90+
The `docker-tool.sh test-uat` subcommand wraps starting the container, waiting
91+
for `/version`, running the UAT, and stopping the container:
92+
93+
[source,bash]
94+
----
95+
cd tika-server/docker-build
96+
./docker-tool.sh test-uat <DOCKER_VERSION>
97+
----
98+
99+
=== As part of the e2e tests (CI)
100+
101+
The Maven module `tika-e2e-tests/tika-server` unpacks the bin.zip, forks
102+
`java -jar tika-server.jar`, and invokes this script via
103+
`org.apache.tika.server.e2e.RunUatSmokeTest`. The CI workflow
104+
`.github/workflows/main-jdk17-build.yml` runs this automatically on every PR
105+
via `mvn -pl tika-e2e-tests -am clean verify -Pe2e`.
106+
107+
== When to use it
108+
109+
* *Pre-vote release verification.* Unpack
110+
`tika-server-standard-<VERSION>-bin.zip` from `dist/dev` and run the UAT
111+
against it. Catches packaging regressions before the vote thread starts.
112+
* *Pre-publish docker verification.* Run via `docker-tool.sh test-uat` after
113+
building a new image and before tagging it for release.
114+
* *Local development sanity check.* When changing anything in
115+
`tika-server-core` or the bin.zip assembly descriptor, run the UAT against
116+
the build output to confirm you didn't regress endpoint behavior.
117+
* *Adding new endpoints.* When a new REST endpoint lands, add a corresponding
118+
check to the script so future regressions get caught.
119+
120+
== Platform notes
121+
122+
The script is bash + curl + unzip. It's skipped automatically on Windows by
123+
the e2e test (no bash). On Linux/macOS it runs as-is. No external dependencies
124+
beyond the standard tooling.

0 commit comments

Comments
 (0)