Skip to content
Merged
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
188 changes: 94 additions & 94 deletions .github/workflows/release.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion scripts/prebuild/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ func allSpecs() []prebuildSpec {
{Target: "untserver", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:untserver-prebuild", Source: "./scrolls/lgsm/untserver", Image: steamImage, Ports: []string{"main=27015/udp", "mainv6=27016"}, MinDisk: "7Gi", MinRAM: "1Gi", MinCPU: "0.5", Category: "unturned", Smart: true, PackMeta: true},
{Target: "sdtdserver", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:sdtdserver-prebuild", Source: "./scrolls/lgsm/sdtdserver", Image: steamImage, Ports: []string{"query=26900/udp", "main=26900/udp", "main2=26902/udp", "maintcp=26900"}, MinDisk: "20Gi", MinRAM: "2Gi", MinCPU: "0.5", Category: "7days", PackMeta: true},
{Target: "gmodserver", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:gmodserver-prebuild", Source: "./scrolls/lgsm/gmodserver", Image: steamImage, Ports: []string{"query=27005/udp", "main=27015/udp", "sourcetv=27020/udp", "steam=27015"}, MinDisk: "8Gi", MinRAM: "512Mi", MinCPU: "0.25", Category: "gmod", Smart: true, PackMeta: true},
{Target: "cs2server", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:cs2server-prebuild", Source: "./scrolls/lgsm/cs2server", Image: steamImage, Ports: []string{"main=27015/udp", "rcon=27015"}, MinDisk: "38Gi", BuildDisk: "95Gi", MinRAM: "1Gi", MinCPU: "0.5", Category: "cs2", Smart: true, PackMeta: true},
{Target: "cs2server", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:cs2server-prebuild", Source: "./scrolls/lgsm/cs2server", Image: steamImage, Ports: []string{"main=27015/udp", "rcon=27015"}, MinDisk: "70Gi", BuildDisk: "95Gi", MinRAM: "1Gi", MinCPU: "0.5", Category: "cs2", Smart: true, PackMeta: true},
{Target: "pzserver", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:pzserver-prebuild", Source: "./scrolls/lgsm/pzserver", Image: steamImage, Ports: []string{"main=16261/udp", "main2=16262/udp", "maintcp=16261"}, MinDisk: "3Gi", MinRAM: "512Mi", MinCPU: "0.25", Category: "zomboid", Smart: true, PackMeta: true},
{Target: "csgoserver", Artifact: "artifacts.druid.gg/druid-team/scroll-lgsm:csgoserver-prebuild", Source: "./scrolls/lgsm/csgoserver", Image: steamImage, Ports: []string{"query=27005/udp", "main=27015/udp", "sourcetv=27020/udp", "steam=27015"}, BuildDisk: "45Gi", Category: "csgo", Smart: true, PackMeta: true},
{Target: "rust-vanilla", Artifact: "artifacts.druid.gg/druid-team/scroll-rust-vanilla:latest-prebuild", Source: "./scrolls/rust/rust-vanilla/latest", Image: steamImage, Ports: []string{"main=28015/udp", "query=28017/udp", "rcon=28016", "rustplus=28082"}, MinDisk: "10Gi", BuildDisk: "25Gi", MinRAM: "6Gi", MinCPU: "1", Category: "rust", Smart: true},
Expand Down
129 changes: 129 additions & 0 deletions scripts/validate-release-workflow/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package main

import (
"errors"
"fmt"
"os"
"regexp"
"strconv"
"strings"
)

var (
forbiddenReleaseValues = []string{
"v0.1.248",
"highcard/druid",
"stable-nix",
"latest-nix",
"-nix-steamcmd",
}
portOverrideNamePattern = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_-]*$`)
portOverridePattern = regexp.MustCompile(`^([A-Za-z][A-Za-z0-9_-]*)=([0-9]+)(?:/(tcp|udp|http|https))?$`)
pzserverRequiredPorts = map[string]string{
"main": "16261/udp",
"main2": "16262/udp",
"maintcp": "16261",
}
)

func main() {
path := ".github/workflows/release.yml"
if len(os.Args) > 1 {
path = os.Args[1]
}
if err := validateReleaseWorkflow(path); err != nil {
fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
}
}

func validateReleaseWorkflow(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
lines := strings.Split(string(data), "\n")
var failures []string
foundPZServer := false

for index, line := range lines {
lineNumber := index + 1
for _, forbidden := range forbiddenReleaseValues {
if strings.Contains(line, forbidden) {
failures = append(failures, fmt.Sprintf("%s:%d contains forbidden value %q", path, lineNumber, forbidden))
}
}
if !isArtifactPushLine(line) {
continue
}
fields := strings.Fields(line)
ports, err := validatePortOverrides(fields)
if err != nil {
failures = append(failures, fmt.Sprintf("%s:%d %v", path, lineNumber, err))
}
if strings.Contains(line, "scroll-lgsm:pzserver") {
foundPZServer = true
for name, expected := range pzserverRequiredPorts {
if actual := ports[name]; actual != expected {
failures = append(failures, fmt.Sprintf("%s:%d pzserver requires -p %s=%s, got %q", path, lineNumber, name, expected, actual))
}
}
}
}

if !foundPZServer {
failures = append(failures, fmt.Sprintf("%s: missing pzserver release push", path))
}
if len(failures) > 0 {
return errors.New(strings.Join(failures, "\n"))
}
return nil
}

func isArtifactPushLine(line string) bool {
fields := strings.Fields(line)
for i := 0; i+2 < len(fields); i++ {
if fields[i] == "druid" && fields[i+1] == "push" && fields[i+2] != "category" {
return true
}
}
return false
}

func validatePortOverrides(fields []string) (map[string]string, error) {
ports := make(map[string]string)
var failures []string

for i, field := range fields {
if field != "-p" && field != "--port" {
continue
}
if i+1 >= len(fields) {
failures = append(failures, fmt.Sprintf("%s is missing an override", field))
continue
}
override := fields[i+1]
matches := portOverridePattern.FindStringSubmatch(override)
if matches == nil {
failures = append(failures, fmt.Sprintf("invalid %s override %q; expected name=port or name=port/protocol", field, override))
continue
}
name := matches[1]
portText := matches[2]
port, err := strconv.Atoi(portText)
if err != nil || port < 1 || port > 65535 {
failures = append(failures, fmt.Sprintf("invalid %s override %q; port must be 1-65535", field, override))
continue
}
if !portOverrideNamePattern.MatchString(name) {
failures = append(failures, fmt.Sprintf("invalid %s override %q; invalid port name", field, override))
continue
}
ports[name] = strings.TrimPrefix(override, name+"=")
}

if len(failures) > 0 {
return ports, errors.New(strings.Join(failures, "; "))
}
return ports, nil
}
43 changes: 43 additions & 0 deletions scripts/validate-release-workflow/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"strings"
"testing"
)

func TestValidatePortOverridesAcceptsConcretePorts(t *testing.T) {
fields := strings.Fields("druid push repo:tag ./scroll -p main=25565 -p query=27015/udp -p battle-eye=2304/udp -p webpanel=8080")

ports, err := validatePortOverrides(fields)
if err != nil {
t.Fatal(err)
}
if ports["main"] != "25565" || ports["query"] != "27015/udp" || ports["battle-eye"] != "2304/udp" || ports["webpanel"] != "8080" {
t.Fatalf("ports = %#v", ports)
}
}

func TestValidatePortOverridesRejectsBlankAndBarePorts(t *testing.T) {
for _, value := range []string{
"main",
"main=",
"main=/udp",
"main=0",
"main=0/udp",
"main=65536",
} {
fields := []string{"druid", "push", "repo:tag", "./scroll", "-p", value}
if _, err := validatePortOverrides(fields); err == nil {
t.Fatalf("%s passed validation, want failure", value)
}
}
}

func TestIsArtifactPushLineSkipsCategories(t *testing.T) {
if isArtifactPushLine("druid push category artifacts.druid.gg/foo bar ./meta") {
t.Fatal("category push should not be treated as artifact push")
}
if !isArtifactPushLine("druid push artifacts.druid.gg/foo:tag ./scroll -p main=1") {
t.Fatal("artifact push was not detected")
}
}
2 changes: 2 additions & 0 deletions scripts/validate_all_scrolls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

set -euo pipefail

go run ./scripts/validate-release-workflow

if command -v druid >/dev/null 2>&1 && druid validate --help >/dev/null 2>&1; then
while IFS= read -r file; do
dir="${file%/scroll.yaml}"
Expand Down
24 changes: 24 additions & 0 deletions scrolls/lgsm/.build/versions/pzserver/chunks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
chunks:
- name: configure-pzserver
path: configure-pzserver.sh
- name: install-lgsm
path: install-lgsm.sh
- name: lgsm
path: lgsm
- name: linuxgsm
path: linuxgsm.sh
- name: log
path: log
- name: patch-lgsm-permissions
path: patch-lgsm-permissions.sh
- name: pzserver
path: pzserver
- name: serverfiles
path: serverfiles
chunks:
- name: media
path: media
- name: steamapps
path: steamapps
- name: zombie
path: zombie
25 changes: 25 additions & 0 deletions scrolls/lgsm/pzserver/scroll.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@ desc: pzserver
version: 0.0.2
app_version: pzserver
keepAlivePPM: 5
chunks:
- name: configure-pzserver
path: configure-pzserver.sh
- name: install-lgsm
path: install-lgsm.sh
- name: lgsm
path: lgsm
- name: linuxgsm
path: linuxgsm.sh
- name: log
path: log
- name: patch-lgsm-permissions
path: patch-lgsm-permissions.sh
- name: pzserver
path: pzserver
- name: serverfiles
path: serverfiles
chunks:
- name: media
path: media
- name: steamapps
path: steamapps
- name: zombie
path: zombie

ports:
- name: main
protocol: udp
Expand Down
Loading