145 lines
7.5 KiB
YAML
145 lines
7.5 KiB
YAML
name: Publish inspection and optional packages
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
publish:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
env:
|
|
NUGET_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }}
|
|
NODE_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }}
|
|
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: '1'
|
|
DOTNET_CLI_TELEMETRY_OPTOUT: '1'
|
|
LD_LIBRARY_PATH: /opt/dotnet-libs/usr/lib/x86_64-linux-gnu
|
|
SSL_CERT_FILE: /opt/ca-certificates.crt
|
|
steps:
|
|
- name: Fetch exact workspace and required submodules
|
|
env:
|
|
RELEASE_SHA: ${{ gitea.sha }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
node --input-type=module <<'NODE'
|
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
import { execFileSync } from 'node:child_process';
|
|
const base = 'https://git.crash.work';
|
|
const sha = process.env.RELEASE_SHA;
|
|
if (!/^[a-f0-9]{40}$/.test(sha)) throw new Error('An exact commit is required');
|
|
async function fetchSource(repo, revision, destination) {
|
|
const response = await fetch(`${base}/ShrinkSDK/${repo}/archive/${revision}.tar.gz`);
|
|
if (!response.ok) throw new Error(`Cannot fetch ${repo}: ${response.status}`);
|
|
await writeFile('source.tar.gz', new Uint8Array(await response.arrayBuffer()));
|
|
await mkdir(destination, { recursive: true });
|
|
execFileSync('tar', ['-xzf', 'source.tar.gz', '--strip-components=1', '-C', destination]);
|
|
}
|
|
await fetchSource('Workspace', sha, 'release');
|
|
const response = await fetch(`${base}/api/v1/repos/ShrinkSDK/Workspace/git/trees/${sha}?recursive=true`);
|
|
if (!response.ok) throw new Error(`Cannot resolve submodules: ${response.status}`);
|
|
const tree = await response.json();
|
|
for (const repo of ['ShrinkShared.CodeGen', 'ShrinkNetwork']) {
|
|
const path = `Assets/Modules/${repo}`;
|
|
const entry = tree.tree.find(item => item.path === path && item.type === 'commit');
|
|
if (!entry) throw new Error(`Missing pinned submodule: ${path}`);
|
|
await fetchSource(repo, entry.sha, `release/${path}`);
|
|
}
|
|
NODE
|
|
|
|
- name: Install .NET 8 SDK
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
node --input-type=module <<'NODE'
|
|
import { writeFile } from 'node:fs/promises';
|
|
import { rootCertificates } from 'node:tls';
|
|
|
|
await writeFile('/opt/ca-certificates.crt', rootCertificates.join('\n'));
|
|
|
|
const metadataResponse = await fetch('https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/8.0/releases.json');
|
|
if (!metadataResponse.ok) throw new Error(`Release metadata download failed: ${metadataResponse.status}`);
|
|
const metadata = await metadataResponse.json();
|
|
const sdkVersion = metadata['latest-sdk'];
|
|
const release = metadata.releases.find(item => item.sdk?.version === sdkVersion);
|
|
const file = release?.sdk?.files?.find(item => item.rid === 'linux-x64' && item.name.endsWith('.tar.gz'));
|
|
if (!file) throw new Error(`Linux x64 SDK archive not found for ${sdkVersion}`);
|
|
const archiveResponse = await fetch(file.url);
|
|
if (!archiveResponse.ok) throw new Error(`SDK download failed: ${archiveResponse.status}`);
|
|
await writeFile('/tmp/dotnet-sdk.tar.gz', new Uint8Array(await archiveResponse.arrayBuffer()));
|
|
|
|
const poolUrl = 'https://deb.debian.org/debian-security/pool/updates/main/o/openssl/';
|
|
const poolResponse = await fetch(poolUrl);
|
|
if (!poolResponse.ok) throw new Error(`OpenSSL package index download failed: ${poolResponse.status}`);
|
|
const poolIndex = await poolResponse.text();
|
|
const packages = [...poolIndex.matchAll(/href="(libssl3_[^"]+_amd64\.deb)"/g)].map(match => match[1]).sort();
|
|
const packageName = packages.at(-1);
|
|
if (!packageName) throw new Error('Debian libssl3 package was not found');
|
|
const packageResponse = await fetch(poolUrl + packageName);
|
|
if (!packageResponse.ok) throw new Error(`OpenSSL package download failed: ${packageResponse.status}`);
|
|
await writeFile('/tmp/libssl3.deb', new Uint8Array(await packageResponse.arrayBuffer()));
|
|
NODE
|
|
mkdir -p /opt/dotnet
|
|
tar -xzf /tmp/dotnet-sdk.tar.gz -C /opt/dotnet
|
|
mkdir -p /opt/dotnet-libs
|
|
dpkg-deb -x /tmp/libssl3.deb /opt/dotnet-libs
|
|
rm -f /tmp/dotnet-sdk.tar.gz
|
|
rm -f /tmp/libssl3.deb
|
|
/opt/dotnet/dotnet --info
|
|
|
|
- name: Build supplemental NuGet packages
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
export PATH="/opt/dotnet:$PATH"
|
|
cd release
|
|
projects=(
|
|
Assets/ShrinkInspection/DotNet~/ShrinkSDK.Inspection.csproj
|
|
Assets/Modules/ShrinkNetwork/Adapters~/MessagePack/ShrinkSDK.Network.MessagePack.csproj
|
|
Tools/AgentSupport/Shrink.Inspect/Shrink.Inspect.csproj
|
|
)
|
|
for project in "${projects[@]}"; do
|
|
dotnet restore "$project" --configfile Assets/Modules/ShrinkNetwork/NuGet.Config
|
|
dotnet pack "$project" -c Release --no-restore -o "$PWD/packages"
|
|
done
|
|
|
|
- name: Publish NuGet and UPM packages
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
: "${NUGET_AUTH_TOKEN:?SHRINKSDK_PACKAGE_TOKEN is required}"
|
|
export PATH="/opt/dotnet:$PATH"
|
|
cd release
|
|
dotnet nuget push 'packages/*.nupkg' --api-key "$NUGET_AUTH_TOKEN" --source https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json --skip-duplicate
|
|
npmrc="$HOME/.npmrc"
|
|
trap 'rm -f "$npmrc"' EXIT
|
|
printf '%s\n' \
|
|
'registry=https://git.crash.work/api/packages/ShrinkSDK/npm/' \
|
|
'//git.crash.work/api/packages/ShrinkSDK/npm/:_authToken=${NODE_AUTH_TOKEN}' > "$npmrc"
|
|
for package in Assets/ShrinkInspection Assets/Modules/ShrinkNetwork/Adapters~/MessagePack; do
|
|
# Stage only Unity source and documentation; dotnet build output is not a UPM asset.
|
|
stage="$PWD/upm-$(basename "$package")"
|
|
mkdir "$stage"
|
|
cp "$package/package.json" "$package/README.md" "$stage/"
|
|
cp -r "$package/Runtime" "$stage/"
|
|
if [[ -d "$package/Editor" ]]; then cp -r "$package/Editor" "$stage/"; fi
|
|
find "$package" -maxdepth 1 -name '*.meta' -exec cp '{}' "$stage/" \;
|
|
name="$(node -p "require('./$package/package.json').name")"
|
|
version="$(node -p "require('./$package/package.json').version")"
|
|
export PACKAGE_NAME="$name" PACKAGE_VERSION="$version"
|
|
exists="$(node --input-type=module <<'NODE'
|
|
const url = `https://git.crash.work/api/packages/ShrinkSDK/npm/${encodeURIComponent(process.env.PACKAGE_NAME)}`;
|
|
const response = await fetch(url);
|
|
if (response.status === 404) console.log('no');
|
|
else {
|
|
if (!response.ok) throw new Error(`Registry lookup failed: ${response.status}`);
|
|
const metadata = await response.json();
|
|
console.log(metadata.versions?.[process.env.PACKAGE_VERSION] ? 'yes' : 'no');
|
|
}
|
|
NODE
|
|
)"
|
|
if [[ "$exists" = yes ]]; then echo "Already published: $name@$version"; continue; fi
|
|
(cd "$stage" && npm publish --registry=https://git.crash.work/api/packages/ShrinkSDK/npm/)
|
|
done
|