migration: move to bash based build scripts

This commit is contained in:
Matthew Raymer
2025-06-24 11:11:33 +00:00
parent d359263704
commit 94ac7d648d
34 changed files with 3350 additions and 571 deletions

View File

@@ -1,6 +1,6 @@
# Building TimeSafari
This guide explains how to build TimeSafari for different platforms.
This guide explains how to build TimeSafari for different platforms using our unified build scripts.
## Prerequisites
@@ -11,6 +11,57 @@ For a quick dev environment setup, use [pkgx](https://pkgx.dev).
- Git
- For desktop builds: Additional build tools based on your OS
## Unified Build Scripts
TimeSafari now uses unified build scripts that automatically handle environment variables, logging, error handling, and timing. All scripts are located in the `scripts/` directory and use a common utilities library.
### Script Features
- **Automatic Environment Setup**: Each script sets the correct environment variables for its build type
- **Rich Logging**: Colored, timestamped output with different log levels
- **Error Handling**: Proper exit codes and graceful failure recovery
- **Timing**: Automatic execution time tracking for each step
- **Validation**: Checks for required dependencies and files
- **CLI Options**: `--help`, `--verbose`, `--env` flags for all scripts
### Available Scripts
| Script | Purpose | Command |
|--------|---------|---------|
| `electron-dev.sh` | Electron development | `./scripts/electron-dev.sh` |
| `electron-build.sh` | Electron build | `./scripts/build-electron.sh` |
| `capacitor-dev.sh` | Capacitor development | `./scripts/capacitor-dev.sh` |
| `capacitor-build.sh` | Capacitor build | `./scripts/build-capacitor.sh` |
| `web-dev.sh` | Web development | `./scripts/web-dev.sh` |
| `web-build.sh` | Web build | `./scripts/build-web.sh` |
### Environment Variables
All scripts automatically set the correct environment variables for their build type:
| Build Type | VITE_PLATFORM | VITE_PWA_ENABLED | VITE_DISABLE_PWA | NODE_ENV |
|------------|---------------|------------------|------------------|----------|
| `electron` | electron | false | true | production* |
| `capacitor` | capacitor | false | true | - |
| `web` | web | true | false | - |
*NODE_ENV=production only set when production mode is enabled
### CLI Options
All scripts support these options:
```bash
# Show help
./scripts/build-electron.sh --help
# Enable verbose logging
./scripts/build-electron.sh --verbose
# Show environment variables
./scripts/build-electron.sh --env
```
## Forks
If you have forked this to make your own app, you'll want to customize the iOS & Android files. You can either edit existing ones, or you can remove the `ios` and `android` directories and regenerate them before the `npx cap sync` step in each setup.
@@ -30,18 +81,19 @@ Install dependencies:
npm install
```
## Web Dev Locally
## Web Development
### Local Development
```bash
npm run dev
```
## Web Build for Server
### Web Build for Server
1. Run the production build:
```bash
rm -rf dist
npm run build:web
```
@@ -49,57 +101,288 @@ Install dependencies:
2. To test the production build locally:
You'll likely want to use test locations for the Endorser & image & partner servers; see "DEFAULT_ENDORSER_API_SERVER" & "DEFAULT_IMAGE_API_SERVER" & "DEFAULT_PARTNER_API_SERVER" below.
```bash
npm run serve
```
### Compile and minify for test & production
### Environment Configuration
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
* `npx prettier --write ./sw_scripts/`
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build`
* Commit everything (since the commit hash is used the app).
* Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 1.0.2 && git push origin 1.0.2`.
* For test, build the app (because test server is not yet set up to build):
For different environments, create `.env` files:
```bash
TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app VITE_PASSKEYS_ENABLED=true npm run build:web
# .env.development
VITE_APP_SERVER=https://dev.timesafari.app
VITE_DEFAULT_ENDORSER_API_SERVER=https://dev-api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://dev-image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://dev-partner-api.endorser.ch
VITE_DEFAULT_PUSH_SERVER=https://dev.timesafari.app
VITE_PASSKEYS_ENABLED=true
# .env.production
VITE_APP_SERVER=https://timesafari.app
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
VITE_DEFAULT_PUSH_SERVER=https://timesafari.app
VITE_PASSKEYS_ENABLED=true
```
... and transfer to the test server:
## Desktop Build (Electron)
### Development
For development with automatic environment setup:
```bash
./scripts/electron-dev.sh
```
### Production Build
For production builds with automatic environment setup:
```bash
./scripts/build-electron.sh
```
### Linux Packaging
```bash
# Build AppImage (recommended)
./scripts/build-electron-linux.sh
# Build .deb package
./scripts/build-electron-linux.sh deb
# Build production AppImage
./scripts/build-electron-linux.sh prod
```
The packaged applications will be in `dist-electron-packages/`:
- AppImage: `dist-electron-packages/TimeSafari-x.x.x.AppImage`
- DEB: `dist-electron-packages/timesafari_x.x.x_amd64.deb`
### macOS Packaging
```bash
# Build standard Mac package
./scripts/build-electron-mac.sh
# Build universal package (Intel + Apple Silicon)
./scripts/build-electron-mac.sh universal
```
The packaged applications will be in `dist-electron-packages/`:
- `.app` bundle: `TimeSafari.app`
- `.dmg` installer: `TimeSafari-x.x.x.dmg`
- `.zip` archive: `TimeSafari-x.x.x-mac.zip`
### Code Signing and Notarization (macOS)
For public distribution on macOS, you need to code sign and notarize your app:
1. Set up environment variables in `.env` file:
```bash
rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari
CSC_LINK=/path/to/your/certificate.p12
CSC_KEY_PASSWORD=your_certificate_password
APPLE_ID=your_apple_id
APPLE_ID_PASSWORD=your_app_specific_password
```
(Let's replace that with a .env.development or .env.staging file.)
2. Build with signing:
```bash
./scripts/build-electron-mac.sh
```
(Note: The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there.)
### Running the Packaged App
* For prod, get on the server and run the correct build:
- **Linux**:
- AppImage: Make executable and run
```bash
chmod +x dist-electron-packages/TimeSafari-*.AppImage
./dist-electron-packages/TimeSafari-*.AppImage
```
- DEB: Install and run
```bash
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
timesafari
```
... and log onto the server:
- **macOS**:
- `.app` bundle: Double-click `TimeSafari.app` in Finder
- `.dmg` installer:
1. Double-click the `.dmg` file
2. Drag the app to your Applications folder
3. Launch from Applications
- `.zip` archive:
1. Extract the `.zip` file
2. Move `TimeSafari.app` to your Applications folder
3. Launch from Applications
* `pkgx +npm sh`
Note: If you get a security warning when running the app:
1. Right-click the app
2. Select "Open"
3. Click "Open" in the security dialog
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 1.0.2 && npm install && npm run build:web && cd -`
## Mobile Builds (Capacitor)
(The plain `npm run build:web` uses the .env.production file.)
### Android Build
* Back up the time-safari/dist folder & deploy: `mv time-safari/dist time-safari-dist-prev-2 && mv crowd-funder-for-time-pwa/dist time-safari/`
Prerequisites: Android Studio with Java SDK installed
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, commit, and push. Also record what version is on production.
#### Complete Build Process
Use the unified Android build script:
```bash
./scripts/build-android.sh
```
This script automatically:
1. Sets up environment variables for Capacitor
2. Cleans previous builds
3. Builds web assets
4. Builds Capacitor version
5. Cleans and builds Gradle project
6. Syncs with Capacitor
7. Generates assets
8. Opens Android Studio
#### Manual Steps (if needed)
If you need to run individual steps:
1. Build the web assets:
```bash
npm run build:web
npm run build:capacitor
```
2. Update Android project:
```bash
npx cap sync android
```
3. Generate assets:
```bash
npx capacitor-assets generate --android
```
4. Open in Android Studio:
```bash
npx cap open android
```
#### Console Build
For building from the console:
```bash
cd android
./gradlew clean
./gradlew build -Dlint.baselines.continue=true
cd -
```
For creating an `aab` file:
```bash
cd android
./gradlew bundleDebug -Dlint.baselines.continue=true
cd -
```
For creating a signed release:
1. Setup signing configuration in `app/gradle.properties.secrets`
2. Add signing key file `app/time-safari-upload-key-pkcs12.jks`
3. Update version in `app/build.gradle`
4. Build release:
```bash
cd android
./gradlew bundleRelease -Dlint.baselines.continue=true
cd -
```
The `aab` file will be at `app/build/outputs/bundle/release`.
### iOS Build
Prerequisites: macOS with Xcode installed
#### First-time iOS Configuration
- Generate certificates inside Xcode
- Right-click on App and under Signing & Capabilities set the Team
#### Build Process
1. Build the web assets & update iOS:
```bash
npm run build:web
npm run build:capacitor
npx cap sync ios
```
2. Generate assets:
```bash
# Create required directories
mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
mkdir -p ios/App/App/Assets.xcassets/Splash.imageset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
# Generate assets
npx capacitor-assets generate --ios
```
3. Update version to match Android & package.json:
```bash
cd ios/App
xcrun agvtool new-version 35
perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj
cd -
```
4. Open in Xcode:
```bash
npx cap open ios
```
5. Build and run on simulator or device using Xcode
#### Release Process
1. Choose Product -> Destination -> Any iOS Device
2. Choose Product -> Archive
3. Click Distribute -> App Store Connect
4. In App Store Connect, add the build to the distribution
## Testing
### Complete Test Suite
Run all tests with automatic environment setup:
```bash
./scripts/test-all.sh
```
### Mobile Tests
Run mobile-specific tests:
```bash
./scripts/test-mobile.sh
```
### Environment Testing
Test environment variable handling:
```bash
./scripts/test-env.sh
```
## Docker Deployment
@@ -202,270 +485,11 @@ docker run -d \
- Check nginx configuration
- Verify caching settings
## Desktop Build (Electron)
## Configuration
### Linux Build
### Deep Links
1. Build the electron app in production mode:
```bash
npm run build:electron-prod
```
2. Package the Electron app for Linux:
```bash
# For AppImage (recommended)
npm run electron:build-linux
# For .deb package
npm run electron:build-linux-deb
```
3. The packaged applications will be in `dist-electron-packages/`:
- AppImage: `dist-electron-packages/TimeSafari-x.x.x.AppImage`
- DEB: `dist-electron-packages/timesafari_x.x.x_amd64.deb`
### macOS Build
1. Build the electron app in production mode:
```bash
npm run build:web
npm run build:electron
npm run electron:build-mac
```
2. Package the Electron app for macOS:
```bash
# For Intel Macs
npm run electron:build-mac
# For Universal build (Intel + Apple Silicon)
npm run electron:build-mac-universal
```
3. The packaged applications will be in `dist-electron-packages/`:
- `.app` bundle: `TimeSafari.app`
- `.dmg` installer: `TimeSafari-x.x.x.dmg`
- `.zip` archive: `TimeSafari-x.x.x-mac.zip`
### Code Signing and Notarization (macOS)
For public distribution on macOS, you need to code sign and notarize your app:
1. Set up environment variables:
```bash
export CSC_LINK=/path/to/your/certificate.p12
export CSC_KEY_PASSWORD=your_certificate_password
export APPLE_ID=your_apple_id
export APPLE_ID_PASSWORD=your_app_specific_password
```
2. Build with signing:
```bash
npm run electron:build-mac
```
### Running the Packaged App
- **Linux**:
- AppImage: Make executable and run
```bash
chmod +x dist-electron-packages/TimeSafari-*.AppImage
./dist-electron-packages/TimeSafari-*.AppImage
```
- DEB: Install and run
```bash
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
timesafari
```
- **macOS**:
- `.app` bundle: Double-click `TimeSafari.app` in Finder
- `.dmg` installer:
1. Double-click the `.dmg` file
2. Drag the app to your Applications folder
3. Launch from Applications
- `.zip` archive:
1. Extract the `.zip` file
2. Move `TimeSafari.app` to your Applications folder
3. Launch from Applications
Note: If you get a security warning when running the app:
1. Right-click the app
2. Select "Open"
3. Click "Open" in the security dialog
### Development Testing
For testing the Electron build before packaging:
```bash
# Build and run in development mode (includes DevTools)
npm run electron:dev
# Build in production mode and test
npm run build:electron-prod && npm run electron:start
```
## Mobile Builds (Capacitor)
### iOS Build
Prerequisites: macOS with Xcode installed
#### First-time iOS Configuration
- Generate certificates inside XCode.
- Right-click on App and under Signing & Capabilities set the Team.
#### Each Release
0. First time (or if dependencies change):
- `pkgx +rubygems.org sh`
- ... and you may have to fix these, especially with pkgx:
```bash
gem_path=$(which gem)
shortened_path="${gem_path:h:h}"
export GEM_HOME=$shortened_path
export GEM_PATH=$shortened_path
```
1. Build the web assets & update ios:
```bash
rm -rf dist
npm run build:web
npm run build:capacitor
npx cap sync ios
```
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
3. Copy the assets:
```bash
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents.
mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
mkdir -p ios/App/App/Assets.xcassets/Splash.imageset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
npx capacitor-assets generate --ios
```
4. Bump the version to match Android & package.json:
```
cd ios/App && xcrun agvtool new-version 35 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj && cd -
# Unfortunately this edits Info.plist directly.
#xcrun agvtool new-marketing-version 0.4.5
```
5. Open the project in Xcode:
```bash
npx cap open ios
```
6. Use Xcode to build and run on simulator or device.
* Select Product -> Destination with some Simulator version. Then click the run arrow.
7. Release
* Someday: Under "General" we want to rename a bunch of things to "Time Safari"
* Choose Product -> Destination -> Any iOS Device
* Choose Product -> Archive
* This will trigger a build and take time, needing user's "login" keychain password (user's login password), repeatedly.
* If it fails with `building for 'iOS', but linking in dylib (.../.pkgx/zlib.net/v1.3.0/lib/libz.1.3.dylib) built for 'macOS'` then run XCode outside that terminal (ie. not with `npx cap open ios`).
* Click Distribute -> App Store Connect
* In AppStoreConnect, add the build to the distribution: remove the current build with the "-" when you hover over it, then "Add Build" with the new build.
* May have to go to App Review, click Submission, then hover over the build and click "-".
* It can take 15 minutes for the build to show up in the list of builds.
* You'll probably have to "Manage" something about encryption, disallowed in France.
* Then "Save" and "Add to Review" and "Resubmit to App Review".
### Android Build
Prerequisites: Android Studio with Java SDK installed
1. Build the web assets:
```bash
rm -rf dist
npm run build:web
npm run build:capacitor
```
2. Update Android project with latest build:
```bash
npx cap sync android
```
3. Copy the assets
```bash
npx capacitor-assets generate --android
```
4. Bump version to match iOS & package.json: android/app/build.gradle
5. Open the project in Android Studio:
```bash
npx cap open android
```
6. Use Android Studio to build and run on emulator or device.
## Android Build from the console
```bash
cd android
./gradlew clean
./gradlew build -Dlint.baselines.continue=true
cd -
```
... or, to create the `aab` file, `bundle` instead of `build`:
```bash
./gradlew bundleDebug -Dlint.baselines.continue=true
```
... or, to create a signed release:
* Setup by adding the app/gradle.properties.secrets file (see properties at top of app/build.gradle) and the app/time-safari-upload-key-pkcs12.jks file
* In app/build.gradle, bump the versionCode and maybe the versionName
* Then `bundleRelease`:
```bash
cd android
./gradlew bundleRelease -Dlint.baselines.continue=true
cd -
```
... and find your `aab` file at app/build/outputs/bundle/release
At play.google.com/console:
- Go to the Testing Track (eg. Closed).
- Click "Create new release".
- Upload the `aab` file.
- Hit "Next".
- Save, go to "Publishing Overview" as prompted, and click "Send changes for review".
- Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
## Android Configuration for deep links
#### Android Configuration
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
@@ -478,4 +502,52 @@ You must add the following intent filter to the `android/app/src/main/AndroidMan
</intent-filter>
```
... though when we tried that most recently it failed to 'build' the APK with: http(s) scheme and host attribute are missing, but are required for Android App Links [AppLinkUrlError]
Note: When using `timesafari://` scheme, you may encounter build errors about missing http(s) scheme and host attributes. This is expected for custom URL schemes.
#### iOS Configuration
For iOS deep links, configure the URL scheme in Xcode:
1. Open the project in Xcode
2. Select your app target
3. Go to Info tab
4. Add URL Types with scheme `timesafari`
## Troubleshooting
### Common Issues
1. **Environment Variables Not Set**
- Use `--env` flag to check current environment: `./scripts/build-electron.sh --env`
- Verify `.env` file exists and is properly formatted
- Check script output for environment setup messages
2. **Build Failures**
- Use `--verbose` flag for detailed logging: `./scripts/build-electron.sh --verbose`
- Check prerequisites are installed
- Verify all dependencies are installed: `npm install`
3. **Permission Issues**
- Make scripts executable: `chmod +x scripts/*.sh`
- Check file permissions on build directories
4. **Platform-Specific Issues**
- **Linux**: Ensure AppImage dependencies are installed
- **macOS**: Check code signing certificates and entitlements
- **Android**: Verify Android Studio and SDK are properly configured
- **iOS**: Ensure Xcode and certificates are set up correctly
### Getting Help
- Check script help: `./scripts/build-electron.sh --help`
- Review script documentation in `scripts/README.md`
- Test environment setup: `./scripts/test-env.sh`
- Test common utilities: `./scripts/test-common.sh`
### Platform Support Matrix
| Platform | Mode | PWA Enabled | Native Features | Notes |
|----------|------|-------------|-----------------|-------|
| `web` | web | true | false | Standard web browser |
| `capacitor` | capacitor | false | true | Mobile app (iOS/Android) |
| `electron` | electron | false | true | Desktop app (Windows/macOS/Linux) |