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
74 changes: 74 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Package CyberCore

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]
workflow_dispatch:

permissions:
contents: read

env:
PROJECT_NAME: CyberCore
BUILD_ARGS: clean shadowJar
JAR_SEARCH_DIR: build/libs

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4

- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew --no-daemon $BUILD_ARGS

- name: Prepare jar
id: artifact
shell: bash
run: |
VERSION=$(./gradlew --no-daemon -q properties --property version | awk -F': ' '$1 == "version" { print $2; exit }')
EXPECTED_JAR="${JAR_SEARCH_DIR}/${PROJECT_NAME}-${VERSION}.jar"
JAR_SOURCE=""

if [ -f "$EXPECTED_JAR" ]; then
JAR_SOURCE="$EXPECTED_JAR"
else
mapfile -t JARS < <(find "$JAR_SEARCH_DIR" -maxdepth 1 -type f -name "*.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" ! -name "*-all.jar" | sort)
JAR_SOURCE="${JARS[0]:-}"
fi

if [ -z "$JAR_SOURCE" ] || [ ! -f "$JAR_SOURCE" ]; then
echo "Could not find final jar in $JAR_SEARCH_DIR."
find "$JAR_SEARCH_DIR" -maxdepth 1 -type f -name "*.jar" -print || true
exit 1
fi

mkdir -p release-artifact
JAR_PATH="release-artifact/${PROJECT_NAME}-${VERSION}.jar"
cp "$JAR_SOURCE" "$JAR_PATH"

echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "path=$JAR_PATH" >> "$GITHUB_OUTPUT"

- name: Upload jar
uses: actions/upload-artifact@v4
with:
name: ${{ env.PROJECT_NAME }}-${{ steps.artifact.outputs.version }}
path: ${{ steps.artifact.outputs.path }}
if-no-files-found: error
retention-days: 7
232 changes: 232 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
name: Release CyberCore

on:
workflow_run:
workflows: [ "Package CyberCore" ]
types: [ completed ]
branches: [ "main", "master" ]

permissions:
actions: read
contents: write
pull-requests: read

concurrency:
group: cybercore-release-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: false

env:
PROJECT_NAME: CyberCore
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
GH_TOKEN: ${{ github.token }}

jobs:
release:
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'pull_request'
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0

- name: Download build artifact
shell: bash
run: |
gh run download "${{ github.event.workflow_run.id }}" \
--repo "$GITHUB_REPOSITORY" \
--dir release-assets

mapfile -t JARS < <(find release-assets -type f -name "${PROJECT_NAME}-*.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" ! -name "*-all.jar" | sort)
RELEASE_JAR="${JARS[0]:-}"

if [ -z "$RELEASE_JAR" ] || [ ! -f "$RELEASE_JAR" ]; then
echo "Could not find ${PROJECT_NAME} jar in downloaded artifacts."
find release-assets -type f -print
exit 1
fi

BASENAME=$(basename "$RELEASE_JAR" .jar)
PREFIX="${PROJECT_NAME}-"
VERSION="${BASENAME#$PREFIX}"

echo "RELEASE_JAR=$RELEASE_JAR" >> "$GITHUB_ENV"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
echo "TAG=$VERSION" >> "$GITHUB_ENV"

- name: Generate release notes
shell: bash
run: |
set -euo pipefail

OWNER="${GITHUB_REPOSITORY%/*}"
REPO="${GITHUB_REPOSITORY#*/}"

git fetch --tags --force

if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release delete "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--cleanup-tag \
--yes
elif git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then
gh api \
--method DELETE \
"repos/$GITHUB_REPOSITORY/git/refs/tags/$TAG" || true
fi

BUMP_SUBJECT="chore: bump version to $VERSION"
LOG_FILE=$(mktemp)
git log --format='%H%x09%s' "$HEAD_SHA" > "$LOG_FILE"
BUMP_COMMIT=$(awk -F '\t' -v subject="$BUMP_SUBJECT" '$2 == subject { print $1; exit }' "$LOG_FILE")

if [ -n "$BUMP_COMMIT" ]; then
if BUMP_PARENT=$(git rev-parse "$BUMP_COMMIT^" 2>/dev/null); then
RANGE="$BUMP_PARENT..$HEAD_SHA"
CHANGELOG_BASE="$BUMP_PARENT"
else
RANGE="$HEAD_SHA"
CHANGELOG_BASE="$BUMP_COMMIT"
fi
else
RELEASE_TAGS=$(gh release list \
--repo "$GITHUB_REPOSITORY" \
--exclude-drafts \
--limit 100 \
--json tagName \
--jq ".[].tagName | select(. != \"$TAG\")")

PREVIOUS_TAG=$(awk 'NF { print; exit }' <<< "$RELEASE_TAGS")

if [ -z "$PREVIOUS_TAG" ]; then
echo "Could not find '$BUMP_SUBJECT' or a previous release tag."
echo "Refusing to generate release notes from the full repository history."
exit 1
fi

RANGE="$PREVIOUS_TAG..$HEAD_SHA"
CHANGELOG_BASE="$PREVIOUS_TAG"
fi

FULL_CHANGELOG="https://github.com/$GITHUB_REPOSITORY/compare/$CHANGELOG_BASE...$TAG"

QUERY='
query($owner:String!, $repo:String!, $oid:GitObjectID!) {
repository(owner:$owner, name:$repo) {
object(oid:$oid) {
... on Commit {
messageHeadline
abbreviatedOid
author {
name
user {
login
}
}
associatedPullRequests(first: 1) {
nodes {
number
title
author {
login
}
}
}
}
}
}
}'

declare -A SEEN_PULL_REQUESTS
CONTRIBUTORS=$(mktemp)
PREVIOUS_CONTRIBUTORS=$(mktemp)

if [ -n "${CHANGELOG_BASE:-}" ] && git rev-parse "$CHANGELOG_BASE" >/dev/null 2>&1; then
git log --format='%aN' "$CHANGELOG_BASE" | sort -fu > "$PREVIOUS_CONTRIBUTORS"
fi

{
echo "## What's Changed"
echo
} > release-notes.md

HAS_CHANGES=false
while read -r SHA; do
[ -z "$SHA" ] && continue
HAS_CHANGES=true

DATA=$(gh api graphql \
-f query="$QUERY" \
-f owner="$OWNER" \
-f repo="$REPO" \
-F oid="$SHA")

PR_NUMBER=$(echo "$DATA" | jq -r '.data.repository.object.associatedPullRequests.nodes[0].number // empty')
PR_TITLE=$(echo "$DATA" | jq -r '.data.repository.object.associatedPullRequests.nodes[0].title // empty')
PR_AUTHOR=$(echo "$DATA" | jq -r '.data.repository.object.associatedPullRequests.nodes[0].author.login // empty')

COMMIT_TITLE=$(echo "$DATA" | jq -r '.data.repository.object.messageHeadline')
COMMIT_AUTHOR_LOGIN=$(echo "$DATA" | jq -r '.data.repository.object.author.user.login // empty')
COMMIT_AUTHOR_NAME=$(echo "$DATA" | jq -r '.data.repository.object.author.name // "unknown"')
SHORT_SHA=$(echo "$DATA" | jq -r '.data.repository.object.abbreviatedOid')

if [ -n "$PR_NUMBER" ]; then
if [ -z "${SEEN_PULL_REQUESTS[$PR_NUMBER]+x}" ]; then
echo "- $PR_TITLE by @$PR_AUTHOR in #$PR_NUMBER" >> release-notes.md
[ -n "$PR_AUTHOR" ] && echo "$PR_AUTHOR" >> "$CONTRIBUTORS"
SEEN_PULL_REQUESTS[$PR_NUMBER]=1
fi
else
if [ -n "$COMMIT_AUTHOR_LOGIN" ]; then
echo "- $COMMIT_TITLE by @$COMMIT_AUTHOR_LOGIN ($SHORT_SHA)" >> release-notes.md
echo "$COMMIT_AUTHOR_LOGIN" >> "$CONTRIBUTORS"
else
echo "- $COMMIT_TITLE by $COMMIT_AUTHOR_NAME ($SHORT_SHA)" >> release-notes.md
fi
fi
done < <(git rev-list --reverse "$RANGE")

if [ "$HAS_CHANGES" = false ]; then
echo "- No code changes detected for this release." >> release-notes.md
fi

if [ -s "$CONTRIBUTORS" ]; then
NEW_CONTRIBUTORS=$(mktemp)
sort -u "$CONTRIBUTORS" \
| grep -Fvxif "$PREVIOUS_CONTRIBUTORS" \
> "$NEW_CONTRIBUTORS" || true

if [ -s "$NEW_CONTRIBUTORS" ]; then
{
echo
echo "## New Contributors"
echo
sed 's/^/- @/' "$NEW_CONTRIBUTORS"
} >> release-notes.md
fi

{
echo
echo "## Contributors"
echo
sort -u "$CONTRIBUTORS" | sed 's/^/- @/'
} >> release-notes.md
fi

{
echo
echo "**Full Changelog**: $FULL_CHANGELOG"
} >> release-notes.md

- name: Publish GitHub prerelease
shell: bash
run: |
gh release create "$TAG" "$RELEASE_JAR" \
--repo "$GITHUB_REPOSITORY" \
--title "$VERSION" \
--notes-file release-notes.md \
--target "$HEAD_SHA" \
--prerelease \
--latest=false
Loading
Loading