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
85 changes: 65 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,79 @@ concurrency:
group: release
cancel-in-progress: false

# Needed to push the tag and to create the GitHub release.
# Needed to push the tag/create the release and inspect prior publishing attempts.
permissions:
contents: write
actions: read

jobs:
release:
name: Tag, release and publish to Sonatype
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Check publishing credentials
env:
ORG_GRADLE_PROJECT_centralUsername: ${{ secrets.CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_centralPassword: ${{ secrets.CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
run: |
if [ "${ORG_GRADLE_PROJECT_centralUsername}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_centralPassword}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_signingKey}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_signingPassword}" = "" ]; then
echo "Configure the following secrets to enable uploading to Sonatype:"
echo "CENTRAL_USERNAME, CENTRAL_PASSWORD, SIGNING_KEY, SIGNING_PASSWORD"
exit 1
fi

- name: Clone the repo
uses: actions/checkout@v4
with:
# the version counter is computed from the tags that already exist
fetch-depth: 0
fetch-tags: true

- name: Compute the release version
- name: Reserve or reuse the release version
id: version
run: echo "version=$(bash scripts/next-version.sh)" >> "$GITHUB_OUTPUT"
run: |
# Run IDs survive retries; a new dispatch still gets a new version.
marker="Release workflow ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
tags="$(git for-each-ref --format='%(objecttype)%09%(refname:strip=2)%09%(contents:subject)' refs/tags)"
version="$(awk -F '\t' -v marker="$marker" '$1 == "tag" && $3 == marker { print $2 }' <<< "$tags")"

if [ -n "$version" ]; then
# Also reject multiple matching tags (the result would contain newlines).
if [[ ! "$version" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}(-[0-9]+)?$ ]]; then
echo "Invalid or ambiguous release tag for this workflow run." >&2
exit 1
fi
if [ "$(git rev-parse "refs/tags/${version}^{commit}")" != "$GITHUB_SHA" ]; then
echo "The release tag does not point to this workflow's commit." >&2
exit 1
fi
echo "Reusing release ${version}"
else
version="$(bash scripts/next-version.sh)"
git -c user.name='github-actions[bot]' \
-c user.email='41898282+github-actions[bot]@users.noreply.github.com' \
tag --annotate "$version" "$GITHUB_SHA" --message "$marker"
git push origin "refs/tags/${version}"
fi
echo "version=${version}" >> "$GITHUB_OUTPUT"

- name: Push the tag and create the GitHub release
- name: Create the GitHub release if needed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
version='${{ steps.version.outputs.version }}'
echo "Releasing ${version}"
gh api --method POST "repos/${GITHUB_REPOSITORY}/git/refs" \
-f ref="refs/tags/${version}" \
-f sha="${GITHUB_SHA}"
gh release create "${version}" \
--title "${version}" \
--generate-notes
if ! gh release view "$VERSION" > /dev/null 2>&1; then
gh release create "$VERSION" \
--verify-tag --title "$VERSION" --generate-notes
fi

- name: Setup the java environment
uses: actions/setup-java@v4
Expand All @@ -65,19 +106,23 @@ jobs:

- name: Publish and close the Sonatype staging repository
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
ORG_GRADLE_PROJECT_centralUsername: ${{ secrets.CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_centralPassword: ${{ secrets.CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
run: |
if [ "${ORG_GRADLE_PROJECT_centralUsername}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_centralPassword}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_signingKey}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_signingPassword}" = "" ]; then
echo "Configure the following secrets to enable uploading to Sonatype:"
echo "CENTRAL_USERNAME, CENTRAL_PASSWORD, SIGNING_KEY, SIGNING_PASSWORD"
exit 1
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
# A later step (including cleanup) may have failed after publication.
published="$(gh api --paginate \
"repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs?filter=all&per_page=100" \
--jq '.jobs[].steps[]? | select(.name == "Publish and close the Sonatype staging repository" and .conclusion == "success") | .conclusion')"
if [ -n "$published" ]; then
echo "Release ${VERSION} was already published successfully; skipping upload."
exit 0
fi
fi
./gradlew publishToSonatype closeSonatypeStagingRepository \
-PtestdataVersion="${{ steps.version.outputs.version }}" \
-PtestdataVersion="$VERSION" \
--console=plain --stacktrace
26 changes: 22 additions & 4 deletions .github/workflows/snapshot.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
name: Publish snapshot to Maven Central

# Every commit that lands on the default branch publishes a snapshot of
# Every push to the default branch requests a snapshot of
# org.jmonkeyengine:jme3-testdata to Sonatype, using the same date based
# versioning as the releases (scripts/next-version.sh) plus the -SNAPSHOT
# qualifier: <YYYY-MM-DD>-SNAPSHOT.
#
# Contrary to the releases, no tag and no GitHub release are created, and the
# version is not numbered: a Maven snapshot can be republished, so every commit
# of the day simply updates the <YYYY-MM-DD>-SNAPSHOT version.
# version is not numbered: a Maven snapshot can be republished, so commits of
# the day update the <YYYY-MM-DD>-SNAPSHOT version. Superseded commits are skipped.

on:
push:
branches: [master]

# Snapshot uploads share Maven metadata, so never interrupt or overlap them.
concurrency:
group: publish-testdata-snapshot
cancel-in-progress: false

permissions:
contents: read

jobs:
snapshot:
name: Publish snapshot to Sonatype
Expand All @@ -23,7 +31,9 @@ jobs:

- name: Compute the snapshot version
id: version
run: echo "version=$(bash scripts/next-version.sh --snapshot)" >> "$GITHUB_OUTPUT"
run: |
version="$(bash scripts/next-version.sh --snapshot)"
echo "version=${version}" >> "$GITHUB_OUTPUT"

- name: Setup the java environment
uses: actions/setup-java@v4
Expand All @@ -38,6 +48,14 @@ jobs:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
run: |
# Queued runs and manual reruns can target a superseded commit.
master_ref="$(git ls-remote --exit-code origin refs/heads/master)"
master_sha="${master_ref%%[[:space:]]*}"
if [ "${GITHUB_SHA}" != "${master_sha}" ]; then
echo "Skipping snapshot for ${GITHUB_SHA}; master is now ${master_sha}."
exit 0
fi

if [ "${ORG_GRADLE_PROJECT_centralUsername}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_centralPassword}" = "" ] || \
[ "${ORG_GRADLE_PROJECT_signingKey}" = "" ] || \
Expand Down
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,18 @@ resets the next day:
| 3rd | `2026-09-19-3` |
| 1st of the next day | `2026-09-20` |

Snapshots are published on every commit to `master` by the **Publish snapshot to
Maven Central** workflow (`.github/workflows/snapshot.yml`), as
`org.jmonkeyengine:jme3-testdata:<YYYY-MM-DD>-SNAPSHOT`.
Publishing credentials are checked before creating a tag or GitHub release. If a
release run fails, rerun it from the Actions tab: once its tag has been pushed,
every attempt reuses the same version and GitHub release, even on a later day.
An upload that a previous attempt recorded as successful is skipped. A new
manual dispatch starts a separate release and allocates a new version.

Every push to `master` triggers the **Publish snapshot to Maven Central** workflow
(`.github/workflows/snapshot.yml`), publishing
`org.jmonkeyengine:jme3-testdata:<YYYY-MM-DD>-SNAPSHOT`. Snapshot uploads are
serialized without cancelling an upload in progress. Runs whose commit is no
longer the head of `master` are skipped before uploading, so a queued run or a
rerun of an older commit cannot replace a newer snapshot.

The version of the day and the counter are computed by
[`scripts/next-version.sh`](scripts/next-version.sh), covered by
Expand Down
Loading