From 838df9fc433931cf119358d2b4fdebbae338c8ef Mon Sep 17 00:00:00 2001 From: Werner Dietl Date: Wed, 7 Oct 2026 01:47:09 -0400 Subject: [PATCH 1/2] Take the Annotation File Utilities from the Checker Framework releases The Annotation File Utilities are built from the Checker Framework repository, and annotation-tools-VERSION.zip is an asset of each Checker Framework release. Look for the Checker Framework zip by name, since a release now has two zips, and look for the Annotation File Utilities zip in the Checker Framework releases first, then in the archived annotation-tools repository. Update the installation instructions, source code location, and bug-report location accordingly. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/publish-website.yml | 7 +- README.md | 6 ++ .../eisop/website/EisopSiteGenerator.java | 101 +++++++++++------- src/main/resources/afu-template.md | 18 ++-- src/main/resources/cf-template.md | 2 +- 5 files changed, 84 insertions(+), 50 deletions(-) diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml index 7dcf6c64..bbdff7f1 100644 --- a/.github/workflows/publish-website.yml +++ b/.github/workflows/publish-website.yml @@ -41,7 +41,12 @@ jobs: # Scheduled run: check if latest releases are already published on the site CF_TAG=$(gh api repos/eisop/checker-framework/releases --jq '.[0].tag_name') - AFU_ZIP=$(gh api repos/eisop/annotation-tools/releases --jq '.[0].assets[0].name') + # The Annotation File Utilities zip is an asset of the Checker Framework release. + # Older releases are in the former annotation-tools repository. + AFU_ZIP=$(gh api repos/eisop/checker-framework/releases --jq '[.[].assets[] | select(.name | startswith("annotation-tools-"))] | .[0].name') + if [ -z "$AFU_ZIP" ] || [ "$AFU_ZIP" = "null" ]; then + AFU_ZIP=$(gh api repos/eisop/annotation-tools/releases --jq '.[0].assets[0].name') + fi CF_STATUS=$(curl -s -o /dev/null -w '%{http_code}' "https://eisop.github.io/cf/${CF_TAG}/index.html") AFU_STATUS=$(curl -s -o /dev/null -w '%{http_code}' "https://eisop.github.io/afu/${AFU_ZIP}") diff --git a/README.md b/README.md index 3958e110..16d8e3f6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ The website is updated automatically via a daily GitHub Actions schedule that checks if new Checker Framework or Annotation File Utilities releases have been published. If new releases exist, it generates and publishes the pages. +A release of the Checker Framework has two zip assets, +`checker-framework-VERSION.zip` and `annotation-tools-VERSION.zip`. +The former repository `eisop/annotation-tools` is archived; its releases +are used for the Annotation File Utilities versions before the first release +of the Checker Framework that has the second asset. + You can also run the **Publish website** workflow manually from the Actions tab. It checks out `master` for the generator, builds it, checks out `gh-pages`, downloads any release that is not on the site yet, regenerates the pages, and pushes. diff --git a/src/main/java/io/github/eisop/website/EisopSiteGenerator.java b/src/main/java/io/github/eisop/website/EisopSiteGenerator.java index f66a291e..c3f6aa0d 100644 --- a/src/main/java/io/github/eisop/website/EisopSiteGenerator.java +++ b/src/main/java/io/github/eisop/website/EisopSiteGenerator.java @@ -127,6 +127,16 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < limit; i++) { boolean isLocalRelease = (i == 0 && localReleaseZip != null); + // A release has other assets as well, such as the Annotation File Utilities zip. + JSONObject latestAssetsData = + findZipAsset((JSONObject) frameworkReleases.get(i), "checker-framework-"); + if (latestAssetsData == null) { + System.out.println( + "Skipping release without a Checker Framework zip: " + + ((JSONObject) frameworkReleases.get(i)).get("tag_name")); + continue; + } + if (!isLocalRelease) { releaseFileHTML += "[" @@ -138,11 +148,6 @@ public static void main(String[] args) throws IOException { + "/index.html)\n"; } - // Get data on release assets - JSONObject latestAssetsData = - (JSONObject) - ((((JSONArray) ((JSONObject) frameworkReleases.get(i)).get("assets")) - .get(0))); int connectTimeout = 0; int readTimeout = 0; String fileUrlString = String.valueOf(latestAssetsData.get("browser_download_url")); @@ -314,13 +319,7 @@ public static void main(String[] args) throws IOException { latestCheckerFrameworkReleaseDownloadLink); String latestCheckerFrameworkReleaseDate = - String.valueOf( - ((JSONObject) - ((((JSONArray) - ((JSONObject) frameworkReleases.get(i)) - .get("assets")) - .get(0)))) - .get("created_at")); + String.valueOf(latestAssetsData.get("created_at")); latestCheckerFrameworkReleaseDate = getReadableDate(latestCheckerFrameworkReleaseDate); htmlString = htmlString.replace( @@ -491,6 +490,28 @@ static JSONArray getAPIResponse(URL apiURL) throws IOException { } } + /** + * Returns the zip asset of the given release whose name starts with the given prefix. + * + * @param release a GitHub release + * @param prefix the start of the name of the asset + * @return the asset, or null if the release has none + */ + static JSONObject findZipAsset(JSONObject release, String prefix) { + JSONArray assets = (JSONArray) release.get("assets"); + if (assets == null) { + return null; + } + for (Object assetObject : assets) { + JSONObject asset = (JSONObject) assetObject; + String name = String.valueOf(asset.get("name")); + if (name.startsWith(prefix) && name.endsWith(".zip")) { + return asset; + } + } + return null; + } + static void getAFU(boolean onlyLatest) throws IOException { File directoryPath = new File(System.getProperty("user.dir") + "/afu"); if (!directoryPath.exists()) { @@ -503,21 +524,35 @@ static void getAFU(boolean onlyLatest) throws IOException { System.out.println("Folder already exists at: " + directoryPath); } - // Get list of framework releases - URL listReleasesURL = - URI.create( - "https://api.github.com/repos/eisop/annotation-tools/releases?per_page=100") - .toURL(); - JSONArray frameworkReleases = getAPIResponse(listReleasesURL); + // Get the releases of the Annotation File Utilities. Since the Annotation File Utilities + // became part of the Checker Framework repository, each Checker Framework release has an + // annotation-tools-VERSION.zip asset. Older releases are in the former repository. + // The releases are ordered from the newest to the oldest. + List afuAssets = new ArrayList<>(); + for (String repo : new String[] {"checker-framework", "annotation-tools"}) { + URL listReleasesURL = + URI.create( + "https://api.github.com/repos/eisop/" + + repo + + "/releases?per_page=100") + .toURL(); + JSONArray releases = getAPIResponse(listReleasesURL); + for (Object release : releases) { + JSONObject afuAsset = findZipAsset((JSONObject) release, "annotation-tools-"); + if (afuAsset != null) { + afuAssets.add(afuAsset); + } + } + } + if (afuAssets.isEmpty()) { + throw new IOException("No Annotation File Utilities release found."); + } - // Loop through list of framework releases - int limit = onlyLatest ? 1 : frameworkReleases.size(); + // Loop through the list of Annotation File Utilities releases + int limit = onlyLatest ? 1 : afuAssets.size(); for (int i = 0; i < limit; i++) { // Get data on release assets - JSONObject latestAssetsData = - (JSONObject) - ((((JSONArray) ((JSONObject) frameworkReleases.get(i)).get("assets")) - .get(0))); + JSONObject latestAssetsData = afuAssets.get(i); int connectTimeout = 0; int readTimeout = 0; String fileUrlString = String.valueOf(latestAssetsData.get("browser_download_url")); @@ -557,13 +592,7 @@ static void getAFU(boolean onlyLatest) throws IOException { if (globalIndexHTML.exists()) { FileUtils.forceDelete(globalIndexHTML); } - String latestReleaseZipName = - String.valueOf( - ((JSONObject) - ((JSONArray) ((JSONObject) frameworkReleases.get(0)) - .get("assets")) - .get(0)) - .get("name")); + String latestReleaseZipName = String.valueOf(afuAssets.get(0).get("name")); String latestReleaseName = latestReleaseZipName.substring(0, latestReleaseZipName.length() - 4); @@ -611,13 +640,7 @@ static void getAFU(boolean onlyLatest) throws IOException { "/afu/" + latestAnnotationFileUtilitiesReleaseZip; String latestAnnotationFileUtilitiesReleaseDate = - String.valueOf( - ((JSONObject) - ((((JSONArray) - ((JSONObject) frameworkReleases.get(0)) - .get("assets")) - .get(0)))) - .get("created_at")); + String.valueOf(afuAssets.get(0).get("created_at")); latestAnnotationFileUtilitiesReleaseDate = getReadableDate(latestAnnotationFileUtilitiesReleaseDate); @@ -634,6 +657,8 @@ static void getAFU(boolean onlyLatest) throws IOException { String[] parts = latestReleaseName.split("-"); String latestAnnotationFileUtilitiesRelease = parts[parts.length - 2]; + // The name of the release, such as annotation-tools-1.2.3-eisop1. + mdString = mdString.replace("$LatestAnnotationFileUtilitiesReleaseName", latestReleaseName); mdString = mdString.replace( "$LatestAnnotationFileUtilitiesReleaseDate", diff --git a/src/main/resources/afu-template.md b/src/main/resources/afu-template.md index 723efa3b..f2dc6ce8 100644 --- a/src/main/resources/afu-template.md +++ b/src/main/resources/afu-template.md @@ -67,26 +67,26 @@ The following instructions assume either a Linux or Windows system using a comma The current release is Annotation File Utilities version $LatestAnnotationFileUtilitiesRelease, $LatestAnnotationFileUtilitiesReleaseDate. 1. Download [$LatestAnnotationFileUtilitiesReleaseZip]($LatestAnnotationFileUtilitiesReleaseDownloadLink). -2. Create a directory named `annotation-tools` by unpacking the distribution zipfile. (You will typically make `annotation-tools/` a sibling of `checker-framework/`.) +2. Unpack the distribution zipfile, which creates a directory named `$LatestAnnotationFileUtilitiesReleaseName`. - unzip annotation-tools-$LatestAnnotationFileUtilitiesRelease.zip + unzip $LatestAnnotationFileUtilitiesReleaseName.zip -3. Add the `annotation-file-utilities` directory to your path. +3. Add the `annotation-file-utilities/bin` directory to your path. * For **Unix** (including Linux and MacOS), add the directory to your PATH environment variable. If your shell is sh or bash, add to your `~/.bashrc` or `~/.bash_profile` file: - export PATH=${PATH}:/path/to/annotation-tools/annotation-file-utilities/scripts + export PATH=${PATH}:/path/to/$LatestAnnotationFileUtilitiesReleaseName/annotation-file-utilities/bin * For **Windows**, add the directory to your `PATH` system variable by going to Control Panel -> System -> Advanced -> Environment Variables - From there, find the `PATH` variable under “System variables” and append to it the directory `_path\to_\annotation-tools\annotation-file-utilities\scripts`. + From there, find the `PATH` variable under “System variables” and append to it the directory `_path\to_\$LatestAnnotationFileUtilitiesReleaseName\annotation-file-utilities\bin`. ### Building from source The annotation file utilities are pre-compiled (a jar file is included in the distribution), so most users do not need to compile it themselves. -There are two ways to obtain the source code. Source code is provided in the [distribution](https://github.com/eisop/annotation-tools/releases). Alternately, see the source code repository at [https://github.com/eisop/annotation-tools](https://github.com/eisop/annotation-tools). +The source code is in the `annotation-file-utilities` directory of the [EISOP Checker Framework repository](https://github.com/eisop/checker-framework). The Annotation File Utilities are also available from Maven Central, as `io.github.eisop:annotation-file-utilities`. The former repository, [eisop/annotation-tools](https://github.com/eisop/annotation-tools), is archived. To compile and run tests, do `./gradlew build` from the `annotation-file-utilities` subdirectory. @@ -258,12 +258,10 @@ If there are remaining `Insertion`s that were not matched to a node in the abstr Feedback and bug reports ------------------------ -To submit a bug report or request a new feature, use the [issue tracker](https://github.com/eisop/annotation-tools/issues). When reporting a bug, please include exact instructions on how to reproduce it, and please also attach relevant input files. This will let us resolve the issue quickly. - -You can also reach the developers at [annotation-tools-dev@googlegroups.com](mailto:annotation-tools-dev@googlegroups.com). But please use the [issue tracker](https://github.com/eisop/annotation-tools/issues) for bug reports and feature requests. +To submit a bug report or request a new feature, use the [issue tracker](https://github.com/eisop/checker-framework/issues). When reporting a bug, please include exact instructions on how to reproduce it, and please also attach relevant input files. This will let us resolve the issue quickly. ### Changelog -The [changelog](changelog.html) describes what is new in each release. +The [changelog](changelog.html) describes what is new in each release up to 3.49.5-eisop1. Later changes are in the [Checker Framework changelog](https://github.com/eisop/checker-framework/blob/master/docs/CHANGELOG.md). * * * \ No newline at end of file diff --git a/src/main/resources/cf-template.md b/src/main/resources/cf-template.md index 8f78c70c..ed81360a 100644 --- a/src/main/resources/cf-template.md +++ b/src/main/resources/cf-template.md @@ -32,7 +32,7 @@ The Checker Framework enhances Java's type system to make it more powerful and u * Optional related tools: * The [**Annotation File Utilities**](../afu/annotation-file-utilities.md) extract annotations from, and write annotations to, `.java` and `.class` files. It also provides a representation (called an “annotation file”) for annotations that is outside the source code or the `.class` file. The tools support both Java 5 declaration annotations and Java 8 type annotations. * [$LatestAnnotationFileUtilitiesReleaseZip]($LatestAnnotationFileUtilitiesReleaseDownloadLink) ($LatestAnnotationFileUtilitiesReleaseDate) - * [source code repository](https://github.com/eisop/annotation-tools/) + * [source code](https://github.com/eisop/checker-framework/tree/master/annotation-file-utilities) * [Documentation](../afu/annotation-file-utilities.html) is included in the zip archive and in the repository. * [Archive of previous releases](releases/releases.html) of the Checker Framework * Research papers: See the [Checker Framework manual](manual/manual.html#publications) From 2e92af5ff6136498a3540210fc128d17f5f514e5 Mon Sep 17 00:00:00 2001 From: Werner Dietl Date: Wed, 7 Oct 2026 02:20:47 -0400 Subject: [PATCH 2/2] Look for annotation-file-utilities-VERSION.zip in the Checker Framework releases The zip of the Annotation File Utilities is named like the Maven artifact, annotation-file-utilities-VERSION.zip. The releases of the archived annotation-tools repository still have annotation-tools-VERSION.zip. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/publish-website.yml | 2 +- README.md | 6 +++--- .../java/io/github/eisop/website/EisopSiteGenerator.java | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml index bbdff7f1..9c210959 100644 --- a/.github/workflows/publish-website.yml +++ b/.github/workflows/publish-website.yml @@ -43,7 +43,7 @@ jobs: CF_TAG=$(gh api repos/eisop/checker-framework/releases --jq '.[0].tag_name') # The Annotation File Utilities zip is an asset of the Checker Framework release. # Older releases are in the former annotation-tools repository. - AFU_ZIP=$(gh api repos/eisop/checker-framework/releases --jq '[.[].assets[] | select(.name | startswith("annotation-tools-"))] | .[0].name') + AFU_ZIP=$(gh api repos/eisop/checker-framework/releases --jq '[.[].assets[] | select(.name | startswith("annotation-file-utilities-"))] | .[0].name') if [ -z "$AFU_ZIP" ] || [ "$AFU_ZIP" = "null" ]; then AFU_ZIP=$(gh api repos/eisop/annotation-tools/releases --jq '.[0].assets[0].name') fi diff --git a/README.md b/README.md index 16d8e3f6..c1429604 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ checks if new Checker Framework or Annotation File Utilities releases have been published. If new releases exist, it generates and publishes the pages. A release of the Checker Framework has two zip assets, -`checker-framework-VERSION.zip` and `annotation-tools-VERSION.zip`. -The former repository `eisop/annotation-tools` is archived; its releases -are used for the Annotation File Utilities versions before the first release +`checker-framework-VERSION.zip` and `annotation-file-utilities-VERSION.zip`. +The former repository `eisop/annotation-tools` is archived; its releases, +with zips named `annotation-tools-VERSION.zip`, are used for the Annotation File Utilities versions before the first release of the Checker Framework that has the second asset. You can also run the **Publish website** workflow manually from the Actions tab. diff --git a/src/main/java/io/github/eisop/website/EisopSiteGenerator.java b/src/main/java/io/github/eisop/website/EisopSiteGenerator.java index c3f6aa0d..695629e4 100644 --- a/src/main/java/io/github/eisop/website/EisopSiteGenerator.java +++ b/src/main/java/io/github/eisop/website/EisopSiteGenerator.java @@ -529,6 +529,8 @@ static void getAFU(boolean onlyLatest) throws IOException { // annotation-tools-VERSION.zip asset. Older releases are in the former repository. // The releases are ordered from the newest to the oldest. List afuAssets = new ArrayList<>(); + // The zips of the former repository are named annotation-tools-VERSION.zip, and the zips of + // the Checker Framework releases are named annotation-file-utilities-VERSION.zip. for (String repo : new String[] {"checker-framework", "annotation-tools"}) { URL listReleasesURL = URI.create( @@ -538,7 +540,11 @@ static void getAFU(boolean onlyLatest) throws IOException { .toURL(); JSONArray releases = getAPIResponse(listReleasesURL); for (Object release : releases) { - JSONObject afuAsset = findZipAsset((JSONObject) release, "annotation-tools-"); + JSONObject afuAsset = + findZipAsset((JSONObject) release, "annotation-file-utilities-"); + if (afuAsset == null) { + afuAsset = findZipAsset((JSONObject) release, "annotation-tools-"); + } if (afuAsset != null) { afuAssets.add(afuAsset); }