Skip to content

Commit 4e8de56

Browse files
khatchadclaude
andauthored
Prototype: CI-published p2 update site (GitHub Pages composite repo) (#52)
* Prototype: CI-published p2 update site via GitHub Pages composite repo Replaces the in-repo, cumulative, hand-assembled update site with a CI-built, Pages-published p2 composite repository (no binaries in master). See docs/RELEASING.md for the comparison. - Add updatesite/category.xml so Tycho's eclipse-repository build produces a complete per-version p2 repo (fixes the empty-build quirk; no GUI / p2 publisher / -append needed). - Add tools/p2-composite.sh to generate p2 composite indexes; verified the Eclipse p2 director loads the composite and resolves the feature. - Add .github/workflows/release.yml: manual-dispatch release pipeline (set-version, build/test, tag + GitHub Release with the p2 repo zip, publish to gh-pages as a composite, next-dev bump). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015krtPy49YGqBERvq4yDjCa * Restyle RELEASING.md: title-case headers, no-space em-dashes, no line wrapping Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015krtPy49YGqBERvq4yDjCa * Drop category.xml from prototype (merged separately via #53/#54) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015krtPy49YGqBERvq4yDjCa * Commit the release version before tagging in release.yml The tag must point at the release-version sources, and master needs a "Release vX.Y.Z." commit, so commit the version bump and push master before tagging (mirrors release.sh). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015krtPy49YGqBERvq4yDjCa --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b5d6b8b commit 4e8de56

3 files changed

Lines changed: 224 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
name: Release (CI-published p2 site)
2+
3+
# PROTOTYPE of a CI-published release flow that replaces the in-repo,
4+
# cumulative, hand-assembled P2 update site (see docs/RELEASING.md).
5+
#
6+
# What it does, on manual dispatch:
7+
# 1. set the release version, build + test (Tycho), producing a complete
8+
# per-version p2 repo at .../updatesite/target/repository
9+
# (works because category.xml was added; no GUI / p2 publisher needed)
10+
# 2. tag vX.Y.Z and create a GitHub Release with the p2 repo zipped as an asset
11+
# 3. publish that repo to the gh-pages branch under /releases/X.Y.Z and
12+
# regenerate the p2 *composite* indexes so the single Pages URL exposes
13+
# every released version
14+
# 4. bump master to the next development version
15+
#
16+
# No binaries are ever committed to master. The gh-pages branch holds the
17+
# published site (an orphan branch independent of source history).
18+
19+
on:
20+
workflow_dispatch:
21+
inputs:
22+
release_version:
23+
description: "Release version (X.Y.Z)"
24+
required: true
25+
next_version:
26+
description: "Next dev version (X.Y.Z, -SNAPSHOT added). Blank = bump minor."
27+
required: false
28+
29+
permissions:
30+
contents: write
31+
32+
concurrency:
33+
group: release
34+
cancel-in-progress: false
35+
36+
env:
37+
UPDATESITE: edu.cuny.citytech.refactoring.common.updatesite
38+
PAGES_URL: https://ponder-lab.github.io/Common-Eclipse-Refactoring-Framework
39+
40+
jobs:
41+
release:
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v4
45+
with:
46+
ref: master
47+
fetch-depth: 0
48+
submodules: recursive
49+
50+
- uses: actions/setup-java@v4
51+
with:
52+
java-version: "21"
53+
distribution: temurin
54+
cache: maven
55+
56+
- name: Configure git
57+
run: |
58+
git config user.name "github-actions[bot]"
59+
git config user.email "github-actions[bot]@users.noreply.github.com"
60+
61+
- name: Compute versions
62+
id: v
63+
run: |
64+
REL="${{ github.event.inputs.release_version }}"
65+
NEXT="${{ github.event.inputs.next_version }}"
66+
[[ "$REL" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "bad release version"; exit 1; }
67+
if [[ -z "$NEXT" ]]; then IFS=. read -r MA MI PA <<<"$REL"; NEXT="${MA}.$((MI+1)).0"; fi
68+
echo "rel=$REL" >> "$GITHUB_OUTPUT"
69+
echo "next=${NEXT}-SNAPSHOT" >> "$GITHUB_OUTPUT"
70+
71+
- name: Set release version
72+
run: ./mvnw -B -q org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion=${{ steps.v.outputs.rel }}
73+
74+
- name: Build, test, verify formatting
75+
run: |
76+
./mvnw -B spotless:check
77+
./mvnw -B -U -DtrimStackTrace=true clean install
78+
79+
- name: Sanity-check the built p2 repo is non-empty
80+
run: |
81+
test -f "$UPDATESITE/target/repository/content.jar"
82+
test -n "$(find "$UPDATESITE/target/repository/features" -name '*.jar')"
83+
84+
- name: Zip the p2 repo for the release asset
85+
run: |
86+
(cd "$UPDATESITE/target/repository" && zip -qr "$GITHUB_WORKSPACE/p2-repo-${{ steps.v.outputs.rel }}.zip" .)
87+
88+
- name: Commit release version, tag, push, and create GitHub Release
89+
env:
90+
GH_TOKEN: ${{ github.token }}
91+
run: |
92+
REL="${{ steps.v.outputs.rel }}"
93+
git add -A
94+
git commit -q -m "Release v${REL}."
95+
git tag -a "v${REL}" -m "Release v${REL}."
96+
git push origin master
97+
git push origin "v${REL}"
98+
gh release create "v${REL}" \
99+
--title "v${REL}" --generate-notes \
100+
"p2-repo-${REL}.zip#p2 update site (zip)"
101+
102+
- name: Publish to gh-pages as a composite repository
103+
run: |
104+
REL="${{ steps.v.outputs.rel }}"
105+
git fetch origin gh-pages || true
106+
rm -rf .pages && mkdir .pages
107+
git worktree add -B gh-pages .pages "origin/gh-pages" 2>/dev/null \
108+
|| git worktree add --orphan -B gh-pages .pages
109+
mkdir -p ".pages/releases/$REL"
110+
rm -rf ".pages/releases/$REL"/*
111+
cp -r "$UPDATESITE/target/repository/." ".pages/releases/$REL/"
112+
tools/p2-composite.sh ".pages/releases" "Common Refactoring Framework" "$(date +%s000)"
113+
# root index.html -> composite under /releases
114+
printf '<meta http-equiv="refresh" content="0; url=releases/">\n' > .pages/index.html
115+
( cd .pages
116+
git add -A
117+
git commit -q -m "Publish v$REL to composite p2 site" || echo "nothing to commit"
118+
git push origin gh-pages )
119+
120+
- name: Prepare next development version
121+
run: |
122+
./mvnw -B -q org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion=${{ steps.v.outputs.next }}
123+
git add -A
124+
git commit -q -m "Prepare next development version."
125+
git push origin master
126+
127+
- name: Summary
128+
run: |
129+
echo "Released v${{ steps.v.outputs.rel }}" >> "$GITHUB_STEP_SUMMARY"
130+
echo "Update site: ${PAGES_URL}/releases/" >> "$GITHUB_STEP_SUMMARY"
131+
echo "master now on ${{ steps.v.outputs.next }}" >> "$GITHUB_STEP_SUMMARY"

docs/RELEASING.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Releasing
2+
3+
This repo has two release mechanisms. The **current** one is in-repo and manual/scripted; the **prototype** one is CI-published. This document compares them so we can decide whether to migrate.
4+
5+
## Current Model (`release.sh`, Committed Update Site)
6+
7+
The P2 update site lives **inside the source repo** (`edu.cuny.citytech.refactoring.common.updatesite/`) and is **cumulative**: every release commits its feature + plugin jars and rewrites the shared `artifacts.jar`/`content.jar` index, served from `raw.githubusercontent.com/.../updatesite`.
8+
9+
`./release.sh X.Y.Z` automates it: `set-version`→build→stage jars→bump `site.xml`→regenerate the cumulative index with the Eclipse p2 publisher (`-append`)→commit/tag/push→GitHub Release→next-dev bump.
10+
11+
Trade-offs:
12+
13+
- ➖ Binaries accumulate in `master` history **forever**—every release grows every clone, unrecoverably.
14+
- ➖ Requires a local Eclipse install with the p2 publisher apps; the index is hand-assembled (`-append`), which is fragile (category-id qualification, easy to leak a local path).
15+
-`raw.githubusercontent.com` is not a real artifact host (no CDN/SLA).
16+
- ➕ Zero infra; everything is in one repo; offline-capable.
17+
18+
## Prototype Model (This Branch: CI→GitHub Pages Composite Repo)
19+
20+
The update site is **built in CI and published to the `gh-pages` branch**, never committed to `master`. Each release publishes its **own** small p2 repo under `releases/X.Y.Z/`, and a p2 **composite repository** at the root ties them all together—so one stable URL exposes every version without a monolithic index.
21+
22+
Stable update-site URL (composite):
23+
24+
```
25+
https://ponder-lab.github.io/Common-Eclipse-Refactoring-Framework/releases/
26+
```
27+
28+
Pieces added on this branch:
29+
30+
- **`edu.cuny.citytech.refactoring.common.updatesite/category.xml`**—the key fix. Tycho's `eclipse-repository` build was producing an *empty* repo because the module only had the legacy `site.xml`. With a `category.xml`, a plain `./mvnw clean install` produces a **complete** per-version p2 repo at `updatesite/target/repository` (feature + 8 bundles + category)—no GUI, no p2 publisher, no `-append`.
31+
- **`tools/p2-composite.sh`**—regenerates `compositeContent.xml`/`compositeArtifacts.xml` from the per-version child dirs. (Verified: the Eclipse p2 director loads the composite and resolves the feature.)
32+
- **`.github/workflows/release.yml`**—manual-dispatch pipeline: set-version→build/test→tag + GitHub Release (with the p2 repo zipped as an asset)→publish to `gh-pages` as a composite→next-dev bump.
33+
34+
Trade-offs:
35+
36+
-**No binaries in `master`**—source history stays lean. The published bits live on the orphan `gh-pages` branch, independent of source clones.
37+
- ➕ One CLI build produces the repo; no GUI, no hand-assembled index.
38+
- ➕ Composite layout scales to any number of versions; each release is an isolated, immutable child—no risk of corrupting a shared index.
39+
- ➕ Released p2 repo is also attached to the GitHub Release as a zip.
40+
- ➖ Relies on GitHub Pages + Actions (infra, perms).
41+
-`gh-pages` still accumulates binaries, but on a branch you can prune/squash without touching source history.
42+
43+
## Migration Notes (Not Done on This Branch)
44+
45+
1. Enable GitHub Pages for the `gh-pages` branch.
46+
2. Update the README's update-site URL to the Pages composite URL.
47+
3. Optionally seed `gh-pages` with the existing historical versions (one child dir per past release) so nothing 404s, then **drop the committed `updatesite/` binaries** from `master` going forward (and, if desired, purge them from history).
48+
4. Retire `release.sh` (or keep as an offline fallback).

tools/p2-composite.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
#
3+
# p2-composite.sh — (re)generate p2 composite repository indexes.
4+
#
5+
# A composite p2 repository is just two XML files that reference per-version
6+
# child repositories. This lets a single, stable update-site URL expose every
7+
# released version without a monolithic cumulative index and without keeping
8+
# any binaries in the source repo.
9+
#
10+
# Usage: p2-composite.sh <site-root> <repo-name> <epoch-millis>
11+
# <site-root> directory whose immediate subdirectories are child p2 repos
12+
# (each containing content.jar / artifacts.jar)
13+
# <repo-name> human-readable repository name
14+
# <epoch-millis> timestamp to stamp (pass in; CI provides it)
15+
#
16+
set -euo pipefail
17+
ROOT="${1:?site-root}"; NAME="${2:?repo-name}"; TS="${3:?epoch-millis}"
18+
19+
# children = immediate subdirs that look like a p2 repo
20+
mapfile -t CHILDREN < <(
21+
find "$ROOT" -mindepth 2 -maxdepth 2 -name content.jar -printf '%h\n' \
22+
| sed "s#^$ROOT/##" | sort -V
23+
)
24+
25+
emit() { # $1 = filename, $2 = processing-instruction, $3 = repo type
26+
local out="$ROOT/$1" pi="$2" type="$3"
27+
{
28+
echo "<?xml version='1.0' encoding='UTF-8'?>"
29+
echo "<?$pi version='1.0.0'?>"
30+
echo "<repository name='$NAME' type='$type' version='1.0.0'>"
31+
echo " <properties size='1'>"
32+
echo " <property name='p2.timestamp' value='$TS'/>"
33+
echo " </properties>"
34+
echo " <children size='${#CHILDREN[@]}'>"
35+
for c in "${CHILDREN[@]}"; do echo " <child location='$c'/>"; done
36+
echo " </children>"
37+
echo "</repository>"
38+
} > "$out"
39+
echo "wrote $out (${#CHILDREN[@]} children)"
40+
}
41+
42+
emit compositeContent.xml compositeMetadataRepository \
43+
org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository
44+
emit compositeArtifacts.xml compositeArtifactRepository \
45+
org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository

0 commit comments

Comments
 (0)