Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci(gh-actions): upgrade release workflow #2043

Closed
wants to merge 2 commits into from
Closed
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
14 changes: 13 additions & 1 deletion .github/bin/constants.sh
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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
40 changes: 40 additions & 0 deletions .github/bin/dist-nuget.sh
Original file line number Diff line number Diff line change
@@ -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
86 changes: 73 additions & 13 deletions .github/bin/dist-pack.sh
Original file line number Diff line number Diff line change
@@ -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
38 changes: 37 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ name: release

on:
push:
branches:
- "main"
- "development"
tags:
- v*
- "*"

jobs:
release:
Expand All @@ -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 }}
1 change: 1 addition & 0 deletions Lib9c/Lib9c.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<IntermediateOutputPath>.obj</IntermediateOutputPath>
<RootNamespace>Nekoyume</RootNamespace>
<LangVersion>8</LangVersion>
<VersionPrefix>0.4.0</VersionPrefix>
<EnableDynamicLoading>true</EnableDynamicLoading>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
Expand Down
6 changes: 6 additions & 0 deletions scripts/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[*.js]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
max_line_length = 80
144 changes: 144 additions & 0 deletions scripts/determine-version.js
Original file line number Diff line number Diff line change
@@ -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 = /<VersionPrefix>([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();
Loading