0
0
mirror of https://github.com/sp-tarkov/build.git synced 2025-02-12 14:30:46 -05:00

Build Scripts

Got to a point where the server and modules are being compiled correctly. Launcher script needs... something. It's failing to build and I don't know why.

TODO:
- Fix Launcher Build Script
- Combine sub-builds into output directory
- Compress output directory
- Upload release to public folder
- Adapt build script to work with a dynamic tag value
- Update script to only run _any_ builds when the tag exists in all three
- Write drone configuration version of the dockerfile/script
- Testing within the Drone env
This commit is contained in:
Refringe 2024-02-14 01:35:01 -05:00
commit 9ba230f190
No known key found for this signature in database
GPG Key ID: 64E03E5F892C6F9E
11 changed files with 521 additions and 0 deletions

20
.drone.yml Normal file
View File

@ -0,0 +1,20 @@
kind: pipeline
type: docker
name: windows-build
platform:
os: windows
arch: amd64
trigger:
event:
- tag
steps:
- name: build-and-package
image: mcr.microsoft.com/windows/servercore:ltsc2019
commands:
- powershell -File project/build-script.ps1
environment:
GITEA_TOKEN:
from_secret: gitea_token

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"[markdown]": {
"editor.defaultFormatter": null
}
}

31
Dockerfile Normal file
View File

@ -0,0 +1,31 @@
## This image is configured just as the drone runner image but expected to be run locally for
## rapid development and testing. It is not intended to be used in production.
# Start with the .NET 6.0 SDK Windows Server Core base image
FROM mcr.microsoft.com/dotnet/sdk:6.0-windowsservercore-ltsc2022
# Use PowerShell
SHELL ["powershell", "-Command"]
# Install Chocolatey package manager
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; \
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; \
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
# Use Chocolatey to install Node.js and Git
RUN choco install nodejs --version=20.10.0 -y
RUN choco install git -y
# Log Versions
RUN node --version
RUN npm --version
RUN git --version
# Copy build scripts into the container
COPY project/build.ps1 /Code/project/
COPY project/build_server.ps1 /Code/project/
COPY project/build_modules.ps1 /Code/project/
COPY project/build_launcher.ps1 /Code/project/
# Set the working directory to /Code
WORKDIR /Code

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Tyler Brownell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

86
README.md Normal file
View File

@ -0,0 +1,86 @@
# SPT Build Project - CI/CD Process
This document outlines the Continuous Integration and Continuous Deployment (CI/CD) setup for the `SPT-AKI/Build` project, which automates the build and release process for three interconnected repositories: `SPT-AKI/Modules`, `SPT-AKI/Server`, and `SPT-AKI/Launcher`. The process is orchestrated using Drone CI with Gitea and relies on a Windows Docker runner to execute PowerShell scripts for building and packaging the projects.
## Project Repositories
Each of the three project repositories (`SPT-AKI/Modules`, `SPT-AKI/Server`, `SPT-AKI/Launcher`) requires a `.drone.yml` file configured to trigger a build in this `SPT-AKI/Build` repository using the Drone downstream plugin upon a new tag push (e.g., `v3.8.0`). The contents of the `.drone.yml` file can be found in `project-trigger.yml`. Note that the file must be present and named `.drone.yml` to trigger the build process.
### Build Process
This repository's `.drone.yml` initiates the CI/CD process by running a PowerShell script `build.ps1` on a Windows Docker runner. The PowerShell script performs the following actions:
1. Checks if the passed in tag exists in all three project repositories.
1. Clones the tagged commits of each repository.
1. Builds each project.
1. Combines and compresses the build files into a release file.
1. Copies the release file to a web-accessible location.
1. Release notifications (creates a Gitea release, sends a Discord notification, etc.)
## Drone Runner Configuration
Drone CI Runner Requirements:
- Windows Server 2022 Host
- Docker Community Edition (CE)
### Install Docker CE
Docker CE needs to be installed (not Docker Desktop). The following steps outline the installation process for Windows Server 2022:
To install Docker CE on Windows Server 2022, follow these steps:
1. Open `Windows Server Manager`
1. Select `Manage`
1. Select `Add Roles and Features`
1. Click `Next` on the `Before You Begin` page
1. Select `Role-based or feature-based installation`
1. Select the name of the server where the feature will be installed and click `Next`
1. Select `Hyper-V` and click `Next`
1. Select `Containers` and click `Next`
1. Click `Install` on the `Confirm installation selections` page
1. Click `Close` on the `Installation progress` page
1. Open a PowerShell terminal (as admin) and run the following commands to install Docker CE:
```powershell
# Download install script
Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1" -o install-docker-ce.ps1
# Run install script
.\install-docker-ce.ps1
# Test Docker installation
Get-Service Docker
```
### Run the Runner
Use the command below to start the Drone CI Runner. But first...
- Replace the `DRONE_RPC_HOST` value with the host of the Drone server that should be connected to for builds.
- Replace the `DRONE_RPC_SECRET` value with the Drone server secret.
- Replace the `DRONE_RUNNER_NAME` value with a unique name for the runner.
- Replace the `DRONE_UI_PASSWORD` value with a password to access the web runner UI.
- Adjust `DRONE_RUNNER_CAPACITY` to the number of builds that should be allowed to run at once.
```powershell
docker run --detach --volume=//./pipe/docker_engine://./pipe/docker_engine --env=DRONE_RPC_PROTO=https --env=DRONE_RPC_HOST=example.com --env=DRONE_RPC_SECRET=secret --env=DRONE_RUNNER_CAPACITY=2 --env=DRONE_RUNNER_NAME=example --env=DRONE_UI_DISABLE=false --env=DRONE_UI_USERNAME=root --env=DRONE_UI_PASSWORD=password --publish=3000:3000 --restart=always --name=runner drone/drone-runner-docker:latest
```
## Module Requirements
To build the Modules project, a link to a private repository is required for the build process. The link is stored as a secret in the Drone CI/CD environment. The secret is named `MODULE_DOMAIN` and is used to download files from the private repository.
## Testing Build Process
To test the build process, the following commands can be used to build the Docker image and run the container on the Windows Server 2022 host. Be sure to replace the `MODULE_DOMAIN` environment variable with a valid value.
```powershell
# Clone the repository and move inside the project directory
git clone https://dev.sp-tarkov.com/SPT-AKI/Build.git C:\Code\Build
cd C:\Code\Build
# Build the Docker image
docker build -t spt-build-environment .
# Test the build process
docker run --rm -v "C:\Code\Build:C:\Code" -e MODULE_DOMAIN="https://example.com" spt-build-environment powershell -File C:\Code\project\build.ps1
```

12
build.code-workspace Normal file
View File

@ -0,0 +1,12 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"[markdown]": {
"editor.defaultFormatter": null
}
}
}

19
project-trigger.yml Normal file
View File

@ -0,0 +1,19 @@
kind: pipeline
type: docker
name: trigger-spt-build
trigger:
event:
- tag
steps:
- name: trigger-build-check
image: plugins/downstream
settings:
repositories:
- SPT-AKI/Build
server: https://drone.sp-tarkov.com
token:
from_secret: gitea_token
when:
event: tag

27
project/build.ps1 Normal file
View File

@ -0,0 +1,27 @@
Write-Output " » Beginning SPT Build Process"
# Check for required environment variables
if ([string]::IsNullOrWhiteSpace($env:MODULE_DOMAIN)) {
Write-Output " » FAIL: The MODULE_DOMAIN environment variable can not be empty."
exit 1 # Fail the build
}
$MODULE_DOMAIN = $env:MODULE_DOMAIN
# TODO: This is dynamic, based on the incoming commit information.
$RELEASE_TAG = "3.8.0-BE"
# TODO: Validate that the tag exists in all three repositories before continuing the build.
#$BEPINEX_RELEASE = "https://github.com/BepInEx/BepInEx/releases/download/v5.4.21/BepInEx_x64_5.4.21.0.zip"
$OUTPUT_DIR = ".\output"
if (Test-Path -Path $OUTPUT_DIR) {
Write-Output " » Removing Previous Output Directory"
Remove-Item -Recurse -Force $OUTPUT_DIR
}
# Build the projects
pwsh .\project\build_server.ps1 $RELEASE_TAG
pwsh .\project\build_modules.ps1 $RELEASE_TAG $MODULE_DOMAIN
pwsh .\project\build_launcher.ps1 $RELEASE_TAG

View File

@ -0,0 +1,62 @@
Param(
[Parameter(Mandatory = $true)]
[string] $RELEASE_TAG
)
Write-Output " » Building Launcher"
# Set directories
$DIR_ABS = (Get-Location).Path
$DIR = "$DIR_ABS\Launcher"
$DIR_PROJECT = "$DIR\project"
$DIR_BUILD = "$DIR_PROJECT\build"
# Remove the output folder if it already exists
if (Test-Path -Path $DIR) {
Write-Output " » Removing Previous Build Directory"
Remove-Item -Recurse -Force $DIR
}
# Pull down the server project, at the tag, with no history
Write-Output " » Cloning Launcher Project"
$REPO = "https://dev.sp-tarkov.com/SPT-AKI/Launcher.git"
try {
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
$processInfo.FileName = "git"
$processInfo.Arguments = "clone $REPO --branch $RELEASE_TAG --depth 1 `"$DIR`""
$processInfo.RedirectStandardError = $true
$processInfo.RedirectStandardOutput = $true
$processInfo.UseShellExecute = $false
$processInfo.CreateNoWindow = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processInfo
$process.Start() | Out-Null
$process.WaitForExit()
$stdout = $process.StandardOutput.ReadToEnd()
$stderr = $process.StandardError.ReadToEnd()
Write-Output $stdout
if ($process.ExitCode -ne 0) {
throw "git clone command failed with exit code $($process.ExitCode). Output: $stderr"
}
}
catch {
$errorMessage = " » FAIL: Error Executing git clone: $_"
Write-Error $errorMessage
exit 1 # Fail the build
}
# Create the any necessary subdirectories
New-Item -Path $DIR_BUILD -ItemType Directory -Force
Set-Location $DIR_PROJECT
Write-Output " » Installing .NET Dependencies"
dotnet restore
Write-Output " » Running Build Task"
dotnet build
Write-Output "⚡ Launcher Built ⚡"

148
project/build_modules.ps1 Normal file
View File

@ -0,0 +1,148 @@
Param(
[Parameter(Mandatory = $true)]
[string] $RELEASE_TAG,
[Parameter(Mandatory = $true)]
[string] $MODULE_DOMAIN
)
Write-Output " » Building Modules"
# Set directorys
$DIR_ABS = (Get-Location).Path
$DIR = "$DIR_ABS\Modules"
$DIR_PROJECT = "$DIR\project"
$DIR_BUILD = "$DIR_PROJECT\build"
$DIR_MANAGED = "$DIR_PROJECT\Shared\Managed"
# Remove the output folder if it already exists
if (Test-Path -Path $DIR) {
Write-Output " » Removing Previous Build Directory"
Remove-Item -Recurse -Force $DIR
}
# Pull down the server project, at the tag, with no history
Write-Output " » Cloning Modules Project"
$REPO = "https://dev.sp-tarkov.com/SPT-AKI/Modules.git"
try {
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
$processInfo.FileName = "git"
$processInfo.Arguments = "clone $REPO --branch $RELEASE_TAG --depth 1 `"$DIR`""
$processInfo.RedirectStandardError = $true
$processInfo.RedirectStandardOutput = $true
$processInfo.UseShellExecute = $false
$processInfo.CreateNoWindow = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processInfo
$process.Start() | Out-Null
$process.WaitForExit()
$stdout = $process.StandardOutput.ReadToEnd()
$stderr = $process.StandardError.ReadToEnd()
Write-Output $stdout
if ($process.ExitCode -ne 0) {
throw "git clone command failed with exit code $($process.ExitCode). Output: $stderr"
}
}
catch {
$errorMessage = " » FAIL: Error Executing git clone: $_"
Write-Error $errorMessage
exit 1 # Fail the build
}
# Create the any necessary subdirectories
New-Item -Path $DIR_BUILD -ItemType Directory -Force
New-Item -Path $DIR_MANAGED -ItemType Directory -Force
Set-Location $DIR
Write-Output " » Fetching Required Client Version"
$coreJsonPath = "$DIR_ABS\Server\project\build\Aki_Data\Server\configs\core.json"
if (-not (Test-Path -Path $coreJsonPath) -or (Get-Item -Path $coreJsonPath).Length -eq 0) {
Write-Output " » FAIL: core.json does not exist or is empty."
exit 1 # Fail the build
}
try {
# Attempt to read and parse the core.json file
$RELEASE_METADATA_RAW = Get-Content -Path $coreJsonPath -ErrorAction Stop
$RELEASE_METADATA = $RELEASE_METADATA_RAW | ConvertFrom-Json -ErrorAction Stop
$CLIENT_VERSION = $RELEASE_METADATA.compatibleTarkovVersion.Split('.') | Select-Object -Last 1
# Check if the $CLIENT_VERSION is valid
if ([string]::IsNullOrWhiteSpace($CLIENT_VERSION)) {
throw "Invalid or missing 'compatibleTarkovVersion' in core.json."
}
}
catch {
Write-Error " » FAIL: Error fetching or parsing core.json: $_"
exit 1 # Fail the build
}
Write-Output " » Client Version: $CLIENT_VERSION fetched successfully."
# Download the module files
Write-Output " » Downloading Client Modules"
$DOWNLOAD_PATH = "$DIR_MANAGED\$CLIENT_VERSION.zip"
$DOWNLOAD_URL = "$MODULE_DOMAIN/$CLIENT_VERSION.zip"
try {
Invoke-WebRequest -Uri $DOWNLOAD_URL -OutFile $DOWNLOAD_PATH -UseBasicParsing -ErrorAction Stop
if (-not (Test-Path -Path $DOWNLOAD_PATH) -or (Get-Item -Path $DOWNLOAD_PATH).Length -eq 0) {
throw "The module download does not exist or is empty."
}
}
catch {
Write-Error " » FAIL: Unable to download the module. Error: $_"
exit 1 # Fail the build
}
Write-Output " » Download successful: $DOWNLOAD_PATH"
Write-Output " » Extracting Client Modules"
try {
Expand-Archive -Path $DOWNLOAD_PATH -DestinationPath $DIR_MANAGED -Force -ErrorAction Stop
Write-Output " » Client Modules extracted to $DIR_MANAGED"
}
catch {
Write-Error " » FAIL: Error extracting client modules: $_"
exit 1 # Fail the build
}
# Delete the modules archive now that it's been uncompressed
try {
Remove-Item -Path $DOWNLOAD_PATH -Force -ErrorAction Stop
Write-Output " » Client Modules Archive Deleted"
}
catch {
Write-Warning " » Failed to delete ZIP file: $_"
exit 1 # Fail the build
}
Set-Location $DIR_PROJECT
Write-Output " » Installing .NET Dependencies"
try {
$restoreResult = dotnet restore
if ($LASTEXITCODE -ne 0) {
throw "dotnet restore failed with exit code $LASTEXITCODE"
}
Write-Output $restoreResult
}
catch {
Write-Error " » FAIL: Error executing dotnet restore: $_"
exit 1 # Fail the build
}
Write-Output " » Running Build Task"
try {
$buildResult = dotnet build
if ($LASTEXITCODE -ne 0) {
throw "dotnet build failed with exit code $LASTEXITCODE"
}
Write-Output $buildResult
}
catch {
Write-Error " » FAIL: Error executing dotnet build: $_"
exit 1 # Fail the build
}
Write-Output "⚡ Modules Built ⚡"

90
project/build_server.ps1 Normal file
View File

@ -0,0 +1,90 @@
Param(
[Parameter(Mandatory = $true)]
[string] $RELEASE_TAG
)
Write-Output " » Building Server"
# Set directorys
$DIR_ABS = (Get-Location).Path
$DIR = "$DIR_ABS\Server"
$DIR_PROJECT = "$DIR\project"
$DIR_BUILD = "$DIR_PROJECT\build"
# Remove the output folder if it already exists
if (Test-Path -Path $DIR) {
Write-Output " » Removing Previous Build Directory"
Remove-Item -Recurse -Force $DIR
}
# Pull down the server project, at the tag, with no history
Write-Output " » Cloning Server Project"
$REPO = "https://dev.sp-tarkov.com/SPT-AKI/Server.git"
try {
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
$processInfo.FileName = "git"
$processInfo.Arguments = "clone $REPO --branch $RELEASE_TAG --depth 1 `"$DIR`""
$processInfo.RedirectStandardError = $true
$processInfo.RedirectStandardOutput = $true
$processInfo.UseShellExecute = $false
$processInfo.CreateNoWindow = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processInfo
$process.Start() | Out-Null
$process.WaitForExit()
$stdout = $process.StandardOutput.ReadToEnd()
$stderr = $process.StandardError.ReadToEnd()
Write-Output $stdout
if ($process.ExitCode -ne 0) {
throw "git clone command failed with exit code $($process.ExitCode). Output: $stderr"
}
}
catch {
$errorMessage = " » FAIL: Error Executing git clone: $_"
Write-Error $errorMessage
exit 1 # Fail the build
}
# Create the any necessary subdirectories
New-Item -Path $DIR_BUILD -ItemType Directory -Force
# Ensure we are in the correct directory
Set-Location $DIR
# Pull down the LFS files
git lfs fetch
git lfs pull
# Set the build type based on whether the tag matches the release regex or not.
# A tag in the format of `1.2.3` will be considered a release build, while anything else will be considered debug.
$BUILD_TYPE_REGEX = '^(v?\d+\.\d+\.\d+)$'
if ($RELEASE_TAG -match $BUILD_TYPE_REGEX) {
$BUILD_TYPE = "release"
}
else {
$BUILD_TYPE = "debug"
}
Write-Output " » Build Type: $BUILD_TYPE"
Set-Location $DIR_PROJECT
Write-Output " » Installing NPM Dependencies"
try {
npm install
} catch {
Write-Error " » npm install failed: $_"
exit 1
}
Write-Output " » Running Build Task"
try {
npm run build:$BUILD_TYPE
} catch {
Write-Error " » npm run build failed: $_"
exit 1
}
Write-Output "⚡ Server Built ⚡"