├── coverage
└── .gitkeep
├── test_reports
└── .gitkeep
├── coverage_report
└── .gitkeep
├── app
├── ios
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ ├── AppDelegate.swift
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ └── Info.plist
│ ├── Runner.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── xcshareddata
│ │ │ └── xcschemes
│ │ │ │ ├── Dev.xcscheme
│ │ │ │ ├── UAT.xcscheme
│ │ │ │ └── Prod.xcscheme
│ │ └── project.pbxproj
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── .gitignore
├── android
│ ├── gradle.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── values
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ │ └── orevial
│ │ │ │ │ │ └── flutter_ci_cd_demo
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── settings.gradle
│ └── build.gradle
├── lib
│ ├── main_dev.dart
│ ├── main_uat.dart
│ ├── main_prod.dart
│ ├── app.dart
│ └── pages
│ │ └── home_page.dart
├── pubspec.yaml
├── test
│ └── app_test.dart
└── pubspec.lock
├── design_system
├── lib
│ ├── design_system.dart
│ └── design
│ │ ├── theme.dart
│ │ ├── spacings.design.dart
│ │ └── colors.design.dart
├── pubspec.yaml
├── test
│ └── design_test.dart
└── pubspec.lock
├── scripts
├── pubspec_template.yaml
├── generate-html-coverage.sh
├── keystore_properties_template.yaml
├── semver.sh
├── combine-coverage.sh
└── test-with-coverage.sh
├── .releaserc.json
├── .releaserc.prod.json
├── .releaserc.uat.json
├── README.md
├── .gitignore
├── .metadata
├── .github
└── workflows
│ ├── _deploy-env-apps.yml
│ ├── deploy-uat-apps.yml
│ ├── build.yml
│ ├── deploy-prod-apps.yml
│ ├── _test_with_coverage.yml
│ ├── notify-pull-requests.yml
│ ├── _deploy-android-app.yml
│ └── _deploy-ios-app.yml
├── melos.yaml
└── analysis_options.yaml
/coverage/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_reports/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/coverage_report/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/app/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/design_system/lib/design_system.dart:
--------------------------------------------------------------------------------
1 | export 'design/theme.dart';
2 |
--------------------------------------------------------------------------------
/app/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/app/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/lib/main_dev.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ci_cd_demo/app.dart';
3 |
4 | void main() {
5 | runApp(FlutterDemo(env: 'Dev'));
6 | }
7 |
--------------------------------------------------------------------------------
/app/lib/main_uat.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ci_cd_demo/app.dart';
3 |
4 | void main() {
5 | runApp(FlutterDemo(env: 'UAT'));
6 | }
7 |
--------------------------------------------------------------------------------
/app/lib/main_prod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ci_cd_demo/app.dart';
3 |
4 | void main() {
5 | runApp(FlutterDemo(env: 'Prod'));
6 | }
7 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/HEAD/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/scripts/pubspec_template.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_ci_cd_demo
2 | description: Dart Code Metrics helper for aggregated report generation
3 |
4 | environment:
5 | sdk: '>=2.19.0 <3.0.0'
6 | flutter: ">=3.7.0 <4.0.0"
--------------------------------------------------------------------------------
/design_system/lib/design/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'colors.design.dart';
4 |
5 | final ThemeData lightTheme = ThemeData(
6 | primarySwatch: kMaterialPrimarySwatch,
7 | );
8 |
--------------------------------------------------------------------------------
/scripts/generate-html-coverage.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ## Generate coverage report
4 | PROJECT_ROOT_PATH=$1
5 | genhtml -o $PROJECT_ROOT_PATH/coverage_report/ $PROJECT_ROOT_PATH/coverage_report/cleaned_combined_lcov.info
6 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/android/app/src/main/kotlin/com/orevial/flutter_ci_cd_demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.orevial.flutter_ci_cd_demo
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/app/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/scripts/keystore_properties_template.yaml:
--------------------------------------------------------------------------------
1 | prodStoreFile=dumbValue
2 | prodStorePassword=dumbValue
3 | prodKeyAlias=dumbValue
4 | prodKeyPassword=dumbValue
5 |
6 | uatStoreFile=dumbValue
7 | uatKeyAlias=dumbValue
8 | uatStorePassword=dumbValue
9 | uatKeyPassword=dumbValue
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/design_system/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: design_system
2 | description: Design
3 | version: 1.0.0
4 | publish_to: none
5 |
6 | environment:
7 | sdk: '>=2.19.0 <3.0.0'
8 | flutter: ">=3.7.0 <4.0.0"
9 |
10 | dependencies:
11 | # Flutter SDK dependencies
12 | flutter:
13 | sdk: flutter
14 |
15 | dev_dependencies:
16 | flutter_test:
17 | sdk: flutter
18 |
19 | flutter:
20 | uses-material-design: true
--------------------------------------------------------------------------------
/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "ci": true,
3 | "dryRun": true,
4 | "branches": [
5 | "main"
6 | ],
7 | "tagFormat": "release/prod/${version}",
8 | "plugins": [
9 | "@semantic-release/commit-analyzer",
10 | "@semantic-release/release-notes-generator",
11 | [
12 | "@semantic-release/changelog",
13 | {
14 | "changelogFile": "CHANGELOG.md",
15 | "changelogTitle": "# CHANGELOG"
16 | }
17 | ]
18 | ]
19 | }
--------------------------------------------------------------------------------
/.releaserc.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "ci": true,
3 | "dryRun": true,
4 | "branches": [
5 | "main"
6 | ],
7 | "tagFormat": "release/prod/${version}",
8 | "plugins": [
9 | "@semantic-release/commit-analyzer",
10 | "@semantic-release/release-notes-generator",
11 | [
12 | "@semantic-release/changelog",
13 | {
14 | "changelogFile": "CHANGELOG.md",
15 | "changelogTitle": "# CHANGELOG"
16 | }
17 | ]
18 | ]
19 | }
--------------------------------------------------------------------------------
/.releaserc.uat.json:
--------------------------------------------------------------------------------
1 | {
2 | "ci": true,
3 | "dryRun": true,
4 | "branches": [
5 | "main"
6 | ],
7 | "tagFormat": "release/prod/${version}",
8 | "plugins": [
9 | "@semantic-release/commit-analyzer",
10 | "@semantic-release/release-notes-generator",
11 | [
12 | "@semantic-release/changelog",
13 | {
14 | "changelogFile": "CHANGELOG.md",
15 | "changelogTitle": "# CHANGELOG"
16 | }
17 | ]
18 | ]
19 | }
--------------------------------------------------------------------------------
/app/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/design_system/test/design_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:design_system/design/colors.design.dart';
2 | import 'package:design_system/design/spacings.design.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_test/flutter_test.dart';
5 |
6 | void main() {
7 | test('Colors are fine', () {
8 | expect(
9 | getMaterialPrimarySwatch().shade900,
10 | Color(0xFFAF4B00),
11 | );
12 | });
13 |
14 | test('Theme spacings are fine', () {
15 | expect(ThemeSpacing.l, 40.0);
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/lib/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:design_system/design_system.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_ci_cd_demo/pages/home_page.dart';
4 |
5 | class FlutterDemo extends StatelessWidget {
6 | final String env;
7 |
8 | const FlutterDemo({
9 | required this.env,
10 | super.key,
11 | });
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return MaterialApp(
16 | title: 'Flutter CI/CD demo app',
17 | theme: lightTheme,
18 | home: HomePage(env: env),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_ci_cd_demo
2 | description: A new Flutter project.
3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
4 |
5 | version: 1.0.0+1
6 |
7 | environment:
8 | sdk: '>=2.19.0 <3.0.0'
9 | flutter: ">=3.7.0 <4.0.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | design_system:
15 | path: ../design_system
16 | cupertino_icons: ^1.0.2
17 |
18 | dev_dependencies:
19 | flutter_test:
20 | sdk: flutter
21 |
22 | flutter_lints: ^2.0.0
23 |
24 | flutter:
25 | uses-material-design: true
26 |
--------------------------------------------------------------------------------
/design_system/lib/design/spacings.design.dart:
--------------------------------------------------------------------------------
1 | // Small spacing ids are legit, they are well-known identifier
2 | //ignore_for_file: prefer-correct-identifier-length
3 |
4 | class ThemeSize {
5 | static const double xxs = 4.0;
6 | static const double xs = 8.0;
7 | static const double s = 12.0;
8 | static const double sm = 16.0;
9 | static const double m = 24.0;
10 | static const double lm = 32.0;
11 | static const double l = 40.0;
12 | static const double xl = 48.0;
13 | static const double xxl = 56.0;
14 | }
15 |
16 | typedef ThemeSpacing = ThemeSize;
17 |
--------------------------------------------------------------------------------
/scripts/semver.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | RE='([0-9]+)\.([0-9]+)\.([0-9]+)\+?([0-9]+)?'
4 |
5 | lastVersion="$1"
6 |
7 | if [ -z "$2" ]
8 | then
9 | nextVersion=$lastVersion
10 | else
11 | nextVersion="$2"
12 | fi
13 |
14 | LAST_UAT_BUILD_NUMBER=`echo $lastVersion | sed -E "s/$RE/\4/"`
15 |
16 | NEXT_VERSION_MAJOR=`echo $nextVersion | sed -E "s/$RE/\1/"`
17 | NEXT_VERSION_MINOR=`echo $nextVersion | sed -E "s/$RE/\2/"`
18 | NEXT_VERSION_PATCH=`echo $nextVersion | sed -E "s/$RE/\3/"`
19 |
20 | ((LAST_UAT_BUILD_NUMBER++))
21 | echo "$NEXT_VERSION_MAJOR.$NEXT_VERSION_MINOR.$NEXT_VERSION_PATCH+$LAST_UAT_BUILD_NUMBER"
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_ci_cd_demo
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 |
14 | For help getting started with Flutter development, view the
15 | [online documentation](https://docs.flutter.dev/), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/scripts/combine-coverage.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PROJECT_ROOT_PATH=$1
4 | while read FILENAME; do
5 | LCOV_INPUT_FILES="$LCOV_INPUT_FILES -a \"$PROJECT_ROOT_PATH/coverage/$FILENAME\""
6 | done < <( ls "$1/coverage/" )
7 |
8 | eval lcov "${LCOV_INPUT_FILES}" -o $PROJECT_ROOT_PATH/coverage_report/combined_lcov.info
9 |
10 | lcov --remove $PROJECT_ROOT_PATH/coverage_report/combined_lcov.info \
11 | "lib/main_*.dart" \
12 | "*.gr.dart" \
13 | "*.g.dart" \
14 | "*.freezed.dart" \
15 | "*di.config.dart" \
16 | "*.i69n.dart" \
17 | "*/generated/*" \
18 | "*.theme_extension.dart" \
19 | -o $PROJECT_ROOT_PATH/coverage_report/cleaned_combined_lcov.info
--------------------------------------------------------------------------------
/design_system/lib/design/colors.design.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const MaterialColor kMaterialPrimarySwatch =
4 | MaterialColor(0xFFAF4B00, {
5 | 50: Color(0xFFF9EAE6),
6 | 100: Color(0xFFF9CFBA),
7 | 200: Color(0xFFF6B18D),
8 | 300: Color(0xFFF3945F),
9 | 400: Color(0xFFF07F3A),
10 | 500: Color(0xFFED6D0F),
11 | 600: Color(0xFFE3660A),
12 | 700: Color(0xFFD55F05),
13 | 800: Color(0xFFC85803),
14 | 900: Color(0xFFAF4B00),
15 | });
16 |
17 | // Useless method but we need at least one method
18 | // to be called for coverage report to be generated...
19 | MaterialColor getMaterialPrimarySwatch() {
20 | return kMaterialPrimarySwatch;
21 | }
22 |
--------------------------------------------------------------------------------
/app/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/app/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/app/test/app_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility in the flutter_test package. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter_ci_cd_demo/app.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | void main() {
12 | testWidgets('App is displayed', (WidgetTester tester) async {
13 | await tester.pumpWidget(const FlutterDemo(env: 'Test'));
14 |
15 | expect(find.text('Flutter CI/CD demo'), findsOneWidget);
16 | expect(find.text('Your are currently on Test environment'), findsOneWidget);
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/scripts/test-with-coverage.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ## Generate coverage report
4 | PROJECT_ROOT_PATH=$1
5 | PACKAGE_PATH=$2
6 | PACKAGE_NAME=$3
7 |
8 | PACKAGE_LCOV_INFO_PATH=$PROJECT_ROOT_PATH/coverage/lcov_$PACKAGE_NAME.info
9 | PACKAGE_TEST_REPORT_PATH=$PROJECT_ROOT_PATH/test_reports/${PACKAGE_NAME}_test_report.json
10 |
11 | mkdir -p $PROJECT_ROOT_PATH/coverage/
12 | flutter test \
13 | --no-pub \
14 | --machine \
15 | --coverage \
16 | --coverage-path $PACKAGE_LCOV_INFO_PATH > $PACKAGE_TEST_REPORT_PATH
17 |
18 | escapedPath="$(echo $PACKAGE_PATH | sed 's/\//\\\//g')"
19 |
20 | # Requires gsed on MacOS machines because otherwise sed is not the same...
21 | if [[ "$OSTYPE" =~ ^darwin ]]; then
22 | gsed -i "s/^SF:lib/SF:$escapedPath\/lib/g" $PACKAGE_LCOV_INFO_PATH
23 | else
24 | sed -i "s/^SF:lib/SF:$escapedPath\/lib/g" $PACKAGE_LCOV_INFO_PATH
25 | fi
26 |
--------------------------------------------------------------------------------
/app/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/lib/pages/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:design_system/design/spacings.design.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class HomePage extends StatelessWidget {
5 | final String env;
6 |
7 | const HomePage({
8 | required this.env,
9 | super.key,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | appBar: AppBar(title: Text('Flutter CI/CD demo')),
16 | body: Center(
17 | child: Column(
18 | mainAxisSize: MainAxisSize.min,
19 | children: [
20 | Text(
21 | '🏠 Welcome to Flutter CI/CD demo page !',
22 | style: Theme.of(context).textTheme.bodyLarge,
23 | ),
24 | SizedBox(height: ThemeSpacing.l),
25 | Text('Your are currently on $env environment'),
26 | ],
27 | ),
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | build/
32 | coverage/*
33 | coverage_report/*
34 | junit_test_reports/*
35 | test_reports/*
36 | test_results.xml
37 | **/failures/
38 |
39 | # Web related
40 | lib/generated_plugin_registrant.dart
41 |
42 | # Exceptions to above rules.
43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
44 | .metadata
45 | !coverage/.gitkeep
46 | !coverage_report/.gitkeep
47 | !junit_test_reports/.gitkeep
48 | !test_reports/.gitkeep
49 |
50 | .fvm/flutter_sdk
51 | **/.bundle
52 | **/fastlane/report.xml
53 |
54 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
17 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
18 | - platform: android
19 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
20 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
21 | - platform: ios
22 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
23 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf
24 |
25 | # User provided section
26 |
27 | # List of Local paths (relative to this file) that should be
28 | # ignored by the migrate tool.
29 | #
30 | # Files that are not part of the templates will be ignored by default.
31 | unmanaged_files:
32 | - 'lib/main.dart'
33 | - 'ios/Runner.xcodeproj/project.pbxproj'
34 |
--------------------------------------------------------------------------------
/app/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CADisableMinimumFrameDurationOnPhone
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleDisplayName
10 | Flutter Ci Cd Demo
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | flutter_ci_cd_demo
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | $(FLUTTER_BUILD_NAME)
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | $(FLUTTER_BUILD_NUMBER)
27 | LSRequiresIPhoneOS
28 |
29 | UIApplicationSupportsIndirectInputEvents
30 |
31 | UILaunchStoryboardName
32 | LaunchScreen
33 | UIMainStoryboardFile
34 | Main
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 | UIViewControllerBasedStatusBarAppearance
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/.github/workflows/_deploy-env-apps.yml:
--------------------------------------------------------------------------------
1 | name: 📦🚀 Build & deploy iOS & Android app
2 |
3 | on:
4 | workflow_call:
5 | inputs:
6 | # Common inputs
7 | short-environment-name:
8 | required: true
9 | type: string
10 | flavor:
11 | required: true
12 | type: string
13 | new-pubspec-version:
14 | required: true
15 | type: string
16 | # Android specific inputs
17 | android-environment-name:
18 | required: true
19 | type: string
20 | android-environment-url:
21 | required: true
22 | type: string
23 | android-package-name:
24 | required: true
25 | type: string
26 | android-release-status:
27 | required: true
28 | type: string
29 | # iOS specific inputs
30 | ios-environment-name:
31 | required: true
32 | type: string
33 | ios-environment-url:
34 | required: true
35 | type: string
36 |
37 | jobs:
38 | deployAndroid:
39 | name: 🤖📦🚀 Build & deploy Android ${{ inputs.short-environment-name }} release
40 | uses: ./.github/workflows/_deploy-android-app.yml
41 | secrets: inherit
42 | with:
43 | environment-name: ${{ inputs.android-environment-name }}
44 | environment-url: ${{ inputs.android-environment-url }}
45 | package-name: ${{ inputs.android-package-name }}
46 | release-status: ${{ inputs.android-release-status }}
47 | short-environment-name: ${{ inputs.short-environment-name }}
48 | flavor: ${{ inputs.flavor }}
49 | new-pubspec-version: ${{ inputs.new-pubspec-version }}
50 | deployIos:
51 | name: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release
52 | uses: ./.github/workflows/_deploy-ios-app.yml
53 | secrets: inherit
54 | with:
55 | environment-name: ${{ inputs.ios-environment-name }}
56 | environment-url: ${{ inputs.ios-environment-url }}
57 | short-environment-name: ${{ inputs.short-environment-name }}
58 | flavor: ${{ inputs.flavor }}
59 | new-pubspec-version: ${{ inputs.new-pubspec-version }}
--------------------------------------------------------------------------------
/app/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-uat-apps.yml:
--------------------------------------------------------------------------------
1 | name: 📦🚀 Build & deploy UAT release
2 |
3 | permissions: write-all
4 |
5 | on:
6 | push:
7 | branches:
8 | - 'main'
9 | paths-ignore:
10 | - '**.md'
11 | - 'doc/**'
12 | - '.git/'
13 | - '.vscode/'
14 |
15 | jobs:
16 | testAndCoverage:
17 | name: 🧪 Test
18 | uses: ./.github/workflows/_test_with_coverage.yml
19 | secrets: inherit
20 |
21 | gitRelease:
22 | name: Create git release for UAT app
23 | runs-on: ubuntu-latest
24 | outputs:
25 | new_pubspec_version: "${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
26 | steps:
27 | - name: ⬇️ Checkout repository with tags
28 | uses: actions/checkout@v3
29 | with:
30 | fetch-depth: 0
31 | - name: 🏷️🧪 Get latest UAT release
32 | id: get_latest_uat_release
33 | uses: "WyriHaximus/github-action-get-previous-tag@v1"
34 | with:
35 | prefix: "release/uat/"
36 | fallback: 0.0.1
37 | - name: ⚙️ Prepare semantic release configuration
38 | run: |
39 | mv .releaserc.uat.json .releaserc.json
40 | - name: 🏷️🔮 Get next UAT release semver version
41 | id: semantic_release_info
42 | uses: cycjimmy/semantic-release-action@v3.2.0
43 | env:
44 | GITHUB_TOKEN: ${{ secrets.RELEASE_AUTOMATOR_PAT }}
45 | with:
46 | semantic_version: 19
47 | - name: 📝 Calculate complete UAT version for next version
48 | id: get_new_pubspec_version
49 | run: |
50 | last_uat_release=$(echo "${{ steps.get_latest_uat_release.outputs.tag }}" | sed -E "s/release\/uat\/(.*)/\1/")
51 | next_pubspec_version=$(./scripts/semver.sh "$last_uat_release" "${{ steps.semantic_release_info.outputs.new_release_version }}")
52 | echo "next_pubspec_version=$next_pubspec_version" >> $GITHUB_OUTPUT
53 | - name: 🏷️✍️ Create new UAT release tag
54 | uses: rickstaa/action-create-tag@v1
55 | with:
56 | tag: "release/uat/${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
57 | message: "UAT release ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
58 | github_token: ${{ secrets.RELEASE_AUTOMATOR_PAT }}
59 |
60 | deployUat:
61 | name: Deploy UAT
62 | uses: ./.github/workflows/_deploy-env-apps.yml
63 | needs: gitRelease
64 | secrets: inherit
65 | with:
66 | android-environment-name: 'Android UAT'
67 | android-environment-url: 'https://play.google.com/console/u/0/developers/7200533445067191438/app/4975719898219218293/tracks/internal-testing'
68 | android-package-name: 'com.orevial.uat'
69 | android-release-status: 'completed'
70 | ios-environment-name: 'iOS UAT'
71 | ios-environment-url: 'https://appstoreconnect.apple.com/apps/1664853019/testflight'
72 | short-environment-name: 'UAT'
73 | flavor: 'uat'
74 | new-pubspec-version: ${{ needs.gitRelease.outputs.new_pubspec_version }}
75 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: 🔨🧪 Build & Test
2 |
3 | permissions: write-all
4 |
5 | concurrency:
6 | group: ${{ github.workflow }}-${{ github.head_ref }}
7 | cancel-in-progress: true
8 |
9 | on:
10 | pull_request:
11 | types:
12 | - opened
13 | - reopened
14 | - synchronize
15 | - ready_for_review
16 | branches:
17 | - 'main'
18 | paths-ignore:
19 | - '**.md'
20 | - 'doc/**'
21 | - '.git/'
22 | - '.vscode/'
23 |
24 | jobs:
25 | testAndCoverage:
26 | name: 🧪 Test
27 | if: github.event.pull_request.draft == false
28 | uses: ./.github/workflows/_test_with_coverage.yml
29 | secrets: inherit
30 |
31 | analyze:
32 | name: Analyze
33 | if: github.event.pull_request.draft == false
34 | timeout-minutes: 30
35 | runs-on: ubuntu-latest
36 | steps:
37 | - name: ⬇️ Checkout repository
38 | uses: actions/checkout@v3
39 | - name: ⚙️ Setup Flutter
40 | uses: subosito/flutter-action@v2
41 | with:
42 | channel: 'stable'
43 | cache: true
44 | - name: ⚙️ Setup Melos
45 | uses: bluefireteam/melos-action@v2
46 | - name: ⚙️ Install dependencies for all packages
47 | run: melos build:pub_get:all
48 | - name: 📄 Move dummy pubspec.yaml to root
49 | run: cp scripts/pubspec_template.yaml pubspec.yaml
50 | - name: ⚠️ℹ️ Run Dart analysis for app package
51 | uses: zgosalvez/github-actions-analyze-dart@v2.0.9
52 | with:
53 | working-directory: "${{github.workspace}}/app/"
54 | - name: ⚠️ℹ️ Run Dart analysis for data package
55 | uses: zgosalvez/github-actions-analyze-dart@v2.0.9
56 | with:
57 | working-directory: "${{github.workspace}}/design_system/"
58 | - name: 📈 Check metrics
59 | uses: dart-code-checker/dart-code-metrics-action@v3.0.0
60 | with:
61 | github_token: ${{ secrets.GITHUB_TOKEN }}
62 | pull_request_comment: true
63 | check_unused_files: true
64 | folders: 'app, design_system'
65 |
66 | build:
67 | name: Build Android
68 | if: github.event.pull_request.draft == false
69 | runs-on: ubuntu-latest
70 | timeout-minutes: 30
71 | steps:
72 | - name: ⬇️ Checkout repository
73 | uses: actions/checkout@v3
74 | - name: ⚙️ Setup Flutter
75 | uses: subosito/flutter-action@v2
76 | with:
77 | channel: 'stable'
78 | cache: true
79 | - name: ⚙️ Setup Java
80 | uses: actions/setup-java@v3
81 | with:
82 | distribution: 'zulu'
83 | java-version: "12.x"
84 | cache: 'gradle'
85 | id: java
86 | - name: ⚙️ Setup Melos
87 | uses: bluefireteam/melos-action@v2
88 | - name: ⚙️ Install dependencies for all packages
89 | run: melos build:pub_get:all
90 | - name: 🤖🔨 Build Android app
91 | run: |
92 | pushd app/
93 | flutter build appbundle --debug --flavor dev -t lib/main_dev.dart
94 | popd
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Dev.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/UAT.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-prod-apps.yml:
--------------------------------------------------------------------------------
1 | name: 📦🚀 Build & deploy Prod release
2 |
3 | permissions: write-all
4 |
5 | on: workflow_dispatch
6 |
7 | jobs:
8 | gitRelease:
9 | name: Create git release for Prod app
10 | runs-on: ubuntu-latest
11 | outputs:
12 | new_pubspec_version: "${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
13 | steps:
14 | - name: 👁️ Check branch validity
15 | if: github.ref != 'refs/heads/main'
16 | run: |
17 | echo "⚠️ Error: you tried to create a release from '${{ github.ref }}' branch but production releases can only be created from 'main' branch"
18 | - name: ⬇️ Checkout repository with tags
19 | uses: actions/checkout@v3
20 | with:
21 | fetch-depth: 0
22 | token: ${{ secrets.RELEASE_AUTOMATOR_PAT }}
23 | - name: 🏷️🧪 Get latest Prod release
24 | id: get_latest_prod_release
25 | uses: "WyriHaximus/github-action-get-previous-tag@v1"
26 | with:
27 | prefix: "release/prod/"
28 | fallback: 0.0.1
29 | - name: ⚙️ Prepare semantic release configuration
30 | run: |
31 | mv .releaserc.prod.json .releaserc.json
32 | - name: 🏷️✍️ Create new Prod release tag
33 | id: semantic_release_info
34 | uses: cycjimmy/semantic-release-action@v3.2.0
35 | env:
36 | GITHUB_TOKEN: ${{ secrets.RELEASE_AUTOMATOR_PAT }}
37 | with:
38 | semantic_version: 19
39 | - name: 📝 Edit pubspec version
40 | id: get_new_pubspec_version
41 | run: |
42 | last_prod_release=$(echo "${{ steps.get_latest_prod_release.outputs.tag }}" | sed -E "s/release\/prod\/(.*)/\1/")
43 | next_pubspec_version=$(./scripts/semver.sh "$last_prod_release" "${{ steps.semantic_release_info.outputs.new_release_version }}")
44 | sed -Ei "s/^version: (.*)/version: $next_pubspec_version/" app/pubspec.yaml
45 | echo "next_pubspec_version=$next_pubspec_version" >> $GITHUB_OUTPUT
46 | - name: 🔀 Push bump commit with changelog to repository
47 | uses: stefanzweifel/git-auto-commit-action@v4.16.0
48 | with:
49 | commit_message: "chore(*): bump to version ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }} [skip ci]"
50 | - name: 🏷️✍️ Create new Prod release tag
51 | uses: rickstaa/action-create-tag@v1
52 | with:
53 | tag: "release/prod/${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
54 | message: "UAT release ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}"
55 | github_token: ${{ secrets.RELEASE_AUTOMATOR_PAT }}
56 |
57 | deployProd:
58 | name: Deploy Prod
59 | uses: ./.github/workflows/_deploy-env-apps.yml
60 | needs: gitRelease
61 | secrets: inherit
62 | with:
63 | android-environment-name: 'Android Prod'
64 | android-environment-url: 'https://play.google.com/console/u/0/developers/7200533445067191438/app/4976229890619914417/tracks/internal-testing'
65 | android-package-name: 'com.orevial'
66 | android-release-status: 'completed'
67 | ios-environment-name: 'iOS Prod'
68 | ios-environment-url: 'https://appstoreconnect.apple.com/apps/1292528725/testflight/ios'
69 | short-environment-name: 'Prod'
70 | flavor: 'prod'
71 | new-pubspec-version: ${{ needs.gitRelease.outputs.new_pubspec_version }}
72 |
--------------------------------------------------------------------------------
/.github/workflows/_test_with_coverage.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Test with coverage 📊
2 |
3 | on:
4 | workflow_call:
5 |
6 | jobs:
7 | coverage:
8 | name: 🧪 Test
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 30
11 | steps:
12 | - name: ⬇️ Checkout repository
13 | uses: actions/checkout@v3
14 | - name: ⚙️ Install lcov
15 | run: |
16 | sudo apt-get update
17 | sudo apt-get -y install lcov
18 | - name: ⚙️ Setup Flutter
19 | uses: subosito/flutter-action@v2
20 | with:
21 | channel: 'stable'
22 | cache: true
23 | - name: ⚙️ Setup Melos
24 | uses: bluefireteam/melos-action@v2
25 | - name: ⚙️ Install dependencies for all packages
26 | run: melos build:pub_get:all
27 | - name: 🧪 Run tests with coverage
28 | run: melos test:with-lcov-coverage:all
29 | - name: 🧪✅❌ Publish test results
30 | id: compute_test_results
31 | uses: dorny/test-reporter@v1.6.0
32 | with:
33 | name: '🧪📊 Unit tests report'
34 | path: test_reports/*_test_report.json
35 | reporter: 'flutter-json'
36 | max-annotations: '50'
37 | token: ${{ secrets.GITHUB_TOKEN }}
38 | - name: 🪪 Create passing test results badge
39 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
40 | uses: schneegans/dynamic-badges-action@v1.6.0
41 | with:
42 | auth: ${{ secrets.BADGE_GIST_TOKEN }}
43 | gistID: "2e904f1d8a9ef0e1e1458de1e7fcfba6"
44 | filename: "passing-tests-badge.json"
45 | label: 'Tests'
46 | message: '${{ steps.compute_test_results.outputs.passed }} passed, ${{ steps.compute_test_results.outputs.failed }} failed'
47 | namedLogo: "TestCafe"
48 | labelColor: 'lightgrey'
49 | color: ${{ steps.compute_test_results.outputs.failed == 0 && 'brightgreen' || 'red' }}
50 | - name: 🧪📊 Publish coverage report
51 | if: github.event_name == 'pull_request'
52 | uses: romeovs/lcov-reporter-action@v0.3.1
53 | with:
54 | lcov-file: coverage_report/cleaned_combined_lcov.info
55 | github-token: ${{ secrets.GITHUB_TOKEN }}
56 | title: 'Coverage Report'
57 | - name: 🥤 Extract test coverage percentage
58 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
59 | run: |
60 | melos run test:generate-html-coverage
61 | grep -o '.*headerCovTableEntryLo.*' coverage_report/index.html | sed -E 's/.*>(.*) %<.*/\1/' > coverage_percentage.txt
62 | percentage=$(cat coverage_percentage.txt)
63 | echo "Coverage percentage: $percentage"
64 | echo "coverage_percentage=$percentage" >> $GITHUB_ENV
65 | - name: 🪪 Create test coverage badge
66 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
67 | uses: schneegans/dynamic-badges-action@v1.6.0
68 | with:
69 | auth: ${{ secrets.BADGE_GIST_TOKEN }}
70 | gistID: "2e904f1d8a9ef0e1e1458de1e7fcfba6"
71 | filename: "test-coverage-badge.json"
72 | label: 'Test coverage'
73 | message: '${{ env.coverage_percentage }} %'
74 | namedLogo: "Codecov"
75 | labelColor: 'lightgrey'
76 | valColorRange: ${{ env.coverage_percentage }}
77 | minColorRange: 50
78 | maxColorRange: 80
79 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Prod.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | // Note: we need to put dummy keystore so that compiler does not complain
29 | def keystorePropertiesFile = rootProject.file("keystore.properties")
30 | def keystoreProperties = new Properties()
31 | if (keystorePropertiesFile.exists() && !keystorePropertiesFile.isDirectory()) {
32 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
33 | } else {
34 | keystoreProperties['uatStoreFile'] = 'dummy.keystore';
35 | keystoreProperties['prodStoreFile'] = 'dummy.keystore';
36 | }
37 |
38 | if (keystoreProperties['uatStoreFile'] == null) {
39 | keystoreProperties['uatStoreFile'] = 'dummy.keystore'
40 | }
41 |
42 | if (keystoreProperties['prodStoreFile'] == null) {
43 | keystoreProperties['prodStoreFile'] = 'dummy.keystore'
44 | }
45 |
46 | android {
47 | compileSdkVersion flutter.compileSdkVersion
48 | ndkVersion flutter.ndkVersion
49 |
50 | compileOptions {
51 | sourceCompatibility JavaVersion.VERSION_1_8
52 | targetCompatibility JavaVersion.VERSION_1_8
53 | }
54 |
55 | kotlinOptions {
56 | jvmTarget = '1.8'
57 | }
58 |
59 | sourceSets {
60 | main.java.srcDirs += 'src/main/kotlin'
61 | }
62 |
63 | defaultConfig {
64 | applicationId "com.orevial.flutter_ci_cd_demo"
65 | minSdkVersion Math.max(flutter.minSdkVersion, 21)
66 | targetSdkVersion flutter.targetSdkVersion
67 | versionCode flutterVersionCode.toInteger()
68 | versionName flutterVersionName
69 | }
70 |
71 | flavorDimensions "flavor-type"
72 |
73 | signingConfigs {
74 | uatRelease {
75 | storeFile file(keystoreProperties['uatStoreFile'])
76 | storePassword keystoreProperties['uatStorePassword']
77 | keyAlias keystoreProperties['uatKeyAlias']
78 | keyPassword keystoreProperties['uatKeyPassword']
79 | }
80 |
81 | prodRelease {
82 | storeFile file(keystoreProperties['prodStoreFile'])
83 | storePassword keystoreProperties['prodStorePassword']
84 | keyAlias keystoreProperties['prodKeyAlias']
85 | keyPassword keystoreProperties['prodKeyPassword']
86 | }
87 | }
88 |
89 | productFlavors {
90 | dev {
91 | dimension "flavor-type"
92 | resValue "string", "app_name", "CI/CD Demo - Dev"
93 | applicationIdSuffix ".dev"
94 | versionNameSuffix "-dev"
95 | }
96 | uat {
97 | dimension "flavor-type"
98 | resValue "string", "app_name", "CI/CD Demo - UAT"
99 | applicationIdSuffix ".uat"
100 | versionNameSuffix "-uat"
101 | signingConfig signingConfigs.uatRelease
102 | }
103 | prod {
104 | dimension "flavor-type"
105 | resValue "string", "app_name", "CI/CD Demo"
106 | signingConfig signingConfigs.prodRelease
107 | }
108 | }
109 | }
110 |
111 | flutter {
112 | source '../..'
113 | }
114 |
115 | dependencies {
116 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
117 | }
118 |
--------------------------------------------------------------------------------
/design_system/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.10.0"
12 | boolean_selector:
13 | dependency: transitive
14 | description:
15 | name: boolean_selector
16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.1.1"
20 | characters:
21 | dependency: transitive
22 | description:
23 | name: characters
24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "1.2.1"
28 | clock:
29 | dependency: transitive
30 | description:
31 | name: clock
32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.1.1"
36 | collection:
37 | dependency: transitive
38 | description:
39 | name: collection
40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.17.0"
44 | fake_async:
45 | dependency: transitive
46 | description:
47 | name: fake_async
48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.3.1"
52 | flutter:
53 | dependency: "direct main"
54 | description: flutter
55 | source: sdk
56 | version: "0.0.0"
57 | flutter_test:
58 | dependency: "direct dev"
59 | description: flutter
60 | source: sdk
61 | version: "0.0.0"
62 | js:
63 | dependency: transitive
64 | description:
65 | name: js
66 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
67 | url: "https://pub.dev"
68 | source: hosted
69 | version: "0.6.5"
70 | matcher:
71 | dependency: transitive
72 | description:
73 | name: matcher
74 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
75 | url: "https://pub.dev"
76 | source: hosted
77 | version: "0.12.13"
78 | material_color_utilities:
79 | dependency: transitive
80 | description:
81 | name: material_color_utilities
82 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
83 | url: "https://pub.dev"
84 | source: hosted
85 | version: "0.2.0"
86 | meta:
87 | dependency: transitive
88 | description:
89 | name: meta
90 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
91 | url: "https://pub.dev"
92 | source: hosted
93 | version: "1.8.0"
94 | path:
95 | dependency: transitive
96 | description:
97 | name: path
98 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
99 | url: "https://pub.dev"
100 | source: hosted
101 | version: "1.8.2"
102 | sky_engine:
103 | dependency: transitive
104 | description: flutter
105 | source: sdk
106 | version: "0.0.99"
107 | source_span:
108 | dependency: transitive
109 | description:
110 | name: source_span
111 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
112 | url: "https://pub.dev"
113 | source: hosted
114 | version: "1.9.1"
115 | stack_trace:
116 | dependency: transitive
117 | description:
118 | name: stack_trace
119 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
120 | url: "https://pub.dev"
121 | source: hosted
122 | version: "1.11.0"
123 | stream_channel:
124 | dependency: transitive
125 | description:
126 | name: stream_channel
127 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
128 | url: "https://pub.dev"
129 | source: hosted
130 | version: "2.1.1"
131 | string_scanner:
132 | dependency: transitive
133 | description:
134 | name: string_scanner
135 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
136 | url: "https://pub.dev"
137 | source: hosted
138 | version: "1.2.0"
139 | term_glyph:
140 | dependency: transitive
141 | description:
142 | name: term_glyph
143 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
144 | url: "https://pub.dev"
145 | source: hosted
146 | version: "1.2.1"
147 | test_api:
148 | dependency: transitive
149 | description:
150 | name: test_api
151 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
152 | url: "https://pub.dev"
153 | source: hosted
154 | version: "0.4.16"
155 | vector_math:
156 | dependency: transitive
157 | description:
158 | name: vector_math
159 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
160 | url: "https://pub.dev"
161 | source: hosted
162 | version: "2.1.4"
163 | sdks:
164 | dart: ">=2.19.0 <4.0.0"
165 | flutter: ">=3.7.0"
166 |
--------------------------------------------------------------------------------
/.github/workflows/notify-pull-requests.yml:
--------------------------------------------------------------------------------
1 | name: 🔔 PR Notifier
2 |
3 | on:
4 | pull_request:
5 | types:
6 | - closed
7 | - review_requested
8 | branches:
9 | - 'main'
10 | pull_request_review:
11 | types:
12 | - submitted
13 | branches:
14 | - 'main'
15 |
16 | jobs:
17 | notifyPREvent:
18 | name: 🔔 Notify Discord of a new Pull Request event
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: 🔔🧑💻 Send a notification to known reviewer when a PR review is requested
22 | if: github.event_name == 'pull_request' && github.event.action == 'review_requested' && contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.requested_reviewer.login)
23 | uses: sarisia/actions-status-discord@v1
24 | with:
25 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
26 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }}
27 | username: |
28 | Pull Request notifier
29 | color: 0x12AFFA
30 | content: |
31 | 👋 Hey <@${{ fromJSON(vars.IDS_GITHUB_TO_DISCORD)[github.event.requested_reviewer.login].discord_id }}>, you've been asked to review a PR 🤓
32 | description: |
33 | Go and [check it now](${{ github.event.pull_request.self }}) !
34 | title: |
35 | Pull Request: ${{ github.event.pull_request.title }}
36 | url: ${{ github.event.pull_request.self }}
37 | noprefix: true
38 | - name: 🔔❓ Send a notification to unknown reviewer when a PR review is requested
39 | if: github.event_name == 'pull_request' && github.event.action == 'review_requested' && !contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.requested_reviewer.login)
40 | uses: sarisia/actions-status-discord@v1
41 | with:
42 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
43 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }}
44 | username: |
45 | Pull Request notifier
46 | color: 0x12AFFA
47 | content: |
48 | 👋 Hey ${{ github.event.requested_reviewer.login }}, you've been asked to review a PR 🤓
49 | description: |
50 | Go and [check it now](${{ github.event.pull_request.self }}) !
51 | ⚠️ Important: ${{ github.event.requested_reviewer.login }}, your Discord id is not referenced in [Github Actions mappings (`IDS_GITHUB_TO_DISCORD` variable)](https://github.com/orevial/flutter-ci-cd-demo/settings/variables/actions), please add it !
52 | title: |
53 | Pull Request: ${{ github.event.pull_request.title }}
54 | url: ${{ github.event.pull_request.self }}
55 | noprefix: true
56 | - name: 🔔🧑💻 Send a notification to know PR author when a new review is submitted
57 | if: github.event_name == 'pull_request_review' && github.event.action == 'submitted' && contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.pull_request.user.login)
58 | uses: sarisia/actions-status-discord@v1
59 | with:
60 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
61 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }}
62 | username: |
63 | Pull Request notifier
64 | color: 0x1B385E
65 | content: |
66 | 👋 Hey <@${{ fromJSON(vars.IDS_GITHUB_TO_DISCORD)[github.event.pull_request.user.login].discord_id }}>, there's a new review available for your PR 💬
67 | description: |
68 | Go and [check it now](${{ github.event.pull_request.self }}) !
69 | title: |
70 | Pull Request: ${{ github.event.pull_request.title }}
71 | url: ${{ github.event.pull_request.self }}
72 | noprefix: true
73 | - name: 🔔❓ Send a notification to unknown PR author when a new review is submitted
74 | if: github.event_name == 'pull_request_review' && github.event.action == 'submitted' && !contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.pull_request.user.login)
75 | uses: sarisia/actions-status-discord@v1
76 | with:
77 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
78 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }}
79 | username: |
80 | Pull Request notifier
81 | color: 0x1B385E
82 | content: |
83 | Go and [check it now](${{ github.event.pull_request.self }}) !
84 | 👋 Hey ${{ github.event.pull_request.user.login }}, there's a new review available for your PR 💬
85 | description: |
86 | ⚠️ Important: ${{ github.event.pull_request.user.login }}, your Discord id is not referenced in [Github Actions mappings (`IDS_GITHUB_TO_DISCORD` variable)](https://github.com/orevial/flutter-ci-cd-demo/settings/variables/actions), please add it !
87 | title: |
88 | Pull Request: ${{ github.event.pull_request.title }}
89 | url: ${{ github.event.pull_request.self }}
90 | noprefix: true
91 | - name: 🔔🔀 Send a notification when a PR is merged
92 | if: github.event_name == 'pull_request' && github.event.pull_request.merged == true
93 | uses: sarisia/actions-status-discord@v1
94 | with:
95 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
96 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }}
97 | username: |
98 | Pull Request notifier
99 | color: 0x00C02C
100 | title: |
101 | 🔀✅ PR merged: ${{ github.event.pull_request.title }} merged !
102 | description: |
103 | Good job, a [pull request](${{ github.event.pull_request.self }}) has been merged !
104 | Time to start UAT release 📦🚀
105 | url: ${{ github.event.pull_request.self }}
106 | noprefix: true
--------------------------------------------------------------------------------
/.github/workflows/_deploy-android-app.yml:
--------------------------------------------------------------------------------
1 | name: 📦🚀 Build & deploy Android app for an environment
2 |
3 | on:
4 | workflow_call:
5 | inputs:
6 | environment-name:
7 | required: true
8 | type: string
9 | environment-url:
10 | required: true
11 | type: string
12 | package-name:
13 | required: true
14 | type: string
15 | release-status:
16 | required: true
17 | type: string
18 | short-environment-name:
19 | required: true
20 | type: string
21 | flavor:
22 | required: true
23 | type: string
24 | new-pubspec-version:
25 | required: true
26 | type: string
27 |
28 | jobs:
29 | deployAndroid:
30 | name: 🤖📦🚀 Build & deploy Android ${{ inputs.short-environment-name }} release
31 | runs-on: ubuntu-latest
32 | environment:
33 | name: ${{ inputs.environment-name }}
34 | url: ${{ inputs.environment-url }}
35 | steps:
36 | - name: ⬇️ Checkout repository
37 | uses: actions/checkout@v3
38 | - name: ⚙️ Setup Java
39 | uses: actions/setup-java@v3
40 | with:
41 | distribution: 'zulu'
42 | java-version: "12.x"
43 | cache: 'gradle'
44 | id: java
45 | - name: ⚙️ Setup Flutter
46 | uses: subosito/flutter-action@v2
47 | with:
48 | flutter-version: "3.7.0"
49 | channel: 'stable'
50 | cache: true
51 | id: flutter
52 | - name: 🔐 Retrieve base64 keystore and decode it to a file
53 | env:
54 | KEYSTORE_BASE64: ${{ secrets.KEYSTORE_FILE_BASE64 }}
55 | run: echo $KEYSTORE_BASE64 | base64 --decode > "${{ github.workspace }}/android-keystore.jks"
56 | - name: 📝🔐 Create keystore.properties file
57 | env:
58 | KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/keystore.properties
59 | run: |
60 | echo '${{ inputs.flavor }}StoreFile=${{ github.workspace }}/android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH
61 | echo '${{ inputs.flavor }}KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH
62 | echo '${{ inputs.flavor }}StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH
63 | echo '${{ inputs.flavor }}KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH
64 | - name: 📝 Edit pubspec version
65 | run: |
66 | sed -Ei "s/^version: (.*)/version: ${{ inputs.new-pubspec-version }}/" app/pubspec.yaml
67 | - name: ⚙️ Setup Melos
68 | uses: bluefireteam/melos-action@v2
69 | - name: ⚙️ Install dependencies for all packages
70 | run: melos build:pub_get:all
71 | - name: 🤖📦 Create Android ${{ inputs.short-environment-name }} appbundle release
72 | run: |
73 | pushd app
74 | mkdir debug-symbols
75 | flutter build appbundle \
76 | --release \
77 | --flavor ${{ inputs.flavor }} \
78 | --target lib/main_${{ inputs.flavor }}.dart
79 | popd
80 | - name: 🤖🚀 Upload Android ${{ inputs.short-environment-name }} Release to Play Store
81 | uses: r0adkll/upload-google-play@v1.0.19
82 | with:
83 | packageName: ${{ inputs.package-name }}
84 | track: internal
85 | status: ${{ inputs.release-status }}
86 | releaseFiles: ${{ github.workspace }}/app/build/app/outputs/bundle/${{ inputs.flavor }}Release/app-${{ inputs.flavor }}-release.aab
87 | serviceAccountJsonPlainText: "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_JSON }}"
88 | - name: 💬 Pick a random success catchphrase
89 | if: success()
90 | id: success_catchphrase
91 | run: |
92 | sentences=('🤩 AMAZING !' 'Woop woop 🎉' 'Oh wow 😮' '😎 Yeahhhh !' '📣 Amazing announcement !' '📢 Your attention please...' '👏 Great work !' '🍾 Champagne !' '🙌 High five !' '🥳 Time to celebrate !')
93 | arrayLength=${#sentences[@]}
94 | randomNumber=$(($RANDOM%$arrayLength))
95 | pickedSentence=${sentences[$randomNumber]}
96 | echo "picked_sentence=$pickedSentence" >> $GITHUB_OUTPUT
97 | - name: 🔔✅ Send success notif to Discord
98 | if: success()
99 | uses: sarisia/actions-status-discord@v1
100 | with:
101 | webhook: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_URL }}
102 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }}
103 | username: "${{ inputs.short-environment-name }} notifier"
104 | content: "${{ steps.success_catchphrase.outputs.picked_sentence }}"
105 | title: "🤖 New version of ${{ inputs.environment-name }} app available !"
106 | description: |
107 | Version `${{ inputs.new-pubspec-version }}`
108 | Click [here](${{ inputs.environment-url }}) to download
109 | url: ${{ inputs.environment-url }}
110 | nofail: true
111 | nodetail: true
112 | - name: 🔔❌ Send failure notif to Discord
113 | if: failure()
114 | uses: sarisia/actions-status-discord@v1
115 | env:
116 | RUN_URL: "https://github.com/orevial/flutter-ci-cd-demo/actions/runs/${{ github.run_id }}"
117 | with:
118 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
119 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }}
120 | username: "${{ inputs.short-environment-name }} notifier"
121 | content: "Oh no 😢"
122 | title: "🤖 Release of ${{ inputs.environment-name }} app has failed..."
123 | description: |
124 | Failed job: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release
125 | Failed to release version `${{ inputs.new-pubspec-version }}` of ${{ inputs.environment-name }} app
126 | Click [here](${{ env.RUN_URL }}) to go to failed run output
127 | url: ${{ env.RUN_URL }}
128 | nofail: true
129 | nodetail: true
--------------------------------------------------------------------------------
/app/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.10.0"
12 | boolean_selector:
13 | dependency: transitive
14 | description:
15 | name: boolean_selector
16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.1.1"
20 | characters:
21 | dependency: transitive
22 | description:
23 | name: characters
24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "1.2.1"
28 | clock:
29 | dependency: transitive
30 | description:
31 | name: clock
32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.1.1"
36 | collection:
37 | dependency: transitive
38 | description:
39 | name: collection
40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.17.0"
44 | cupertino_icons:
45 | dependency: "direct main"
46 | description:
47 | name: cupertino_icons
48 | sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.0.5"
52 | design_system:
53 | dependency: "direct main"
54 | description:
55 | path: "../design_system"
56 | relative: true
57 | source: path
58 | version: "1.0.0"
59 | fake_async:
60 | dependency: transitive
61 | description:
62 | name: fake_async
63 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
64 | url: "https://pub.dev"
65 | source: hosted
66 | version: "1.3.1"
67 | flutter:
68 | dependency: "direct main"
69 | description: flutter
70 | source: sdk
71 | version: "0.0.0"
72 | flutter_lints:
73 | dependency: "direct dev"
74 | description:
75 | name: flutter_lints
76 | sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
77 | url: "https://pub.dev"
78 | source: hosted
79 | version: "2.0.1"
80 | flutter_test:
81 | dependency: "direct dev"
82 | description: flutter
83 | source: sdk
84 | version: "0.0.0"
85 | js:
86 | dependency: transitive
87 | description:
88 | name: js
89 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
90 | url: "https://pub.dev"
91 | source: hosted
92 | version: "0.6.5"
93 | lints:
94 | dependency: transitive
95 | description:
96 | name: lints
97 | sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
98 | url: "https://pub.dev"
99 | source: hosted
100 | version: "2.0.1"
101 | matcher:
102 | dependency: transitive
103 | description:
104 | name: matcher
105 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
106 | url: "https://pub.dev"
107 | source: hosted
108 | version: "0.12.13"
109 | material_color_utilities:
110 | dependency: transitive
111 | description:
112 | name: material_color_utilities
113 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
114 | url: "https://pub.dev"
115 | source: hosted
116 | version: "0.2.0"
117 | meta:
118 | dependency: transitive
119 | description:
120 | name: meta
121 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
122 | url: "https://pub.dev"
123 | source: hosted
124 | version: "1.8.0"
125 | path:
126 | dependency: transitive
127 | description:
128 | name: path
129 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
130 | url: "https://pub.dev"
131 | source: hosted
132 | version: "1.8.2"
133 | sky_engine:
134 | dependency: transitive
135 | description: flutter
136 | source: sdk
137 | version: "0.0.99"
138 | source_span:
139 | dependency: transitive
140 | description:
141 | name: source_span
142 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
143 | url: "https://pub.dev"
144 | source: hosted
145 | version: "1.9.1"
146 | stack_trace:
147 | dependency: transitive
148 | description:
149 | name: stack_trace
150 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
151 | url: "https://pub.dev"
152 | source: hosted
153 | version: "1.11.0"
154 | stream_channel:
155 | dependency: transitive
156 | description:
157 | name: stream_channel
158 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
159 | url: "https://pub.dev"
160 | source: hosted
161 | version: "2.1.1"
162 | string_scanner:
163 | dependency: transitive
164 | description:
165 | name: string_scanner
166 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
167 | url: "https://pub.dev"
168 | source: hosted
169 | version: "1.2.0"
170 | term_glyph:
171 | dependency: transitive
172 | description:
173 | name: term_glyph
174 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
175 | url: "https://pub.dev"
176 | source: hosted
177 | version: "1.2.1"
178 | test_api:
179 | dependency: transitive
180 | description:
181 | name: test_api
182 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
183 | url: "https://pub.dev"
184 | source: hosted
185 | version: "0.4.16"
186 | vector_math:
187 | dependency: transitive
188 | description:
189 | name: vector_math
190 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
191 | url: "https://pub.dev"
192 | source: hosted
193 | version: "2.1.4"
194 | sdks:
195 | dart: ">=2.19.0 <4.0.0"
196 | flutter: ">=3.7.0"
197 |
--------------------------------------------------------------------------------
/.github/workflows/_deploy-ios-app.yml:
--------------------------------------------------------------------------------
1 | name: 📦🚀 Build & deploy iOS app for an environment
2 |
3 | on:
4 | workflow_call:
5 | inputs:
6 | environment-name:
7 | required: true
8 | type: string
9 | environment-url:
10 | required: true
11 | type: string
12 | short-environment-name:
13 | required: true
14 | type: string
15 | flavor:
16 | required: true
17 | type: string
18 | new-pubspec-version:
19 | required: true
20 | type: string
21 |
22 | jobs:
23 | deployIos:
24 | name: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release
25 | runs-on: macos-latest
26 | environment:
27 | name: ${{ inputs.environment-name }}
28 | url: ${{ inputs.environment-url }}
29 | steps:
30 | - name: ⬇️ Checkout repository
31 | uses: actions/checkout@v3
32 | - name: 🔐 Install Apple certificate and provisioning profile
33 | env:
34 | P12_DISTRIBUTION_CERTIFICATE_BASE64: "${{ secrets.IOS_P12_DISTRIBUTION_CERTIFICATE_BASE64 }}"
35 | P12_DISTRIBUTION_CERTIFICATE_PASSWORD: "${{ secrets.IOS_P12_DISTRIBUTION_CERTIFICATE_PASSWORD }}"
36 | DISTRIBUTION_PROVISIONING_PROFILE_BASE64: "${{ secrets.IOS_DISTRIBUTION_PROVISIONING_PROFILE_BASE64 }}"
37 | KEYCHAIN_PASSWORD: "${{ secrets.IOS_RUNNER_LOCAL_KEYCHAIN_PASSWORD }}"
38 | EXPORT_OPTIONS_BASE64: "${{ secrets.IOS_EXPORT_OPTIONS_BASE64 }}"
39 | run: |
40 | # create variables
41 | CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
42 | PROVISIONING_PROFILE_PATH=$RUNNER_TEMP/build_pp.mobileprovision
43 | KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
44 | EXPORT_OPTIONS_PATH="${{ github.workspace }}/app/ios/Runner/ExportOptions.plist"
45 |
46 | # import certificate, provisioning profile and export options from secrets
47 | echo -n "$P12_DISTRIBUTION_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
48 | echo -n "$DISTRIBUTION_PROVISIONING_PROFILE_BASE64" | base64 --decode -o $PROVISIONING_PROFILE_PATH
49 | echo -n "$EXPORT_OPTIONS_BASE64" | base64 --decode -o $EXPORT_OPTIONS_PATH
50 |
51 | # create temporary keychain
52 | security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
53 | security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
54 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
55 |
56 | # import certificate to keychain
57 | security import $CERTIFICATE_PATH -P "$P12_DISTRIBUTION_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
58 | security list-keychain -d user -s $KEYCHAIN_PATH
59 |
60 | # apply provisioning profile
61 | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
62 | cp $PROVISIONING_PROFILE_PATH ~/Library/MobileDevice/Provisioning\ Profiles
63 | - name: 📝 Edit pubspec version
64 | run: |
65 | sed -Ei "" "s/^version: (.*)/version: ${{ inputs.new-pubspec-version }}/" app/pubspec.yaml
66 | - name: ⚙️ Setup Flutter
67 | uses: subosito/flutter-action@v2
68 | with:
69 | flutter-version: "3.7.0"
70 | channel: 'stable'
71 | cache: true
72 | id: flutter
73 | - name: ⚙️ Setup Melos
74 | uses: bluefireteam/melos-action@v2
75 | - name: ⚙️ Install dependencies for all packages
76 | run: melos build:pub_get:all
77 | - name: 🍏📦 Create iOS ${{ inputs.short-environment-name }} appbundle release
78 | run: |
79 | pushd app/
80 | flutter build ipa \
81 | --release \
82 | --flavor ${{ inputs.flavor }} \
83 | --target lib/main_${{ inputs.flavor }}.dart \
84 | --export-options-plist=ios/Runner/ExportOptions.plist
85 | popd
86 | - name: 🍏🚀 Deploy to App Store (Testflight)
87 | uses: apple-actions/upload-testflight-build@v1
88 | with:
89 | app-path: ${{ github.workspace }}/app/build/ios/ipa/flutter_ci_cd_demo.ipa
90 | issuer-id: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
91 | api-key-id: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
92 | api-private-key: ${{ secrets.APP_STORE_CONNECT_API_PRIVATE_KEY }}
93 | - name: 💬 Pick a random success catchphrase
94 | if: success()
95 | id: success_catchphrase
96 | run: |
97 | sentences=('🤩 AMAZING !' 'Woop woop 🎉' 'Oh wow 😮' '😎 Yeahhhh !' '📣 Amazing announcement !' '📢 Your attention please...' '👏 Great work !' '🍾 Champagne !' '🙌 High five !' '🥳 Time to celebrate !')
98 | arrayLength=${#sentences[@]}
99 | randomNumber=$(($RANDOM%$arrayLength))
100 | pickedSentence=${sentences[$randomNumber]}
101 | echo "picked_sentence=$pickedSentence" >> $GITHUB_OUTPUT
102 | - name: 🔔✅ Send success notif to Discord
103 | if: success()
104 | uses: sarisia/actions-status-discord@v1
105 | with:
106 | webhook: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_URL }}
107 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }}
108 | username: "${{ inputs.short-environment-name }} notifier"
109 | content: "${{ steps.success_catchphrase.outputs.picked_sentence }}"
110 | title: "🍏 New version of ${{ inputs.environment-name }} app available !"
111 | description: |
112 | Version `${{ inputs.new-pubspec-version }}`
113 | Click [here](${{ inputs.environment-url }}) to download
114 | url: ${{ inputs.environment-url }}
115 | nofail: true
116 | nodetail: true
117 | - name: 🔔❌ Send failure notif to Discord
118 | if: failure()
119 | uses: sarisia/actions-status-discord@v1
120 | env:
121 | RUN_URL: "https://github.com/orevial/flutter-ci-cd-demo/actions/runs/${{ github.run_id }}"
122 | with:
123 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }}
124 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }}
125 | username: "${{ inputs.short-environment-name }} notifier"
126 | content: "Oh no 😢"
127 | title: "🍏 Release of ${{ inputs.environment-name }} app has failed..."
128 | description: |
129 | Failed job: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release
130 | Failed to release version `${{ inputs.new-pubspec-version }}` of ${{ inputs.environment-name }} app
131 | Click [here](${{ env.RUN_URL }}) to go to failed run output
132 | url: ${{ env.RUN_URL }}
133 | nofail: true
134 | nodetail: true
--------------------------------------------------------------------------------
/melos.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_ci_cd_demo
2 |
3 | packages:
4 | - app
5 | - design_system
6 |
7 | scripts:
8 | ###############################################
9 | ## BUILD COMMANDS ##
10 | ###############################################
11 | build:pub_get:all:
12 | run: flutter pub get
13 | exec:
14 | concurrency: 6
15 | description: Install all dependencies
16 |
17 | build:clean:
18 | run: |
19 | flutter clean && \
20 | flutter pub get
21 | exec:
22 | concurrency: 6
23 | description: Clean Flutter package and install dependencies
24 |
25 | build:clean:all:
26 | run: melos run --no-select build:clean
27 | description: Clean Flutter package and install dependencies for all packages
28 |
29 | build:codegen:build:
30 | run: flutter pub run build_runner build --delete-conflicting-outputs
31 | exec:
32 | concurrency: 1
33 | orderDependents: true
34 | select-package:
35 | depends-on: "build_runner"
36 | description: Run code generation using build_runner in a specific package
37 |
38 | build:codegen:build:all:
39 | run: melos run build:codegen:build --no-select
40 | description: Run code generation using build_runner for all packages in the project
41 |
42 | build:codegen:watch:
43 | run: flutter pub run build_runner watch --delete-conflicting-outputs
44 | exec:
45 | concurrency: 1
46 | orderDependents: true
47 | select-package:
48 | depends-on: "build_runner"
49 | description: Run code generation using build_runner in a specific package, and watch any changes in this package
50 |
51 | build:build-dev-app:
52 | exec: flutter build appbundle --release --flavor dev -t lib/main_dev.dart
53 | description: Build dev app
54 | select-package:
55 | scope: "flutter_ci_cd_demo"
56 |
57 | build:build-uat-app:
58 | exec: flutter build appbundle --release --flavor uat -t lib/main_uat.dart
59 | description: Build UAT app
60 | select-package:
61 | scope: "flutter_ci_cd_demo"
62 |
63 | build:build-prod-app:
64 | exec: flutter build appbundle --release --flavor prod -t lib/main_prod.dart
65 | description: Build prod app
66 | select-package:
67 | scope: "flutter_ci_cd_demo"
68 |
69 | ###############################################
70 | ## QUALITY COMMANDS ##
71 | ###############################################
72 | quality:analyze:
73 | exec: |
74 | flutter analyze --no-fatal-infos --no-fatal-warnings && \
75 | flutter pub run dart_code_metrics:metrics analyze --no-fatal-warnings . && \
76 | flutter format .
77 | select-package:
78 | dir-exists:
79 | - lib
80 | description: |
81 | Run Flutter static analysis checks and format
82 | Note: you can also rely on your IDEs Dart Analysis / Issues window.
83 |
84 | quality:analyze:all:
85 | run: melos run --no-select quality:analyze
86 | description: |
87 | Run Flutter static analysis checks and format all packages
88 | Note: you can also rely on your IDEs Dart Analysis / Issues window.
89 |
90 | quality:dcm-checks:
91 | exec: |
92 | flutter pub run dart_code_metrics:metrics check-unnecessary-nullable --no-fatal-found . && \
93 | flutter pub run dart_code_metrics:metrics check-unused-code --no-fatal-unused --exclude "{**.g.dart,**.gen.dart,**.freezed.dart}" . && \
94 | flutter pub run dart_code_metrics:metrics check-unused-files --no-fatal-unused . && \
95 | flutter pub run dart_code_metrics:metrics check-unused-l10n --no-fatal-unused .
96 | select-package:
97 | dir-exists:
98 | - lib
99 | description: Run Dart Code Metrics (DCM) extended checks
100 |
101 | quality:dcm-checks:all:
102 | run: melos run --no-select quality:dcm-checks
103 | description: Run Dart Code Metrics (DCM) extended checks on all packages
104 |
105 |
106 | ###############################################
107 | ## TEST COMMANDS ##
108 | ###############################################
109 | test:
110 | run: flutter test --no-pub --reporter compact
111 | exec:
112 | concurrency: 6
113 | select-package:
114 | dir-exists:
115 | - test
116 | description: Run `flutter test` for a specific package.
117 |
118 | test:all:
119 | run: melos run test --no-select
120 | description: Run all Flutter tests in this project.
121 |
122 | test:update-goldens:
123 | run: flutter test --no-pub --reporter compact --update-goldens
124 | exec:
125 | concurrency: 6
126 | select-package:
127 | dir-exists:
128 | - test
129 | scope:
130 | - "design_system"
131 | - "flutter_ci_cd_demo"
132 | description: Run `flutter test` and update goldens for a specific package.
133 |
134 | test:update-goldens:all:
135 | run: melos run test:update-goldens --no-select
136 | description: Run Flutter tests and update goldens for all packages in this project
137 |
138 | test:with-lcov-coverage:
139 | run: MELOS_ROOT_PATH/scripts/test-with-coverage.sh MELOS_ROOT_PATH MELOS_PACKAGE_PATH MELOS_PACKAGE_NAME
140 | exec:
141 | concurrency: 6
142 | select-package:
143 | dir-exists:
144 | - test
145 | description: Run Flutter tests and publish local lcov coverage for a specific package
146 |
147 | test:with-lcov-coverage:all:
148 | run: |
149 | melos run test:with-lcov-coverage --no-select && \
150 | melos run test:combine-coverage
151 | description: Run Flutter tests for all packages and generate a combined lcov coverage report
152 |
153 | test:with-html-coverage:
154 | run: |
155 | MELOS_ROOT_PATH/scripts/test-with-coverage.sh MELOS_ROOT_PATH MELOS_PACKAGE_PATH MELOS_PACKAGE_NAME && \
156 | melos run test:combine-coverage && \
157 | melos run test:generate-html-coverage
158 | exec:
159 | concurrency: 6
160 | select-package:
161 | dir-exists:
162 | - test
163 | description: Run Flutter tests for a specific package and updates global HTML coverage report
164 |
165 | test:with-html-coverage:all:
166 | run: |
167 | melos run test:with-lcov-coverage --no-select && \
168 | melos run test:combine-coverage && \
169 | melos run test:generate-html-coverage
170 | echo "🧪📊 You can find coverage report in the following folder: MELOS_ROOT_PATH/coverage_report/index.html\n\n💡To open it just run: open MELOS_ROOT_PATH/coverage_report/index.html"
171 | description: Run Flutter tests for all packages and generate a combined HTML coverage report
172 |
173 | test:with-html-coverage:all:auto-open:
174 | run: |
175 | melos run test:with-lcov-coverage --no-select && \
176 | melos run test:combine-coverage && \
177 | melos run test:generate-html-coverage
178 | open MELOS_ROOT_PATH/coverage_report/index.html
179 | description: Run Flutter tests for all packages and generate a combined HTML coverage report
180 |
181 | test:combine-coverage:
182 | run: MELOS_ROOT_PATH/scripts/combine-coverage.sh MELOS_ROOT_PATH
183 | description: Combine individual lcov coverage into a single lcov coverage file
184 |
185 | test:generate-html-coverage:
186 | run: MELOS_ROOT_PATH/scripts/generate-html-coverage.sh MELOS_ROOT_PATH
187 | description: Take combined lcov file and generate a human-readable HTML report
188 |
189 | run:dev-app:
190 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_dev.dart' --flavor dev
191 | select-package:
192 | scope: "flutter_ci_cd_demo"
193 |
194 | ###############################################
195 | ## RUN COMMANDS ##
196 | ###############################################
197 | run:uat-app:
198 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_uat.dart' --flavor uat
199 | select-package:
200 | scope: "flutter_ci_cd_demo"
201 |
202 | run:prod-app:
203 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_prod.dart' --flavor prod
204 | select-package:
205 | scope: "flutter_ci_cd_demo"
206 |
207 | environment:
208 | sdk: '>=2.19.0 <3.0.0'
209 | flutter: ">=3.7.0 <4.0.0"
210 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1300;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | alwaysOutOfDate = 1;
175 | buildActionMask = 2147483647;
176 | files = (
177 | );
178 | inputPaths = (
179 | );
180 | name = "Thin Binary";
181 | outputPaths = (
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | shellPath = /bin/sh;
185 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
186 | };
187 | 9740EEB61CF901F6004384FC /* Run Script */ = {
188 | isa = PBXShellScriptBuildPhase;
189 | alwaysOutOfDate = 1;
190 | buildActionMask = 2147483647;
191 | files = (
192 | );
193 | inputPaths = (
194 | );
195 | name = "Run Script";
196 | outputPaths = (
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | shellPath = /bin/sh;
200 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
201 | };
202 | /* End PBXShellScriptBuildPhase section */
203 |
204 | /* Begin PBXSourcesBuildPhase section */
205 | 97C146EA1CF9000F007C117D /* Sources */ = {
206 | isa = PBXSourcesBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
210 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
211 | );
212 | runOnlyForDeploymentPostprocessing = 0;
213 | };
214 | /* End PBXSourcesBuildPhase section */
215 |
216 | /* Begin PBXVariantGroup section */
217 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
218 | isa = PBXVariantGroup;
219 | children = (
220 | 97C146FB1CF9000F007C117D /* Base */,
221 | );
222 | name = Main.storyboard;
223 | sourceTree = "";
224 | };
225 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
226 | isa = PBXVariantGroup;
227 | children = (
228 | 97C147001CF9000F007C117D /* Base */,
229 | );
230 | name = LaunchScreen.storyboard;
231 | sourceTree = "";
232 | };
233 | /* End PBXVariantGroup section */
234 |
235 | /* Begin XCBuildConfiguration section */
236 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
237 | isa = XCBuildConfiguration;
238 | buildSettings = {
239 | ALWAYS_SEARCH_USER_PATHS = NO;
240 | CLANG_ANALYZER_NONNULL = YES;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
242 | CLANG_CXX_LIBRARY = "libc++";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
246 | CLANG_WARN_BOOL_CONVERSION = YES;
247 | CLANG_WARN_COMMA = YES;
248 | CLANG_WARN_CONSTANT_CONVERSION = YES;
249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251 | CLANG_WARN_EMPTY_BODY = YES;
252 | CLANG_WARN_ENUM_CONVERSION = YES;
253 | CLANG_WARN_INFINITE_RECURSION = YES;
254 | CLANG_WARN_INT_CONVERSION = YES;
255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
259 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
260 | CLANG_WARN_STRICT_PROTOTYPES = YES;
261 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
262 | CLANG_WARN_UNREACHABLE_CODE = YES;
263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
265 | COPY_PHASE_STRIP = NO;
266 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
267 | ENABLE_NS_ASSERTIONS = NO;
268 | ENABLE_STRICT_OBJC_MSGSEND = YES;
269 | GCC_C_LANGUAGE_STANDARD = gnu99;
270 | GCC_NO_COMMON_BLOCKS = YES;
271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
273 | GCC_WARN_UNDECLARED_SELECTOR = YES;
274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
275 | GCC_WARN_UNUSED_FUNCTION = YES;
276 | GCC_WARN_UNUSED_VARIABLE = YES;
277 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
278 | MTL_ENABLE_DEBUG_INFO = NO;
279 | SDKROOT = iphoneos;
280 | SUPPORTED_PLATFORMS = iphoneos;
281 | TARGETED_DEVICE_FAMILY = "1,2";
282 | VALIDATE_PRODUCT = YES;
283 | };
284 | name = Profile;
285 | };
286 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
287 | isa = XCBuildConfiguration;
288 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
289 | buildSettings = {
290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
291 | CLANG_ENABLE_MODULES = YES;
292 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
293 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
294 | ENABLE_BITCODE = NO;
295 | INFOPLIST_FILE = Runner/Info.plist;
296 | LD_RUNPATH_SEARCH_PATHS = (
297 | "$(inherited)",
298 | "@executable_path/Frameworks",
299 | );
300 | PRODUCT_BUNDLE_IDENTIFIER = com.orevial.flutterCiCdDemo;
301 | PRODUCT_NAME = "$(TARGET_NAME)";
302 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
303 | SWIFT_VERSION = 5.0;
304 | VERSIONING_SYSTEM = "apple-generic";
305 | };
306 | name = Profile;
307 | };
308 | 7645275C29A8277C00230228 /* Debug-UAT */ = {
309 | isa = XCBuildConfiguration;
310 | buildSettings = {
311 | ALWAYS_SEARCH_USER_PATHS = NO;
312 | CLANG_ANALYZER_NONNULL = YES;
313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
314 | CLANG_CXX_LIBRARY = "libc++";
315 | CLANG_ENABLE_MODULES = YES;
316 | CLANG_ENABLE_OBJC_ARC = YES;
317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
318 | CLANG_WARN_BOOL_CONVERSION = YES;
319 | CLANG_WARN_COMMA = YES;
320 | CLANG_WARN_CONSTANT_CONVERSION = YES;
321 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
322 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
323 | CLANG_WARN_EMPTY_BODY = YES;
324 | CLANG_WARN_ENUM_CONVERSION = YES;
325 | CLANG_WARN_INFINITE_RECURSION = YES;
326 | CLANG_WARN_INT_CONVERSION = YES;
327 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
328 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
329 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
331 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
332 | CLANG_WARN_STRICT_PROTOTYPES = YES;
333 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
334 | CLANG_WARN_UNREACHABLE_CODE = YES;
335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
336 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
337 | COPY_PHASE_STRIP = NO;
338 | DEBUG_INFORMATION_FORMAT = dwarf;
339 | ENABLE_STRICT_OBJC_MSGSEND = YES;
340 | ENABLE_TESTABILITY = YES;
341 | GCC_C_LANGUAGE_STANDARD = gnu99;
342 | GCC_DYNAMIC_NO_PIC = NO;
343 | GCC_NO_COMMON_BLOCKS = YES;
344 | GCC_OPTIMIZATION_LEVEL = 0;
345 | GCC_PREPROCESSOR_DEFINITIONS = (
346 | "DEBUG=1",
347 | "$(inherited)",
348 | );
349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
351 | GCC_WARN_UNDECLARED_SELECTOR = YES;
352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
353 | GCC_WARN_UNUSED_FUNCTION = YES;
354 | GCC_WARN_UNUSED_VARIABLE = YES;
355 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
356 | MTL_ENABLE_DEBUG_INFO = YES;
357 | ONLY_ACTIVE_ARCH = YES;
358 | SDKROOT = iphoneos;
359 | TARGETED_DEVICE_FAMILY = "1,2";
360 | };
361 | name = "Debug-UAT";
362 | };
363 | 7645275D29A8277C00230228 /* Debug-UAT */ = {
364 | isa = XCBuildConfiguration;
365 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
366 | buildSettings = {
367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368 | CLANG_ENABLE_MODULES = YES;
369 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
370 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
371 | ENABLE_BITCODE = NO;
372 | INFOPLIST_FILE = Runner/Info.plist;
373 | LD_RUNPATH_SEARCH_PATHS = (
374 | "$(inherited)",
375 | "@executable_path/Frameworks",
376 | );
377 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.uat";
378 | PRODUCT_NAME = "$(TARGET_NAME)";
379 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
380 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
381 | SWIFT_VERSION = 5.0;
382 | VERSIONING_SYSTEM = "apple-generic";
383 | };
384 | name = "Debug-UAT";
385 | };
386 | 7645275E29A8278A00230228 /* Debug-Dev */ = {
387 | isa = XCBuildConfiguration;
388 | buildSettings = {
389 | ALWAYS_SEARCH_USER_PATHS = NO;
390 | CLANG_ANALYZER_NONNULL = YES;
391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
392 | CLANG_CXX_LIBRARY = "libc++";
393 | CLANG_ENABLE_MODULES = YES;
394 | CLANG_ENABLE_OBJC_ARC = YES;
395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
396 | CLANG_WARN_BOOL_CONVERSION = YES;
397 | CLANG_WARN_COMMA = YES;
398 | CLANG_WARN_CONSTANT_CONVERSION = YES;
399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
401 | CLANG_WARN_EMPTY_BODY = YES;
402 | CLANG_WARN_ENUM_CONVERSION = YES;
403 | CLANG_WARN_INFINITE_RECURSION = YES;
404 | CLANG_WARN_INT_CONVERSION = YES;
405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
409 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
410 | CLANG_WARN_STRICT_PROTOTYPES = YES;
411 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
412 | CLANG_WARN_UNREACHABLE_CODE = YES;
413 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
414 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
415 | COPY_PHASE_STRIP = NO;
416 | DEBUG_INFORMATION_FORMAT = dwarf;
417 | ENABLE_STRICT_OBJC_MSGSEND = YES;
418 | ENABLE_TESTABILITY = YES;
419 | GCC_C_LANGUAGE_STANDARD = gnu99;
420 | GCC_DYNAMIC_NO_PIC = NO;
421 | GCC_NO_COMMON_BLOCKS = YES;
422 | GCC_OPTIMIZATION_LEVEL = 0;
423 | GCC_PREPROCESSOR_DEFINITIONS = (
424 | "DEBUG=1",
425 | "$(inherited)",
426 | );
427 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
428 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
429 | GCC_WARN_UNDECLARED_SELECTOR = YES;
430 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
431 | GCC_WARN_UNUSED_FUNCTION = YES;
432 | GCC_WARN_UNUSED_VARIABLE = YES;
433 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
434 | MTL_ENABLE_DEBUG_INFO = YES;
435 | ONLY_ACTIVE_ARCH = YES;
436 | SDKROOT = iphoneos;
437 | TARGETED_DEVICE_FAMILY = "1,2";
438 | };
439 | name = "Debug-Dev";
440 | };
441 | 7645275F29A8278A00230228 /* Debug-Dev */ = {
442 | isa = XCBuildConfiguration;
443 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
444 | buildSettings = {
445 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
446 | CLANG_ENABLE_MODULES = YES;
447 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
448 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
449 | ENABLE_BITCODE = NO;
450 | INFOPLIST_FILE = Runner/Info.plist;
451 | LD_RUNPATH_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "@executable_path/Frameworks",
454 | );
455 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.dev";
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
458 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
459 | SWIFT_VERSION = 5.0;
460 | VERSIONING_SYSTEM = "apple-generic";
461 | };
462 | name = "Debug-Dev";
463 | };
464 | 7645276029A8279900230228 /* Release-UAT */ = {
465 | isa = XCBuildConfiguration;
466 | buildSettings = {
467 | ALWAYS_SEARCH_USER_PATHS = NO;
468 | CLANG_ANALYZER_NONNULL = YES;
469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
470 | CLANG_CXX_LIBRARY = "libc++";
471 | CLANG_ENABLE_MODULES = YES;
472 | CLANG_ENABLE_OBJC_ARC = YES;
473 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
474 | CLANG_WARN_BOOL_CONVERSION = YES;
475 | CLANG_WARN_COMMA = YES;
476 | CLANG_WARN_CONSTANT_CONVERSION = YES;
477 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
478 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
479 | CLANG_WARN_EMPTY_BODY = YES;
480 | CLANG_WARN_ENUM_CONVERSION = YES;
481 | CLANG_WARN_INFINITE_RECURSION = YES;
482 | CLANG_WARN_INT_CONVERSION = YES;
483 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
484 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
485 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
486 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
487 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
488 | CLANG_WARN_STRICT_PROTOTYPES = YES;
489 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
490 | CLANG_WARN_UNREACHABLE_CODE = YES;
491 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
492 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
493 | COPY_PHASE_STRIP = NO;
494 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
495 | ENABLE_NS_ASSERTIONS = NO;
496 | ENABLE_STRICT_OBJC_MSGSEND = YES;
497 | GCC_C_LANGUAGE_STANDARD = gnu99;
498 | GCC_NO_COMMON_BLOCKS = YES;
499 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
500 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
501 | GCC_WARN_UNDECLARED_SELECTOR = YES;
502 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
503 | GCC_WARN_UNUSED_FUNCTION = YES;
504 | GCC_WARN_UNUSED_VARIABLE = YES;
505 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
506 | MTL_ENABLE_DEBUG_INFO = NO;
507 | SDKROOT = iphoneos;
508 | SUPPORTED_PLATFORMS = iphoneos;
509 | SWIFT_COMPILATION_MODE = wholemodule;
510 | SWIFT_OPTIMIZATION_LEVEL = "-O";
511 | TARGETED_DEVICE_FAMILY = "1,2";
512 | VALIDATE_PRODUCT = YES;
513 | };
514 | name = "Release-UAT";
515 | };
516 | 7645276129A8279900230228 /* Release-UAT */ = {
517 | isa = XCBuildConfiguration;
518 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
519 | buildSettings = {
520 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
521 | CLANG_ENABLE_MODULES = YES;
522 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
523 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
524 | ENABLE_BITCODE = NO;
525 | INFOPLIST_FILE = Runner/Info.plist;
526 | LD_RUNPATH_SEARCH_PATHS = (
527 | "$(inherited)",
528 | "@executable_path/Frameworks",
529 | );
530 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.uat";
531 | PRODUCT_NAME = "$(TARGET_NAME)";
532 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
533 | SWIFT_VERSION = 5.0;
534 | VERSIONING_SYSTEM = "apple-generic";
535 | };
536 | name = "Release-UAT";
537 | };
538 | 7645276229A827A400230228 /* Release-Dev */ = {
539 | isa = XCBuildConfiguration;
540 | buildSettings = {
541 | ALWAYS_SEARCH_USER_PATHS = NO;
542 | CLANG_ANALYZER_NONNULL = YES;
543 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
544 | CLANG_CXX_LIBRARY = "libc++";
545 | CLANG_ENABLE_MODULES = YES;
546 | CLANG_ENABLE_OBJC_ARC = YES;
547 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
548 | CLANG_WARN_BOOL_CONVERSION = YES;
549 | CLANG_WARN_COMMA = YES;
550 | CLANG_WARN_CONSTANT_CONVERSION = YES;
551 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
552 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
553 | CLANG_WARN_EMPTY_BODY = YES;
554 | CLANG_WARN_ENUM_CONVERSION = YES;
555 | CLANG_WARN_INFINITE_RECURSION = YES;
556 | CLANG_WARN_INT_CONVERSION = YES;
557 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
558 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
559 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
560 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
561 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
562 | CLANG_WARN_STRICT_PROTOTYPES = YES;
563 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
564 | CLANG_WARN_UNREACHABLE_CODE = YES;
565 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
566 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
567 | COPY_PHASE_STRIP = NO;
568 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
569 | ENABLE_NS_ASSERTIONS = NO;
570 | ENABLE_STRICT_OBJC_MSGSEND = YES;
571 | GCC_C_LANGUAGE_STANDARD = gnu99;
572 | GCC_NO_COMMON_BLOCKS = YES;
573 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
574 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
575 | GCC_WARN_UNDECLARED_SELECTOR = YES;
576 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
577 | GCC_WARN_UNUSED_FUNCTION = YES;
578 | GCC_WARN_UNUSED_VARIABLE = YES;
579 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
580 | MTL_ENABLE_DEBUG_INFO = NO;
581 | SDKROOT = iphoneos;
582 | SUPPORTED_PLATFORMS = iphoneos;
583 | SWIFT_COMPILATION_MODE = wholemodule;
584 | SWIFT_OPTIMIZATION_LEVEL = "-O";
585 | TARGETED_DEVICE_FAMILY = "1,2";
586 | VALIDATE_PRODUCT = YES;
587 | };
588 | name = "Release-Dev";
589 | };
590 | 7645276329A827A400230228 /* Release-Dev */ = {
591 | isa = XCBuildConfiguration;
592 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
593 | buildSettings = {
594 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
595 | CLANG_ENABLE_MODULES = YES;
596 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
597 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
598 | ENABLE_BITCODE = NO;
599 | INFOPLIST_FILE = Runner/Info.plist;
600 | LD_RUNPATH_SEARCH_PATHS = (
601 | "$(inherited)",
602 | "@executable_path/Frameworks",
603 | );
604 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.de";
605 | PRODUCT_NAME = "$(TARGET_NAME)";
606 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
607 | SWIFT_VERSION = 5.0;
608 | VERSIONING_SYSTEM = "apple-generic";
609 | };
610 | name = "Release-Dev";
611 | };
612 | 97C147031CF9000F007C117D /* Debug-Prod */ = {
613 | isa = XCBuildConfiguration;
614 | buildSettings = {
615 | ALWAYS_SEARCH_USER_PATHS = NO;
616 | CLANG_ANALYZER_NONNULL = YES;
617 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
618 | CLANG_CXX_LIBRARY = "libc++";
619 | CLANG_ENABLE_MODULES = YES;
620 | CLANG_ENABLE_OBJC_ARC = YES;
621 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
622 | CLANG_WARN_BOOL_CONVERSION = YES;
623 | CLANG_WARN_COMMA = YES;
624 | CLANG_WARN_CONSTANT_CONVERSION = YES;
625 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
626 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
627 | CLANG_WARN_EMPTY_BODY = YES;
628 | CLANG_WARN_ENUM_CONVERSION = YES;
629 | CLANG_WARN_INFINITE_RECURSION = YES;
630 | CLANG_WARN_INT_CONVERSION = YES;
631 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
632 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
633 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
634 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
635 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
636 | CLANG_WARN_STRICT_PROTOTYPES = YES;
637 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
638 | CLANG_WARN_UNREACHABLE_CODE = YES;
639 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
640 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
641 | COPY_PHASE_STRIP = NO;
642 | DEBUG_INFORMATION_FORMAT = dwarf;
643 | ENABLE_STRICT_OBJC_MSGSEND = YES;
644 | ENABLE_TESTABILITY = YES;
645 | GCC_C_LANGUAGE_STANDARD = gnu99;
646 | GCC_DYNAMIC_NO_PIC = NO;
647 | GCC_NO_COMMON_BLOCKS = YES;
648 | GCC_OPTIMIZATION_LEVEL = 0;
649 | GCC_PREPROCESSOR_DEFINITIONS = (
650 | "DEBUG=1",
651 | "$(inherited)",
652 | );
653 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
654 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
655 | GCC_WARN_UNDECLARED_SELECTOR = YES;
656 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
657 | GCC_WARN_UNUSED_FUNCTION = YES;
658 | GCC_WARN_UNUSED_VARIABLE = YES;
659 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
660 | MTL_ENABLE_DEBUG_INFO = YES;
661 | ONLY_ACTIVE_ARCH = YES;
662 | SDKROOT = iphoneos;
663 | TARGETED_DEVICE_FAMILY = "1,2";
664 | };
665 | name = "Debug-Prod";
666 | };
667 | 97C147041CF9000F007C117D /* Release-Prod */ = {
668 | isa = XCBuildConfiguration;
669 | buildSettings = {
670 | ALWAYS_SEARCH_USER_PATHS = NO;
671 | CLANG_ANALYZER_NONNULL = YES;
672 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
673 | CLANG_CXX_LIBRARY = "libc++";
674 | CLANG_ENABLE_MODULES = YES;
675 | CLANG_ENABLE_OBJC_ARC = YES;
676 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
677 | CLANG_WARN_BOOL_CONVERSION = YES;
678 | CLANG_WARN_COMMA = YES;
679 | CLANG_WARN_CONSTANT_CONVERSION = YES;
680 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
681 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
682 | CLANG_WARN_EMPTY_BODY = YES;
683 | CLANG_WARN_ENUM_CONVERSION = YES;
684 | CLANG_WARN_INFINITE_RECURSION = YES;
685 | CLANG_WARN_INT_CONVERSION = YES;
686 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
687 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
688 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
689 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
690 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
691 | CLANG_WARN_STRICT_PROTOTYPES = YES;
692 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
693 | CLANG_WARN_UNREACHABLE_CODE = YES;
694 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
695 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
696 | COPY_PHASE_STRIP = NO;
697 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
698 | ENABLE_NS_ASSERTIONS = NO;
699 | ENABLE_STRICT_OBJC_MSGSEND = YES;
700 | GCC_C_LANGUAGE_STANDARD = gnu99;
701 | GCC_NO_COMMON_BLOCKS = YES;
702 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
703 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
704 | GCC_WARN_UNDECLARED_SELECTOR = YES;
705 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
706 | GCC_WARN_UNUSED_FUNCTION = YES;
707 | GCC_WARN_UNUSED_VARIABLE = YES;
708 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
709 | MTL_ENABLE_DEBUG_INFO = NO;
710 | SDKROOT = iphoneos;
711 | SUPPORTED_PLATFORMS = iphoneos;
712 | SWIFT_COMPILATION_MODE = wholemodule;
713 | SWIFT_OPTIMIZATION_LEVEL = "-O";
714 | TARGETED_DEVICE_FAMILY = "1,2";
715 | VALIDATE_PRODUCT = YES;
716 | };
717 | name = "Release-Prod";
718 | };
719 | 97C147061CF9000F007C117D /* Debug-Prod */ = {
720 | isa = XCBuildConfiguration;
721 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
722 | buildSettings = {
723 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
724 | CLANG_ENABLE_MODULES = YES;
725 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
726 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
727 | ENABLE_BITCODE = NO;
728 | INFOPLIST_FILE = Runner/Info.plist;
729 | LD_RUNPATH_SEARCH_PATHS = (
730 | "$(inherited)",
731 | "@executable_path/Frameworks",
732 | );
733 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo";
734 | PRODUCT_NAME = "$(TARGET_NAME)";
735 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
736 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
737 | SWIFT_VERSION = 5.0;
738 | VERSIONING_SYSTEM = "apple-generic";
739 | };
740 | name = "Debug-Prod";
741 | };
742 | 97C147071CF9000F007C117D /* Release-Prod */ = {
743 | isa = XCBuildConfiguration;
744 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
745 | buildSettings = {
746 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
747 | CLANG_ENABLE_MODULES = YES;
748 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
749 | DEVELOPMENT_TEAM = 4SSCF9D3M8;
750 | ENABLE_BITCODE = NO;
751 | INFOPLIST_FILE = Runner/Info.plist;
752 | LD_RUNPATH_SEARCH_PATHS = (
753 | "$(inherited)",
754 | "@executable_path/Frameworks",
755 | );
756 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo";
757 | PRODUCT_NAME = "$(TARGET_NAME)";
758 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
759 | SWIFT_VERSION = 5.0;
760 | VERSIONING_SYSTEM = "apple-generic";
761 | };
762 | name = "Release-Prod";
763 | };
764 | /* End XCBuildConfiguration section */
765 |
766 | /* Begin XCConfigurationList section */
767 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
768 | isa = XCConfigurationList;
769 | buildConfigurations = (
770 | 97C147031CF9000F007C117D /* Debug-Prod */,
771 | 7645275E29A8278A00230228 /* Debug-Dev */,
772 | 7645275C29A8277C00230228 /* Debug-UAT */,
773 | 97C147041CF9000F007C117D /* Release-Prod */,
774 | 7645276229A827A400230228 /* Release-Dev */,
775 | 7645276029A8279900230228 /* Release-UAT */,
776 | 249021D3217E4FDB00AE95B9 /* Profile */,
777 | );
778 | defaultConfigurationIsVisible = 0;
779 | defaultConfigurationName = "Release-Prod";
780 | };
781 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
782 | isa = XCConfigurationList;
783 | buildConfigurations = (
784 | 97C147061CF9000F007C117D /* Debug-Prod */,
785 | 7645275F29A8278A00230228 /* Debug-Dev */,
786 | 7645275D29A8277C00230228 /* Debug-UAT */,
787 | 97C147071CF9000F007C117D /* Release-Prod */,
788 | 7645276329A827A400230228 /* Release-Dev */,
789 | 7645276129A8279900230228 /* Release-UAT */,
790 | 249021D4217E4FDB00AE95B9 /* Profile */,
791 | );
792 | defaultConfigurationIsVisible = 0;
793 | defaultConfigurationName = "Release-Prod";
794 | };
795 | /* End XCConfigurationList section */
796 | };
797 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
798 | }
799 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | ##################################################################################
2 | ## Linter rules for all packages ##
3 | ## ----------------------------- ##
4 | ## Note that there is no need to define another ##
5 | ## analysis-options.yaml in each package because they will ##
6 | ## automatically go up the tree if not found in the package. See here: ##
7 | ## https://dart.dev/guides/language/analysis-options#the-analysis-options-file ##
8 | ##################################################################################
9 | include: package:very_good_analysis/analysis_options.3.0.1.yaml
10 |
11 | ##
12 | # Lint rules to be used for apps without developer facing API. i.e. command line tools and Flutter applications
13 | ##
14 | analyzer:
15 | language:
16 | strict-casts: true
17 | strict-inference: true
18 | strict-raw-types: true
19 | errors:
20 | # treat missing required parameters as an error (not a hint)
21 | missing_required_param: error
22 | # treat missing returns as an error (not a hint)
23 | missing_return: error
24 | # Reassignment should be treated as warning (not a hint)
25 | parameter_assignments: warning
26 | plugins:
27 | - dart_code_metrics
28 |
29 | # Exclude auto-generated files from dart analysis
30 | exclude:
31 | - '**/lib/**.freezed.dart'
32 | - '**/lib/**/di.config.dart'
33 | - '**/lib/**.g.dart'
34 | - '**/lib/**.gr.dart'
35 | - '**/test/**.freezed.dart'
36 | - '**/test/**.g.dart'
37 | - '**/lib/i18n/**.i69n.dart'
38 |
39 | dart_code_metrics:
40 | metrics:
41 | cyclomatic-complexity: 20
42 | halstead-volume: 150
43 | lines-of-code: 100
44 | source-lines-of-code: 75
45 | maintainability-index: 50
46 | maximum-nesting-level: 5
47 | maximum-nesting: 5
48 | number-of-methods: 10
49 | number-of-parameters: 4
50 | technical-debt:
51 | threshold: 16
52 | todo-cost: 4
53 | ignore-cost: 8
54 | ignore-for-file-cost: 16
55 | as-dynamic-cost: 16
56 | deprecated-annotations-cost: 2
57 | file-nullsafety-migration-cost: 2
58 | unit-type: "hours"
59 | anti-patterns:
60 | - long-method:
61 | exclude:
62 | - '**/test/**_test.dart'
63 | # Although Bloc methods should be split to separate methods, it is okay to have a long
64 | # constructors within blocs because this is where the on<> method are used
65 | # !MONITOR!
66 | # Maybe:
67 | # - lib/bloc/**/*_bloc.dart
68 | # While this is generally a good practice, sometimes it's just more convenient to pass
69 | # a longer list of parameters. Plus Dart named parameters make it easier to understand what
70 | # the parameters actually mean in the context of a method call
71 | # - long-parameter-list
72 | rules:
73 | ########################################################################
74 | ## DART CODE METRICS PLUGIN: ENABLED RULES ##
75 | ## ##
76 | ## Rules below are all the rules from dart-code-metrics that we use. ##
77 | ########################################################################
78 | - avoid-banned-imports:
79 | entries:
80 | # Deny Flutter imports from core, data and domain packages
81 | - paths: [ "packages/core/.*.dart", "packages/data/.*.dart", "packages/domain/.*.dart" ]
82 | deny: [ "package:flutter/.*.dart" ]
83 | message: "Do not import Flutter Material Design library, we should not depend on it!"
84 | # Deny data and presentation imports from domain package
85 | - paths: [ "packages/domain/.*.dart" ]
86 | deny: [ "package:data/.*.dart", "package:presentation/.*.dart" ]
87 | message: "Domain package should not depend on data or presentation layers!"
88 | # Deny data imports from presentation package
89 | - paths: [ "packages/presentation/.*.dart" ]
90 | deny: [ "package:data/.*.dart" ]
91 | message: "Presentation package should not depend on data layer!"
92 | # Absolutely no package should depend on app (except itself, of course)
93 | - paths: [ "packages/core/.*.dart", "packages/data/.*.dart", "packages/domain/.*.dart", "packages/presentation/.*.dart" ]
94 | deny: [ "package:app/.*.dart" ]
95 | message: "Do not import app package, we should not depend on it!"
96 | - paths: [ "packages/presentation/screens/home/*.dart" ]
97 | deny: [ "package:flutter/widgets.dart" ]
98 | message: "Test 1"
99 | - paths: [ "packages/presentation/screens/home/.*.dart" ]
100 | deny: [ "package:flutter/widgets.dart" ]
101 | message: "Test 2"
102 | # Newly added !MONITOR!
103 | - avoid-cascade-after-if-null
104 | - avoid-collection-methods-with-unrelated-types
105 | - avoid-double-slash-imports
106 | - avoid-duplicate-exports
107 | - avoid-global-state
108 | - avoid-missing-enum-constant-in-map
109 | - avoid-nested-conditional-expressions:
110 | acceptable-level: 1
111 | # !MONITOR!
112 | # Maybe: While this rule is interesting, it leads to only false-positives in our case because we use
113 | # non-ascii symbols correctly : '€' only in european flavors, and others that don't relate
114 | # to specific locales such as '≈', '∞'...
115 | - avoid-non-ascii-symbols
116 | # Newly added !MONITOR!
117 | - avoid-redundant-async
118 | # !MONITOR!
119 | # Maybe: our custom exceptions thrown in catch blocks seem legit
120 | #- avoid-throw-in-catch-block
121 | # !MONITOR!
122 | # Maybe: While this rule can be useful, there are too many scenari where having top level declarations
123 | # make sense (e.g. shared alchemist/golden config, common mocks, shared widgets, etc)
124 | - avoid-top-level-members-in-tests:
125 | exclude:
126 | - "**/test/mocks/**"
127 | - avoid-unnecessary-conditionals
128 | - avoid-unnecessary-type-assertions
129 | - avoid-unnecessary-type-casts
130 | - avoid-unrelated-type-assertions
131 | - avoid-unused-parameters
132 | - binary-expression-operand-order
133 | - double-literal-format
134 | # !MONITOR!
135 | # This rule is pretty opinionated, which is okay if the starting team agrees on the
136 | # order that this rule enforces
137 | # Let's try the default ordering : https://dartcodemetrics.dev/docs/rules/common/member-ordering
138 | - member-ordering
139 | - missing-test-assertion:
140 | include-assertions: [ 'verify', 'verifyNever' ]
141 | - no-boolean-literal-compare
142 | # !MONITOR!
143 | # Maybe: Although sometimes useful (and helped remove a lot of useless code),
144 | # empty blocks can also be okay to use in Flutter. Examples:
145 | # - empty state reload `setState(() {})`
146 | # - callbacks `() {}`
147 | - no-empty-block:
148 | exclude:
149 | - "**/test/**"
150 | - no-equal-then-else
151 | # !MONITOR!
152 | # Maybe: Although a lot of magic number could be avoided by using widgets or other stuff,
153 | # this rule adds too much noise overall.
154 | # We should still try and reduce a lot of magic numbers though.
155 | # Maybe add:
156 | # exclude:
157 | # - "**/test/**"
158 | - no-magic-number:
159 | allowed: [ -1, 0, 1, 2 ]
160 | exclude:
161 | - "**/test/**"
162 | - no-object-declaration
163 | - prefer-commenting-analyzer-ignores
164 | - prefer-correct-identifier-length:
165 | exceptions:
166 | # counters
167 | - i
168 | - j
169 | # coordinates
170 | - x
171 | - y
172 | # various
173 | - id
174 | - db
175 | # Theme spacings
176 | - xs
177 | - xl
178 | - s
179 | - m
180 | - sm
181 | - l
182 | - lm
183 | - prefer-correct-test-file-name
184 | - prefer-correct-type-name:
185 | min-length: 3
186 | max-length: 50
187 | - prefer-enums-by-name
188 | - prefer-first
189 | - prefer-immediate-return
190 | # Newly added !MONITOR!
191 | - prefer-iterable-of
192 | - prefer-last
193 | # Newly added !MONITOR!
194 | - prefer-static-class:
195 | - ignore-private: true
196 | - prefer-trailing-comma
197 | # Flutter specific
198 | - always-remove-listener
199 | # Newly added !MONITOR!
200 | - avoid-border-all
201 | - avoid-expanded-as-spacer
202 | # !MONITOR!
203 | # Maybe: Although it is good practice to extract widget builders methods to custom widget
204 | # (mostly from a performance point-of-view), we have way too many of them and sometimes
205 | # functions are okay for very small portions of code
206 | - avoid-returning-widgets:
207 | exclude:
208 | - '**/test/**_test.dart'
209 | # Newly added !MONITOR!
210 | - avoid-shrink-wrap-in-lists
211 | - avoid-unnecessary-setstate
212 | - avoid-wrapping-in-padding
213 | # Newly added !MONITOR!
214 | - check-for-equals-in-render-object-setters
215 | # Newly added !MONITOR!
216 | - consistent-update-render-object
217 | # Newly added !MONITOR!
218 | - prefer-const-border-radius
219 | - prefer-correct-edge-insets-constructor
220 | # !MONITOR!
221 | # Maybe: Although it is good practice to try and separate widgets into different files, sometimes
222 | # it's okay to put multiple simple widgets into the same file so this rule might be too restrictive.
223 | # However, the rule might work as we can ignore private widgets from the rule, let's now monitor it...
224 | - prefer-single-widget-per-file:
225 | ignore-private-widgets: true
226 | - prefer-using-list-view
227 | # Newly added !MONITOR!
228 | - use-setstate-synchronously
229 |
230 | - avoid-passing-async-when-sync-expected:
231 | exclude:
232 | - '**/test/**'
233 |
234 | ########################################################################
235 | ## DART CODE METRICS PLUGIN: DISABLED RULES ##
236 | ## ##
237 | ## Rules below are all the rules from dart-code-metrics ##
238 | ## that we DO NOT use, and why. ##
239 | ########################################################################
240 | # Doesn't seem very useful, named arguments are already named so who cares
241 | # if they are passed in order...
242 | # arguments-ordering
243 |
244 | # Although mostly useful over the app, creates too much clutter when running DCM analyze action on CI,
245 | # for some reason...
246 | #- avoid-dynamic:
247 | # exclude:
248 | # - "**/test/**"
249 |
250 | # It's sometimes justified to use non-null assertion operator, this rule is too generic to be really useful
251 | # - avoid-non-null-assertion
252 |
253 | # Not sure if that rule could be useful for us...
254 | # - ban-name
255 |
256 | # This rule seems would introduce some very opinionated views
257 | # - format-comment
258 |
259 | # We will be using freezed instead of equatable, this rule doesn't apply for us
260 | # - list-all-equatable-fields
261 |
262 | # Too many false positive with Flutter widget system
263 | # - no-equal-arguments
264 |
265 | # Mostly uninteresting
266 | # - prefer-match-file-name
267 |
268 | # Too many false positives : there are many cases where it's okay not to use
269 | # the return value of a method call
270 | # - avoid-ignoring-return-values:
271 |
272 | # Although it is good practice to extract long callbacks to methods,
273 | # this rule is too restritive. Sometimes a 2-3 lines inline callback is more readable than a function,
274 | # and the function might be overkill
275 | # - prefer-extracting-callbacks
276 |
277 | # Coding style preference, too opinionated
278 | # - newline-before-return
279 |
280 | # Too opinionated, then is just fine and is sometimes more readable than async/await succession
281 | # - prefer-async-await
282 |
283 | # Too opinionated and often less readable than the good ol' if/else.
284 | # Plus conflicts with package:lint default rule 'prefer_if_elements_to_conditional_expressions'
285 | # - prefer-conditional-expressions
286 |
287 | # Mostly uninteresting
288 | # - tag-name
289 |
290 | # late keyword is okay to use
291 | # - avoid-late-keyword
292 |
293 | # Annoying as hell when using context variables
294 | # - prefer-moving-to-variable
295 |
296 | linter:
297 | rules:
298 | ########################################################################
299 | ## CUSTOM RULES ##
300 | ## ----------------------- ##
301 | ## ##
302 | ## Those rules are either : ##
303 | ## - disabled in inherited package and enabled here (if true here) ##
304 | ## - enabled in inherited package and disabled here (if false here) ##
305 | ########################################################################
306 |
307 | always_put_required_named_parameters_first: true
308 |
309 | # Since nullsafety landed in dart, `int?` is completely fine to return null and `int` can't return `null` at all.
310 | #
311 | # In general there are plenty of valid reasons to return `null`, not a useful rule
312 | #
313 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31)
314 | avoid_returning_null: true
315 |
316 | # Nobody wants to manually wrap lines when changing a few words. This rule is too hard to be a "general" rule
317 | lines_longer_than_80_chars: false
318 |
319 | # Types for local variables can improve readability and shouldn't be forced to be removed.
320 | #
321 | # Dart SDK: >= 2.0.0 • (Linter v0.1.30)
322 | #
323 | omit_local_variable_types: false
324 |
325 | # Defining interfaces (abstract classes), with only one method, makes sense architecture wise
326 | # Discussion: https://github.com/passsy/dart-lint/issues/2
327 | #
328 | #
329 | one_member_abstracts: false
330 |
331 | # Only relevant for packages, not applications or general dart code
332 | package_api_docs: false
333 |
334 | # Definitely not a rule for standard dart code. Maybe relevant for packages
335 | public_member_api_docs: false
336 |
337 | # There is no argument which makes int literals better than double literals for doubles.
338 | #
339 | prefer_int_literals: false
340 |
341 | # "Any sorting is better than no sorting"... probably but it's also a lot of work
342 | # for little added value on pub dependencies. Sometimes it's even less readable
343 | # because logical groups can be made with packages that might now follow each other
344 | # in the alphabetical order
345 | sort_pub_dependencies: false
346 |
347 | # Use whatever makes you happy. lint doesn't define a style
348 | # Conflicts with prefer_double_quotes
349 | #
350 | prefer_single_quotes: false
351 |
352 | # Working, results in consistent code. But too opinionated
353 | # Discussion: https://github.com/passsy/dart-lint/issues/1
354 | #
355 | # Also, we rather want to use member-ordering rule from Dart Code Metrics
356 | # (https://dartcodemetrics.dev/docs/rules/common/member-ordering) to
357 | # have consistent code that match our opinionated way to do it
358 | #
359 | sort_constructors_first: false
360 |
361 | ########################################################################
362 | ## Dart 2.19 rules ##
363 | ## ----------------------- ##
364 | ## ##
365 | ## We use the plugin "very_good_analysis" in version 3.1.0 ##
366 | ## as our base rules set. ##
367 | ## However as of 2023/02/06 new Dart 2.19 rules have not been ##
368 | ## added to this plugin yet, so we will put them there for now. ##
369 | ########################################################################
370 |
371 | # !MONITOR!
372 | # New Dart 2.19 rule (as of 2023/02/06)
373 | collection_methods_unrelated_type: true
374 |
375 | # !MONITOR!
376 | # New Dart 2.19 rule (as of 2023/02/06)
377 | combinators_ordering: true
378 |
379 | # !MONITOR!
380 | # New Dart 2.19 rule (as of 2023/02/06)
381 | dangling_library_doc_comments: true
382 |
383 | # !MONITOR!
384 | # New Dart 2.19 rule (as of 2023/02/06)
385 | library_annotations: true
386 |
387 | # !MONITOR!
388 | # New Dart 2.19 rule (as of 2023/02/06)
389 | unnecessary_library_directive: true
390 |
391 | # !MONITOR!
392 | # New Dart 2.19 rule (as of 2023/02/06)
393 | implicit_call_tearoffs: true
394 |
395 | # !MONITOR!
396 | # New Dart 2.19 rule (as of 2023/02/06)
397 | unreachable_from_main: true
398 |
399 | # !MONITOR!
400 | # New Dart 2.19 rule (as of 2023/02/06)
401 | use_string_in_part_of_directives: true
402 |
403 | ########################################################################
404 | ## INHERITED ENABLED RULES ##
405 | ## ----------------------- ##
406 | ## ##
407 | ## Rules below come from package ##
408 | ## https://pub.dev/packages/very_good_analysis ##
409 | ########################################################################
410 | # Prevents accidental return type changes which results in a breaking API change.
411 | # Enforcing return type makes API changes visible in a diff
412 | #
413 | # - always_declare_return_types
414 |
415 | # All non nullable named parameters should be and annotated with @required.
416 | # This allows API consumers to get warnings via lint rather than a crash a runtime.
417 | # Might become obsolete with Non-Nullable types
418 | #
419 | # - always_require_non_null_named_parameters
420 |
421 | # Protect against unintentionally overriding superclass members
422 | #
423 | # - annotate_overrides
424 |
425 | # Highlights boolean expressions which can be simplified
426 | # - avoid_bool_literals_in_conditional_expressions
427 |
428 | # Errors aren't for catching but to prevent prior to runtime
429 | #
430 | # - avoid_catching_errors
431 |
432 | # Never accidentally use dynamic invocations, as it makes type error very hard to find
433 | # Dart SDK: unreleased • (Linter v1.0)
434 | # - avoid_dynamic_calls
435 |
436 | # Since all dart code may be compiled to JS this should be considered.
437 | # Disable it manually when you're explicitly not targeting web
438 | #
439 | # - avoid_double_and_int_checks
440 |
441 | # Prevents accidental empty else cases. See samples in documentation
442 | #
443 | # - avoid_empty_else
444 |
445 | # Use different quotes instead of escaping
446 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111)
447 | # - avoid_escaping_inner_quotes
448 |
449 | # Prevents unnecessary allocation of a field
450 | #
451 | # - avoid_field_initializers_in_const_classes
452 |
453 | # Since lint `parameter_assignments` is enabled, the final parameter doesn't add more safety, it would be just verbose
454 | # Conflicts with prefer_final_parameters
455 | #
456 | # - avoid_final_parameters
457 |
458 | # Prevents allocating a lambda and allows return/break/continue control flow statements inside the loop
459 | #
460 | # Dart SDK: >= 2.0.0 • (Linter v0.1.30)
461 | #
462 | # - avoid_function_literals_in_foreach_calls
463 |
464 | # Removes redundant `= null;`
465 | # - avoid_init_to_null
466 |
467 | # Not useful for coding golf, but in every environment where code is maintained by multiple authors.
468 | #
469 | # Dart SDK: 2.13.0 • (Linter v1.1.0)
470 | #
471 | # - avoid_multiple_declarations_per_line
472 |
473 | # Null checks aren't required in ==() operators
474 | #
475 | # - avoid_null_checks_in_equality_operators
476 |
477 | # Good APIs don't use ambiguous boolean parameters. Instead use named parameters
478 | # - avoid_positional_boolean_parameters
479 |
480 | # Don't call print in production code
481 | #
482 | # - avoid_print
483 |
484 | # Always prefer function references over typedefs.
485 | # Jumping twice in code to see the signature of a lambda sucks. This is different from the flutter analysis_options
486 | # - avoid_private_typedef_functions
487 |
488 | # Setters always return void, therefore defining void is redundant
489 | #
490 | # - avoid_return_types_on_setters
491 |
492 | # Don't use `Future?`, therefore never return null instead of a Future.
493 | # Will become obsolete one Non-Nullable types land
494 | # - avoid_returning_null_for_future
495 |
496 | # Use empty returns, don't show off with you knowledge about dart internals.
497 | # - avoid_returning_null_for_void
498 |
499 | # Prevents logical inconsistencies. It's good practice to define getters for all existing setters.
500 | # - avoid_setters_without_getters
501 |
502 | # Don't reuse a type parameter when one with the same name already exists in the same scope
503 | #
504 | # - avoid_shadowing_type_parameters
505 |
506 | # A single cascade operator can be replaced with a normal method call
507 | #
508 | # - avoid_single_cascade_in_expression_statements
509 |
510 | # Don't use .toString() in production code which might be minified
511 | # Dart SDK: >= 2.10.0-144.0.dev • (Linter v0.1.119)
512 | # - avoid_type_to_string
513 |
514 | # Don't use a parameter names which can be confused with a types (i.e. int, bool, num, ...)
515 | #
516 | # - avoid_types_as_parameter_names
517 |
518 | # Containers without parameters have no effect and can be removed
519 | # - avoid_unnecessary_containers
520 |
521 | # Unused parameters should be removed
522 | # - avoid_unused_constructor_parameters
523 |
524 | # For async functions use `Future` as return value, not `void`
525 | # This allows usage of the await keyword and prevents operations from running in parallel.
526 | #
527 | # - avoid_void_async
528 |
529 | # Flutter mobile only: Web packages aren't available in mobile flutter apps
530 | # - avoid_web_libraries_in_flutter
531 |
532 | # Use the await keyword only for futures. There is nothing to await in synchronous code
533 | #
534 | # - await_only_futures
535 |
536 | # Follow the style guide and use UpperCamelCase for extensions
537 | #
538 | # - camel_case_extensions
539 |
540 | # Follow the style guide and use UpperCamelCase for class names and typedefs
541 | #
542 | # - camel_case_types
543 |
544 | # Prevents leaks and code executing after their lifecycle.
545 | # Discussion https://github.com/passsy/dart-lint/issues/4
546 | #
547 | #
548 | # - cancel_subscriptions
549 |
550 | # Don't cast T? to T. Use ! instead
551 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120)
552 | # - cast_nullable_to_non_nullable
553 |
554 | # Checks that files in conditional imports exist
555 | #
556 | # Linter v1.16.0
557 | # - conditional_uri_does_not_exist
558 |
559 | # Prevents hard to debug code
560 | #
561 | # - control_flow_in_finally
562 |
563 | # Single line `if`s are fine, but when a new line splits the bool expression and body curly braces
564 | # are recommended. It prevents the danging else problem and easily allows the addition of more lines inside
565 | # the if body
566 | #
567 | # Dart SDK: >= 2.0.0 • (Linter v0.1.57)
568 | #
569 | # - curly_braces_in_flow_control_structures
570 |
571 | # Requires all referenced dependencies to be declared as direct dependencies in pubspec.yaml. Transitive
572 | # dependencies might be removed by a dependency, breaking your code.
573 | #
574 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0)
575 | #
576 | # - depend_on_referenced_packages
577 |
578 | # When deprecating classes, also deprecate the constructor. When deprecating fields, also deprecate the constructor
579 | # parameter. That rule is useful for apps and especially for packages
580 | #
581 | # Dart SDK: 2.13.0 • (Linter v1.0.0)
582 | #
583 | # - deprecated_consistency
584 |
585 | # Follows dart style. Fully supported by IDEs and no manual effort for a consistent style
586 | #
587 | # - directives_ordering
588 |
589 | # Add a comment why no further error handling is required
590 | #
591 | # - empty_catches
592 |
593 | # Removed empty constructor bodies
594 | #
595 | # - empty_constructor_bodies
596 |
597 | # Don't allow empty if bodies. Works together with curly_braces_in_flow_control_structures
598 | #
599 | # - empty_statements
600 |
601 | # That's good habit, but not necessary. It might be useful for some parsers that split lines based on the
602 | # new line character. Common in simple bash scripts.
603 | #
604 | # Most IDEs do this automatically, therefore zero effort for devs
605 | #
606 | # Dart SDK: >=2.14.0-360.0.dev • (Linter v1.8.0)
607 | #
608 | # - eol_at_end_of_file
609 |
610 | # Enums aren't powerful enough, now enum like classes get the same linting support
611 | #
612 | # Dart SDK: >= 2.9.0-12.0.dev • (Linter v0.1.116)
613 | #
614 | # - exhaustive_cases
615 |
616 | # Follow dart file naming schema
617 | # - file_names
618 |
619 | # hashCode and equals need to be consistent. One can't live without another.
620 | # - hash_and_equals
621 |
622 | # DON'T import implementation files from another package.
623 | # If you need access to some internal code, create an issue
624 | # - implementation_imports
625 |
626 | # Although there are some false positives, this lint generally catches unnecessary checks
627 | # - https://github.com/dart-lang/linter/issues/811
628 | #
629 | #
630 | # - invariant_booleans
631 |
632 | # Type check for `Iterable.contains(other)` where `other is! T`
633 | # Without this, `contains` will always report false. Those errors are usually very hard to catch.
634 | #
635 | # - iterable_contains_unrelated_type
636 |
637 | # Hint to join return and assignment.
638 | #
639 | # - join_return_with_assignment
640 |
641 | # Add leading \n which which makes multiline strings easier to read
642 | # Dart SDK: >= 2.8.0-dev.16.0 • (Linter v0.1.113)
643 | # - leading_newlines_in_multiline_strings
644 |
645 | # Makes sure a library name is a valid dart identifier.
646 | # This comes in handy for test files combining multiple tests where the file name can be used as identifier
647 | #
648 | # ```
649 | # import src/some_test.dart as some_test;
650 | #
651 | # main() {
652 | # some_test.main();
653 | # }
654 | # ```
655 | #
656 | # - library_names
657 |
658 | # Follow dart style
659 | #
660 | # - library_prefixes
661 |
662 | # Type check for List.remove(item) where item is! T
663 | # The list can't contain item. Those errors are not directly obvious especially when refactoring.
664 | # - list_remove_unrelated_type
665 |
666 | # Don't forget the whitespaces at the end
667 | #
668 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110)
669 | #
670 | # - missing_whitespace_between_adjacent_strings
671 |
672 | # Concat Strings obviously with `+` inside a list.
673 | #
674 | # - no_adjacent_strings_in_list
675 |
676 | # Second case is basically dead code which will never be reached.
677 | #
678 | # - no_duplicate_case_values
679 |
680 | # private library prefixes don't exist, don't try to introduce concepts that have no effect
681 | #
682 | # Linter v1.15
683 | # - no_leading_underscores_for_library_prefixes
684 |
685 | # private identifier prefixes don't exist, don't try to introduce concepts that have no effect
686 | #
687 | # Linter v1.15
688 | # - no_leading_underscores_for_local_identifiers
689 |
690 | # Flutter only: `createState` shouldn't pass information into the state
691 | #
692 | # - no_logic_in_create_state
693 |
694 | # calling `runtimeType` may be a performance problem
695 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110)
696 | # - no_runtimeType_toString
697 |
698 | # Follow dart style naming conventions
699 | #
700 | # - non_constant_identifier_names
701 |
702 | # Don't call unnecessary conversion methods on primitives
703 | #
704 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0)
705 | #
706 | # - noop_primitive_operations
707 |
708 | # Generic T might have a value of String or String?. Both are valid.
709 | # This lint triggers when ! is used on T? casting (String?)? to String and not (String?)? to String?
710 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120)
711 | # - null_check_on_nullable_type_parameter
712 |
713 | # Might become irrelevant when non-nullable types land in dart. Until then use this lint check which checks for
714 | # non null arguments for specific dart sdk methods.
715 | #
716 | # - null_closures
717 |
718 |
719 | # Highlights unintentionally overridden fields.
720 | # overridden_fields
721 |
722 | # Follow dart style package naming convention
723 | #
724 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31)
725 | #
726 | # - package_names
727 |
728 | # Seems very rare, especially for applications.
729 | # - package_prefixed_library_names
730 |
731 | # Most likely a mistake, if not: bad practice
732 | #
733 | # - parameter_assignments
734 |
735 | # Makes it easier to migrate to const constructors and to have final fields
736 | #
737 | # - prefer_asserts_in_initializer_lists
738 |
739 | # Collection literals are shorter. They exists, use them.
740 | #
741 | # - prefer_collection_literals
742 |
743 | # Use the ??= operator when possible
744 | #
745 | # - prefer_conditional_assignment
746 |
747 | # Always use const when possible, make runtime faster
748 | #
749 | # prefer_const_constructors
750 |
751 | # Add a const constructor when possible
752 | #
753 | # prefer_const_constructors_in_immutables
754 |
755 | # final is good, const is better
756 | # prefer_const_declarations
757 |
758 | # Always use const when possible, make runtime faster
759 | #
760 | # prefer_const_literals_to_create_immutables
761 |
762 | # Dart has named constructors. Static methods in other languages (java) are a workaround which don't have
763 | # named constructors.
764 | #
765 | # prefer_constructors_over_static_methods
766 |
767 | # Contains may be faster and is easier to read
768 | #
769 | # - prefer_contains
770 |
771 | # Prevent confusion with call-side when using named parameters
772 | #
773 | # - prefer_equal_for_default_values
774 |
775 | # Avoid accidental reassignments and allows the compiler to do optimizations.
776 | #
777 | # - prefer_final_fields
778 |
779 | # Helps avoid accidental reassignments and allows the compiler to do optimizations.
780 | #
781 | # - prefer_final_in_for_each
782 |
783 | # Helps avoid accidental reassignments and allows the compiler to do optimizations.
784 | #
785 | # - prefer_final_locals
786 |
787 | # Saves lot of code
788 | #
789 | # - prefer_for_elements_to_map_fromIterable
790 |
791 | # As Dart allows local function declarations, it is a good practice to use them in the place of function literals.
792 | # - prefer_function_declarations_over_variables
793 |
794 | # For consistency
795 | #
796 | # - prefer_generic_function_type_aliases
797 |
798 | # Allows potential usage of const
799 | # - prefer_if_elements_to_conditional_expressions
800 |
801 | # Dart has a special operator for this, use it
802 | #
803 | # - prefer_if_null_operators
804 |
805 | # Terser code
806 | # - prefer_initializing_formals
807 |
808 | # Easier move towards const, and way easier to read
809 | #
810 | # - prefer_inlined_adds
811 |
812 | # Interpolate, use less "", '' and +
813 | # - prefer_interpolation_to_compose_strings
814 |
815 | # Iterables do not necessary know their length
816 | #
817 | # - prefer_is_empty
818 |
819 | # Easier to read
820 | #
821 | # Dart SDK: >= 2.0.0 • (Linter v0.1.5)
822 | #
823 | # - prefer_is_not_empty
824 |
825 | # Use the `foo is! Foo` instead of `!(foo is Foo)`
826 | # - prefer_is_not_operator
827 |
828 | # Easier to read
829 | #
830 | # - prefer_iterable_whereType
831 |
832 | # It's shorter and should be preferred. Especially helpful for devs new to dart.
833 | #
834 | # Dart SDK: 2.14.0-2.0.dev • (Linter v1.3.0)
835 | #
836 | # - prefer_null_aware_method_calls
837 |
838 | # Makes expressions with null checks easier to read.
839 | # - prefer_null_aware_operators
840 |
841 | # Allows potential usage of const
842 | #
843 | # - prefer_spread_collections
844 |
845 | # Define types
846 | #
847 | # - prefer_typing_uninitialized_variables
848 |
849 | # Null is not a type, use void
850 | # - prefer_void_to_null
851 |
852 | # Document the replacement API
853 | # - provide_deprecation_message
854 |
855 | # Hints accidental recursions
856 | #
857 | # - recursive_getters
858 |
859 | # Dartfmt formats differently when adding trailing commas. This lint makes sure there is zero doubt in how code
860 | # should be formatted.
861 | #
862 | # This rule is debatable, though.
863 | # A non-representative [vote](https://twitter.com/passsy/status/1427220769050972162) shows a strong tendency towards
864 | # enabling this rule. Especially because the code example does only include the debatable formatting changes. There
865 | # are more, especially in Flutter build methods which make the code clearly better.
866 | #
867 | # Dart SDK: 2.14.0-2.0.dev • (Linter v1.3.0)
868 | #
869 | # - require_trailing_commas
870 |
871 | # Use https in pubspec.yaml
872 | #
873 | # Linter v1.15
874 | # - secure_pubspec_urls
875 |
876 | # Flutter only, prefer SizedBox over Container which offers a const constructors
877 | # Dart SDK: >= 2.9.0-4.0.dev • (Linter v0.1.115)
878 | # - sized_box_for_whitespace
879 |
880 | # Use the SizeBox.expand or SizeBox.shrink constructor instead of setting both width and height
881 | # to `0` or `double.infinity`
882 | #
883 | # Linter v1.15
884 | # - sized_box_shrink_expand
885 |
886 | # Follow dart style use triple slashes
887 | #
888 | # - slash_for_doc_comments
889 |
890 | # Flutter only, always put child last
891 | #
892 | # - sort_child_properties_last
893 |
894 | # Default constructor comes first.
895 | #
896 | # - sort_unnamed_constructors_first
897 |
898 | # First test, then cast
899 | #
900 | # - test_types_in_equals
901 |
902 | # Hard to debug and bad style
903 | #
904 | # - throw_in_finally
905 |
906 | # Help the compiler at compile time with non-null asserts rather than crashing at runtime
907 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120)
908 | # - tighten_type_of_initializing_formals
909 |
910 | # Type annotations make the compiler intelligent, use them
911 | # - type_annotate_public_apis
912 |
913 | # Don't add types for already typed constructor parameters.
914 | #
915 | # - type_init_formals
916 |
917 | # Remove async/await clutter when not required
918 | # - unnecessary_await_in_return
919 |
920 | # Remove unnecessary braces
921 | #
922 | # - unnecessary_brace_in_string_interps
923 |
924 | # Yes, const everywhere. But not in an already const scope
925 | #
926 | # unnecessary_const
927 |
928 | # unnecessary_constructor_name
929 |
930 | # Getter/setters can be added later on in a non API breaking manner
931 | #
932 | # - unnecessary_getters_setters
933 |
934 | # Remove the optional `new` keyword
935 | #
936 | # - unnecessary_new
937 |
938 | # Don't assign `null` when value is already `null`.
939 | #
940 | # - unnecessary_null_aware_assignments
941 |
942 | # Remove ! when already non-nullable
943 | # Dart SDK: >= 2.10.0-144.0.dev • (Linter v0.1.119)
944 | # - unnecessary_null_checks
945 |
946 | # Don't assign `null` when value is already `null`.
947 | #
948 | # - unnecessary_null_in_if_null_operators
949 |
950 | # If a variable doesn't change and is initialized, no need to define it as nullable (NNDB)
951 | # Dart SDK: >= 2.10.0-10.0.dev • (Linter v0.1.118)
952 | # - unnecessary_nullable_for_final_variable_declarations
953 |
954 | # Remove overrides which simply call super
955 | # - unnecessary_overrides
956 |
957 | # Remove clutter where possible
958 | # - unnecessary_parenthesis
959 |
960 | # Use raw string only when needed
961 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111)
962 | # - unnecessary_raw_strings
963 |
964 | # Avoid magic overloads of + operators
965 | # - unnecessary_statements
966 |
967 | # Remove unnecessary escape characters
968 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111)
969 | # - unnecessary_string_escapes
970 |
971 | # - unnecessary_late
972 |
973 | # Completely unnecessary code, simplify to save a few CPU cycles
974 | #
975 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110)
976 | #
977 | # - unnecessary_string_interpolations
978 |
979 | # The variable is clear, remove clutter
980 | #
981 | # - unnecessary_this
982 |
983 | # Highlights potential bugs where unrelated types are compared with another. (always *not* equal).
984 | #
985 | # - unrelated_type_equality_checks
986 |
987 | # Web only
988 | #
989 | # - unsafe_html
990 |
991 | # Very useful in preventing Flutter BuildContext bugs in async callbacks
992 | #
993 | # Dart SDK: 2.13.0 • (Linter v1.1.0)
994 | #
995 | # - use_build_context_synchronously
996 |
997 | # Yet another "Container might be overkill" lint
998 | #
999 | # Linter v1.15
1000 | # - use_decorated_box
1001 |
1002 | # Always use hex syntax Color(0x00000001), never Color(1)
1003 | #
1004 | # - use_full_hex_values_for_flutter_colors
1005 |
1006 | # Always use generic function type syntax, don't mix styles
1007 | #
1008 | # - use_function_type_syntax_for_parameters
1009 |
1010 | # Don't use the modulo operator for isEven/isOdd checks
1011 | #
1012 | # Linter v0.1.116
1013 | # - use_is_even_rather_than_modulo
1014 |
1015 | # Replace const values with predefined constants
1016 | # `const Duration(seconds: 0)` -> `Duration.zero`
1017 | #
1018 | # Dart SDK: 2.13.0 • (Linter v1.0.0)
1019 | #
1020 | # use_named_constants
1021 |
1022 | # Some might argue `late` is a code smell, this lint is very opinionated. It triggers only for private fields and
1023 | # therefore might actually cleanup some code.
1024 | # There is no performance impact either way https://github.com/dart-lang/linter/pull/2189#discussion_r457945301
1025 | #
1026 | # Dart SDK: >= 2.10.0-10.0.dev • (Linter v0.1.118)
1027 | #
1028 | # - use_late_for_private_fields_and_variables
1029 |
1030 | # Use rethrow to preserve the original stacktrace.
1031 | #
1032 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31)
1033 | #
1034 | # - use_rethrow_when_possible
1035 |
1036 | # Use the setter syntax
1037 | #
1038 | # - use_setters_to_change_properties
1039 |
1040 | # In most cases, using a string buffer is preferred for composing strings due to its improved performance.
1041 | # - use_string_buffers
1042 |
1043 | # Don't use try-catch with fail(), instead catch the error with the `throwsA` matcher. The big advantage:
1044 | # When another error is thrown, the assertion fails whereas catching a specific error would miss the catch block
1045 | #
1046 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0)
1047 | #
1048 | # - use_test_throws_matchers
1049 |
1050 | # Catches invalid regular expressions.
1051 | #
1052 | # - valid_regexps
1053 |
1054 | # Don't assign anything to void
1055 | # - void_checks
1056 |
1057 | # Carries more meaning than a generic Container
1058 | # - use_colored_box
1059 |
1060 | # - always_use_package_imports # project rule to differentiate external package imports from our code
1061 | # - avoid_relative_lib_imports # obviously if above is true this one is true too
1062 |
1063 | # It is expected that mutable objects which override hash & equals shouldn't be used as keys for hashmaps.
1064 | # avoid_equals_and_hash_code_on_mutable_classes
1065 |
1066 | # Only useful when targeting JS
1067 | # Warns about too large integers when compiling to JS
1068 | #
1069 | # - avoid_js_rounded_ints
1070 |
1071 | # - avoid_redundant_argument_values
1072 |
1073 | # - avoid_renaming_method_parameters
1074 |
1075 | # - avoid_returning_this
1076 |
1077 | # - constant_identifier_names
1078 |
1079 | # - flutter_style_todos
1080 |
1081 | # - no_default_cases
1082 |
1083 | # Since Errors aren't intended to be caught (see avoid_catching_errors), throwing anything
1084 | # doesn't cause trouble.
1085 | # - only_throw_errors
1086 |
1087 | # - prefer_adjacent_string_concatenation
1088 |
1089 | # - prefer_asserts_with_message
1090 |
1091 | # - unnecessary_to_list_in_spreads
1092 |
1093 | # - use_enums
1094 |
1095 | # Useful for testing and debug purposes
1096 | # - use_key_in_widget_constructors
1097 |
1098 | # - use_raw_strings
1099 |
1100 | # - use_super_parameters
1101 |
1102 | # - use_to_and_as_if_applicable
1103 |
1104 | ########################################################################
1105 | ## INHERITED ENABLED RULES: NEED MONITORING ! ##
1106 | ## ------------------------------------------ ##
1107 | ## ##
1108 | ## Those rules need monitoring because we are not sure yet ##
1109 | ## if they are pertinent or will just create clutter. ##
1110 | ## ##
1111 | ## Rules below come from package ##
1112 | ## https://pub.dev/packages/very_good_analysis ##
1113 | ########################################################################
1114 |
1115 | # !MONITOR!
1116 | # Too many false positives.
1117 | # Using the pedantic package for the unawaited function doesn't make code better readable
1118 | # unawaited_futures # @orevial not sure about this one, I would usually enable it but we might want unawaited futures, let's check at how many cases are send and if they are legit : probably deactive after analyze
1119 |
1120 | # !MONITOR!
1121 | # Flutter setState is a good example where a lambda should always be used.
1122 | #
1123 | # Some generic code sometimes requires lambdas, otherwise the generic type isn't forwarded correctly.
1124 | #
1125 | # - unnecessary_lambdas
1126 |
1127 | # !MONITOR!
1128 | # Write `if (nullableBool ?? false)` instead of `if (nullableBool == true)`
1129 | # Not enabled, because `nullableBool == true` is very explicit, whereas `nullableBool ?? false` requires
1130 | # cognitive effort to process
1131 | #
1132 | # Dart SDK: 2.13.0 • (Linter v1.0.0)
1133 | #
1134 | # - use_if_null_to_convert_nulls_to_bools
1135 |
1136 | # !MONITOR!
1137 | # Good for libraries to prevent unnecessary code paths.
1138 | # False positives may occur for applications when boolean properties are generated by external programs
1139 | # producing auto-generated source code
1140 | #
1141 | # Known issue: while(true) loops https://github.com/dart-lang/linter/issues/453
1142 | #
1143 | #
1144 | # - literal_only_boolean_expressions
1145 |
1146 | # !MONITOR!
1147 | # Might cause frame drops because of synchronous file access on mobile, especially on older phones with slow storage.
1148 | # There are no known measurements sync access does *not* drop frames.
1149 | #
1150 | # - avoid_slow_async_io
1151 |
1152 | # !MONITOR!
1153 | # The cascade syntax is weird and you shouldn't be forced to use it.
1154 | # Potential false positives:
1155 | # https://github.com/dart-lang/linter/issues/1589
1156 | #
1157 | # - cascade_invocations
1158 |
1159 | # !MONITOR!
1160 | # Potential false positives:
1161 | # - https://github.com/dart-lang/linter/issues/1142
1162 | #
1163 | # - comment_references
1164 |
1165 |
1166 | ########################################################################
1167 | ## INHERITED DISABLED RULES ##
1168 | ## ------------------------ ##
1169 | ## ##
1170 | ## Rules below come from package ##
1171 | ## https://pub.dev/packages/very_good_analysis ##
1172 | ########################################################################
1173 |
1174 | # All methods should define a return type. dynamic is no exception.
1175 | # Violates Effective Dart "PREFER annotating with dynamic instead of letting inference fail"
1176 | #
1177 | # - avoid_annotating_with_dynamic
1178 |
1179 | # A leftover from dart1, should be deprecated
1180 | #
1181 | # - https://github.com/dart-lang/linter/issues/1401
1182 | # - avoid_as
1183 |
1184 | # There are no strong arguments to enable this rule because it is very strict. Catching anything is useful
1185 | # and common even if not always the most correct thing to do.
1186 | #
1187 | # - avoid_catches_without_on_clauses
1188 |
1189 | # Adding the type is not required, but sometimes improves readability. Therefore removing it doesn't always help
1190 | # - avoid_types_on_closure_parameters
1191 |
1192 | # False positives, not reliable enough
1193 | # - https://github.com/dart-lang/linter/issues/1381
1194 | #
1195 | #
1196 | # - close_sinks
1197 |
1198 | # Still experimental and pretty much work when enforced
1199 | # - diagnostic_describe_all_properties
1200 |
1201 | # String.fromEnvironment looks up env variables at compile time. The variable is baked in by the compiler
1202 | # and can't be changed by environment variables.
1203 | #
1204 | # For dart apps:
1205 | # Better look up an environment variable at runtime with Platform.environment
1206 | # or use code generation to define variables at compile time.
1207 | #
1208 | # For Flutter apps:
1209 | # String.fromEnvironment is the recommended way to include variables defined with `flutter build --dart-define`
1210 | #
1211 | #
1212 | # Dart SDK: >= 2.10.0-0.0.dev • (Linter v0.1.117)
1213 | # - do_not_use_environment
1214 |
1215 | # Single line methods + implementation makes it hard to write comments for that line.
1216 | # Dense code isn't necessarily better code.
1217 | #
1218 | # - prefer_expression_function_bodies
1219 |
1220 | # While prefer_final_fields and prefer_final_locals is enabled, this lint would add a lot of clutter to methods,
1221 | # especially lambdas.
1222 | # parameter_assignments is already enabled, catching this error
1223 | # Conflicts with avoid_final_parameters
1224 | #
1225 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0)
1226 | #
1227 | # - prefer_final_parameters
1228 |
1229 | # Dense code isn't necessarily better code
1230 | #
1231 | # - prefer_foreach
1232 |
1233 | # Users of a 3rd party mixins can't change 3rd party code to use the mixin syntax.
1234 | # This makes the rule useless
1235 | # - prefer_mixin
1236 |
1237 | # Use whatever makes you happy. lint doesn't define a style
1238 | # Conflicts with prefer_single_quotes
1239 | #
1240 | # - prefer_double_quotes
1241 |
1242 | # Disabled because `final` prevents accidental reassignment
1243 | # - unnecessary_final
1244 |
1245 | # - prefer_relative_imports
1246 |
1247 | # - always_put_control_body_on_new_line
1248 |
1249 | # - always_specify_types
1250 |
1251 | # Can usually be replaced with an extension
1252 | # => Yes, but sometimes static classes are okay...
1253 | #
1254 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31)
1255 | #
1256 | # - avoid_classes_with_only_static_members
1257 |
1258 | # Don't break value types by implementing them
1259 | # - avoid_implementing_value_types
1260 |
1261 | # unnecessary_null_aware_operator_on_extension_on_nullable
1262 |
1263 | # use_string_in_part_of_directives
--------------------------------------------------------------------------------