Skip to content

unpinned flutter version #196

unpinned flutter version

unpinned flutter version #196

Workflow file for this run

name: Build and Release Applications
on:
push:
branches:
- develop
workflow_dispatch:
env:
STRAVA_CLIENT_ID: ${{ secrets.STRAVA_CLIENT_ID }}
STRAVA_CLIENT_SECRET: ${{ secrets.STRAVA_CLIENT_SECRET }}
INTERVALS_CLIENT_ID: ${{ secrets.INTERVALS_CLIENT_ID }}
INTERVALS_CLIENT_SECRET: ${{ secrets.INTERVALS_CLIENT_SECRET }}
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.set_version.outputs.version }}
steps:
- uses: actions/checkout@v2
# Download and extract latest SmartSpin2k firmware.bin from GitHub release
- name: Download and extract latest SmartSpin2k firmware
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
mkdir -p assets
# Get latest release info
release_json=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/doudar/SmartSpin2k/releases/latest)
# Find .bin.zip asset URL
asset_url=$(echo "$release_json" | grep 'browser_download_url' | grep '.bin.zip' | head -n1 | cut -d '"' -f4)
if [ -z "$asset_url" ]; then
echo "No .bin.zip asset found in latest release!" >&2
exit 1
fi
echo "Downloading: $asset_url"
curl -L -o /tmp/firmware.zip "$asset_url"
unzip -o /tmp/firmware.zip -d /tmp/firmware_extracted
if [ ! -f /tmp/firmware_extracted/firmware.bin ]; then
echo "firmware.bin not found in zip!" >&2
exit 1
fi
mv /tmp/firmware_extracted/firmware.bin assets/firmware.bin
echo "Firmware placed at assets/firmware.bin"
# Extract version tag and write to assets/version.txt
version_tag=$(echo "$release_json" | grep '"tag_name"' | head -n1 | cut -d '"' -f4)
if [ -z "$version_tag" ]; then
echo "No version tag found in release!" >&2
exit 1
fi
echo "$version_tag" > assets/version.txt
echo "Version written to assets/version.txt: $version_tag"
# Commit and push firmware.bin and version.txt to the repository
- name: Commit, push, and open PR for updated firmware and version
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git fetch origin
git checkout ${{ github.ref_name }}
git add assets/firmware.bin assets/version.txt
if git diff --cached --quiet; then
echo "No changes to commit."
exit 0
fi
git commit -m "chore: update firmware.bin and version.txt from latest SmartSpin2k release"
# Try to push to the current branch (will fail if protected)
if git push origin HEAD:${{ github.ref_name }}; then
echo "Pushed directly to ${{ github.ref_name }}."
exit 0
fi
# If push fails, create a new branch and open a PR
update_branch="auto/firmware-update-$(date +%Y%m%d%H%M%S)"
git checkout -b "$update_branch"
git push origin "$update_branch"
echo "Creating pull request to ${{ github.ref_name }}..."
# Install GitHub CLI if not present
if ! command -v gh >/dev/null 2>&1; then
echo "Installing GitHub CLI..."
sudo apt-get update && sudo apt-get install -y gh
fi
# Use GH_TOKEN for authentication (no gh auth login needed in CI)
gh pr create --base "${{ github.ref_name }}" --head "$update_branch" --title "chore: update firmware.bin and version.txt from latest SmartSpin2k release" --body "Automated update of firmware.bin and version.txt from the latest SmartSpin2k release."
- name: Extract version from pubspec.yaml
id: extract_version
run: |
VERSION=$(grep 'version: ' pubspec.yaml | sed 's/version: //')
echo "VERSION=${VERSION}" >> $GITHUB_ENV
- name: Check if tag exists
id: check_tag
run: |
TAG_EXISTS=$(git tag -l "$VERSION")
if [[ "$TAG_EXISTS" == "$VERSION" ]]; then
SUFFIX=1
NEW_TAG="$VERSION-$SUFFIX"
while [[ $(git tag -l "$NEW_TAG") == "$NEW_TAG" ]]; do
SUFFIX=$((SUFFIX+1))
NEW_TAG="$VERSION-$SUFFIX"
done
echo "NEW_TAG=$NEW_TAG" >> $GITHUB_ENV
else
echo "NEW_TAG=$VERSION" >> $GITHUB_ENV
fi
- name: Set output
id: set_version
run: echo "::set-output name=version::$NEW_TAG"
build-android:
needs: prepare
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v2
with:
java-version: '21'
distribution: 'temurin'
- name: Setup Dart SDK
uses: dart-lang/setup-dart@v1
with:
sdk: 'stable'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version-file: pubspec.yaml
- name: Accept Android SDK licenses
shell: bash
run: |
yes | sdkmanager --licenses || true
sdkmanager --install "platforms;android-36" "build-tools;36.0.0" || true
- name: Create env.local.dart
env:
STRAVA_CLIENT_ID: ${{ secrets.STRAVA_CLIENT_ID }}
STRAVA_CLIENT_SECRET: ${{ secrets.STRAVA_CLIENT_SECRET }}
INTERVALS_CLIENT_ID: ${{ secrets.INTERVALS_CLIENT_ID }}
INTERVALS_CLIENT_SECRET: ${{ secrets.INTERVALS_CLIENT_SECRET }}
run: |
mkdir -p lib/config
umask 077
cat > lib/config/env.local.dart <<EOL
class Environment {
static const String stravaClientId = '${STRAVA_CLIENT_ID}';
static const String stravaClientSecret = '${STRAVA_CLIENT_SECRET}';
static const String intervalsClientId = '${INTERVALS_CLIENT_ID}';
static const String intervalsClientSecret = '${INTERVALS_CLIENT_SECRET}';
static bool get hasStravaConfig =>
stravaClientId.isNotEmpty && stravaClientSecret.isNotEmpty;
static bool get hasIntervalsConfig =>
intervalsClientId.isNotEmpty && intervalsClientSecret.isNotEmpty;
}
EOL
# Replace environment variables
envsubst < lib/config/env.local.dart > lib/config/env.local.dart.tmp
mv lib/config/env.local.dart.tmp lib/config/env.local.dart
- name: Build Android APK
run: flutter build apk --no-tree-shake-icons
- name: Create artifacts
run: |
mkdir -p artifacts
mv build/app/outputs/flutter-apk/app-release.apk artifacts/ss2kconfigapp-${{ needs.prepare.outputs.version }}.apk
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: android-artifacts
path: artifacts/
build-macos:
needs: prepare
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Setup Dart SDK
uses: dart-lang/setup-dart@v1
with:
sdk: 'stable'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version-file: pubspec.yaml
# Debug environment variables
- name: Debug Environment Variables
run: |
echo "Checking environment variables (secrets will be masked):"
env | grep -i STRAVA || true
- name: Create env.local.dart
env:
STRAVA_CLIENT_ID: ${{ secrets.STRAVA_CLIENT_ID }}
STRAVA_CLIENT_SECRET: ${{ secrets.STRAVA_CLIENT_SECRET }}
INTERVALS_CLIENT_ID: ${{ secrets.INTERVALS_CLIENT_ID }}
INTERVALS_CLIENT_SECRET: ${{ secrets.INTERVALS_CLIENT_SECRET }}
run: |
mkdir -p lib/config
umask 077
cat > lib/config/env.local.dart << \EOL
class Environment {
static const String stravaClientId = '${STRAVA_CLIENT_ID}';
static const String stravaClientSecret = '${STRAVA_CLIENT_SECRET}';
static const String intervalsClientId = '${INTERVALS_CLIENT_ID}';
static const String intervalsClientSecret = '${INTERVALS_CLIENT_SECRET}';
static bool get hasStravaConfig =>
stravaClientId.isNotEmpty && stravaClientSecret.isNotEmpty;
static bool get hasIntervalsConfig =>
intervalsClientId.isNotEmpty && intervalsClientSecret.isNotEmpty;
}
EOL
# Replace environment variables
envsubst < lib/config/env.local.dart > lib/config/env.local.dart.tmp
mv lib/config/env.local.dart.tmp lib/config/env.local.dart
# Verify file exists but don't show contents
ls -l lib/config/env.local.dart
- name: Build iOS App
run: flutter build ios --release --no-codesign --no-tree-shake-icons
- name: Build macOS App
run: flutter build macos --release --no-tree-shake-icons
- name: Create artifacts
run: |
mkdir -p artifacts
zip -r artifacts/ss2kconfigapp-${{ needs.prepare.outputs.version }}.zip build/ios/iphoneos build/macos/Build/Products/Release
# Clean up sensitive files
- name: Clean up env.local.dart
if: always()
run: |
if [ -f lib/config/env.local.dart ]; then
rm lib/config/env.local.dart
echo "Cleaned up env.local.dart"
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: macos-artifacts
path: artifacts/
build-linux:
needs: prepare
# Use native runners for each architecture (amd64 & arm64) instead of emulation
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-latest
- arch: arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v2
- name: Setup Dart SDK
uses: dart-lang/setup-dart@v1
with:
sdk: 'stable'
# Use official action for amd64
- name: Setup Flutter (amd64)
if: matrix.arch == 'amd64'
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version-file: pubspec.yaml
# Manual install for arm64 (action currently fails to resolve version on ubuntu-24.04-arm)
- name: Setup Flutter (arm64 manual)
if: matrix.arch == 'arm64'
run: |
set -e
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y git curl unzip xz-utils zip
# Clone flutter stable at desired version (tag 3.38.1)
git clone https://github.com/flutter/flutter.git -b stable $HOME/flutter
cd $HOME/flutter
# Ensure we are at or past desired version; attempt to checkout tag if exists
if git rev-parse -q --verify refs/tags/3.38.1 >/dev/null; then
git fetch --tags
git checkout 3.38.1 || true
fi
echo "$HOME/flutter/bin" >> $GITHUB_PATH
$HOME/flutter/bin/flutter config --no-analytics
$HOME/flutter/bin/flutter doctor -v || true
- name: Install Dart (arm64, stable)
if: matrix.arch == 'arm64'
run: |
set -e
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https curl gnupg ca-certificates
curl -fsSL https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg
echo "deb [signed-by=/usr/share/keyrings/dart.gpg] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main" | sudo tee /etc/apt/sources.list.d/dart_stable.list
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y dart
echo "/usr/lib/dart/bin" >> $GITHUB_PATH
- name: Create env.local.dart
env:
STRAVA_CLIENT_ID: ${{ secrets.STRAVA_CLIENT_ID }}
STRAVA_CLIENT_SECRET: ${{ secrets.STRAVA_CLIENT_SECRET }}
INTERVALS_CLIENT_ID: ${{ secrets.INTERVALS_CLIENT_ID }}
INTERVALS_CLIENT_SECRET: ${{ secrets.INTERVALS_CLIENT_SECRET }}
run: |
mkdir -p lib/config
umask 077
cat > lib/config/env.local.dart <<EOL
class Environment {
static const String stravaClientId = '${STRAVA_CLIENT_ID}';
static const String stravaClientSecret = '${STRAVA_CLIENT_SECRET}';
static const String intervalsClientId = '${INTERVALS_CLIENT_ID}';
static const String intervalsClientSecret = '${INTERVALS_CLIENT_SECRET}';
static bool get hasStravaConfig =>
stravaClientId.isNotEmpty && stravaClientSecret.isNotEmpty;
static bool get hasIntervalsConfig =>
intervalsClientId.isNotEmpty && intervalsClientSecret.isNotEmpty;
}
EOL
# Replace environment variables
envsubst < lib/config/env.local.dart > lib/config/env.local.dart.tmp
mv lib/config/env.local.dart.tmp lib/config/env.local.dart
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \
libgtk-3-dev libx11-dev pkg-config cmake ninja-build \
libblkid-dev liblzma-dev libsecret-1-dev libjsoncpp-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev
- name: Enable Linux Desktop
run: flutter config --enable-linux-desktop
- name: Build Linux App
run: |
# Install additional build dependencies (clang & runtime libs)
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \
clang libstdc++-12-dev libglu1-mesa fontconfig libpulse0 || true
# Handle ALSA time64 transition on Ubuntu 24.04 (libasound2t64)
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libasound2 || \
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libasound2t64 || true
export CXX=clang++
flutter config --no-analytics
flutter pub get
# Build (native arch)
flutter build linux --release --no-tree-shake-icons -v
- name: Create Debian Package
run: |
# Create package directory structure
mkdir -p debian/DEBIAN
mkdir -p debian/usr/bin
mkdir -p debian/usr/share/applications
mkdir -p debian/usr/share/icons/hicolor/256x256/apps
# Create control file
cat > debian/DEBIAN/control <<EOL
Package: ss2kconfigapp
Version: ${{ needs.prepare.outputs.version }}
Section: utils
Priority: optional
Architecture: ${{ matrix.arch }}
Maintainer: SmartSpin2k Team
Description: SmartSpin2k Configuration Application
A Flutter application for configuring and controlling SmartSpin2k devices.
EOL
# Copy application files based on architecture
BUILD_PATH=""
if [ "${{ matrix.arch }}" = "arm64" ]; then
BUILD_PATH="build/linux/arm64/release/bundle"
else
BUILD_PATH="build/linux/x64/release/bundle"
fi
# Verify build path exists
if [ ! -d "$BUILD_PATH" ]; then
echo "Error: Build output not found at $BUILD_PATH"
ls -la build/linux/
exit 1
fi
# Copy files
echo "Copying files from $BUILD_PATH to debian/usr/bin/"
cp -rv "$BUILD_PATH"/* debian/usr/bin/
# Copy icon
cp assets/icons/ss2kv3.png debian/usr/share/icons/hicolor/256x256/apps/ss2kconfigapp.png
# Create desktop file
cat > debian/usr/share/applications/ss2kconfigapp.desktop <<EOL
[Desktop Entry]
Name=SmartSpin2k Config App
Exec=/usr/bin/ss2kconfigapp
Icon=ss2kconfigapp
Type=Application
Categories=Utility;
EOL
# Set permissions
chmod 755 debian/usr/bin/ss2kconfigapp
chmod -R 755 debian/DEBIAN
# Build the package with architecture in filename
dpkg-deb --build debian ss2kconfigapp-${{ matrix.arch }}.deb
- name: Create artifacts
run: |
mkdir -p artifacts
mv ss2kconfigapp-${{ matrix.arch }}.deb artifacts/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux-artifacts-${{ matrix.arch }}
path: artifacts/
create-release:
needs: [prepare, build-android, build-macos, build-linux]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: all-artifacts
- name: Prepare release bundle
run: |
mkdir -p release
cp all-artifacts/android-artifacts/ss2kconfigapp-${{ needs.prepare.outputs.version }}.apk release/ss2kconfigapp-${{ needs.prepare.outputs.version }}.apk
cp all-artifacts/macos-artifacts/ss2kconfigapp-${{ needs.prepare.outputs.version }}.zip release/
cp all-artifacts/linux-artifacts-amd64/ss2kconfigapp-amd64.deb release/ss2kconfigapp-${{ needs.prepare.outputs.version }}-amd64.deb
cp all-artifacts/linux-artifacts-arm64/ss2kconfigapp-arm64.deb release/ss2kconfigapp-${{ needs.prepare.outputs.version }}-arm64.deb
- name: Create release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.prepare.outputs.version }}
name: SmartSpin2kConfigApp ${{ needs.prepare.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
body: ${{ github.event.head_commit.message }}
files: |
release/ss2kconfigapp-${{ needs.prepare.outputs.version }}.apk
release/ss2kconfigapp${{ needs.prepare.outputs.version }}.zip
release/ss2kconfigapp-${{ needs.prepare.outputs.version }}-amd64.deb
release/ss2kconfigapp-${{ needs.prepare.outputs.version }}-arm64.deb