Skip to content

Commit

Permalink
Merge pull request #41 from wednesday-solutions/mason
Browse files Browse the repository at this point in the history
Add support for mason and create destinations template
  • Loading branch information
shounak-mulay authored Mar 22, 2023
2 parents 960ca62 + 2af39c5 commit a260c12
Show file tree
Hide file tree
Showing 57 changed files with 524 additions and 86 deletions.
4 changes: 4 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OPEN_WEATHER_API_KEY=YOUR_API_KEY
OPEN_WEATHER_BASE_URL=https://api.openweathermap.org/
USE_GOOGLE_FONTS=false
RENDER_FONTS_IN_TEST=false
8 changes: 5 additions & 3 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
# Replace with your Personal Access Tokens
with:
token: ${{ secrets.SHOUNAK_GITHUB_TOKEN }}

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.qa
env:
Expand Down Expand Up @@ -87,13 +88,14 @@ jobs:
name: Release iOS to TestFlight
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
token: ${{ secrets.SHOUNAK_GITHUB_TOKEN }}

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.qa
env:
Expand Down Expand Up @@ -153,7 +155,7 @@ jobs:
always() &&
(needs.build-android.result == 'success' || needs.build-ios.result == 'success')
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
# Replace with your Personal Access Token
with:
token: ${{ secrets.SHOUNAK_GITHUB_TOKEN }}
Expand Down
94 changes: 88 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
name: CI
on:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint-test:
name: Lint and Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.dev
env:
Expand All @@ -33,18 +39,25 @@ jobs:
run: derry format

- name: Unit tests
run: derry test exclude-goldens
run: derry test exclude-goldens -- --coverage-path=coverage/lcov.base.info --coverage

- uses: actions/upload-artifact@v3
with:
name: base-coverage-${{ github.event.number }}
path: coverage
retention-days: 7

build-android:
name: Build Android
runs-on: ubuntu-latest
needs: [ lint-test ]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.dev
env:
Expand All @@ -69,11 +82,12 @@ jobs:
runs-on: macos-latest
needs: [ lint-test ]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.dev
env:
Expand All @@ -89,8 +103,76 @@ jobs:
- name: Run build_runner
run: derry build_runner

- uses: actions/download-artifact@v3
with:
name: base-coverage-${{ github.event.number }}
path: coverage

- name: Setup lcov
run: brew install lcov

- name: Golden tests
run: derry test goldens
run: derry test goldens -- --merge-coverage --coverage

- uses: actions/upload-artifact@v3
with:
name: coverage-${{ github.event.number }}
path: coverage
retention-days: 7

- name: Build iOS
run: derry build ios dev
run: derry build ios dev

build-web:
name: Build Web
runs-on: ubuntu-latest
needs: [ lint-test ]
steps:
- uses: actions/checkout@v3

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup .env.dev
env:
ENV_FILE: ${{ secrets.ENV_DEV }}
run: echo -n $ENV_FILE | base64 --decode > .env.dev

- name: Activate derry
run: flutter pub global activate derry

- name: Get Dependencies
run: flutter pub get

- name: Run build_runner
run: derry build_runner

- name: Build Web
run: derry build web dev

sonar-scan:
name: SonarQube Scan
runs-on: ubuntu-latest
needs: [build-android,build-ios,build-web]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- uses: actions/download-artifact@v3
with:
name: coverage-${{ github.event.number }}
path: coverage
- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
# If you wish to fail your job when the Quality Gate is red, uncomment the
# following lines. This would typically be used to fail a deployment.
# We do not recommend to use this in a pull request. Prefer using pull request
# decoration instead.
# - uses: sonarsource/sonarqube-quality-gate-action@master
# timeout-minutes: 5
# env:
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
17 changes: 10 additions & 7 deletions .github/workflows/update_goldens.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true

- name: Setup app_secrets.dart
- name: Setup .env.dev
env:
APP_SECRETS: ${{ secrets.APP_SECRETS }}
APP_SECRETS_PATH: lib/secrets/app_secrets.dart
run: echo -n $APP_SECRETS | base64 --decode > $APP_SECRETS_PATH
ENV_FILE: ${{ secrets.ENV_DEV }}
run: echo -n $ENV_FILE | base64 --decode > .env.dev

- name: Activate derry
run: flutter pub global activate derry

- name: Get Dependencies
run: flutter pub get

- name: Run build_runner
run: flutter pub run build_runner build
run: derry build_runner

- name: Generate Goldens
run: flutter test --tags=golden test/presentation/goldens --update-goldens
run: derry test update-goldens

- name: Configure Git
run: |
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
/build/

# Web related
lib/generated_plugin_registrant.dart

# Symbolication related
app.*.symbols
Expand Down Expand Up @@ -71,3 +70,7 @@ app.*.map.json
# Secrets
lib/secrets/
!lib/secrets/app_secrets.skeleton.dart

.mason

.scannerwork
53 changes: 51 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@


<img align="left" src="flutter_template_github.svg" width="480" height="440" />

<div>
Expand Down Expand Up @@ -194,6 +195,40 @@ Each widget the requires access to data from the view model it split into two da
### Screen
A [`Screen`](lib/presentation/entity/screen/screen.dart) is a class that represents a `Page` in the context of navigation. It holds the `path` used by the navigator to navigate to a `Page` and also holds any arguments required to navigate to that `Page`.

## Templating
As you can read from the [Architecture](#architecture) section, adding a new page in the app can require a lot of files to be created. The template uses [`mason`](https://pub.dev/packages/mason_cli) as it's templating engine to automate some of this work.

To get started with mason, first activate mason globally
```bash
dart pub global activate mason_cli
```

Similar to using `pub get` we need to run `mason get` to setup the `bricks` (templates are called brick in mason).
```bash
mason get
```
You can learn more about `mason` [here](https://docs.brickhub.dev/).

#### Destination Brick
The template comes with a pre setup brick called `destination`.
Run the `destination` brick using the following command.
```bash
mason make destination -o lib/presentation/destinations/notes --name notesList
```
`-o` flag sets the output directory for the `brick` and `--name` is the name used for the files and classes. This brick generates the required file structure and runs `build_runner` (via mason hooks) to trigger code generation. After running the command, this is what you should see:

<img width="408" alt="Screenshot 2023-03-21 at 2 55 45 PM" src="https://user-images.githubusercontent.com/58199625/226564828-3172bc70-5324-486c-a31d-6ce7f19aa8bb.png">

## Testing

The template also includes a testing setup for
- [`Unit Tests`](test/repository).
- [`Widget Tests`](test/presentation/integration)
- [`Golden Tests`](test/presentation/goldens)

The test coverage and code quality reporting is done using [`sonarqube`](https://docs.sonarqube.org/latest/).
You can read the documentation about integrating `sonarqube` in you CI workflow [here](https://docs.sonarqube.org/latest/devops-platform-integration/github-integration/#analyzing-projects-with-github-actions).

## Content
The Flutter Template contains:
- A [`Flutter`](https://flutter.dev/) application.
Expand All @@ -205,7 +240,9 @@ The Flutter Template contains:
- [`Freezed`](https://pub.dev/packages/freezed) for data class functionality.
- [`Get It`](https://pub.dev/packages/get_it) for dependency injection.
- [`Flutter Lints`](https://pub.dev/packages/flutter_lints) for linting.
- [`derry`](https://pub.dev/packages/derry) for script management
- [`derry`](https://pub.dev/packages/derry) for script management.
- [`mason`](https://pub.dev/packages/mason_cli) for templating.
- [`sonarqube`](https://docs.sonarqube.org/latest/) for code inspection.

The template contains an example (displaying weather data) with responsive widgets, reactive state management, offline storage and api calls.

Expand All @@ -217,9 +254,13 @@ The [`CI`](.github/workflows/ci.yml) workflow performs the following checks on e
- Lints the code with `flutter analyze`.
- Check formatting with `dart format`
- Runs tests using `flutter test`.
- Run golden test.
- Report code coverage and code quality using `sonarqube`.
- Build the android app.
- Build the ios app.

You can read the documentation about integrating `sonarqube` in you CI workflow [here](https://docs.sonarqube.org/latest/devops-platform-integration/github-integration/#analyzing-projects-with-github-actions).

### CD
The [`CD`](.github/workflows/cd.yml) workflow performs the following actions:
- Bump the build number by 1.
Expand Down Expand Up @@ -336,7 +377,15 @@ openssl base64 < FILENAME | tr -d '\n' | tee ENCODED_FILENAME.txt
**If you do not plan to use the CD workflow on protected branches, you can remove the token part from the checkout actions.**

## Gotchas
- Flutter apps might have issues on some android devices with variable refresh rate where the app is locked at 60fps instead of running at the highest refresh rate. This might make your app look like it is running slower than other apps on the device. To fix this the template uses the [`flutter_displaymode`](https://pub.dev/packages/flutter_displaymode) package. The template sets the highest refresh rate available. If you don't want this behaviour you can remove the lines 40 to 46 in [`app.dart`](lib/app.dart#L40). [`Link to frame rate issue on flutter`](https://github.com/flutter/flutter/issues/35162).

#### Refresh Rate
Flutter apps might have issues on some android devices with variable refresh rate where the app is locked at 60fps instead of running at the highest refresh rate. This might make your app look like it is running slower than other apps on the device. To fix this the template uses the [`flutter_displaymode`](https://pub.dev/packages/flutter_displaymode) package. The template sets the highest refresh rate available. If you don't want this behaviour you can remove the lines 40 to 46 in [`app.dart`](lib/app.dart#L40). [`Link to frame rate issue on flutter`](https://github.com/flutter/flutter/issues/35162).

#### Golden Tests
Golden test screenshots (goldens) are rendered using the rendering mechanisms on the os that you are running the tests on. Because of the slight differences in each os, the goldens generated on each os differ slightly from each other. Goldens generated on macos won't match exactly to the goldens generated on windows or linux and your tests will fail.
To work around this, make sure to generate goldens and run golden tests on a single os. This template uses macos as it's os of choice to deal with goldens. You will find that on [CI](.github/workflows/ci.yml), the golden tests are run on a macos host.

- `What if your team members use different operating systems for development?` - In that case, the devs not using your os of choice should have a way to generate goldens on your os of choice. This template has a [`update_goldens`](.github/workflows/update_goldens.yml) workflow that can be manually triggered on any branch. It will generate the golden files on macos and commit the changes to the same branch.

## License
Flutter Template is licensed under the MIT license. Check the [LICENSE](LICENSE) file for details.
Expand Down
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ analyzer:
- "**.gr.dart"
- "**/translation_keys.dart"
- "**/translation_loader.dart"
- "bricks/**"
3 changes: 3 additions & 0 deletions bricks/destination/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 0.1.0+1

- TODO: Describe initial release.
1 change: 1 addition & 0 deletions bricks/destination/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Add your license here.
27 changes: 27 additions & 0 deletions bricks/destination/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# destination

[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason)

A new brick created with the Mason CLI.

_Generated by [mason][1] 🧱_

## Getting Started 🚀

This is a starting point for a new brick.
A few resources to get you started if this is your first brick template:

- [Official Mason Documentation][2]
- [Code generation with Mason Blog][3]
- [Very Good Livestream: Felix Angelov Demos Mason][4]
- [Flutter Package of the Week: Mason][5]
- [Observable Flutter: Building a Mason brick][6]
- [Meet Mason: Flutter Vikings 2022][7]

[1]: https://github.com/felangel/mason
[2]: https://docs.brickhub.dev
[3]: https://verygood.ventures/blog/code-generation-with-mason
[4]: https://youtu.be/G4PTjA6tpTU
[5]: https://youtu.be/qjA0JFiPMnQ
[6]: https://youtu.be/o8B1EfcUisw
[7]: https://youtu.be/LXhgiF5HiQg
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class {{name.pascalCase()}}PageBody extends ConsumerWidget {
const {{name.pascalCase()}}PageBody({
super.key,
});

@override
Widget build(BuildContext context, WidgetRef ref) {
final {{name.camelCase()}}ViewModel = ref.watch({{name.camelCase()}}ViewModelProvider.notifier);

return {{name.pascalCase()}}PageBodyContent();
}
}
Loading

0 comments on commit a260c12

Please sign in to comment.