Publish installers to current repo for cross-repo tag releases; mark branch releases as pre-releases - #478
Merged
Conversation
When target_repository points at a different repository (typically a public repo fronting a private one), tag releases now also get a copy of the installer artifacts, plus a release body with download links, in the repository running the workflow, which already has a release for the tag. Only the installers are copied; the remaining release files (platform bundles, package-info.json, icons, etc..) stay in the target repository, which remains the publication channel. The CLI installation links in the copied release notes continue to point at the target repository, since that is where the package metadata lives. Also mark branch releases in the target repository as pre-releases. They were being promoted to "Latest" because `gh release create` defaults to a full release, unlike the same-repo path which already passes prerelease. Adds two CLI commands used by the action: - github-installer-files: lists the installer artifacts in the prepared release files directory, one path per line. - github-release-notes: regenerates the release notes, optionally pointing the download links at a different repository than the CLI install links via JDEPLOY_RELEASE_NOTES_DOWNLOAD_REPOSITORY. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KQuAnJXfX5ZvXTgnHWdPqs
The two steps added for cross-repo tag releases called `jdeploy github-installer-files` and `jdeploy github-release-notes`, which exist only in this branch. action.yml is consumed from a git ref while the CLI comes from npm at the version the caller pins, so those steps failed for any jdeploy_version predating the commands - including the action's own default. An unknown subcommand prints help and exits 1, and with the output captured by a command substitution the step failed with no message at all. Derive the installer list from the jdeploy/installers directory that github-prepare-release already writes, mapped to the release file names it copies them to, and rewrite the download-link prefix in the generated release notes with a literal bash substitution. Both work with every jdeploy version, so the action no longer depends on CLI features that ship separately from it. Reverts the github-installer-files and github-release-notes commands and the GithubReleaseNotesMutator refactor, which are now unused. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KQuAnJXfX5ZvXTgnHWdPqs
The two steps that copy installers into the current repository's release used inputs.github_token, which is the credential for the target repository. When the target is a different repository that token generally cannot write here, and GitHub answers an unauthorized write with 404 rather than 403, so it surfaced as "HTTP 404: Not Found" on the releases endpoint. Use github.token, the calling workflow's own token, for both steps. Also stop failing the release when that copy does not go through. The installers are already published to the target repository, which is the distribution channel, so a missing permission here is reported as a warning annotation naming what is needed rather than failing an otherwise successful release. The body update skips with a warning when no release exists to update. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KQuAnJXfX5ZvXTgnHWdPqs
A tag build runs against a release that already exists in this repository, so the step only ever adds assets to it. The create fallback was reached only because the wrong token made the preceding lookup fail, turning a permissions error into a confusing one, and creating a release in the caller's own repository is a surprising side effect. Report and skip instead when the release cannot be read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KQuAnJXfX5ZvXTgnHWdPqs
shannah
marked this pull request as ready for review
September 8, 2026 19:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes to the GitHub action's release publishing when
target_repositorydiffers from the repository running the workflow (the private-repo → public-repo setup).1. Tag releases now also get installers in the current repository
Previously, when
target_repositorywas a different repository, all release artifacts went there and nothing was added to the current repository's release. For versioned (tag) releases we already have a release in the current repo, so it now also receives:package-info.json, icons,jdeploy-files.zip, npm tarball) stay in the target repository, which remains the publication channel.<!-- JDEPLOY BEGIN -->/<!-- JDEPLOY END -->markers used by the same-repo path.The CLI installation links in that body keep pointing at
target_repository, since that is where the package metadata (package-info.json) and the jdeploy.com download page live.Branch releases are unchanged — they still publish only to the target repository.
2. Branch releases in the target repository are marked as pre-releases
The cross-repo path used
gh release createwith no--prerelease, so a branch snapshot was promoted to "Latest" in the target repository. The same-repo path already passesprerelease: true. Branch builds now pass--prerelease; tag builds still create full releases.Changes
action.ymlonly (plus a README line). No Java changes — see below.Upload files to Github Release in Target Repository(renamed from "...Snapshot Release for Branch", since it also handles tags): adds--prereleasewhengithub.ref_type == 'branch'.Upload Installers to Github Release for Tag in Current Repository: adds the installers to the release that already exists for the tag, viagh release upload --clobber.Update release body for Tag in Current Repository: rewrites the download links to this repository and PATCHes the release body.Both new steps are gated on
target_repository != github.repository && ref_type == 'tag', so they cannot affect single-repo workflows.Three things live testing caught
This started out larger and got corrected twice by real cross-repo deploys. Recording it here since the reasoning matters more than the diff.
1. It depended on CLI commands that ship separately from the action. The first version added two
jdeploysubcommands (github-installer-files,github-release-notes) and called them. Butaction.ymlis consumed from a git ref while the CLI comes from npm at whatever version the caller pins — they're versioned independently, so the steps failed for anyjdeploy_versionpredating the commands, including this action's own default. An unknown subcommand prints help and exits 1, and because the step captured stdout in a command substitution, it failed with no error message at all.Both jobs are now done with what every jdeploy version already provides:
jdeploy/installersdirectory thatgithub-prepare-releasewrites, mapped to the release-file names it copies them to (spaces replaced by dots), with a fallback to the unmodified name.${NOTES//"$from"/"$to"}, deliberately not a regex, so a repository name containing a dot cannot match the wrong text) on thehttps://github.com/<target>/releases/download/prefix in the already-generated notes. The CLI install links arejdeploy.com/gh/<repo>URLs, so the rewrite leaves them on the target repository, which is what we want.The two new subcommands and the
GithubReleaseNotesMutatorrefactor became unused and were reverted, which is why this PR touches no Java.2. It used the wrong token. Both steps used
inputs.github_token, which is the credential for the target repository. When the target is a different repository that token generally cannot write to the current one — and GitHub answers an unauthorized write with404, not403, so it surfaced as a bafflingHTTP 404: Not Foundon/repos/<current>/releases. They now use${{ github.token }}, the calling workflow's own token, which is the right credential for the caller's own release.3. It tried to create a release it should only add to. A tag build runs against a release that already exists here, so the step only ever uploads assets now. The create fallback was reached solely because the wrong token made the preceding
gh release view404, turning a permissions error into a misleading one — and creating a release in the caller's own repository is a surprising side effect (the target repo's release is jdeploy-managed and gets deleted/recreated; the caller's is theirs).Both steps are also non-fatal now. The installers are already published to the target repository — the actual distribution channel — by the time these run, so a missing permission produces a warning annotation naming what's needed rather than failing an otherwise-successful release.
Testing
-win-/-linux-duplicates), and nopackage-info.json,package.json,icon.png,jdeploy-files.zip, or.tgzbundle. The rewrite moved the download links to the current repository and left thejdeploy.com/gh/<target>link untouched.Test Action Scriptsstatic suite: 10/10 passing locally and in CI.action.ymlvalidated as YAML.shared/clisuites are identical tomaster.Still unverified
The cross-repo path can't be exercised from CI here — it needs a real private/public pair. Failures 2 and 3 above were both found that way, so the token/permission seam is worth one more trial deploy before this is relied on. If the permission is wrong the step should now say so in a warning rather than failing the release.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KQuAnJXfX5ZvXTgnHWdPqs