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
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: "09:00"
timezone: Etc/UTC
labels:
- dependencies
- github-actions
commit-message:
prefix: "ci"

# Watches the upstream Apache Jackrabbit coordinate declared (tracker-only)
# in pom.xml's <dependencyManagement>. When Apache cuts a new release,
# Dependabot bumps the upstream.jackrabbit.version property; the
# bump-on-dependabot.yml workflow then re-vendors sources.jar, runs
# OpenRewrite, and updates the project version, committing back to the
# Dependabot branch.
- package-ecosystem: maven
directory: /
schedule:
interval: weekly
day: monday
time: "09:00"
timezone: Etc/UTC
labels:
- dependencies
- upstream-bump
commit-message:
prefix: "upstream"
open-pull-requests-limit: 1
64 changes: 64 additions & 0 deletions .github/scripts/bump-upstream.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
#
# Re-vendor upstream Apache Jackrabbit WebDAV sources and re-apply the
# Jakarta EE 10 transform.
#
# Invoked from .github/workflows/bump-on-dependabot.yml after Dependabot
# opens a PR bumping the upstream.jackrabbit.version property in pom.xml.
# Reads the new upstream version straight from the pom property, downloads
# the matching sources.jar from Maven Central, replaces src/main/{java,
# resources}, runs OpenRewrite, and updates the project version. Caller is
# responsible for committing and pushing.
#
# Idempotent: if the project version already matches the upstream property
# (i.e. nothing left to bump), exits 0 without modifying any files.

set -euo pipefail

UPSTREAM_VERSION="$(mvn -q -B -ntp help:evaluate -Dexpression=upstream.jackrabbit.version -DforceStdout)"
CURRENT_PROJECT_VERSION="$(mvn -q -B -ntp help:evaluate -Dexpression=project.version -DforceStdout)"
EXPECTED_PROJECT_VERSION="${UPSTREAM_VERSION}-jakarta-ee10"

echo "Upstream version from pom.xml property: ${UPSTREAM_VERSION}"
echo "Current project.version: ${CURRENT_PROJECT_VERSION}"
echo "Target project.version: ${EXPECTED_PROJECT_VERSION}"

if [[ "${CURRENT_PROJECT_VERSION}" == "${EXPECTED_PROJECT_VERSION}" ]]; then
echo "Project version already matches upstream property — nothing to do."
exit 0
fi

URL="https://repo1.maven.org/maven2/org/apache/jackrabbit/jackrabbit-webdav/${UPSTREAM_VERSION}/jackrabbit-webdav-${UPSTREAM_VERSION}-sources.jar"
echo "Downloading ${URL}"
curl -fsSL -o sources.jar.new "${URL}"
mv sources.jar.new sources.jar

workspace="$PWD"
rm -rf src/main/java src/main/resources
mkdir -p src/main/java src/main/resources

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
unzip -q sources.jar -d "$tmp"
rm -rf "$tmp/META-INF"

# .java sources → src/main/java; everything else (e.g. .properties) →
# src/main/resources. Upstream sources.jar contains both intermixed.
(cd "$tmp" && find . -type f -name '*.java' | while read -r f; do
dest="$workspace/src/main/java/${f#./}"
mkdir -p "$(dirname "$dest")"
cp "$f" "$dest"
done)
(cd "$tmp" && find . -type f ! -name '*.java' | while read -r f; do
dest="$workspace/src/main/resources/${f#./}"
mkdir -p "$(dirname "$dest")"
cp "$f" "$dest"
done)

echo "Re-applying Jakarta EE 10 transform via OpenRewrite"
mvn -B -ntp rewrite:run

echo "Setting project version to ${EXPECTED_PROJECT_VERSION}"
mvn -B -ntp versions:set -DnewVersion="${EXPECTED_PROJECT_VERSION}" -DgenerateBackupPoms=false

echo "Bump complete: jackrabbit-webdav ${UPSTREAM_VERSION} → ${EXPECTED_PROJECT_VERSION}"
73 changes: 73 additions & 0 deletions .github/workflows/bump-on-dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Apply upstream bump on Dependabot PR

# Replaces the prior cron-driven check-upstream.yml: Dependabot handles the
# polling (see .github/dependabot.yml's maven ecosystem entry, which watches
# the tracker-only <dependencyManagement> coordinate in pom.xml). When
# Dependabot opens a PR bumping the upstream.jackrabbit.version property,
# this workflow does the irreducible follow-up work that Dependabot itself
# can't do: re-vendor sources.jar, re-apply the OpenRewrite Jakarta EE 10
# transform, and update the project version — all committed back onto the
# Dependabot branch so ci.yml's smoke test gates merge.

on:
pull_request_target:
types: [opened, synchronize]

permissions:
contents: write
pull-requests: write

jobs:
apply-bump:
# Three guards (per Joe's review):
# 1. Author is Dependabot — bot-opened PRs only
# 2. Label is upstream-bump — distinguishes the Maven ecosystem update
# from the github-actions one (which has no follow-up work)
# 3. PR head is in this repo — Dependabot branches are always in-repo;
# a head from a fork means a malicious actor is impersonating the
# label or actor check, so refuse to run
if: >-
github.actor == 'dependabot[bot]'
&& contains(github.event.pull_request.labels.*.name, 'upstream-bump')
&& github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest

steps:
- name: Checkout PR head
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref }}
# Use the workflow token so the follow-up commit can be pushed back
# to the Dependabot branch.
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
cache: maven

- name: Configure git identity
run: |
git config user.name 'dependabot[bot]'
git config user.email '49699333+dependabot[bot]@users.noreply.github.com'

# The bump script lives at .github/scripts/bump-upstream.sh (checked in,
# never read from the PR's pom.xml). Dependabot's manifest-only PR diffs
# don't touch this path, so in practice we're always executing the
# main-branch script — but the three guards above (bot author, label,
# same-repo head) are what actually keep arbitrary code from running
# under the pull_request_target token.
- name: Run upstream bump script
run: ./.github/scripts/bump-upstream.sh

- name: Commit and push if changed
run: |
if [[ -z "$(git status --porcelain)" ]]; then
echo "No changes produced by bump script; nothing to commit."
exit 0
fi
git add -A
git commit -m "Re-vendor sources and re-apply Jakarta EE 10 transform"
git push
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
name: Build + smoke test
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
cache: maven

- name: Build and run smoke test
run: mvn -B -ntp verify
41 changes: 41 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Publish to GitHub Packages

on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
ref:
description: 'Ref (branch, tag, or SHA) to publish from'
required: false
default: 'main'

jobs:
publish:
name: Maven deploy
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.ref || github.ref }}

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
cache: maven
server-id: github
server-username: GITHUB_ACTOR
server-password: GITHUB_TOKEN

- name: Deploy
run: mvn -B -ntp -DskipTests deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120 changes: 120 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# jackrabbit-webdav-jakarta

A thin fork of [Apache Jackrabbit WebDAV](https://jackrabbit.apache.org/) with the
`javax.servlet` → `jakarta.servlet` namespace transform applied so [eXist-db 7.0](https://github.com/eXist-db/exist)
(Jetty 12, Jakarta Servlet 6.0) can link against it.

This artifact exists only until Apache publishes a Jakarta-Servlet-native release of
`jackrabbit-webdav` upstream, at which point this repo will be archived and the
eXist-db dependency redirected to the upstream coordinate.

## Coordinates

```xml
<dependency>
<groupId>org.exist-db.thirdparty.org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-webdav</artifactId>
<version>2.22.3-jakarta-ee10</version>
</dependency>
```

Published to GitHub Packages: <https://maven.pkg.github.com/eXist-db/jackrabbit-webdav-jakarta>

## Versioning

`<upstream-version>-jakarta-ee10`

- `2.22.3-jakarta-ee10` → Apache Jackrabbit `2.22.3` + this repo's Jakarta EE 10 transform
- Snapshots use `<upstream>-jakarta-ee10-SNAPSHOT`

The version string makes the upstream provenance auditable at a glance — both the
upstream tag and the Jakarta profile are encoded in the version, with no hidden
metadata in classifiers or qualifiers.

## How the transform works

Upstream Apache Jackrabbit sources are vendored at `src/main/java/`, pre-transformed
to `jakarta.servlet.*`. The canonical pre-transform source archive is the
`sources.jar` at the repo root (extracted from Maven Central). The transform is
applied via the [OpenRewrite Maven plugin](https://docs.openrewrite.org/) using
the `org.openrewrite.java.migrate.jakarta.JakartaEE10` recipe — but the rewrite
runs **at upstream-bump time**, not at every build:

```sh
# After extracting a new sources.jar over src/main/java/:
mvn rewrite:run
```

The transformed result is committed to the repo, so day-to-day builds are plain
`mvn compile` against already-jakarta source. There are no manual patches, no
`sed` scripts, and no hand-edited source files — the only diff against upstream
is whatever OpenRewrite produces.

## How upstream tracking works

Dependabot handles the polling. A tracker-only `<dependencyManagement>` entry
in `pom.xml` declares `org.apache.jackrabbit:jackrabbit-webdav` at
`${upstream.jackrabbit.version}`, with no corresponding `<dependencies>` entry —
so the coordinate stays off the compile classpath but is visible to Dependabot's
Maven manifest scan ([`.github/dependabot.yml`](.github/dependabot.yml)).

When Apache cuts a new `jackrabbit-webdav` release, Dependabot opens a PR
labelled `upstream-bump` that bumps the `upstream.jackrabbit.version` property.
That PR fires [`bump-on-dependabot.yml`](.github/workflows/bump-on-dependabot.yml),
which does the work Dependabot can't:

1. Reads the new upstream version from the bumped property
2. Downloads the matching `*-sources.jar` from Maven Central, replacing the
`sources.jar` at the repo root
3. Re-extracts source into `src/main/java/` (`.java` files) and
`src/main/resources/` (everything else)
4. Runs `mvn rewrite:run` to re-apply the Jakarta EE 10 transform
5. Bumps the project `<version>` to `<new-upstream>-jakarta-ee10`
6. Commits and pushes back onto the Dependabot branch

The smoke test ([`ci.yml`](.github/workflows/ci.yml)) then re-runs against the
follow-up commit and gates merge: if the new upstream version still cleanly
transforms and links against Jakarta Servlet 6.0, the bump is safe to merge.

## How to cut a release

1. Land all bump / fix PRs on `main`
2. Tag the release commit:
```sh
git tag v2.22.3-jakarta-ee10
git push origin v2.22.3-jakarta-ee10
```
3. The publish workflow ([`publish.yml`](.github/workflows/publish.yml)) fires on
`v*` tag push and deploys to GitHub Packages
4. Confirm the artifact resolves at
`https://maven.pkg.github.com/eXist-db/jackrabbit-webdav-jakarta`

`workflow_dispatch` is also wired up if you need to publish a SNAPSHOT manually.

## Consuming from a local Maven build

GitHub Packages requires authentication for read access. Add to `~/.m2/settings.xml`:

```xml
<servers>
<server>
<id>github-jackrabbit-webdav-jakarta</id>
<username>YOUR_GITHUB_USERNAME</username>
<password>YOUR_PAT_WITH_read:packages</password>
</server>
</servers>
```

The same PAT works across every `github-*` server id the eXist-db org publishes
(`github`, `github-xqts-runner`, and this one) — one PAT, multiple `<server>`
blocks. The repository declaration lives in `exist-parent/pom.xml` in
[eXist-db/exist](https://github.com/eXist-db/exist).

## License / attribution

Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0),
inherited from upstream. This repository is a derivative work of
[apache/jackrabbit](https://github.com/apache/jackrabbit); all credit for the
WebDAV implementation belongs to the Apache Jackrabbit project. The only
modifications applied here are the OpenRewrite namespace transforms required for
Jakarta EE 10 compatibility.
Loading