#!/usr/bin/env bash # # The contents of this file are subject to the terms of the Common Development and # Distribution License (the License). You may not use this file except in compliance with the # License. # # You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the # specific language governing permission and limitations under the License. # # When distributing Covered Software, include this CDDL Header Notice in each file and include # the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL # Header, with the fields enclosed by brackets [] replaced by your own identifying # information: "Portions Copyright [year] [name of copyright owner]". # # Copyright 2026 3A Systems, LLC # # Regenerates the Debian and RPM package changelogs from the GitHub Releases of # OpenIdentityPlatform/OpenDJ. Run this at release time (it needs network + an # authenticated `gh`); the produced files are committed so the Maven build stays # offline and reproducible. # # Usage (from the repository root): # opendj-packages/resources/generate-changelog.sh # # Requires: gh (authenticated), python3. set -euo pipefail REPO="${OPENDJ_REPO:-OpenIdentityPlatform/OpenDJ}" HERE="$(cd "$(dirname "$0")" && pwd)" DEB_FILE="${HERE}/../opendj-deb/resources/changelog" RPM_FILE="${HERE}/../opendj-rpm/resources/changelog" echo "Fetching releases from ${REPO} ..." >&2 RELEASES_TMP="$(mktemp)" trap 'rm -f "$RELEASES_TMP"' EXIT gh api --paginate "repos/${REPO}/releases" > "$RELEASES_TMP" 2>/dev/null DEB_FILE="${DEB_FILE}" RPM_FILE="${RPM_FILE}" RELEASES_TMP="${RELEASES_TMP}" REPO="${REPO}" python3 - <<'PY' import json, os, re, sys, textwrap with open(os.environ["RELEASES_TMP"]) as _f: releases = json.load(_f) MAINTAINER = "Open Identity Platform Community " DOW = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] MON = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def parse_iso(ts): # e.g. 2026-06-11T19:19:48Z -> (Y, M, D, h, m, s, weekday) import datetime dt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ") return dt def clean_bullets(body): bullets = [] for raw in (body or "").splitlines(): line = raw.strip() if not line.startswith(("* ", "- ")): continue line = line[2:].strip() line = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", line) # md link -> text line = re.sub(r"\bin https?://\S+", "", line) # drop PR url line = re.sub(r"https?://\S+", "", line) # drop bare urls line = re.sub(r"\b(by|thanks)\s+@[\w-]+(\[bot\])?", "", line) # drop "by/thanks @author" line = re.sub(r"@[\w-]+(\[bot\])?", "", line) # drop any leftover @mention line = line.replace("**", "").replace("`", "") line = re.sub(r"[←-➿️❤☀-⛿]", "", line) # emoji/hearts line = re.sub(r"\s+", " ", line).strip(" -") if line: bullets.append(line) return bullets def version_of(rel): return (rel.get("tag_name") or rel.get("name") or "").lstrip("v").strip() deb_chunks, rpm_chunks = [], [] for rel in releases: if rel.get("draft"): continue ver = version_of(rel) if not ver or not ver[0].isdigit(): continue dt = parse_iso(rel["published_at"]) bullets = clean_bullets(rel.get("body")) or [ "See release notes: https://github.com/%s/releases/tag/%s" % (os.environ.get("REPO", "OpenIdentityPlatform/OpenDJ"), ver) ] # --- Debian stanza --- # "-1" is the package revision the control file declares (deb.release). deb = ["opendj (%s-1) unstable; urgency=medium" % ver, ""] for b in bullets: wrapped = textwrap.fill(b, width=78, initial_indent=" * ", subsequent_indent=" ") deb.append(wrapped) deb_date = "%s, %02d %s %d %02d:%02d:%02d +0000" % ( DOW[dt.weekday()], dt.day, MON[dt.month - 1], dt.year, dt.hour, dt.minute, dt.second) deb.append("") deb.append(" -- %s %s" % (MAINTAINER, deb_date)) deb_chunks.append("\n".join(deb)) # --- RPM stanza --- rpm_date = "%s %s %2d %d" % (DOW[dt.weekday()], MON[dt.month - 1], dt.day, dt.year) rpm = ["* %s %s - %s-1" % (rpm_date, MAINTAINER, ver)] for b in bullets: rpm.append(textwrap.fill(b, width=78, initial_indent="- ", subsequent_indent=" ")) rpm_chunks.append("\n".join(rpm)) with open(os.environ["DEB_FILE"], "w") as f: f.write("\n\n".join(deb_chunks) + "\n") RPM_PREAMBLE = """# # The contents of this file are subject to the terms of the Common Development and # Distribution License (the License). You may not use this file except in compliance with the # License. # # You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the # specific language governing permission and limitations under the License. # # When distributing Covered Software, include this CDDL Header Notice in each file and include # the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL # Header, with the fields enclosed by brackets [] replaced by your own identifying # information: "Portions Copyright [year] [name of copyright owner]". # # Copyright 2013-2015 ForgeRock AS. # Portions Copyright 2026 3A Systems, LLC. # ============================= # opendj rpm package changelog # ============================= %changelog """ with open(os.environ["RPM_FILE"], "w") as f: f.write(RPM_PREAMBLE + "\n".join(rpm_chunks) + "\n") print("Wrote %d releases to:\n %s\n %s" % (len(deb_chunks), os.environ["DEB_FILE"], os.environ["RPM_FILE"]), file=sys.stderr) PY