Skip to content

[GITHUB] Add weekly pre-releases workflow for Generals and GeneralsMD #929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
36 changes: 34 additions & 2 deletions .github/workflows/build-toolchain.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ on:
default: false
type: boolean
description: "Build extras"
release-name:
required: false
type: string
description: "Release name for the build, used in versioning"
build_user:
required: false
type: string
description: "Override VERSION_BUILDUSER"
build_loc:
required: false
type: string
description: "Override VERSION_BUILDLOC"
build_num:
required: false
type: string
description: "Override VERSION_BUILDNUM"

jobs:
build:
Expand All @@ -41,10 +57,10 @@ jobs:
uses: actions/cache@v4
with:
path: C:\VC6
key: vc6-permanent-cache-v2
key: vc6-permanent-cache-v3

- name: Cache CMake Dependencies
id: cache-cmake-deps
id: cache-cmake-deps-v2
uses: actions/cache@v4
with:
path: build\${{ inputs.preset }}\_deps
Expand Down Expand Up @@ -110,6 +126,22 @@ jobs:
"-DRTS_BUILD_GENERALS=${{ inputs.game == 'Generals' && 'ON' || 'OFF' }}"
)

if ("${{ inputs.release-name }}") {
$buildFlags += "-DRELEASE_NAME:STRING=${{ inputs.release-name }}"
}

if ("${{ inputs.build_user }}") {
$buildFlags += "-DVERSION_BUILDUSER:STRING=${{ inputs.build_user }}"
}

if ("${{ inputs.build_loc }}") {
$buildFlags += "-DVERSION_BUILDLOC:STRING=${{ inputs.build_loc }}"
}

if ("${{ inputs.build_num }}") {
$buildFlags += "-DVERSION_BUILDNUM:INT=${{ inputs.build_num }}"
}

$gamePrefix = "${{ inputs.game == 'Generals' && 'GENERALS' || 'ZEROHOUR' }}"
$buildFlags += "-DRTS_BUILD_CORE_TOOLS=${{ inputs.tools && 'ON' || 'OFF' }}"
$buildFlags += "-DRTS_BUILD_${gamePrefix}_TOOLS=${{ inputs.tools && 'ON' || 'OFF' }}"
Expand Down
235 changes: 235 additions & 0 deletions .github/workflows/weekly-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
name: Weekly Release

permissions:
contents: write
pull-requests: write

on:
workflow_dispatch:
inputs:
build_notes:
description: 'Build notes (optional)'
required: false
default: ''
type: string
known_issues:
description: 'Known issues (optional)'
required: false
default: ''
type: string
force_changed:
description: 'Force build'
required: false
default: 'false'
type: choice
options:
- 'false'
- 'true'
pre-release:
description: 'Mark release as pre-release'
required: false
default: 'false'
type: choice
options:
- 'false'
- 'true'
build_user:
description: 'Override BUILDUSER (optional)'
required: false
type: string
build_loc:
description: 'override BUILDLOC (optional)'
required: false
type: string

schedule:
- cron: '0 8 * * 5'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
get-date:
runs-on: ubuntu-latest
outputs:
date: ${{ steps.date.outputs.date }}
steps:
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT

detect-scm-changes:
needs: [get-date]
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.check.outputs.changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- id: check
run: |
if [ "${{ github.event.inputs.force_changed }}" = "true" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
exit 0
fi

echo LAST TAG:
git describe --tags --abbrev=0 2>/dev/null || echo ""

LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
exit 0
fi
CHANGED=$(git diff --name-only $LAST_TAG..HEAD | grep -v '.github/workflows/' | wc -l)
if [ "$CHANGED" -eq "0" ]; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi

build-generals:
needs: [detect-scm-changes, get-date]
if: needs.detect-scm-changes.outputs.changed == 'true'
name: Build Generals${{ matrix.preset && '' }}
strategy:
matrix:
include:
- preset: "vc6"
tools: true
extras: false
release: true
fail-fast: false
uses: ./.github/workflows/build-toolchain.yml
with:
game: "Generals"
preset: ${{ matrix.preset }}
tools: ${{ matrix.tools }}
extras: ${{ matrix.extras }}
release-name: ${{ needs.get-date.outputs.date }}
build_user: ${{ github.event.inputs.build_user || 'TheSuperHackers' }}
build_loc: ${{ github.event.inputs.build_loc || 'https://github.com/TheSuperHackers/GeneralsGameCode/' }}
build_num: ${{ needs.calculate-version.outputs.tag_count }}
secrets: inherit

build-generalsmd:
needs: [detect-scm-changes, get-date]
if: needs.detect-scm-changes.outputs.changed == 'true'
name: Build GeneralsMD${{ matrix.preset && '' }}
strategy:
matrix:
include:
- preset: "vc6"
tools: true
extras: false
release: true
fail-fast: false
uses: ./.github/workflows/build-toolchain.yml
with:
game: "GeneralsMD"
preset: ${{ matrix.preset }}
tools: ${{ matrix.tools }}
extras: ${{ matrix.extras }}
release-name: ${{ needs.get-date.outputs.date }}
build_user: ${{ github.event.inputs.build_user || 'TheSuperHackers' }}
build_loc: ${{ github.event.inputs.build_loc || 'https://github.com/TheSuperHackers/GeneralsGameCode/' }}
build_num: ${{ needs.calculate-version.outputs.tag_count }}
secrets: inherit

create-release:
name: Create Release
needs: [build-generals, build-generalsmd, get-date]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Collect commits since last release
id: changelog
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
CHANGELOG_COMMITS=$(git log --pretty="format:- %s" --no-merges HEAD | head -n 10 || true)
else
CHANGELOG_COMMITS=$(git log --pretty="format:- %s" --no-merges "$LAST_TAG"..HEAD || true)
fi
if [ -z "$CHANGELOG_COMMITS" ]; then
CHANGELOG_COMMITS="- No relevant changes detected since the last release."
fi
{
echo 'commits<<CHANGELOG_EOF'
echo "$CHANGELOG_COMMITS"
echo 'CHANGELOG_EOF'
} >> "$GITHUB_OUTPUT"

# Generals vc6
- name: Download Generals VC6 Artifacts
uses: actions/download-artifact@v4
with:
name: Generals-vc6+t
path: generals-vc6-artifacts

- name: Prepare and Zip Generals VC6
run: |
mkdir generals-vc6-release
cp generals-vc6-artifacts/generalsv.exe generals-vc6-release/GeneralsV.exe
cp generals-vc6-artifacts/W3DViewV.exe generals-vc6-release/W3DViewV.exe
cp generals-vc6-artifacts/WorldBuilderV.exe generals-vc6-release/WorldBuilderV.exe
zip -j generals-preview-${{ needs.get-date.outputs.date }}.zip generals-vc6-release/*

# GeneralsMD vc6
- name: Download GeneralsMD VC6 Artifacts
uses: actions/download-artifact@v4
with:
name: GeneralsMD-vc6+t
path: generalsmd-vc6-artifacts

- name: Prepare and Zip GeneralsMD VC6
run: |
mkdir generalsmd-vc6-release
cp generalsmd-vc6-artifacts/generalszh.exe generalsmd-vc6-release/GeneralsZHv.exe
cp generalsmd-vc6-artifacts/W3DViewZH.exe generalsmd-vc6-release/W3DViewZHv.exe
cp generalsmd-vc6-artifacts/WorldBuilderZH.exe generalsmd-vc6-release/WorldBuilderZHv.exe
zip -j generalszh-preview-${{ needs.get-date.outputs.date }}.zip generalsmd-vc6-release/*

- name: Generate release notes
id: release_body
run: |
BODY=""
if [ "${{ github.event.inputs.build_notes }}" != "" ]; then
BODY="${BODY}### Build notes\n${{ github.event.inputs.build_notes }}\n"
fi
if [ "${{ github.event.inputs.known_issues }}" != "" ]; then
BODY="${BODY}### Known issues\n${{ github.event.inputs.known_issues }}\n"
fi
BODY="${BODY}### Changelog\n${{ steps.changelog.outputs.commits }}"
echo "body<<EOF" >> $GITHUB_OUTPUT
echo -e "$BODY" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: preview-${{ needs.get-date.outputs.date }}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this the format for the release name/tag should be preview-$DATE, but the most recent runs on your repo don't reflect that despite it being 2 weeks since you last pushed the branch? I'm guessing you need to push it to main for that to happen or something? Just wanted to check the output before I gace it the okay.

Also, do we want to call it "preview" which implies its just an early release of what could be final when in practice that won't be the case? Maybe just prefix "weekly" instead? Thoughts?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"weekly" is also fine

Maybe "weekly-preview" :D

Copy link
Author

@fbraz3 fbraz3 Aug 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Guys,

@OmniBlade my fork uses a different versioning schema (semVer) - in this schema 0.x versions implies that is a pre/beta release. For superhackers project we agreed to use a date-based versioning. Just need to decide if we want to user preview-$date or weekly-preview-$date and I will change in asap.
imho using weekly or nightly naming automatcaly implies in a non production-ready version so the preview tag could not necessary.

@xezon just send a change to override the version name using the RELEASE_NAME build flasg in toolchain. This cmake change is suggested by copilot, so i'm not sure if it will work properly if you can suggest something better i would appreciate.

I'm also available for a pair programming if you guys find useful, it will be a great opportunity for me to learning a bit of c++ from more skilled engineers =)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the version string now look in the game?

name: preview-${{ needs.get-date.outputs.date }}
prerelease: ${{ github.event.inputs.pre-release == 'true' }}
body: ${{ steps.release_body.outputs.body }}
files: |
generals-preview-${{ needs.get-date.outputs.date }}.zip
generalszh-preview-${{ needs.get-date.outputs.date }}.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Clean up release folders
if: always()
run: |
rm -rf generals-vc6-release generalsmd-vc6-release
rm -rf generals-vc6-artifacts generalsmd-vc6-artifacts
rm -f generals-preview-${{ needs.get-date.outputs.date }}.zip
rm -f generalszh-preview-${{ needs.get-date.outputs.date }}.zip
49 changes: 35 additions & 14 deletions Generals/Code/GameEngine/Source/Common/version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,22 +329,32 @@ UnicodeString Version::getUnicodeProductString() const

if (!productTitle.isEmpty())
{
UnicodeString productVersion = TheGameText->FETCH_OR_SUBSTITUTE("Version:ProductVersion", getUnicodeProductVersion().str());
UnicodeString productAuthor = TheGameText->FETCH_OR_SUBSTITUTE("Version:ProductAuthor", getUnicodeProductAuthor().str());

str.concat(productTitle);

if (!productVersion.isEmpty())
// Get build user or author name
AsciiString asciiUser = getAsciiBuildUserOrGitCommitAuthorName();
UnicodeString user;
if (!asciiUser.isEmpty())
{
str.concat(L" ");
str.concat(productVersion);
user.translate(asciiUser);
}
else
{
user = L"Unknown";
}

if (!productAuthor.isEmpty())
// Get release name from gitinfo
UnicodeString releaseName;
if (ReleaseName[0] != '\0')
{
releaseName.translate(ReleaseName);
}
else
{
str.concat(L" ");
str.concat(productAuthor);
releaseName = getUnicodeGitTagOrHash();
}

str.concat(productTitle);
str.concat(L" by ");
str.concat(user);
}

return str;
Expand All @@ -356,15 +366,26 @@ UnicodeString Version::getUnicodeProductVersionHashString() const
UnicodeString productString = getUnicodeProductString();
UnicodeString gameVersion = getUnicodeVersion();
UnicodeString gameHash;
gameHash.format(L"exe:%08X ini:%08X", TheGlobalData->m_exeCRC, TheGlobalData->m_iniCRC);

if (ReleaseName[0])
{
AsciiString asciiRel;
asciiRel.concat(ReleaseName);
UnicodeString uRel;
uRel.translate(asciiRel);
gameHash.format(L" release %s", uRel.str());
}
else
{
gameHash.format(L" | exe:%08X ini:%08X", TheGlobalData->m_exeCRC, TheGlobalData->m_iniCRC);
}

if (!productString.isEmpty())
{
str.concat(productString);
str.concat(L" | ");
}
str.concat(gameHash);
str.concat(L" ");
str.concat(L" - ");
str.concat(gameVersion);

return str;
Expand Down
Loading
Loading