[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:
SkyratBot
2023-02-26 19:06:30 -05:00
committed by GitHub
co-authored by Jordan Dominion GoldenAlpharex
parent b047ad0ad8
commit 710319fced
17 changed files with 491 additions and 156 deletions
+3 -7
View File
@@ -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
+13
View File
@@ -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
-8
View File
@@ -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
+3 -3
View File
@@ -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!"))
+1 -1
View File
@@ -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()
-88
View File
@@ -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
-37
View File
@@ -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
+19 -11
View File
@@ -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
+38
View File
@@ -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
+6
View File
@@ -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
+334
View File
@@ -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;
}
+11
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
sealed class StaticFile
{
public string Name { get; set; } = String.Empty;
public bool Populate { get; set; }
}
+15
View File
@@ -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; }
}
+17
View File
@@ -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>
+25
View File
@@ -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