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
163 changes: 4 additions & 159 deletions .github/workflows/flutter-linux.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
name: Flutter Linux

on:
workflow_dispatch:
inputs:
production_release:
description: 'Build an official production Snap (main only)'
type: boolean
required: true
default: false
pull_request:
branches: [main]
push:
Expand All @@ -22,12 +15,6 @@ jobs:
runs-on: ubuntu-24.04

steps:
- name: Require main for manual runs
if: github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/main'
run: |
echo '::error::Manual Linux builds must run from main.'
exit 1

- name: Check out repository
uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -133,60 +120,10 @@ jobs:
integration_test/gtk_header_icons_integration_test.dart -d linux

- name: Test native clock patterns, weekday locale, and GTK time picker
run: |
mkdir -p build/linux/native-tests
g++ -std=c++17 -Wall -Wextra -Werror \
windows/runner/tests/short_time_pattern_test.cpp \
-o build/linux/native-tests/short_time_pattern_test
build/linux/native-tests/short_time_pattern_test
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/first_weekday_test.cc \
-o build/linux/native-tests/first_weekday_test
build/linux/native-tests/first_weekday_test
mkdir -p build/linux/native-tests/weekday-schemas
glib-compile-schemas --strict \
--targetdir=build/linux/native-tests/weekday-schemas \
linux/runner/tests/schemas
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/first_weekday_preference_test.cc \
linux/runner/first_weekday_preference.cc \
-o build/linux/native-tests/first_weekday_preference_test \
$(pkg-config --cflags --libs gio-2.0)
build/linux/native-tests/first_weekday_preference_test \
build/linux/native-tests/weekday-schemas
LC_ALL=C.UTF-8 MALLOC_PERTURB_=165 \
build/linux/native-tests/first_weekday_test
g++ -std=c++17 -Wall -Wextra -Werror \
-fsanitize=address -fno-omit-frame-pointer \
linux/runner/tests/first_weekday_test.cc \
-o build/linux/native-tests/first_weekday_test_asan
ASAN_OPTIONS=detect_leaks=0 \
build/linux/native-tests/first_weekday_test_asan
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/time_picker_test.cc \
-o build/linux/native-tests/time_picker_test \
$(pkg-config --cflags --libs gtk+-3.0)
xvfb-run -a build/linux/native-tests/time_picker_test
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/gtk_window_preferences_test.cc \
linux/runner/gtk_window_preferences.cc \
-o build/linux/native-tests/gtk_window_preferences_test \
$(pkg-config --cflags --libs gtk+-3.0)
xvfb-run -a build/linux/native-tests/gtk_window_preferences_test
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/gtk_header_icons_test.cc \
linux/runner/gtk_header_icons.cc \
-o build/linux/native-tests/gtk_header_icons_test \
$(pkg-config --cflags --libs gtk+-3.0)
XDG_CONFIG_HOME="$RUNNER_TEMP/busymax-gtk-config" \
xvfb-run -a sh -c 'build/linux/native-tests/gtk_header_icons_test'
g++ -std=c++17 -Wall -Wextra -Werror \
linux/runner/tests/gtk_search_entry_theme_test.cc \
linux/runner/gtk_search_entry_theme.cc \
-o build/linux/native-tests/gtk_search_entry_theme_test \
$(pkg-config --cflags --libs gtk+-3.0)
xvfb-run -a env GDK_BACKEND=x11 \
build/linux/native-tests/gtk_search_entry_theme_test
run: BUSYMAX_GTK_CONFIG="$RUNNER_TEMP/busymax-gtk-config" bash tool/release/check_linux_native.sh

- name: Test local release tooling
run: python3 -m unittest discover -s test/tool -p '*_test.py'

- name: Test native registration helper teardown
run: python3 test/tool/registration_native_helper_test.py
Expand All @@ -203,78 +140,10 @@ jobs:
test -f build/linux/x64/release/bundle/data/flutter_assets/docs/google_setup.md
test -f build/linux/x64/release/bundle/data/flutter_assets/docs/microsoft_setup.md

- name: Validate production registrations and protected originals
if: github.event_name == 'workflow_dispatch' && inputs.production_release && github.ref == 'refs/heads/main'
env:
GOOGLE_OAUTH_CLIENT_ID: ${{ vars.GOOGLE_OAUTH_CLIENT_ID }}
GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
GOOGLE_OAUTH_PROJECT_ID: ${{ vars.GOOGLE_OAUTH_PROJECT_ID }}
MICROSOFT_OAUTH_CLIENT_ID: ${{ vars.MICROSOFT_OAUTH_CLIENT_ID }}
MICROSOFT_OAUTH_AUTHORITY_TENANT: ${{ vars.MICROSOFT_OAUTH_AUTHORITY_TENANT }}
BUSYMAX_GOOGLE_OAUTH_CLIENT_ID: ${{ vars.BUSYMAX_GOOGLE_OAUTH_CLIENT_ID }}
BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET }}
BUSYMAX_GOOGLE_OAUTH_PROJECT_ID: ${{ vars.BUSYMAX_GOOGLE_OAUTH_PROJECT_ID }}
BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID: ${{ vars.BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID }}
BUSYMAX_PRIVACY_POLICY_URL: https://busystack.org/privacy-busymax
run: '"$BUSYMAX_DART_EXECUTABLE" run tool/check_desktop_oauth_config.dart'

- name: Build official Linux release with explicit active registrations
if: github.event_name == 'workflow_dispatch' && inputs.production_release && github.ref == 'refs/heads/main'
env:
GOOGLE_OAUTH_CLIENT_ID: ${{ vars.GOOGLE_OAUTH_CLIENT_ID }}
GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
GOOGLE_OAUTH_PROJECT_ID: ${{ vars.GOOGLE_OAUTH_PROJECT_ID }}
MICROSOFT_OAUTH_CLIENT_ID: ${{ vars.MICROSOFT_OAUTH_CLIENT_ID }}
MICROSOFT_OAUTH_AUTHORITY_TENANT: ${{ vars.MICROSOFT_OAUTH_AUTHORITY_TENANT }}
BUSYMAX_GOOGLE_OAUTH_CLIENT_ID: ${{ vars.BUSYMAX_GOOGLE_OAUTH_CLIENT_ID }}
BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET }}
BUSYMAX_GOOGLE_OAUTH_PROJECT_ID: ${{ vars.BUSYMAX_GOOGLE_OAUTH_PROJECT_ID }}
BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID: ${{ vars.BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID }}
BUSYMAX_PRIVACY_POLICY_URL: https://busystack.org/privacy-busymax
run: |
registration_file="$(mktemp "$RUNNER_TEMP/busymax-oauth.XXXXXX.json")"
trap 'rm -f "$registration_file"' EXIT
python3 - "$registration_file" <<'PYCONFIG'
import json, os, sys
keys = [
'GOOGLE_OAUTH_CLIENT_ID', 'GOOGLE_OAUTH_CLIENT_SECRET',
'GOOGLE_OAUTH_PROJECT_ID', 'MICROSOFT_OAUTH_CLIENT_ID',
'MICROSOFT_OAUTH_AUTHORITY_TENANT',
'BUSYMAX_GOOGLE_OAUTH_CLIENT_ID', 'BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET',
'BUSYMAX_GOOGLE_OAUTH_PROJECT_ID', 'BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID',
'BUSYMAX_PRIVACY_POLICY_URL',
]
with open(sys.argv[1], 'w') as output:
json.dump({key: os.environ[key] for key in keys if os.environ.get(key)}, output)
PYCONFIG
"$BUSYMAX_FLUTTER_EXECUTABLE" build linux --release \
-t lib/main_linux.dart --dart-define-from-file="$registration_file"
binary=build/linux/x64/release/bundle/lib/libapp.so
for key in GOOGLE_OAUTH_CLIENT_ID MICROSOFT_OAUTH_CLIENT_ID \
BUSYMAX_GOOGLE_OAUTH_CLIENT_ID BUSYMAX_GOOGLE_OAUTH_CLIENT_SECRET \
BUSYMAX_GOOGLE_OAUTH_PROJECT_ID BUSYMAX_MICROSOFT_OAUTH_CLIENT_ID; do
grep -aFq -- "${!key}" "$binary"
done
if [ -n "$GOOGLE_OAUTH_CLIENT_SECRET" ]; then
grep -aFq -- "$GOOGLE_OAUTH_CLIENT_SECRET" "$binary"
fi

- name: Build strict Snap from the release bundle
id: snapcraft
uses: snapcore/action-build@v1

- name: Build deterministic sibling-layout source archive
run: python3 tool/package_source.py

- name: Upload pinned source artifact
if: github.event_name == 'push'
uses: actions/upload-artifact@v7
with:
name: busymax-source
path: dist/source/
if-no-files-found: error
retention-days: 7

- name: Install strict Snap
run: >-
sudo snap install --dangerous
Expand All @@ -286,27 +155,3 @@ jobs:
grep -Eq '^[[:space:]]*confinement:[[:space:]]+strict$'
# shellcheck disable=SC2016
snap run --shell busymax -c 'test -x "$SNAP/busymax"'

- name: Label non-production Snap artifact
if: github.event_name != 'workflow_dispatch' || !inputs.production_release
env:
SNAP_ARTIFACT: ${{ steps.snapcraft.outputs.snap }}
run: cp -- "$SNAP_ARTIFACT" build/busymax-snap-ci-non-production.snap

- name: Upload non-production Snap artifact
if: github.event_name != 'workflow_dispatch' || !inputs.production_release
uses: actions/upload-artifact@v7
with:
name: busymax-snap-ci-non-production
path: build/busymax-snap-ci-non-production.snap
if-no-files-found: error
retention-days: 7

- name: Upload Snap artifact
if: github.event_name == 'workflow_dispatch' && inputs.production_release && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v7
with:
name: busymax-snap
path: ${{ steps.snapcraft.outputs.snap }}
if-no-files-found: error
retention-days: 7
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ migrate_working_dir/

# Per-run evidence belongs in build/ or a temporary directory.
/docs/validation/
/docs/development/evidence/

# Transient Kotlin compiler session state.
.kotlin/
Expand Down Expand Up @@ -65,3 +66,7 @@ config/windows_store.local.json
*.pem
*.key
*.crt

# Local public release settings; downloaded Google JSON stays outside Git.
config/release.local.json
client_secret*.json
2 changes: 1 addition & 1 deletion android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ android {
// (https://developer.android.com/studio/build/configure-apk-splits#configure-APK-versions)
// You can force using the value of versionCode by specifying the `-P force-version-code-ignoring-abi=true`
// flag during build.
versionCode = 5
versionCode = 6
versionName = flutter.versionName
manifestPlaceholders["busymaxMsalRedirectHost"] = applicationId!!
manifestPlaceholders["busymaxMsalSignatureHash"] = msalSignatureHash
Expand Down
1 change: 1 addition & 0 deletions docs/android_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ outside logs and shell history. Do not replace an established upload identity.
For v0.3.0 the public version is `0.3.0` and the package code is `5`, advancing
the v0.2.4 source and retained test-signed artifact code `4`. During preparation
on 2026-10-11, the owner confirmed `4` is the highest distributed base code.
For v0.3.1, code `6` is confirmed available by the owner on 2026-10-11.
For subsequent releases, verify the distribution ledger and account for ABI
offsets if split APKs were distributed before choosing the next code.

Expand Down
Loading
Loading