mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 23:27:34 +01:00
[MIRROR] Update some TGS stuff [MDB IGNORE] (#19485)
* Update some TGS stuff * You're welcome Cyber --------- Co-authored-by: Jordan Dominion <Cyberboss@users.noreply.github.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
co-authored by
Jordan Dominion
GoldenAlpharex
parent
b047ad0ad8
commit
710319fced
+3
-7
@@ -203,13 +203,9 @@ Temporary Items
|
||||
!/config/title_screens/images/exclude
|
||||
|
||||
#Linux docker
|
||||
/tools/LinuxOneShot/SetupProgram/obj/*
|
||||
/tools/LinuxOneShot/SetupProgram/bin/*
|
||||
/tools/LinuxOneShot/SetupProgram/.vs
|
||||
/tools/LinuxOneShot/Database
|
||||
/tools/LinuxOneShot/TGS_Config
|
||||
/tools/LinuxOneShot/TGS_Instances
|
||||
/tools/LinuxOneShot/TGS_Logs
|
||||
/tools/tgs_test/.vs/*
|
||||
/tools/tgs_test/bin/*
|
||||
/tools/tgs_test/obj/*
|
||||
|
||||
# Autowiki
|
||||
/tools/autowiki/node_modules
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
version: 1
|
||||
byond: 514.1588
|
||||
static_files:
|
||||
- name: config
|
||||
populate: true
|
||||
- name: data
|
||||
linux_scripts:
|
||||
PreCompile.sh: tools/tgs_scripts/PreCompile.sh
|
||||
WatchdogLaunch.sh: tools/tgs_scripts/WatchdogLaunch.sh
|
||||
InstallDeps.sh: tools/tgs_scripts/InstallDeps.sh
|
||||
windows_scripts:
|
||||
PreCompile.bat: tools/tgs_scripts/PreCompile.bat
|
||||
security: Trusted
|
||||
@@ -1,8 +0,0 @@
|
||||
static_files:
|
||||
- name: config
|
||||
populate: true
|
||||
- name: data
|
||||
linux_scripts:
|
||||
PreCompile.sh: tools/tgs4_scripts/PreCompile.sh
|
||||
windows_scripts:
|
||||
PreCompile.bat: tools/tgs4_scripts/PreCompile.bat
|
||||
@@ -138,7 +138,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
if (. == 1) //We were able to create a new master
|
||||
master_iteration = 0
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("Failsafe recovered MC while in emergency state [defcon_pretty()]"))
|
||||
else
|
||||
log_game("FailSafe: Failsafe in emergency state and was unable to recreate MC while in defcon state [defcon_pretty()].")
|
||||
@@ -154,7 +154,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
. = Recreate_MC()
|
||||
if (. == 1) //We were able to create a new master
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after recovering all subsystems!"))
|
||||
else
|
||||
message_admins(span_boldannounce("Failed to create new MC!"))
|
||||
@@ -168,7 +168,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
. = Recreate_MC()
|
||||
if (. == 1) //We were able to create a new master
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after deleting and recreating all subsystems!"))
|
||||
else
|
||||
message_admins(span_boldannounce("Failed to create new MC!"))
|
||||
|
||||
@@ -205,7 +205,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
StartProcessing(10)
|
||||
else
|
||||
to_chat(world, span_boldannounce("The Master Controller is having some issues, we will need to re-initialize EVERYTHING"))
|
||||
Initialize(20, TRUE)
|
||||
Initialize(20, TRUE, FALSE)
|
||||
|
||||
// Please don't stuff random bullshit here,
|
||||
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# REPO MAINTAINERS: KEEP CHANGES TO THIS IN SYNC WITH /tools/LinuxOneShot/SetupProgram/PreCompile.sh
|
||||
# No ~mso
|
||||
set -e
|
||||
set -x
|
||||
|
||||
#load dep exports
|
||||
#need to switch to game dir for Dockerfile weirdness
|
||||
original_dir=$PWD
|
||||
cd "$1"
|
||||
. dependencies.sh
|
||||
cd "$original_dir"
|
||||
|
||||
#find out what we have (+e is important for this)
|
||||
set +e
|
||||
has_git="$(command -v git)"
|
||||
has_cargo="$(command -v ~/.cargo/bin/cargo)"
|
||||
has_sudo="$(command -v sudo)"
|
||||
has_grep="$(command -v grep)"
|
||||
has_youtubedl="$(command -v youtube-dl)"
|
||||
has_pip3="$(command -v pip3)"
|
||||
set -e
|
||||
|
||||
# install cargo if needed
|
||||
if ! [ -x "$has_cargo" ]; then
|
||||
echo "Installing rust..."
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
. ~/.profile
|
||||
fi
|
||||
|
||||
# apt packages, libssl needed by rust-g but not included in TGS barebones install
|
||||
if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
|
||||
echo "Installing apt dependencies..."
|
||||
if ! [ -x "$has_sudo" ]; then
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
apt-get install -y git libssl-dev:i386
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
else
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git libssl-dev:i386
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
fi
|
||||
fi
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
apt-get install -y lib32z1 pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386
|
||||
# update rust-g
|
||||
if [ ! -d "rust-g" ]; then
|
||||
echo "Cloning rust-g..."
|
||||
git clone https://github.com/tgstation/rust-g
|
||||
cd rust-g
|
||||
~/.cargo/bin/rustup target add i686-unknown-linux-gnu
|
||||
else
|
||||
echo "Fetching rust-g..."
|
||||
cd rust-g
|
||||
git fetch
|
||||
~/.cargo/bin/rustup target add i686-unknown-linux-gnu
|
||||
fi
|
||||
|
||||
echo "Deploying rust-g..."
|
||||
git checkout "$RUST_G_VERSION"
|
||||
env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --target=i686-unknown-linux-gnu
|
||||
mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so"
|
||||
cd ..
|
||||
|
||||
# install or update youtube-dl when not present, or if it is present with pip3,
|
||||
# which we assume was used to install it
|
||||
if ! [ -x "$has_youtubedl" ]; then
|
||||
echo "Installing youtube-dl with pip3..."
|
||||
if ! [ -x "$has_sudo" ]; then
|
||||
apt-get install -y python3 python3-pip
|
||||
else
|
||||
sudo apt-get install -y python3 python3-pip
|
||||
fi
|
||||
pip3 install youtube-dl
|
||||
elif [ -x "$has_pip3" ]; then
|
||||
echo "Ensuring youtube-dl is up-to-date with pip3..."
|
||||
pip3 install youtube-dl -U
|
||||
fi
|
||||
|
||||
# compile tgui
|
||||
echo "Compiling tgui..."
|
||||
cd "$1"
|
||||
chmod +x tools/bootstrap/node # Workaround for https://github.com/tgstation/tgstation-server/issues/1167
|
||||
env TG_BOOTSTRAP_CACHE="$original_dir" TG_BOOTSTRAP_NODE_LINUX=1 CBT_BUILD_MODE="TGS" tools/bootstrap/node tools/build/build.js
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
has_python="$(command -v python3)"
|
||||
has_git="$(command -v git)"
|
||||
has_sudo="$(command -v sudo)"
|
||||
has_pip="$(command -v pip3)"
|
||||
|
||||
set -e
|
||||
|
||||
if ! { [ -x "$has_python" ] && [ -x "$has_pip" ] && [ -x "$has_git" ]; }; then
|
||||
echo "Installing apt dependencies..."
|
||||
if ! [ -x "$has_sudo" ]; then
|
||||
apt update
|
||||
apt install -y python3 python3-pip git
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
else
|
||||
sudo apt update
|
||||
sudo apt install -y python3 python3-pip git
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing pip dependencies..."
|
||||
pip3 install PyYaml beautifulsoup4
|
||||
|
||||
cd $1
|
||||
|
||||
echo "Running changelog script..."
|
||||
python3 tools/ss13_genchangelog.py html/changelogs
|
||||
|
||||
echo "Committing changes..."
|
||||
git add html
|
||||
|
||||
#we now don't care about failures
|
||||
set +e
|
||||
git commit -m "Automatic changelog compile, [ci skip]"
|
||||
exit 0
|
||||
Regular → Executable
+19
-11
@@ -1,19 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Special file to ensure all dependencies still exist between server lanuches.
|
||||
# Mainly for use by people who abuse docker by modifying the container's system.
|
||||
set -e
|
||||
set -x
|
||||
|
||||
#find out what we have (+e is important for this)
|
||||
set +e
|
||||
has_git="$(command -v git)"
|
||||
has_cargo="$(command -v ~/.cargo/bin/cargo)"
|
||||
has_sudo="$(command -v sudo)"
|
||||
has_grep="$(command -v grep)"
|
||||
has_youtubedl="$(command -v youtube-dl)"
|
||||
has_pip3="$(command -v pip3)"
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# install cargo if needed
|
||||
if ! [ -x "$has_cargo" ]; then
|
||||
@@ -23,19 +18,32 @@ if ! [ -x "$has_cargo" ]; then
|
||||
fi
|
||||
|
||||
# apt packages, libssl needed by rust-g but not included in TGS barebones install
|
||||
if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386
|
||||
if ! ( [ -x "$has_git" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
|
||||
echo "Installing apt dependencies..."
|
||||
if ! [ -x "$has_sudo" ]; then
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386
|
||||
else
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386
|
||||
fi
|
||||
fi
|
||||
|
||||
# install youtube-dl when not present
|
||||
# install or update youtube-dl when not present, or if it is present with pip3,
|
||||
# which we assume was used to install it
|
||||
if ! [ -x "$has_youtubedl" ]; then
|
||||
echo "Installing youtube-dl with pip3..."
|
||||
if ! [ -x "$has_sudo" ]; then
|
||||
apt-get update
|
||||
apt-get install -y python3 python3-pip
|
||||
else
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y python3 python3-pip
|
||||
fi
|
||||
pip3 install youtube-dl
|
||||
elif [ -x "$has_pip3" ]; then
|
||||
echo "Ensuring youtube-dl is up-to-date with pip3..."
|
||||
pip3 install youtube-dl -U
|
||||
fi
|
||||
@@ -2,7 +2,7 @@
|
||||
cd /D "%~dp0"
|
||||
set TG_BOOTSTRAP_CACHE=%cd%
|
||||
IF NOT %1 == "" (
|
||||
rem TGS4: we are passed the game directory on the command line
|
||||
rem TGS4+: we are passed the game directory on the command line
|
||||
cd %1
|
||||
) ELSE IF EXIST "..\Game\B\tgstation.dmb" (
|
||||
rem TGS3: Game/B/tgstation.dmb exists, so build in Game/A
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
./InstallDeps.sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
#load dep exports
|
||||
#need to switch to game dir for Dockerfile weirdness
|
||||
original_dir=$PWD
|
||||
cd "$1"
|
||||
. dependencies.sh
|
||||
cd "$original_dir"
|
||||
|
||||
# update rust-g
|
||||
if [ ! -d "rust-g" ]; then
|
||||
echo "Cloning rust-g..."
|
||||
git clone https://github.com/tgstation/rust-g
|
||||
cd rust-g
|
||||
~/.cargo/bin/rustup target add i686-unknown-linux-gnu
|
||||
else
|
||||
echo "Fetching rust-g..."
|
||||
cd rust-g
|
||||
git fetch
|
||||
~/.cargo/bin/rustup target add i686-unknown-linux-gnu
|
||||
fi
|
||||
|
||||
echo "Deploying rust-g..."
|
||||
git checkout "$RUST_G_VERSION"
|
||||
env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --target=i686-unknown-linux-gnu
|
||||
mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so"
|
||||
cd ..
|
||||
|
||||
# compile tgui
|
||||
echo "Compiling tgui..."
|
||||
cd "$1"
|
||||
chmod +x tools/bootstrap/node # Workaround for https://github.com/tgstation/tgstation-server/issues/1167
|
||||
env TG_BOOTSTRAP_CACHE="$original_dir" TG_BOOTSTRAP_NODE_LINUX=1 CBT_BUILD_MODE="TGS" tools/bootstrap/node tools/build/build.js
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Special file to ensure all dependencies still exist between server launches.
|
||||
# Mainly for use by people who abuse docker by modifying the container's system.
|
||||
|
||||
./InstallDeps.sh
|
||||
@@ -0,0 +1,334 @@
|
||||
// Simple app meant to test tgstation's TGS integration given a fresh TGS install with the default account
|
||||
//
|
||||
// Args: Repository Owner/Name, TGS instance path, TGS API port, Pushed commit hash (For .tgs.yml access), GitHub Token
|
||||
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
using Octokit;
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Client;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
Console.WriteLine("Parsing args...");
|
||||
|
||||
const int ExpectedArgs = 5;
|
||||
if (args.Length != ExpectedArgs)
|
||||
{
|
||||
Console.WriteLine($"Incorrect number of args: {args.Length}. Expected {ExpectedArgs}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var repoSlug = args[0];
|
||||
var instancePath = args[1];
|
||||
var tgsApiPortString = args[2];
|
||||
var pushedCommitHash = args[3];
|
||||
var gitHubToken = args[4];
|
||||
|
||||
var repoSlugSplits = repoSlug.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
if(repoSlugSplits.Length != 2)
|
||||
{
|
||||
Console.WriteLine($"Invalid repo slug: {repoSlug}");
|
||||
return 2;
|
||||
}
|
||||
|
||||
var repoOwner = repoSlugSplits[0];
|
||||
var repoName = repoSlugSplits[1];
|
||||
|
||||
if (!ushort.TryParse(tgsApiPortString, out var tgsApiPort))
|
||||
{
|
||||
Console.WriteLine($"Invalid port: {tgsApiPortString}");
|
||||
return 3;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Retrieving .tgs.yml (@{pushedCommitHash})...");
|
||||
var assemblyName = Assembly.GetExecutingAssembly().GetName();
|
||||
var gitHubClient = new GitHubClient(
|
||||
new ProductHeaderValue(
|
||||
assemblyName.Name,
|
||||
assemblyName.Version!.Semver().ToString()))
|
||||
{
|
||||
Credentials = new Credentials(gitHubToken)
|
||||
};
|
||||
|
||||
var tgsYmlContent = await gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, ".tgs.yml", pushedCommitHash);
|
||||
var tgsYmlString = Encoding.UTF8.GetString(tgsYmlContent);
|
||||
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(new UnderscoredNamingConvention())
|
||||
.Build();
|
||||
|
||||
var tgsYml = deserializer.Deserialize<TgsYml>(tgsYmlString);
|
||||
|
||||
const int SupportedTgsYmlVersion = 1;
|
||||
if (tgsYml.Version != SupportedTgsYmlVersion)
|
||||
{
|
||||
Console.WriteLine($"Unsupported .tgs.yml version: {tgsYml.Version}. Expected {SupportedTgsYmlVersion}");
|
||||
return 4;
|
||||
}
|
||||
|
||||
var targetByondVersion = Version.Parse(tgsYml.Byond);
|
||||
|
||||
Console.WriteLine($".tgs.yml Security level: {tgsYml.Security}");
|
||||
|
||||
Console.WriteLine("Downloading and checking BYOND version in dependencies.sh...");
|
||||
var dependenciesShContent = await gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, "dependencies.sh", pushedCommitHash);
|
||||
var dependenciesSh = Encoding.UTF8.GetString(dependenciesShContent);
|
||||
var dependenciesShLines = dependenciesSh.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
int dependenciesShByondMajor = 0;
|
||||
int dependenciesShByondMinor = 0;
|
||||
foreach(var dependenciesShLine in dependenciesShLines)
|
||||
{
|
||||
var trimmedLine = dependenciesShLine.Trim();
|
||||
var lineSplit = trimmedLine.Split('=', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (lineSplit.Length != 2)
|
||||
continue;
|
||||
|
||||
if (lineSplit[0].EndsWith("BYOND_MAJOR"))
|
||||
dependenciesShByondMajor = Int32.Parse(lineSplit[1]);
|
||||
else if (lineSplit[0].EndsWith("BYOND_MINOR"))
|
||||
dependenciesShByondMinor = Int32.Parse(lineSplit[1]);
|
||||
}
|
||||
|
||||
var dependenciesByondVersion = new Version(dependenciesShByondMajor, dependenciesShByondMinor);
|
||||
if(dependenciesByondVersion != targetByondVersion)
|
||||
{
|
||||
Console.WriteLine($".tgs.yml BYOND version does not match dependencies.sh! Expected {dependenciesByondVersion} got {targetByondVersion}!");
|
||||
return 5;
|
||||
}
|
||||
|
||||
// Connect to TGS
|
||||
var clientFactory = new ServerClientFactory(
|
||||
new System.Net.Http.Headers.ProductHeaderValue(
|
||||
assemblyName.Name!,
|
||||
assemblyName.Version!.Semver().ToString()));
|
||||
|
||||
var tgsApiUrl = new Uri($"http://127.0.0.1:{tgsApiPort}");
|
||||
var giveUpAt = DateTimeOffset.UtcNow.AddMinutes(2);
|
||||
IServerClient client;
|
||||
for (var I = 1; ; ++I)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"TGS Connection Attempt {I}...");
|
||||
client = await clientFactory.CreateFromLogin(
|
||||
tgsApiUrl,
|
||||
DefaultCredentials.AdminUserName,
|
||||
DefaultCredentials.DefaultAdminUserPassword);
|
||||
break;
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
//migrating, to be expected
|
||||
if (DateTimeOffset.UtcNow > giveUpAt)
|
||||
throw;
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
catch (ServiceUnavailableException)
|
||||
{
|
||||
// migrating, to be expected
|
||||
if (DateTimeOffset.UtcNow > giveUpAt)
|
||||
throw;
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Console.WriteLine("Getting TGS information...");
|
||||
|
||||
var tgsInfo = await client.ServerInformation(default);
|
||||
|
||||
var scriptDictionaryToUse = tgsInfo.WindowsHost ? tgsYml.WindowsScripts : tgsYml.LinuxScripts;
|
||||
Console.WriteLine($"Downloading {scriptDictionaryToUse.Count} EventScripts...");
|
||||
|
||||
var scriptDownloadTasks = new Dictionary<string, Task<byte[]>>();
|
||||
foreach (var scriptKvp in scriptDictionaryToUse)
|
||||
{
|
||||
scriptDownloadTasks.Add(
|
||||
scriptKvp.Key,
|
||||
gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, scriptKvp.Value, pushedCommitHash));
|
||||
}
|
||||
|
||||
await Task.WhenAll(scriptDownloadTasks.Values);
|
||||
|
||||
Console.WriteLine("Setting up TGS instance...");
|
||||
|
||||
var instance = await client.Instances.CreateOrAttach(
|
||||
new InstanceCreateRequest
|
||||
{
|
||||
ConfigurationType = ConfigurationType.HostWrite,
|
||||
Name = "tgstation",
|
||||
Path = instancePath
|
||||
},
|
||||
default);
|
||||
|
||||
instance = await client.Instances.Update(
|
||||
new InstanceUpdateRequest
|
||||
{
|
||||
Id = instance.Id,
|
||||
Online = true
|
||||
},
|
||||
default);
|
||||
|
||||
var instanceClient = client.Instances.CreateClient(instance);
|
||||
|
||||
Console.WriteLine("Cloning main branch of repo...");
|
||||
var repoCloneJob = await instanceClient.Repository.Clone(
|
||||
new RepositoryCreateRequest
|
||||
{
|
||||
Origin = new Uri($"http://github.com/{repoSlug}"),
|
||||
UpdateSubmodules = true,
|
||||
AccessUser = "Testing",
|
||||
AccessToken = gitHubToken
|
||||
},
|
||||
default);
|
||||
|
||||
Console.WriteLine("Installing BYOND...");
|
||||
var byondInstallJob = await instanceClient.Byond.SetActiveVersion(
|
||||
new ByondVersionRequest
|
||||
{
|
||||
Version = targetByondVersion
|
||||
},
|
||||
null,
|
||||
default);
|
||||
|
||||
Console.WriteLine("Updating server/compiler settings...");
|
||||
await instanceClient.DreamMaker.Update(
|
||||
new DreamMakerRequest
|
||||
{
|
||||
ApiValidationSecurityLevel = tgsYml.Security
|
||||
},
|
||||
default);
|
||||
|
||||
await instanceClient.DreamDaemon.Update(
|
||||
new DreamDaemonRequest
|
||||
{
|
||||
SecurityLevel = tgsYml.Security,
|
||||
Visibility = DreamDaemonVisibility.Invisible
|
||||
},
|
||||
default);
|
||||
|
||||
Console.WriteLine("Uploading EventScripts...");
|
||||
var configurationUploadTasks = new List<Task<ConfigurationFileResponse>>();
|
||||
foreach (var scriptDownloadKvp in scriptDownloadTasks)
|
||||
{
|
||||
var scriptContent = await scriptDownloadKvp.Value;
|
||||
|
||||
var memoryStream = new MemoryStream(scriptContent);
|
||||
configurationUploadTasks.Add(
|
||||
instanceClient.Configuration.Write(new ConfigurationFileRequest
|
||||
{
|
||||
Path = $"EventScripts/{scriptDownloadKvp.Key}"
|
||||
},
|
||||
memoryStream,
|
||||
default));
|
||||
}
|
||||
|
||||
await Task.WhenAll(configurationUploadTasks);
|
||||
|
||||
Console.WriteLine("Creating GameStaticFiles structure...");
|
||||
var staticFileDownloadTasks = new Dictionary<string, Dictionary<string, Task<byte[]>>>();
|
||||
foreach (var staticFile in tgsYml.StaticFiles)
|
||||
{
|
||||
if (!staticFile.Populate)
|
||||
{
|
||||
Console.WriteLine($"Creating empty directory GameStaticFiles/{staticFile.Name}...");
|
||||
await instanceClient.Configuration.CreateDirectory(new ConfigurationFileRequest
|
||||
{
|
||||
Path = $"GameStaticFiles/{staticFile.Name}"
|
||||
},
|
||||
default);
|
||||
}
|
||||
else
|
||||
{
|
||||
// not by ref here as we are relying on master being not broken
|
||||
Console.WriteLine($"Enumerating repo path {staticFile.Name}...");
|
||||
var repositoryFilesToUpload = new Queue<RepositoryContent>(await gitHubClient.Repository.Content.GetAllContents(repoOwner, repoName, staticFile.Name));
|
||||
while (repositoryFilesToUpload.Count != 0)
|
||||
{
|
||||
var repositoryFileToUpload = repositoryFilesToUpload.Dequeue();
|
||||
if (repositoryFileToUpload.Type == ContentType.File)
|
||||
{
|
||||
// serial because easier to track errors
|
||||
Console.WriteLine($"Transferring {repositoryFileToUpload.Path}...");
|
||||
var fileContent = await gitHubClient.Repository.Content.GetRawContent(repoOwner, repoName, repositoryFileToUpload.Path);
|
||||
using var memoryStream = new MemoryStream(fileContent);
|
||||
await instanceClient.Configuration.Write(new ConfigurationFileRequest
|
||||
{
|
||||
Path = $"GameStaticFiles/{repositoryFileToUpload.Path}"
|
||||
},
|
||||
memoryStream,
|
||||
default);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Enumerating repo path {repositoryFileToUpload.Path}...");
|
||||
var additionalFiles = await gitHubClient.Repository.Content.GetAllContents(repoOwner, repoName, repositoryFileToUpload.Path);
|
||||
foreach (var additionalFile in additionalFiles)
|
||||
repositoryFilesToUpload.Enqueue(additionalFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task<bool> WaitForJob(JobResponse originalJob, int timeout)
|
||||
{
|
||||
Console.WriteLine($"Waiting for job \"{originalJob.Description}\"...");
|
||||
var job = originalJob;
|
||||
var previousProgress = job.Progress;
|
||||
do
|
||||
{
|
||||
if (job.Progress != previousProgress)
|
||||
Console.WriteLine($"Progress: {previousProgress = job.Progress}");
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
job = await instanceClient!.Jobs.GetId(job, default);
|
||||
--timeout;
|
||||
}
|
||||
while (!job.StoppedAt.HasValue && timeout > 0);
|
||||
|
||||
if (!job.StoppedAt.HasValue)
|
||||
{
|
||||
await instanceClient!.Jobs.Cancel(job, default);
|
||||
Console.WriteLine($"Timed out!");
|
||||
return false;
|
||||
}
|
||||
else if (job.ExceptionDetails != null)
|
||||
{
|
||||
Console.WriteLine($"Error: {job.ExceptionDetails}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!await WaitForJob(byondInstallJob.InstallJob!, 120))
|
||||
return 6;
|
||||
|
||||
if (!await WaitForJob(repoCloneJob.ActiveJob!, 600))
|
||||
return 7;
|
||||
|
||||
Console.WriteLine("Deploying...");
|
||||
var deploymentJob = await instanceClient.DreamMaker.Compile(default);
|
||||
if (!await WaitForJob(deploymentJob, 1800))
|
||||
return 8;
|
||||
|
||||
Console.WriteLine("Launching...");
|
||||
var launchJob = await instanceClient.DreamDaemon.Start(default);
|
||||
if (!await WaitForJob(launchJob, 300))
|
||||
return 9;
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
return 4;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# TGS Test Script
|
||||
|
||||
This is a simple app that does a few things
|
||||
|
||||
- Downloads .tgs.yml information from a specific commit of a given repository.
|
||||
- Checks that the BYOND version in the .tgs.yml file matches the dependencies.sh version.
|
||||
- Connects to a TGS instance via command line parameters.
|
||||
- Uses the .tgs.yml information to automatically set up a TGS instance.
|
||||
- Runs a TGS deploy/launch and validates that they succeeded.
|
||||
|
||||
Look for its invocation in the GitHub workflows
|
||||
@@ -0,0 +1,5 @@
|
||||
sealed class StaticFile
|
||||
{
|
||||
public string Name { get; set; } = String.Empty;
|
||||
public bool Populate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Tgstation.Server.Api.Models;
|
||||
|
||||
sealed class TgsYml
|
||||
{
|
||||
public int Version { get; set; }
|
||||
|
||||
public string Byond { get; set; } = String.Empty;
|
||||
|
||||
public List<StaticFile> StaticFiles { get; set; } = new List<StaticFile>();
|
||||
|
||||
public Dictionary<string, string> WindowsScripts { get; set; } = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> LinuxScripts { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
public DreamDaemonSecurity Security { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.0.0</Version>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="5.0.0" />
|
||||
<PackageReference Include="Tgstation.Server.Client" Version="11.2.1" />
|
||||
<PackageReference Include="YamlDotNet.NetCore" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33213.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tgstation.TgsTest", "Tgstation.TgsTest.csproj", "{3146D745-AAE5-4205-8FF2-0CE471B47B4E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {001721B4-7740-419D-837E-26CE9DABCAB8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user