7 Commits

Author SHA1 Message Date
86187d9069 launch adjustments
Some checks failed
Run linting on the backend code / Build (pull_request) Failing after 28s
Run testing on the backend code / Build (pull_request) Failing after 1m28s
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m35s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 17s
2024-12-29 15:06:23 +01:00
4e07c10969 actually use fastapi lifetime manager to setup logging
Some checks failed
Run testing on the backend code / Build (pull_request) Has been cancelled
Run linting on the backend code / Build (pull_request) Has been cancelled
Build and deploy the backend to staging / Deploy to staging (pull_request) Has been cancelled
Build and deploy the backend to staging / Build and push image (pull_request) Has been cancelled
2024-12-29 14:45:41 +01:00
bc63b57154 dumb type conversion
Some checks failed
Run linting on the backend code / Build (pull_request) Has been cancelled
Run testing on the backend code / Build (pull_request) Has been cancelled
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m14s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 38s
2024-12-28 22:34:14 +01:00
fa083a1080 logging cleanup
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m9s
Run linting on the backend code / Build (pull_request) Failing after 30s
Run testing on the backend code / Build (pull_request) Failing after 1m41s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 18s
2024-12-28 22:25:42 +01:00
c448e2dfb7 more verbose logger setup
Some checks failed
Run linting on the backend code / Build (pull_request) Has been cancelled
Run testing on the backend code / Build (pull_request) Has been cancelled
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m32s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 16s
2024-12-28 15:52:29 +01:00
d9061388dd use additional loki logger
Some checks failed
Run linting on the backend code / Build (pull_request) Successful in 28s
Run testing on the backend code / Build (pull_request) Failing after 1m27s
Build and deploy the backend to staging / Build and push image (pull_request) Failing after 20s
Build and deploy the backend to staging / Deploy to staging (pull_request) Has been skipped
2024-12-28 14:01:21 +01:00
e764393706 Some more pipeline-fixes (#46)
Some checks failed
/ push-to-remote (push) Successful in 13s
Build and deploy the backend to production / Deploy to production (push) Has been cancelled
Build and deploy the backend to production / Build and push image (push) Has been cancelled
Reviewed-on: #46
2024-12-21 15:54:04 +00:00
22 changed files with 149 additions and 1165 deletions

View File

@@ -25,8 +25,6 @@ jobs:
ls -la ls -la
# only install dev-packages # only install dev-packages
pipenv install --categories=dev-packages pipenv install --categories=dev-packages
pipenv run pip freeze
working-directory: backend working-directory: backend
- name: Run linter - name: Run linter

View File

@@ -25,7 +25,6 @@ jobs:
ls -la ls -la
# install all packages, including dev-packages # install all packages, including dev-packages
pipenv install --dev pipenv install --dev
pipenv run pip freeze
working-directory: backend working-directory: backend
- name: Run Tests - name: Run Tests

14
.vscode/launch.json vendored
View File

@@ -9,18 +9,16 @@
"name": "Backend - debug", "name": "Backend - debug",
"type": "debugpy", "type": "debugpy",
"request": "launch", "request": "launch",
"module": "uvicorn",
"env": { "env": {
"DEBUG": "true" "DEBUG": "true"
}, },
"args": [
// "--app-dir",
// "src",
"src.main:app",
"--reload",
],
"jinja": true, "jinja": true,
"cwd": "${workspaceFolder}/backend" "cwd": "${workspaceFolder}/backend",
"module": "fastapi",
"args": [
"dev",
"src/main.py"
]
}, },
{ {
"name": "Backend - tester", "name": "Backend - tester",

View File

@@ -1,3 +0,0 @@
{
"cmake.ignoreCMakeListsMissing": true
}

View File

@@ -14,5 +14,7 @@ EXPOSE 8000
ENV NUM_WORKERS=1 ENV NUM_WORKERS=1
ENV OSM_CACHE_DIR=/cache ENV OSM_CACHE_DIR=/cache
ENV MEMCACHED_HOST_PATH=none ENV MEMCACHED_HOST_PATH=none
ENV LOKI_URL=none
# explicitly use a string instead of an argument list to force a shell and variable expansion
CMD fastapi run src/main.py --port 8000 --workers $NUM_WORKERS CMD fastapi run src/main.py --port 8000 --workers $NUM_WORKERS

View File

@@ -25,3 +25,4 @@ pymemcache = "*"
fastapi-cli = "*" fastapi-cli = "*"
scikit-learn = "*" scikit-learn = "*"
pyqt6 = "*" pyqt6 = "*"
loki-logger-handler = "*"

11
backend/Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "bb22b4e28c7aa199c94b688ad93d3ab0ccf1089a172131f4aec03b78e7bd7f1c" "sha256": "6edd6644586e8814a0b4526adb3352dfc17828ca129de7a68c1d5929efe94daa"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": {}, "requires": {},
@@ -507,6 +507,15 @@
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==1.4.7" "version": "==1.4.7"
}, },
"loki-logger-handler": {
"hashes": [
"sha256:aa1a9c933282c134a1e4271aba3cbaa2a3660eab6ea415bad7a072444ab98aa8",
"sha256:f6114727a9e5e6f3f2058b9b5324d1cab6d1a04e802079f7b57a8aeb7bd0a112"
],
"index": "pypi",
"markers": "python_version >= '2.7'",
"version": "==1.0.2"
},
"lxml": { "lxml": {
"hashes": [ "hashes": [
"sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e", "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e",

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,5 @@
"""Module allowing to access the parameters of route generation""" """Module setting global parameters for the application such as cache, route generation, etc."""
import logging
import os import os
from pathlib import Path from pathlib import Path
@@ -16,21 +15,6 @@ cache_dir_string = os.getenv('OSM_CACHE_DIR', './cache')
OSM_CACHE_DIR = Path(cache_dir_string) OSM_CACHE_DIR = Path(cache_dir_string)
# if we are in a debug session, set verbose and rich logging
if os.getenv('DEBUG', "false") == "true":
from rich.logging import RichHandler
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[RichHandler()]
)
else:
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
)
MEMCACHED_HOST_PATH = os.getenv('MEMCACHED_HOST_PATH', None) MEMCACHED_HOST_PATH = os.getenv('MEMCACHED_HOST_PATH', None)
if MEMCACHED_HOST_PATH == "none": if MEMCACHED_HOST_PATH == "none":
MEMCACHED_HOST_PATH = None MEMCACHED_HOST_PATH = None

View File

@@ -0,0 +1,58 @@
"""Sets up global logging configuration for the application."""
import logging
import os
logger = logging.getLogger(__name__)
def configure_logging():
"""
Called at startup of a FastAPI application instance to setup logging. Depending on the environment, it will log to stdout or to Loki.
"""
is_debug = os.getenv('DEBUG', "false") == "true"
is_kubernetes = os.getenv('KUBERNETES_SERVICE_HOST') is not None
if is_kubernetes:
# in that case we want to log to stdout and also to loki
from loki_logger_handler.loki_logger_handler import LokiLoggerHandler
loki_url = os.getenv('LOKI_URL')
loki_url = "http://localhost:3100/loki/api/v1/push"
if loki_url is None:
raise ValueError("LOKI_URL environment variable is not set")
loki_handler = LokiLoggerHandler(
url = loki_url,
labels = {'app': 'anyway', 'environment': 'staging' if is_debug else 'production'}
)
logger.info(f"Logging to Loki at {loki_url} with {loki_handler.labels} and {is_debug=}")
logging_handlers = [loki_handler, logging.StreamHandler()]
logging_level = logging.DEBUG if is_debug else logging.INFO
# silence the chatty logs loki generates itself
logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)
# no need for time since it's added by loki or can be shown in kube logs
logging_format = '%(name)s - %(levelname)s - %(message)s'
else:
# if we are in a debug (local) session, set verbose and rich logging
from rich.logging import RichHandler
logging_handlers = [RichHandler()]
logging_level = logging.DEBUG if is_debug else logging.INFO
logging_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
logging.basicConfig(
level = logging_level,
format = logging_format,
handlers = logging_handlers
)
# also overwrite the uvicorn loggers
logging.getLogger('uvicorn').handlers = logging_handlers
logging.getLogger('uvicorn.access').handlers = logging_handlers
logging.getLogger('uvicorn.error').handlers = logging_handlers

View File

@@ -2,7 +2,9 @@
import logging import logging
from fastapi import FastAPI, HTTPException, Query from fastapi import FastAPI, HTTPException, Query
from contextlib import asynccontextmanager
from .logging_config import configure_logging
from .structs.landmark import Landmark, Toilets from .structs.landmark import Landmark, Toilets
from .structs.preferences import Preferences from .structs.preferences import Preferences
from .structs.linked_landmarks import LinkedLandmarks from .structs.linked_landmarks import LinkedLandmarks
@@ -11,17 +13,28 @@ from .utils.landmarks_manager import LandmarkManager
from .utils.toilets_manager import ToiletsManager from .utils.toilets_manager import ToiletsManager
from .utils.optimizer import Optimizer from .utils.optimizer import Optimizer
from .utils.refiner import Refiner from .utils.refiner import Refiner
from .persistence import client as cache_client from .cache import client as cache_client
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
app = FastAPI()
manager = LandmarkManager() manager = LandmarkManager()
optimizer = Optimizer() optimizer = Optimizer()
refiner = Refiner(optimizer=optimizer) refiner = Refiner(optimizer=optimizer)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Function to run at the start of the app"""
logger.info("Setting up logging")
configure_logging()
yield
logger.info("Shutting down logging")
app = FastAPI(lifespan=lifespan)
@app.post("/trip/new") @app.post("/trip/new")
def new_trip(preferences: Preferences, def new_trip(preferences: Preferences,
start: tuple[float, float], start: tuple[float, float],

View File

@@ -1,7 +1,7 @@
"""Definition of the Landmark class to handle visitable objects across the world.""" """Definition of the Landmark class to handle visitable objects across the world."""
from typing import Optional, Literal from typing import Optional, Literal
from uuid import uuid4 from uuid import uuid4, UUID
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -29,12 +29,12 @@ class Landmark(BaseModel) :
description (Optional[str]): A text description of the landmark. description (Optional[str]): A text description of the landmark.
duration (Optional[int]): The estimated time to visit the landmark (in minutes). duration (Optional[int]): The estimated time to visit the landmark (in minutes).
name_en (Optional[str]): The English name of the landmark. name_en (Optional[str]): The English name of the landmark.
uuid (str): A unique identifier for the landmark, generated by default using uuid4. uuid (UUID): A unique identifier for the landmark, generated by default using uuid4.
must_do (Optional[bool]): Whether the landmark is a "must-do" attraction. must_do (Optional[bool]): Whether the landmark is a "must-do" attraction.
must_avoid (Optional[bool]): Whether the landmark should be avoided. must_avoid (Optional[bool]): Whether the landmark should be avoided.
is_secondary (Optional[bool]): Whether the landmark is secondary or less important. is_secondary (Optional[bool]): Whether the landmark is secondary or less important.
time_to_reach_next (Optional[int]): Estimated time (in minutes) to reach the next landmark. time_to_reach_next (Optional[int]): Estimated time (in minutes) to reach the next landmark.
next_uuid (Optional[str]): UUID of the next landmark in sequence (if applicable). next_uuid (Optional[UUID]): UUID of the next landmark in sequence (if applicable).
""" """
# Properties of the landmark # Properties of the landmark
@@ -52,7 +52,7 @@ class Landmark(BaseModel) :
name_en : Optional[str] = None name_en : Optional[str] = None
# Unique ID of a given landmark # Unique ID of a given landmark
uuid: str = Field(default_factory=uuid4) uuid: UUID = Field(default_factory=uuid4)
# Additional properties depending on specific tour # Additional properties depending on specific tour
must_do : Optional[bool] = False must_do : Optional[bool] = False
@@ -60,7 +60,7 @@ class Landmark(BaseModel) :
is_secondary : Optional[bool] = False is_secondary : Optional[bool] = False
time_to_reach_next : Optional[int] = 0 time_to_reach_next : Optional[int] = 0
next_uuid : Optional[str] = None next_uuid : Optional[UUID] = None
def __str__(self) -> str: def __str__(self) -> str:
""" """
@@ -139,4 +139,4 @@ class Toilets(BaseModel) :
class Config: class Config:
# This allows us to easily convert the model to and from dictionaries # This allows us to easily convert the model to and from dictionaries
orm_mode = True from_attributes = True

View File

@@ -1,6 +1,6 @@
"""Definition of the Trip class.""" """Definition of the Trip class."""
import uuid from uuid import uuid4, UUID
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from pymemcache.client.base import Client from pymemcache.client.base import Client
@@ -19,9 +19,9 @@ class Trip(BaseModel):
Methods: Methods:
from_linked_landmarks: create a Trip from LinkedLandmarks object. from_linked_landmarks: create a Trip from LinkedLandmarks object.
""" """
uuid: str = Field(default_factory=uuid.uuid4) uuid: UUID = Field(default_factory=uuid4)
total_time: int total_time: int
first_landmark_uuid: str first_landmark_uuid: UUID
@classmethod @classmethod
@@ -31,7 +31,7 @@ class Trip(BaseModel):
""" """
trip = Trip( trip = Trip(
total_time = landmarks.total_time, total_time = landmarks.total_time,
first_landmark_uuid = str(landmarks[0].uuid) first_landmark_uuid = landmarks[0].uuid
) )
# Store the trip in the cache # Store the trip in the cache

View File

@@ -4,7 +4,7 @@ from fastapi import HTTPException
from pydantic import ValidationError from pydantic import ValidationError
from ..structs.landmark import Landmark from ..structs.landmark import Landmark
from ..persistence import client as cache_client from ..cache import client as cache_client
def landmarks_to_osmid(landmarks: list[Landmark]) -> list[int] : def landmarks_to_osmid(landmarks: list[Landmark]) -> list[int] :

View File

@@ -6,14 +6,17 @@ on:
jobs: jobs:
build: build:
runs-on: macos-latest runs-on: macos-latest
env:
# $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: ios/Gemfile
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up ruby env - name: Set up ruby env
uses: ruby/setup-ruby@v1 uses: ruby/setup-ruby@v1
with: with:
ruby-version: 3.2.1 ruby-version: 3.3
bundler-cache: true bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Install Flutter - name: Install Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
@@ -31,16 +34,24 @@ jobs:
echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV
- name: Setup SSH key for match git repo - name: Setup SSH key for match git repo
run: echo "$MATCH_REPO_SSH_KEY" | base64 --decode > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa # and mark the host as known
run: |
echo $MATCH_REPO_SSH_KEY | base64 --decode > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -p 2222 git.kluster.moll.re > ~/.ssh/known_hosts
env: env:
MATCH_REPO_SSH_KEY: ${{ secrets.IOS_MATCH_REPO_SSH_KEY_BASE64 }} MATCH_REPO_SSH_KEY: ${{ secrets.IOS_MATCH_REPO_SSH_KEY_BASE64 }}
- name: Install fastlane - name: Install dependencies and clean up
run: bundle install run: |
flutter pub get
bundle exec pod install
flutter clean
bundle exec pod cache clean --all
working-directory: ios working-directory: ios
- name: Run fastlane lane - name: Run fastlane lane
run: bundle exec fastlane deploy_release run: bundle exec fastlane deploy_release --verbose
working-directory: ios working-directory: ios
env: env:
BUILD_NUMBER: ${{ github.run_number }} BUILD_NUMBER: ${{ github.run_number }}
@@ -50,3 +61,4 @@ jobs:
IOS_ASC_ISSUER_ID: ${{ secrets.IOS_ASC_ISSUER_ID }} IOS_ASC_ISSUER_ID: ${{ secrets.IOS_ASC_ISSUER_ID }}
IOS_ASC_KEY: ${{ secrets.IOS_ASC_KEY }} IOS_ASC_KEY: ${{ secrets.IOS_ASC_KEY }}
MATCH_PASSWORD: ${{ secrets.IOS_MATCH_PASSWORD }} MATCH_PASSWORD: ${{ secrets.IOS_MATCH_PASSWORD }}
IOS_GOOGLE_MAPS_API_KEY: ${{ secrets.IOS_GOOGLE_MAPS_API_KEY }}

View File

@@ -50,13 +50,12 @@ Secrets used by fastlane are stored on hashicorp vault and are fetched by the CI
## Secrets ## Secrets
These are mostly used by the CI/CD pipeline to deploy the application. The main usage for github actions is documented under [https://github.com/hashicorp/vault-action](https://github.com/hashicorp/vault-action). These are mostly used by the CI/CD pipeline to deploy the application. The main usage for github actions is documented under [https://github.com/hashicorp/vault-action](https://github.com/hashicorp/vault-action).
**Global secrets** are used for both versions of the app (android and ios).
- `GOOGLE_MAPS_API_KEY` is used to authenticate with the Google Maps API
**Platform-specific secrets** are used by the CI/CD pipeline to deploy to the respective app stores. **Platform-specific secrets** are used by the CI/CD pipeline to deploy to the respective app stores.
- `GOOGLE_MAPS_API_KEY` is used to authenticate with the Google Maps API and is scoped to the android platform
- `ANDROID_KEYSTORE` is used to sign the android apk - `ANDROID_KEYSTORE` is used to sign the android apk
- `ANDROID_GOOGLE_KEY` is used to authenticate with the Google Play Store api - `ANDROID_GOOGLE_KEY` is used to authenticate with the Google Play Store api
- `IOS_GOOGLE_...` - `IOS_GOOGLE_MAPS_API_KEY` is used to authenticate with the Google Maps API and is scoped to the ios platform
- `IOS_GOOGLE_...` - `IOS_GOOGLE_...`
- `IOS_GOOGLE_...` - `IOS_GOOGLE_...`
- `IOS_GOOGLE_...` - `IOS_GOOGLE_...`

View File

@@ -4,17 +4,15 @@ PODS:
- Flutter - Flutter
- geolocator_apple (1.2.0): - geolocator_apple (1.2.0):
- Flutter - Flutter
- Google-Maps-iOS-Utils (6.0.0): - Google-Maps-iOS-Utils (6.1.0):
- GoogleMaps (~> 9.0) - GoogleMaps (~> 9.0)
- google_maps_flutter_ios (0.0.1): - google_maps_flutter_ios (0.0.1):
- Flutter - Flutter
- Google-Maps-iOS-Utils (< 7.0, >= 5.0) - Google-Maps-iOS-Utils (< 7.0, >= 5.0)
- GoogleMaps (< 10.0, >= 8.4) - GoogleMaps (< 10.0, >= 8.4)
- GoogleMaps (9.1.1): - GoogleMaps (9.2.0):
- GoogleMaps/Maps (= 9.1.1) - GoogleMaps/Maps (= 9.2.0)
- GoogleMaps/Base (9.1.1) - GoogleMaps/Maps (9.2.0)
- GoogleMaps/Maps (9.1.1):
- GoogleMaps/Base
- map_launcher (0.0.1): - map_launcher (0.0.1):
- Flutter - Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
@@ -74,9 +72,9 @@ SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
geocoding_ios: bcbdaa6bddd7d3129c9bcb8acddc5d8778689768 geocoding_ios: bcbdaa6bddd7d3129c9bcb8acddc5d8778689768
geolocator_apple: d981750b9f47dbdb02427e1476d9a04397beb8d9 geolocator_apple: d981750b9f47dbdb02427e1476d9a04397beb8d9
Google-Maps-iOS-Utils: cfe6a0239c7ca634b7e001ad059a6707143dc8dc Google-Maps-iOS-Utils: 0a484b05ed21d88c9f9ebbacb007956edd508a96
google_maps_flutter_ios: 0291eb2aa252298a769b04d075e4a9d747ff7264 google_maps_flutter_ios: 0291eb2aa252298a769b04d075e4a9d747ff7264
GoogleMaps: 80ea184ed6bf44139f383a8b0e248ba3ec1cc8c9 GoogleMaps: 634ec3ca99698b31ca2253d64f017217d70cfb38
map_launcher: fe43bda6720bb73c12fcc1bdd86123ff49a4d4d6 map_launcher: fe43bda6720bb73c12fcc1bdd86123ff49a4d4d6
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
@@ -84,6 +82,6 @@ SPEC CHECKSUMS:
sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3 sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 PODFILE CHECKSUM: bd1a78910c05ac1e3a220e80f392c61ab2cc8789
COCOAPODS: 1.10.2 COCOAPODS: 1.10.2

View File

@@ -8,9 +8,7 @@ import GoogleMaps
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
// load the key from env GMSServices.provideAPIKey("IOS_GOOGLE_MAPS_API_KEY")
let key = ProcessInfo.processInfo.environment["GOOGLE_MAPS_API_KEY"]!
GMSServices.provideAPIKey(key)
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }

View File

@@ -10,4 +10,4 @@ IOS_ASC_ISSUER_ID="sample"
SIGNING_KEY_FILE_PATH="sample" SIGNING_KEY_FILE_PATH="sample"
SIGNING_KEY_PASSWORD="sample" SIGNING_KEY_PASSWORD="sample"
GOOGLE_MAPS_API_KEY="sample" IOS_GOOGLE_MAPS_API_KEY="sample"

View File

@@ -33,7 +33,7 @@ platform :ios do
"flutter", "flutter",
"build", "build",
"ipa", "ipa",
"--release", "--debug",
"--build-name=#{build_name}", "--build-name=#{build_name}",
"--build-number=#{build_number}", "--build-number=#{build_number}",
) )
@@ -44,7 +44,9 @@ platform :ios do
archive_path: "../build/ios/archive/Runner.xcarchive" archive_path: "../build/ios/archive/Runner.xcarchive"
) )
upload_to_testflight upload_to_testflight(
skip_waiting_for_build_processing: true,
)
end end
@@ -62,6 +64,16 @@ platform :ios do
readonly: true, readonly: true,
) )
# replace secrets by real values, the stupid way
sh(
"sed",
"-i",
"",
"s/IOS_GOOGLE_MAPS_API_KEY/#{ENV["IOS_GOOGLE_MAPS_API_KEY"]}/g",
"../Runner/AppDelegate.swift"
)
sh( sh(
"flutter", "flutter",
"build", "build",