diff --git a/.github/bin/constants.sh b/.github/bin/constants.sh
index 6ea3a71055..f1e1fe402d 100755
--- a/.github/bin/constants.sh
+++ b/.github/bin/constants.sh
@@ -1,5 +1,15 @@
#!/bin/bash
+# shellcheck disable=SC2034
+solution="Lib9c"
+projects=(
+ "Lib9c"
+)
+configuration=Release
+executables=(
+ ".Lib9c.StateService"
+)
+
# https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
rids=(linux-x64 osx-x64 osx-arm64 win-x64)
@@ -8,7 +18,9 @@ rids=(linux-x64 osx-x64 osx-arm64 win-x64)
# shellcheck disable=SC2235
if [ "$GITHUB_REPOSITORY" = "planetarium/lib9c" ] && [[ \
"$GITHUB_REF" = refs/tags/* || \
- "$GITHUB_REF" = refs/heads/main
+ "$GITHUB_REF" = refs/heads/main || \
+ "$GITHUB_REF" = refs/heads/development || \
+ "$GITHUB_REF" = refs/heads/release/*
]]; then
publish_package=true
fi
diff --git a/.github/bin/dist-nuget.sh b/.github/bin/dist-nuget.sh
new file mode 100755
index 0000000000..38fb26f0df
--- /dev/null
+++ b/.github/bin/dist-nuget.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Submit .nupkg files to NuGet.
+# Note that this script is intended to be run by GitHub Actions.
+set -e
+
+# shellcheck source=constants.sh
+. "$(dirname "$0")/constants.sh"
+
+if [ ! -f obj/package_version.txt ]; then
+ {
+ echo "obj/package_version.txt file is missing."
+ echo "dist:version action must be run first."
+ } > /dev/stderr
+ exit 1
+fi
+
+if [ "$NUGET_API_KEY" = "" ]; then
+ echo "This script requires NUGET_API_KEY envrionment variable." > /dev/stderr
+ exit 1
+fi
+
+if [ "$publish_package" = "" ]; then
+ function dotnet-nuget {
+ echo "DRY-RUN: dotnet nuget" "$@"
+ }
+else
+ function dotnet-nuget {
+ dotnet nuget "$@"
+ }
+fi
+
+package_version="$(cat obj/package_version.txt)"
+
+for project in "${projects[@]}"; do
+ dotnet-nuget push \
+ "./$project/bin/$configuration/$project.$package_version.nupkg" \
+ --skip-duplicate \
+ --api-key "$NUGET_API_KEY" \
+ --source https://api.nuget.org/v3/index.json
+done
\ No newline at end of file
diff --git a/.github/bin/dist-pack.sh b/.github/bin/dist-pack.sh
index 08b55a3fd4..4efe01a093 100755
--- a/.github/bin/dist-pack.sh
+++ b/.github/bin/dist-pack.sh
@@ -1,27 +1,87 @@
#!/bin/bash
+# Build a .nupkg file.
+# Note that this script is intended to be run by GitHub Actions.
set -e
+# shellcheck source=constants.sh
. "$(dirname "$0")/constants.sh"
-for rid in "${rids[@]}"; do
- output_dir="./Release/$rid/"
- mkdir -p "$output_dir"
+if ! (env | grep '^GITHUB_'); then
+ echo "This script is intended to be run by GitHub Actions." > /dev/stderr
+ exit 1
+fi
- dotnet publish \
- -c Release \
- -r $rid \
- -o $output_dir \
- --self-contained \
- --version-suffix "$(git -C lib9c rev-parse HEAD)"
+version="$(cat obj/package_version.txt)" # e.g. 0.50.0-dev.20230221015836
+version_prefix="$(cat obj/version_prefix.txt)" # e.g. 0.50.0
+if [[ -f obj/version_suffix.txt ]]; then # e.g. dev.20230221015836+35a2dbc
+ version_suffix="$(cat obj/version_suffix.txt)"
+fi
- bin_name=lib9c
+for project in "${executables[@]}"; do
+ for rid in "${rids[@]}"; do
+ output_dir="./$project/bin/$configuration/$rid/"
+ mkdir -p "$output_dir"
+ dotnet publish \
+ --runtime "$rid" \
+ -p:PublishSingleFile=true \
+ --self-contained \
+ -p:Version="$version" \
+ --configuration "$configuration" \
+ --output "$output_dir" \
+ "$project" || \
+ if [[ "$?" = "139" ]]; then
+ # On GitHub Actions, `dotnet` command occasionally fails due to
+ # segfault.
+ dotnet publish \
+ --runtime "$rid" \
+ -p:PublishSingleFile=true \
+ --self-contained \
+ -p:Version="$version" \
+ --configuration "$configuration" \
+ --output "$output_dir" \
+ "$project"
+ else
+ exit 1
+ fi
+ bin_name="$(find "$output_dir" -type f -perm /o+x -exec basename {} \;)"
pushd "$output_dir"
-
if [[ "$rid" = win-* ]]; then
- zip -r9 "../${bin_name%.exe}-$rid.zip" ./*
+ zip -r9 "../${bin_name%.exe}-$version-$rid.zip" ./*
else
- tar cvfJ "../$bin_name-$rid.tar.xz" ./*
+ tar cvfJ "../$bin_name-$version-$rid.tar.xz" ./*
fi
popd
rm -rf "$output_dir"
+ done
+done
+
+for project in "${projects[@]}"; do
+ if [[ "$version_suffix" = "" ]]; then
+ dotnet_args="-p:Version=$version"
+ else
+ dotnet_args="-p:VersionPrefix=$version_prefix" \
+ dotnet_args="$dotnet_args --version-suffix=$version_suffix"
+ dotnet_args="$dotnet_args -p:NoPackageAnalysis=true"
+ fi
+ # shellcheck disable=SC2086
+ dotnet build -c "$configuration" $dotnet_args || \
+ if [[ "$?" = "139" ]]; then
+ # On GitHub Actions, `dotnet` command occasionally fails due to segfault.
+ dotnet build -c "$configuration" $dotnet_args
+ else
+ exit 1
+ fi
+ # shellcheck disable=SC2086
+ dotnet pack "$project" -c "$configuration" $dotnet_args || \
+ if [[ "$?" = "139" ]]; then
+ # On GitHub Actions, `dotnet` command occasionally fails due to segfault.
+ dotnet pack "$project" -c "$configuration" $dotnet_args
+ else
+ exit 1
+ fi
+
+ ls -al "./$project/bin/$configuration/"
+ if [ "$version" != "$version_prefix" ]; then
+ rm -f "./$project/bin/$configuration/$project.$version_prefix.nupkg"
+ fi
done
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 097bb1501e..07cc02b29b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -2,8 +2,11 @@ name: release
on:
push:
+ branches:
+ - "main"
+ - "development"
tags:
- - v*
+ - "*"
jobs:
release:
@@ -18,7 +21,40 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 'lts/*'
+ - id: determine-version
+ run: node scripts/determine-version.js
+ - shell: bash
+ run: |
+ mkdir -p obj
+ echo "$VERSION_PREFIX" > obj/version_prefix.txt
+ if [[ "$VERSION_SUFFIX" != "" ]]; then
+ echo "$VERSION_SUFFIX" > obj/version_suffix.txt
+ fi
+ echo "$PACKAGE_VERSION" > obj/package_version.txt
+ echo "$VERSION_TYPE" > obj/version_type.txt
+ env:
+ VERSION_PREFIX: ${{ steps.determine-version.outputs.version-prefix }}
+ VERSION_SUFFIX: ${{ steps.determine-version.outputs.version-suffix }}
+ PACKAGE_VERSION: ${{ steps.determine-version.outputs.package-version }}
+ VERSION_TYPE: ${{ steps.determine-version.outputs.version-type }}
- run: .github/bin/dist-pack.sh
+ - run: |
+ . .github/bin/constants.sh
+ mkdir -p /tmp/dist-bin/
+ for project in "${projects[@]}"; do
+ cp -r "$project/bin/$configuration"/* /tmp/dist-bin/
+ done
+ - uses: actions/upload-artifact@main
+ with:
+ name: dist-bin
+ path: /tmp/dist-bin/
- run: .github/bin/dist-github-release.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - if: env.NUGET_API_KEY != ''
+ run: .github/bin/dist-nuget.sh
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
diff --git a/Lib9c/Lib9c.csproj b/Lib9c/Lib9c.csproj
index 9fdfd5ab1d..9f1713b993 100644
--- a/Lib9c/Lib9c.csproj
+++ b/Lib9c/Lib9c.csproj
@@ -9,6 +9,7 @@
.obj
Nekoyume
8
+ 0.4.0
true
Debug;Release
AnyCPU
diff --git a/scripts/.editorconfig b/scripts/.editorconfig
new file mode 100644
index 0000000000..7690e84936
--- /dev/null
+++ b/scripts/.editorconfig
@@ -0,0 +1,6 @@
+[*.js]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+max_line_length = 80
diff --git a/scripts/determine-version.js b/scripts/determine-version.js
new file mode 100644
index 0000000000..b1dbf95c76
--- /dev/null
+++ b/scripts/determine-version.js
@@ -0,0 +1,144 @@
+#!/usr/bin/env node
+// This script is used to determine the version of the current build.
+// Intended to be run on CI, but can be run locally as well.
+const fs = require("node:fs").promises;
+const path = require("node:path");
+const util = require("node:util");
+const execFile = util.promisify(require("node:child_process").execFile);
+
+async function readVersionPrefix(xmlFile) {
+ // TODO: Use proper XML parser...
+ const xml = await fs.readFile(xmlFile, "utf8");
+ const pattern = /([0-9]+\.[0-9]+\.[0-9]+)<\/VersionPrefix>/g;
+ const match = pattern.exec(xml);
+ if (!match) {
+ throw new Error(`Could not determine version prefix from ${xmlFile}`);
+ }
+ return match[1];
+}
+
+async function getCommitHash() {
+ if (process.env.GITHUB_SHA) {
+ return process.env.GITHUB_SHA;
+ }
+ const { stdout } = await execFile("git", ["rev-parse", "HEAD"]);
+ return stdout.trim();
+}
+
+async function getCommitTimestamp() {
+ let timestamp;
+ if (process.env.GITHUB_EVENT_PATH) {
+ const event = JSON.parse(await fs.readFile(process.env.GITHUB_EVENT_PATH));
+ timestamp = event.head_commit.timestamp;
+ }
+ const { stdout } = await execFile("git", [
+ "show",
+ "--no-patch",
+ "--format=%cI",
+ "HEAD",
+ ]);
+ timestamp = stdout.trim();
+ if (timestamp) return new Date(timestamp);
+ return new Date();
+}
+
+async function getTag() {
+ if (process.env.GITHUB_REF_TYPE === "branch") return null;
+ if (process.env.GITHUB_REF_TYPE === "tag" && process.env.GITHUB_REF_NAME) {
+ return process.env.GITHUB_REF_NAME;
+ }
+ try {
+ const { stdout } = await execFile("git", [
+ "describe",
+ "--exact-match",
+ "--tags",
+ "HEAD",
+ ]);
+ } catch (e) {
+ return null;
+ }
+ const tag = stdout.trim();
+ if (tag) return tag;
+ return null;
+}
+
+function getScheduledJobDate() {
+ if (process.env.GITHUB_EVENT_NAME?.startsWith("schedule")) {
+ // TODO: Read the date from the event payload for determinism.
+ const now = new Date();
+ return `${now.getUTCFullYear()}${
+ now.getUTCMonth() + 1
+ }${now.getUTCDate()}}`;
+ }
+ return null;
+}
+
+async function main() {
+ const csprojPath = path.join(
+ path.dirname(__dirname),
+ "Lib9c",
+ "Lib9c.csproj",
+ );
+ const versionPrefix = await readVersionPrefix(csprojPath);
+ const scheduledJobDate = getScheduledJobDate();
+ const tag = await getTag();
+ const commitHash = (await getCommitHash()).substring(0, 7);
+ let packageVersion;
+ let versionSuffix;
+ let versionType;
+ if (scheduledJobDate != null) {
+ // Nightly
+ versionSuffix = `nightly.${scheduledJobDate}`;
+ packageVersion = `${versionPrefix}-${versionSuffix}`;
+ versionSuffix += `+${commitHash}`;
+ versionType = "nightly";
+ } else if (tag != null) {
+ // Release
+ if (tag !== versionPrefix) {
+ console.error(
+ `Git tag (${tag}) does not match VersionPrefix (${versionPrefix})`,
+ );
+ process.exit(1);
+ }
+ packageVersion = tag;
+ versionType = "stable";
+ } else {
+ // Dev
+ const timestamp = await getCommitTimestamp();
+ const ts = `${timestamp.getUTCFullYear()}${
+ timestamp.getUTCMonth() + 1
+ }${timestamp.getUTCDate()}${timestamp.getUTCHours()}${
+ timestamp.getUTCMinutes() + 0
+ }${timestamp.getUTCSeconds()}`;
+ versionSuffix = `dev.${ts}`;
+ packageVersion = `${versionPrefix}-${versionSuffix}`;
+ versionSuffix += `+${commitHash}`;
+ versionType = "dev";
+ }
+ console.error("VersionPrefix:", versionPrefix);
+ if (versionSuffix) console.error("VersionSuffix:", versionSuffix);
+ console.error("PackageVersion:", packageVersion);
+ console.error("VersionType:", versionType);
+ if (process.env.GITHUB_OUTPUT) {
+ // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files
+ await fs.appendFile(
+ process.env.GITHUB_OUTPUT,
+ `version-prefix=${versionPrefix}\n`,
+ );
+ if (versionSuffix)
+ await fs.appendFile(
+ process.env.GITHUB_OUTPUT,
+ `version-suffix=${versionSuffix}\n`,
+ );
+ await fs.appendFile(
+ process.env.GITHUB_OUTPUT,
+ `package-version=${packageVersion}\n`,
+ );
+ await fs.appendFile(
+ process.env.GITHUB_OUTPUT,
+ `version-type=${versionType}\n`,
+ );
+ }
+}
+
+main();