Skip to content

Fix release assets preparation to handle file changes gracefully #23

Fix release assets preparation to handle file changes gracefully

Fix release assets preparation to handle file changes gracefully #23

Workflow file for this run

name: Build and Release Flex
on:
push:
branches: [ main, master ]
tags:
- 'v*' # Run when tag is pushed (for versioned releases)
jobs:
build:
name: Build Flex for ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
output_name: flex
asset_name: flex-linux
- os: windows-latest
output_name: flex.exe
asset_name: flex-windows
- os: macos-latest
output_name: flex
asset_name: flex-macos
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Get version information
id: version
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
else
VERSION="dev-$(date +'%Y%m%d')-${GITHUB_SHA::7}"
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
shell: bash
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
shell: bash
- name: Run tests
run: |
cd src
python -m unittest discover -s flex_tester
shell: bash
- name: Build executable with PyInstaller
run: |
cd src
pyinstaller --onefile main.py -n flex
shell: bash
# Windows NSIS Installer
- name: Create Windows Installer
if: runner.os == 'Windows'
run: |
choco install nsis -y
mkdir -p installer
copy src\dist\flex.exe installer\
xcopy src\flex_tester installer\examples\ /E /I
copy README.md installer\
# Create a simple NSIS script file
(
echo !include "MUI2.nsh"
echo Name "Flex Programming Language"
echo OutFile "flex-${{ env.VERSION }}-win.exe"
echo InstallDir "$PROGRAMFILES\Flex"
echo RequestExecutionLevel admin
echo !insertmacro MUI_PAGE_WELCOME
echo !insertmacro MUI_PAGE_DIRECTORY
echo !insertmacro MUI_PAGE_INSTFILES
echo !insertmacro MUI_PAGE_FINISH
echo !insertmacro MUI_LANGUAGE "English"
echo Section
echo SetOutPath "$INSTDIR"
echo File /r "installer\*.*"
echo WriteUninstaller "$INSTDIR\uninstall.exe"
echo CreateDirectory "$SMPROGRAMS\Flex"
echo CreateShortcut "$SMPROGRAMS\Flex\Flex.lnk" "$INSTDIR\flex.exe"
echo CreateShortcut "$SMPROGRAMS\Flex\Uninstall.lnk" "$INSTDIR\uninstall.exe"
echo SectionEnd
echo Section "Uninstall"
echo Delete "$INSTDIR\uninstall.exe"
echo RMDir /r "$INSTDIR"
echo RMDir /r "$SMPROGRAMS\Flex"
echo SectionEnd
) > installer.nsi
REM Compile the installer
makensis installer.nsi
REM Create latest.yml for auto-updater compatibility
echo version: ${{ env.VERSION }} > latest-win.yml
echo files: >> latest-win.yml
echo - url: flex-${{ env.VERSION }}-win.exe >> latest-win.yml
FOR /F "tokens=*" %%a IN ('powershell -Command "(Get-FileHash -Algorithm SHA512 flex-${{ env.VERSION }}-win.exe).Hash.ToLower()"') DO SET FILEHASH=%%a
echo sha512: %FILEHASH% >> latest-win.yml
echo path: flex-${{ env.VERSION }}-win.exe >> latest-win.yml
FOR /F "tokens=*" %%a IN ('powershell -Command "(Get-FileHash -Algorithm SHA512 flex-${{ env.VERSION }}-win.exe).Hash.ToLower()"') DO SET FILEHASH=%%a
echo sha512: %FILEHASH% >> latest-win.yml
shell: cmd
# macOS DMG Package
- name: Create macOS DMG
if: runner.os == 'macOS'
run: |
# Install create-dmg
brew install create-dmg
# Create app bundle structure
mkdir -p Flex.app/Contents/{MacOS,Resources}
cp src/dist/flex Flex.app/Contents/MacOS/
cp -r src/flex_tester Flex.app/Contents/Resources/examples
cp README.md Flex.app/Contents/Resources/
# Create Info.plist
cat > Flex.app/Contents/Info.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>flex</string>
<key>CFBundleIconFile</key>
<string>flex.icns</string>
<key>CFBundleIdentifier</key>
<string>org.flex-lang.flex</string>
<key>CFBundleName</key>
<string>Flex</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>${VERSION}</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF
# Create DMG with basic settings
create-dmg \
--volname "Flex Installer" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--icon "Flex.app" 200 190 \
--hide-extension "Flex.app" \
--app-drop-link 600 185 \
"flex-${VERSION}-mac.dmg" \
"Flex.app"
# Create latest-mac.yml for auto-updater compatibility
echo "version: ${VERSION}" > latest-mac.yml
echo "files:" >> latest-mac.yml
echo " - url: flex-${VERSION}-mac.dmg" >> latest-mac.yml
echo " sha512: $(shasum -a 512 flex-${VERSION}-mac.dmg | awk '{print $1}')" >> latest-mac.yml
echo " size: $(stat -f%z flex-${VERSION}-mac.dmg)" >> latest-mac.yml
echo "path: flex-${VERSION}-mac.dmg" >> latest-mac.yml
echo "sha512: $(shasum -a 512 flex-${VERSION}-mac.dmg | awk '{print $1}')" >> latest-mac.yml
echo "size: $(stat -f%z flex-${VERSION}-mac.dmg)" >> latest-mac.yml
shell: bash
continue-on-error: true # DMG creation might fail if dependencies are missing
# Linux AppImage
- name: Create Linux AppImage and Deb
if: runner.os == 'Linux'
run: |
# Install required tools
sudo apt-get update
sudo apt-get install -y wget fuse libfuse2 dpkg-dev
# Download AppImage tools
wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool
chmod +x appimagetool
# Create AppDir structure
mkdir -p AppDir/usr/{bin,share/applications,share/icons/hicolor/256x256/apps,share/flex/examples}
cp src/dist/flex AppDir/usr/bin/
cp -r src/flex_tester/* AppDir/usr/share/flex/examples/
cp README.md AppDir/usr/share/flex/
# Create desktop file
cat > AppDir/usr/share/applications/flex.desktop << EOF
[Desktop Entry]
Name=Flex
Comment=Flex Programming Language
Exec=flex
Icon=flex
Type=Application
Categories=Development;
Terminal=true
EOF
# Copy desktop file to root (required by AppImage)
cp AppDir/usr/share/applications/flex.desktop AppDir/
# Create AppRun script
cat > AppDir/AppRun << EOF
#!/bin/sh
SELF=\$(readlink -f "\$0")
HERE=\${SELF%/*}
export PATH="\${HERE}/usr/bin:\${PATH}"
exec "\${HERE}/usr/bin/flex" "\$@"
EOF
chmod +x AppDir/AppRun
# Create AppImage
ARCH=x86_64 ./appimagetool AppDir flex-${VERSION}-linux.AppImage
# Create Debian package
mkdir -p flex-deb/DEBIAN
mkdir -p flex-deb/usr/bin
mkdir -p flex-deb/usr/share/flex/examples
mkdir -p flex-deb/usr/share/applications
cp src/dist/flex flex-deb/usr/bin/
cp -r src/flex_tester/* flex-deb/usr/share/flex/examples/
cp AppDir/usr/share/applications/flex.desktop flex-deb/usr/share/applications/
cat > flex-deb/DEBIAN/control << EOF
Package: flex
Version: ${VERSION}
Section: development
Priority: optional
Architecture: amd64
Maintainer: Flex Language Team <info@flex-lang.org>
Description: Flex Programming Language
A modern and flexible programming language.
EOF
dpkg-deb --build flex-deb flex-${VERSION}-linux.deb
# Create latest-linux.yml for auto-updater compatibility
echo "version: ${VERSION}" > latest-linux.yml
echo "files:" >> latest-linux.yml
echo " - url: flex-${VERSION}-linux.AppImage" >> latest-linux.yml
echo " sha512: $(sha512sum flex-${VERSION}-linux.AppImage | awk '{print $1}')" >> latest-linux.yml
echo " size: $(stat -c%s flex-${VERSION}-linux.AppImage)" >> latest-linux.yml
echo "path: flex-${VERSION}-linux.AppImage" >> latest-linux.yml
echo "sha512: $(sha512sum flex-${VERSION}-linux.AppImage | awk '{print $1}')" >> latest-linux.yml
echo "size: $(stat -c%s flex-${VERSION}-linux.AppImage)" >> latest-linux.yml
shell: bash
continue-on-error: true # Some parts might fail if dependencies are missing
# Package distribution (Unix) - keep this as backup for Linux/macOS
- name: Package distribution (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p dist/flex
cp src/dist/flex dist/flex/
cp -r src/flex_tester dist/flex/examples
cp README.md dist/flex/
tar -czf flex-${VERSION}-${{ matrix.asset_name }}.tar.gz -C dist flex
shell: bash
# Package distribution (Windows) - keep this as backup for Windows
- name: Package distribution (Windows)
if: runner.os == 'Windows'
run: |
mkdir -p dist\flex
copy src\dist\flex.exe dist\flex\
xcopy src\flex_tester dist\flex\examples\ /E /I
copy README.md dist\flex\
powershell Compress-Archive -Path dist\flex -DestinationPath flex-%VERSION%-${{ matrix.asset_name }}.zip
shell: cmd
- name: Debug - List files before upload
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
echo "=== Current directory files ==="
dir
echo "=== src/dist directory files ==="
dir src\dist || echo "Directory not found"
echo "=== Current directory - find all flex files ==="
dir /s /b flex* 2>nul || echo "No files found"
else
echo "=== Current directory files ==="
ls -la
echo "=== src/dist directory files ==="
ls -la src/dist || true
echo "=== Current directory - find all flex files ==="
find . -name "flex*" -type f || true
fi
shell: bash
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: flex-${{ matrix.asset_name }}
path: |
flex-*-${{ matrix.asset_name }}.tar.gz
flex-*-${{ matrix.asset_name }}.zip
flex-*-win.exe
flex-*-mac.dmg
flex-*-linux.AppImage
flex-*-linux.deb
latest-*.yml
src/dist/flex*
if-no-files-found: warn
release:
name: Create Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v3
- name: Set up version information
id: version
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
IS_PRERELEASE=false
RELEASE_NAME="Flex ${GITHUB_REF#refs/tags/v}"
TAG_NAME=${GITHUB_REF#refs/tags/}
else
VERSION="dev-$(date +'%Y%m%d')-${GITHUB_SHA::7}"
IS_PRERELEASE=true
RELEASE_NAME="Flex Latest Build"
TAG_NAME="latest"
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "IS_PRERELEASE=$IS_PRERELEASE" >> $GITHUB_ENV
echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV
echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
shell: bash
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release_assets
# Create a source code archive with better error handling
echo "Creating source code archives..."
# First, create a clean copy of the source
mkdir -p temp_source
cp -r . temp_source/
rm -rf temp_source/artifacts temp_source/.git temp_source/release_assets temp_source/temp_source
# Create archives from the clean copy
(cd temp_source && zip -r ../release_assets/flex-${VERSION}-source.zip .)
(cd temp_source && tar --exclude='.DS_Store' -czf ../release_assets/flex-${VERSION}-source.tar.gz .)
# Clean up temporary directory
rm -rf temp_source
# Find and copy all relevant files to release_assets directory
echo "=== Copying artifacts to release directory ==="
for artifact_dir in artifacts/*/; do
echo "Processing ${artifact_dir}..."
find "${artifact_dir}" -type f \( \
-name "*.tar.gz" -o \
-name "*.zip" -o \
-name "*.exe" -o \
-name "*.dmg" -o \
-name "*.AppImage" -o \
-name "*.deb" -o \
-name "*.yml" -o \
-name "flex" -o \
-name "flex.exe" \
\) -exec cp {} release_assets/ \; || true
done
# Rename the release assets if needed to match proper versioning pattern
if [ ! -f "release_assets/latest-win.yml" ]; then
# Copy one of the platform YMLs as the main latest.yml
if [ -f "release_assets/latest-mac.yml" ]; then
cp release_assets/latest-mac.yml release_assets/latest.yml
elif [ -f "release_assets/latest-linux.yml" ]; then
cp release_assets/latest-linux.yml release_assets/latest.yml
fi
else
cp release_assets/latest-win.yml release_assets/latest.yml
fi
echo "=== Files in release_assets ==="
ls -la release_assets/
shell: bash
- name: List downloaded files
run: |
echo "=== Root directory ==="
find . -type f -maxdepth 1 | sort
echo "=== All flex files ==="
find . -name "flex*" -type f | sort
echo "=== All artifacts directories ==="
find artifacts -type d | sort
echo "=== All artifact files ==="
find artifacts -type f | sort
echo "=== All release_assets files ==="
find release_assets -type f | sort
shell: bash
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
with:
name: ${{ env.RELEASE_NAME }}
tag_name: ${{ env.TAG_NAME }}
draft: false
prerelease: ${{ env.IS_PRERELEASE }}
files: release_assets/*
body: |
# ${{ env.RELEASE_NAME }}
Cross-platform executable releases of the Flex programming language.
## Installation
### Windows
- Option 1: Download and run `flex-${{ env.VERSION }}-win.exe` for a full installer with start menu shortcuts
- Option 2: Download and extract `flex-${{ env.VERSION }}-windows.zip`, then run `flex.exe`
### macOS
- Option 1: Download `flex-${{ env.VERSION }}-mac.dmg`, open and drag to Applications folder
- Option 2: Download and extract `flex-${{ env.VERSION }}-macos.tar.gz`, then run `flex`
### Linux
- Option 1: Download `flex-${{ env.VERSION }}-linux.AppImage`, make executable with `chmod +x flex-${{ env.VERSION }}-linux.AppImage` and run
- Option 2: Download `flex-${{ env.VERSION }}-linux.deb` and install with `sudo dpkg -i flex-${{ env.VERSION }}-linux.deb`
- Option 3: Download and extract `flex-${{ env.VERSION }}-linux.tar.gz`, then run `flex`
## Examples
Example code is included in the examples directory.
## Source Code
Source code is available as ZIP or TAR.GZ archive.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}