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
108 changes: 108 additions & 0 deletions .github/workflows/create-draft-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Prepare for Release
on:
workflow_dispatch:
inputs:
name:
description: "Release name"
required: true
default: "ShinRyuModManager-CE 1.0.0"
tag:
description: "Tag for the release (example: 1.2.3)"
required: true
default: "1.0.0"
updater_version:
description: "Version for RyuUpdater (example: 1.2.3)"
required: true
default: "1.0.0"

jobs:
release:
runs-on: ubuntu-latest
permissions: write-all

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

- name: Checkout AppCast Repo
uses: actions/checkout@v4
with:
repository: 'TheTrueColonel/SRMM-AppCast'
token: '${{ secrets.SRMM_APPCAST_TOKEN }}'
path: AppcastRepo

- name: Install .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Install Netsparkle Tool
run: dotnet tool install --global NetSparkleUpdater.Tools.AppCastGenerator

- name: Add .NET tools to PATH
run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH

- name: Create Draft Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.event.inputs.tag }}
release_name: ${{ github.event.inputs.name }}
draft: true
prerelease: false

- name: Run Scripts
run: |
./Scripts/build.sh
./Scripts/package.sh -s ${{ github.event.inputs.tag }} -u ${{ github.event.inputs.updater_version }}
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
SPARKLE_PUBLIC_KEY: ${{ secrets.SPARKLE_PUBLIC_KEY }}

- name: Upload SRMM Release Assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
UPLOAD_URL: ${{ steps.create_release.outputs.upload_url }}
run: |
for file in ${{ github.workspace }}/dist/srmm/out/*; do
name=$(basename "$file")
mime=$(file --brief --mime-type "$file")
echo "Uploading $name ($mime)"
curl \
-X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Content-Type: $mime" \
--data-binary @"$file" \
--no-progress-meter \
"${UPLOAD_URL%%\{*}?name=$name" > /dev/null
done

- name: Commit Appcasts and Updater
run: |
cd ${{ github.workspace }}/AppcastRepo
branch="update-appcasts-${{ github.run_number }}"
git checkout -b "${branch}"

git add .
git commit -m "Update Appcasts and Updater for SRMM version ${{ github.event.inputs.tag }} and Updater version ${{ github.event.inputs.updater_version }}"
git push origin "${branch}"
env:
GIT_AUTHOR_NAME: github-actions
GIT_AUTHOR_EMAIL: github-actions@github.com
GIT_COMMITTER_NAME: github-actions
GIT_COMMITTER_EMAIL: github-actions@github.com

- name: Create Pull Request
run: |
cd ${{ github.workspace }}/AppcastRepo
branch="update-appcasts-${{ github.run_number }}"

gh pr create \
--title "Update Appcasts and Updater" \
--body "Automated update for SRMM version ${{ github.event.inputs.tag }} and Updater version ${{ github.event.inputs.updater_version }}" \
--head "${branch}" \
--base main
env:
GITHUB_TOKEN: ${{ secrets.SRMM_APPCAST_TOKEN }}
125 changes: 125 additions & 0 deletions Scripts/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/bash

set -euo pipefail

### Variables
SRMM_PROJECT="$GITHUB_WORKSPACE/ShinRyuModManager-CE/ShinRyuModManager-CE.csproj"
UPDATER_PROJECT="$GITHUB_WORKSPACE/RyuUpdater/RyuUpdater.csproj"
SRMM_OUTPUT_DIR="$GITHUB_WORKSPACE/dist/srmm"
UPDATER_OUTPUT_DIR="$GITHUB_WORKSPACE/dist/updater"
TEMP_DIR="$RUNNER_TEMP"
PATTERN=".*\.zip$"

FRAMEWORK="net10.0"

DOWNLOAD_REPO="SRMM-Studio/ShinRyuModManager"

FILES_TO_COPY=(
"dinput8.dll"
"winmm.lj"
"YakuzaParless.asi"
)

# Declares runtime and known build params
declare -A TARGET_ARGS=(
["linux"]="linux-x64;--self-contained -p:BuildSuffix=linux"
["linux-slim"]="linux-x64;--no-self-contained -p:BuildSuffix=linux-slim"
["windows"]="win-x64;--self-contained -p:BuildSuffix=windows"
["windows-slim"]="win-x64;--no-self-contained -p:BuildSuffix=windows-slim"
)

declare -A UPDATER_TARGET_ARGS=(
["linux"]="linux-x64;--self-contained"
["windows"]="win-x64;--self-contained"
)

### Get required files from SRMM release
API_URL="https://api.github.com/repos/${DOWNLOAD_REPO}/releases/latest"

# Using `jq` to parse json response
ASSET_URL=$(curl -s "${API_URL}" | jq -r \
--arg pattern "${PATTERN}" '
.assets[]
| select(.name | test($pattern))
| .browser_download_url
')

if [[ -z "${ASSET_URL}" ]]; then
echo "ERROR: No assets matching pattern '${PATTERN}' found."

Check warning on line 48 in Scripts/build.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=TheTrueColonel_ShinRyuModManager-CE&issues=AZrWzGxJc6ZwUjXdphwA&open=AZrWzGxJc6ZwUjXdphwA&pullRequest=21
exit 1
fi

echo "Downloading asset from: ${ASSET_URL}"

ASSET_FILE="${TEMP_DIR}/release.zip"
curl -L "${ASSET_URL}" -o "${ASSET_FILE}"

echo "Extracting release to ${TEMP_DIR}/extracted"

mkdir -p "${TEMP_DIR}/extracted"
unzip -q "${ASSET_FILE}" -d "${TEMP_DIR}/extracted"

### Build

# Build SRMM
for TARGET in "${!TARGET_ARGS[@]}"; do
OUT_DIR="${SRMM_OUTPUT_DIR}/${TARGET}"
mkdir -p "${OUT_DIR}"

# Reads the target's arguments and split them into an array
IFS=";" read -r -a arr <<< "${TARGET_ARGS[${TARGET}]}"

echo "Buidling SRMM ${TARGET}..."

dotnet publish "${SRMM_PROJECT}" \
-c "Release" \
-r "${arr[0]}" \
-f "${FRAMEWORK}" \
-o "${OUT_DIR}" \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:DebugType=None \
-p:DebugSymbols=false \
-p:DebugPortablePdb=false \
${arr[1]}

for FILE in "${FILES_TO_COPY[@]}"; do
SRC="${TEMP_DIR}/extracted/${FILE}"

if [[ -f "${SRC}" ]]; then
cp "${SRC}" "${OUT_DIR}/${FILE}"
echo " Copied: ${FILE}"
else
echo " Warning: Missing file in realease: ${FILE}"
fi
done

#TODO: Remove when merged. Ensures Parless can find the exe on Windows

Check warning on line 97 in Scripts/build.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this 'TODO' comment.

See more on https://sonarcloud.io/project/issues?id=TheTrueColonel_ShinRyuModManager-CE&issues=AZrWzGxJc6ZwUjXdphwB&open=AZrWzGxJc6ZwUjXdphwB&pullRequest=21
if [[ ${TARGET} =~ "windows" ]]; then
mv "${OUT_DIR}/ShinRyuModManager-CE.exe" "${OUT_DIR}/ShinRyuModManager.exe"
fi
done

# Build Updater
for TARGET in "${!UPDATER_TARGET_ARGS[@]}"; do
OUT_DIR="${UPDATER_OUTPUT_DIR}/${TARGET}"
mkdir -p "${OUT_DIR}"

# Reads the target's arguments and split them into an array
IFS=";" read -r -a arr <<< "${TARGET_ARGS[${TARGET}]}"

echo "Buidling RyuUpdater ${TARGET}..."

dotnet publish "${UPDATER_PROJECT}" \
-c "Release" \
-r "${arr[0]}" \
-f "${FRAMEWORK}" \
-o "${OUT_DIR}" \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:DebugType=None \
-p:DebugSymbols=false \
-p:DebugPortablePdb=false \
-p:PublishTrimmed=true \
${arr[1]}
done
131 changes: 131 additions & 0 deletions Scripts/package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/bin/bash

set -euo pipefail

### Check arguments
if ! [[ "${#}" -gt 3 ]]; then
echo "Not enough args! ${#}"
echo "Usage: $0 -s <SRMM Version Number> -u <Updater Version Number>"
exit 1
fi

while getopts s:u: flag; do
case "${flag}" in
s) SRMM_VERSION="${OPTARG}";;
u) UPDATER_VESION="${OPTARG}";;
*) echo "Usage: $0 -s <SRMM Version Number> -u <Updater Version Number>"; exit 1;;
esac
done

if ! [[ "${SRMM_VERSION}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9_]+)?$ || "${UPDATER_VESION}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9_]+)?$ ]]; then
echo "Incorrect format!"
echo "Usage: $0 -s <SRMM Version Number> -u <Updater Version Number>"
exit 1
fi

# Strip leading "v"s
if [[ "${SRMM_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9_]+)?$ ]]; then
SRMM_VERSION=${SRMM_VERSION#v}
fi

if [[ "${UPDATER_VESION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9_]+)?$ ]]; then
UPDATER_VESION=${UPDATER_VESION#v}
fi

### Variables
SRMM_BASE_NAME="ShinRyuModManager-CE"
UPDATER_BASE_NAME="RyuUpdater"
DIST_SELECTOR="$GITHUB_WORKSPACE/dist"
SRMM_SELECTOR="${DIST_SELECTOR}/srmm"
UPDATER_SELECTOR="${DIST_SELECTOR}/updater"

SRMM_OUTPUT_DIR="${SRMM_SELECTOR}/out"
UPDATER_OUTPUT_DIR="${UPDATER_SELECTOR}/out"

APPCAST_OUTPUT_DIR="${DIST_SELECTOR}/appcast"

SRMM_URL_BASE="https://github.com/TheTrueColonel/ShinRyuModManager-CE/releases/download/v"
UPDATER_URL_BASE="https://thetruecolonel.github.io/SRMM-AppCast/updater/"

rm -rf "${SRMM_OUTPUT_DIR}"
rm -rf "${UPDATER_OUTPUT_DIR}"

readarray -t SRMM_BUILD_DIRS < <(find "${SRMM_SELECTOR}" -mindepth 1 -maxdepth 1 -type d -printf '%f\n')
readarray -t UPDATER_BUILD_DIRS < <(find "${UPDATER_SELECTOR}" -mindepth 1 -maxdepth 1 -type d -printf '%f\n')

mkdir -p "${SRMM_OUTPUT_DIR}"
mkdir -p "${UPDATER_OUTPUT_DIR}"

for TARGET in "${SRMM_BUILD_DIRS[@]}"; do
DIR="${SRMM_SELECTOR}/${TARGET}"
OUTPUT_TARGET_STR=$(echo "${TARGET}" | sed -e "s/\b\(.\)/\u\1/g") # Capitalizes each target word: linux-slim -> Linux-Slim
OUTPUT_FILE_BASE="${SRMM_BASE_NAME}-${OUTPUT_TARGET_STR}-${SRMM_VERSION}"

echo "Compressing ${OUTPUT_FILE_BASE}..."

7za a "${SRMM_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.zip" -tzip -bd -y "${DIR}/*" > /dev/null
tar czf "${SRMM_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.tar.gz" --owner=0 --group=0 --numeric-owner -C "${DIR}/" .

### Create Appcast

# Really hate how this is done, but I can't think of anything better
if [[ "${OUTPUT_FILE_BASE}" =~ -Linux- ]]; then
OS_NAME="linux"
EXEC_NAME="${SRMM_BASE_NAME}"
elif [[ "${OUTPUT_FILE_BASE}" =~ -Windows- ]]; then
OS_NAME="windows"
EXEC_NAME="ShinRyuModManager.exe"
fi

# Create only for .zip, as that's universally available
netsparkle-generate-appcast \
-a "${APPCAST_OUTPUT_DIR}" \
--single-file "${SRMM_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.zip" \
-o "${OS_NAME}" \
-n "${EXEC_NAME}" \
--output-file-name "appcast_${TARGET}" \
--use-ed25519-signature-attribute \
--human-readable \
--file-version "${SRMM_VERSION}-${TARGET}" \
-u "${SRMM_URL_BASE}${SRMM_VERSION}/" > /dev/null
done

for TARGET in "${UPDATER_BUILD_DIRS[@]}"; do
DIR="${UPDATER_SELECTOR}/${TARGET}"
OUTPUT_TARGET_STR=$(echo "${TARGET}" | sed -e "s/\b\(.\)/\u\1/g") # Capitalizes each target word: linux-slim -> Linux-Slim
OUTPUT_FILE_BASE="${UPDATER_BASE_NAME}-${OUTPUT_TARGET_STR}-Latest"

echo "Compressing ${OUTPUT_FILE_BASE}..."

7za a "${UPDATER_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.zip" -tzip -bd -y "${DIR}/*" > /dev/null
tar czf "${UPDATER_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.tar.gz" --owner=0 --group=0 --numeric-owner -C "${DIR}/" .

cp -r "${UPDATER_OUTPUT_DIR}/." $GITHUB_WORKSPACE/AppcastRepo/updater/

### Create Appcast

# Really hate how this is done, but I can't think of anything better
if [[ "${OUTPUT_FILE_BASE}" =~ -Linux- ]]; then
OS_NAME="linux"
EXEC_NAME="${UPDATER_BASE_NAME}"
elif [[ "${OUTPUT_FILE_BASE}" =~ -Windows- ]]; then
OS_NAME="windows"
EXEC_NAME="${UPDATER_BASE_NAME}.exe"
fi

# Create only for .zip, as that's universally available
netsparkle-generate-appcast \
-a "${APPCAST_OUTPUT_DIR}" \
--single-file "${UPDATER_OUTPUT_DIR}/${OUTPUT_FILE_BASE}.zip" \
-o "${OS_NAME}" \
-n "${EXEC_NAME}" \
--output-file-name "appcast_ryuupdater-${TARGET}" \
--use-ed25519-signature-attribute \
--human-readable \
--file-version "${SRMM_VERSION}" \
-u "${UPDATER_URL_BASE}" > /dev/null
done

### Copy AppCasts to repo

cp -r "${APPCAST_OUTPUT_DIR}/." $GITHUB_WORKSPACE/AppcastRepo/releases/
3 changes: 3 additions & 0 deletions ShinRyuModManager-CE/BuildAssets/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The slim version requires .NET 10.0 runtime to be installed on the machine.

https://dotnet.microsoft.com/en-us/download/dotnet/10.0
4 changes: 4 additions & 0 deletions ShinRyuModManager-CE/ShinRyuModManager-CE.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@
</Compile>
</ItemGroup>

<ItemGroup Condition="'$(SelfContained)' == 'false'">
<None Update="BuildAssets\README" Link="README" CopyToOutputDirectory="Always" />
</ItemGroup>

</Project>
Loading