This repository provides automated build and release workflows for the Express Engine (eengine) project.
Express Engine is an open-source EXPRESS language parser and interpreter implemented in Steel Bank Common Lisp (SBCL). It is used for parsing, interpreting, and validating EXPRESS schemas and data files.
The eengine source code is hosted at SourceForge. This repository does not contain the eengine source code, but only the GitHub Actions workflows and documentation for building and releasing eengine binaries across multiple platforms.
This work supports the ELF project and the EXPRESS language community by providing easy access to pre-built cross-platform eengine binaries.
-
Daily tag checking to detect new eengine releases
-
Multi-platform builds for Linux, Windows, and macOS
-
Automated GitHub releases with pre-built binaries
-
Version filtering to process only relevant releases
┌─────────────────────────────────────────────────────────────────┐
│ SourceForge Repository │
│ git://git.code.sf.net/p/exp-engine/engine │
│ │
│ Contains: eengine source code with tags (eeng-x.y.z) │
└────────────────────────┬────────────────────────────────────────┘
│
│ Daily check (cron)
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Actions Workflow: check-tags.yml │
├─────────────────────────────────────────────────────────────────┤
│ 1. Checkout eengine repository │
│ 2. List all tags matching eeng-* │
│ 3. Filter for versions ≥ 5.0.0 │
│ 4. Compare with existing GitHub releases │
│ 5. Identify new tags without releases │
│ 6. Trigger build-release.yml for each new tag │
└────────────────────────┬────────────────────────────────────────┘
│
│ Workflow dispatch
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Actions Workflow: build-release.yml │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Platform Build Jobs │ │
│ ├─────────────────────┬─────────────────────────────────────┤ │
│ │ (platform) │ (GitHub runner) │ │
│ ├─────────────────────┼─────────────────────────────────────┤ │
│ │ Linux x64 │ ubuntu-latest │ │
│ │ Linux ARM64 │ ubuntu-22.04-arm │ │
│ │ Windows x64 │ windows-latest │ │
│ │ Windows ARM64 │ windows-11-arm │ │
│ │ macOS Intel │ macos-13 │ │
│ │ macOS ARM64 │ macos-14 │ │
│ └─────────────────────┴─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ Release Job │ │
│ ├──────────────────────────────────┤ │
│ │ 1. Download all artifacts │ │
│ │ 2. Create GitHub Release │ │
│ │ 3. Upload binaries │ │
│ └──────────────────────────────────┘ │
│ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Release │
│ │
│ Tag: eeng-5.2.7 │
│ Artifacts: │
│ - eengine-5.2.7-lnx-x86-64-sbcl (Linux x86-64) │
│ - eengine-5.2.7-lnx-arm64-sbcl (Linux ARM64) │
│ - eengine-5.2.7-win-x86-64-sbcl.exe (Windows x86-64) │
│ - eengine-5.2.7-win-arm64-sbcl.exe (Windows ARM64) │
│ - eengine-5.2.7-mac-x86-64-sbcl (macOS Intel) │
│ - eengine-5.2.7-mac-arm64-sbcl (macOS Apple Silicon) │
└────────────────────────┬────────────────────────────────────────┘
│
│ On release published
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Actions Workflow: trigger-homebrew-update.yml │
├─────────────────────────────────────────────────────────────────┤
│ 1. Extract version from release tag │
│ 2. Dispatch repository_dispatch event to homebrew-eengine │
└────────────────────────┬────────────────────────────────────────┘
│
│ repository_dispatch
▼
┌─────────────────────────────────────────────────────────────────┐
│ homebrew-eengine Repository │
│ (expresslang/homebrew-eengine) │
├─────────────────────────────────────────────────────────────────┤
│ 1. Receive repository_dispatch event │
│ 2. Run generate-formula.rb script │
│ 3. Download release binaries and calculate SHA256 │
│ 4. Update formula-metadata.json │
│ 5. Generate Formula/eengine.rb from template │
│ 6. Create pull request with updated formula │
└─────────────────────────────────────────────────────────────────┘The recommended way to install eengine on macOS and Linux is via Homebrew:
# Add the eengine tap
brew tap expresslang/eengine
# Install eengine
brew install eengine
# Verify installation
eengine --version
# Update to latest version
brew upgrade eengineDownload the appropriate binary for your platform from the Releases page.
# Download latest release (replace version number as needed)
wget https://github.com/expresslang/eengine-releases/releases/download/eeng-5.2.7/eengine-5.2.7-lnx-x86-64-sbcl
# Make executable and install
chmod +x eengine-5.2.7-lnx-x86-64-sbcl
sudo mv eengine-5.2.7-lnx-x86-64-sbcl /usr/local/bin/eengine
# Verify installation
eengine --version# Download latest release (replace version number as needed)
wget https://github.com/expresslang/eengine-releases/releases/download/eeng-5.2.7/eengine-5.2.7-lnx-arm64-sbcl
# Make executable and install
chmod +x eengine-5.2.7-lnx-arm64-sbcl
sudo mv eengine-5.2.7-lnx-arm64-sbcl /usr/local/bin/eengine
# Verify installation
eengine --version# Download latest release (replace version number as needed)
curl -L -o eengine https://github.com/expresslang/eengine-releases/releases/download/eeng-5.2.7/eengine-5.2.7-mac-arm64-sbcl
# Make executable and install
chmod +x eengine
sudo mv eengine /usr/local/bin/
# Verify installation
eengine --version# Download latest release (replace version number as needed)
curl -L -o eengine https://github.com/expresslang/eengine-releases/releases/download/eeng-5.2.7/eengine-5.2.7-mac-x86-64-sbcl
# Make executable and install
chmod +x eengine
sudo mv eengine /usr/local/bin/
# Verify installation
eengine --versionDownload the .exe file from the
Releases page and
add it to your system PATH manually.
Download the ARM64 .exe file from the
Releases page for
Windows ARM devices (Surface Pro X, Copilot+ PCs) and add it to your system
PATH manually.
The check-tags.yml workflow runs daily at midnight UTC via a cron schedule.
It automatically detects new eengine tags from the SourceForge repository and
triggers builds for any tags that don’t yet have corresponding GitHub releases.
This workflow implements the following logic:
-
Clone the eengine repository from SourceForge using
git clone -
List all tags matching the pattern
eeng-* -
Filter tags to include only versions 5.0.0 and above
-
Query existing GitHub releases in this repository
-
Identify new tags without releases
-
Trigger the build-release workflow for each new tag
|
Note
|
We use git clone directly instead of actions/checkout due to
limitations with non-GitHub repositories.
|
The workflow uses AWK to filter tags based on semantic versioning.
-
Old versions (3.x, 4.x) are excluded from processing
-
New major versions (5.x, 6.x, 7.x, etc.) are automatically included
-
The filtering is future-proof and requires no maintenance
The workflow can also be triggered manually using the workflow dispatch event:
-
Navigate to Actions > Check for New Tags
-
Click "Run workflow"
-
Select the branch (typically
main) -
Click "Run workflow"
This is useful for:
-
Testing the workflow after modifications
-
Processing tags immediately without waiting for the daily cron
-
Debugging tag detection issues
The build-release.yml workflow builds eengine binaries for six platforms:
-
Linux x86-64 (ubuntu-latest)
-
Linux ARM64 (ubuntu-22.04-arm)
-
Windows x86-64 (windows-latest)
-
Windows ARM64 (windows-11-arm)
-
macOS Intel (macos-13)
-
macOS ARM64 (macos-14)
Each platform build runs in parallel as a separate job, then all artifacts are collected and uploaded to a single GitHub release.
The build process for each platform follows these steps:
-
Install Steel Bank Common Lisp (SBCL) using the platform’s package manager
-
Verify SBCL installation
-
Checkout the eengine repository at the specified tag
-
Compile the source code using
sbcl --load sbcl/compile.lisp -
Create the deliverable binary using
sbcl --load sbcl/deliver.lisp -
Locate the generated binary using pattern matching
-
Upload the binary as a workflow artifact
Each platform uses its native package manager:
# Linux
sudo apt-get update
sudo apt-get install -y sbcl
# Windows
choco install sbcl -y
# macOS
brew install sbclThe eengine build system automatically names binaries according to the official executable pattern:
eengine-{version}-{platform}-{arch}-sbcl{.exe}
Where:
version-
The semantic version from the tag (e.g.,
5.2.7) platform-
Operating system identifier (
lnx,win, ormac) arch-
Architecture (
x86-64for Linux/Windows,arm64for macOS) sbcl-
Indicates the Common Lisp implementation used
.exe-
Extension added only for Windows binaries
eengine-5.2.7-lnx-x86-64-sbcl # Linux x86-64
eengine-5.2.7-lnx-arm64-sbcl # Linux ARM64
eengine-5.2.7-win-x86-64-sbcl.exe # Windows x86-64
eengine-5.2.7-win-arm64-sbcl.exe # Windows ARM64
eengine-5.2.7-mac-x86-64-sbcl # macOS Intel
eengine-5.2.7-mac-arm64-sbcl # macOS Apple SiliconOnce all platform builds complete successfully, the workflow creates a GitHub release using the softprops/action-gh-release action.
The release process:
-
Downloads all platform-specific artifacts
-
Prepares a release directory with all binaries
-
Creates a GitHub release with the tag name
-
Uploads all three platform binaries to the release
-
Generates release notes automatically from git commits
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag_name }}
name: eengine ${{ steps.prepare.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
files: |
release-files/*
fail_on_unmatched_files: trueThe workflow is configured to:
-
Use the eengine tag name (e.g.,
eeng-5.2.7) as the release tag -
Generate a human-readable release title (e.g.,
eengine 5.2.7) -
Publish releases immediately (not as drafts)
-
Mark stable versions as non-prerelease
-
Auto-generate release notes from the eengine repository commits
-
Fail if any expected binary is missing
The build-release workflow can be triggered manually:
-
Navigate to Actions > Build and Release
-
Click "Run workflow"
-
Enter the tag name (e.g.,
eeng-5.2.7) -
Click "Run workflow"
This is useful for:
-
Rebuilding a release if the initial build failed
-
Testing the build process for a specific tag
-
Creating releases for tags that were missed by the automatic checker
The tag checking workflow implements version filtering to process only relevant eengine releases.
Current filtering criteria:
-
Include: All tags with major version ≥ 5 (5.x, 6.x, 7.x, etc.)
-
Exclude: Legacy versions (3.x, 4.x)
This filtering ensures that:
-
Old releases are not processed unnecessarily
-
The repository remains focused on current and future versions
-
No manual intervention is needed when new major versions are released
The version filtering uses AWK to parse semantic version numbers from tag names:
# Get all tags matching eeng-* pattern
ALL_TAGS=$(git tag -l 'eeng-*' | sort -V)
# Filter for versions >= 5.0.0
FILTERED_TAGS=$(echo "$ALL_TAGS" | awk -F'-' '{
split($2, ver, ".");
major = ver[1];
if (major >= 5) print $0;
}')The AWK script:
-
Splits each tag on the
-character -
Extracts the version portion (second field)
-
Splits the version on
.to get major, minor, patch -
Checks if the major version is 5 or greater
-
Prints matching tags
This approach is robust and handles version numbers with varying formats
(e.g., 5.2.7, 5.10.0.1, 6.0.0).
To change which versions are processed, modify the comparison in the AWK script:
# Process versions >= 6.0.0
if (major >= 6) print $0;
# Process only version 5.x
if (major == 5) print $0;
# Process versions >= 5.2.0
if (major > 5 || (major == 5 && minor >= 2)) print $0;If a platform build fails:
-
Check the Actions tab for error details
-
Verify that SBCL installed correctly on the platform
-
Ensure the eengine tag exists in the SourceForge repository
-
Check that the build scripts (
sbcl/compile.lispandsbcl/deliver.lisp) are present in the tag
If expected releases are not created:
-
Verify the tag name matches the pattern
eeng-* -
Check that the tag’s major version is 5 or greater
-
Ensure the tag doesn’t already have a corresponding GitHub release
-
Review the check-tags workflow logs for filtering details
The eengine source code is maintained at:
To clone the eengine repository:
git clone git://git.code.sf.net/p/exp-engine/engine exp-engine