From df44682489a08fb64d0211e0667d2cd4ba98c767 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 18:32:10 +0100 Subject: [PATCH 01/15] build(deps): add commitlint_cli and jusky packages --- pubspec.lock | 68 +++++++++++++++++++++++++++++++++++++++++----------- pubspec.yaml | 2 ++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 2b6f1fe..9b6cbf7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + ansi: + dependency: transitive + description: + name: ansi + sha256: "070af96189f9da6f996cee46049682bdcd1d191b483e13f9d2a2600729d8b2a1" + url: "https://pub.dev" + source: hosted + version: "0.4.2" ansicolor: dependency: transitive description: @@ -97,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + change_case: + dependency: transitive + description: + name: change_case + sha256: f4e08feaa845e75e4f5ad2b0e15f24813d7ea6c27e7b78252f0c17f752cf1157 + url: "https://pub.dev" + source: hosted + version: "1.1.0" characters: dependency: transitive description: @@ -137,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + commitlint_cli: + dependency: "direct dev" + description: + name: commitlint_cli + sha256: "59921b80b415b81cabbbcf7e18a99aacd3a13eafbb040a19f8804ef4473fd7af" + url: "https://pub.dev" + source: hosted + version: "0.7.1" connectivity_plus: dependency: "direct main" description: @@ -432,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + husky: + dependency: "direct dev" + description: + name: husky + sha256: ce4a92b311c03e67ff66b6e354c8d5b8ee7c663ccaedb954e93798658b439bb2 + url: "https://pub.dev" + source: hosted + version: "0.1.7" image: dependency: transitive description: @@ -476,26 +508,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: @@ -524,18 +556,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: @@ -889,10 +921,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" top_snackbar_flutter: dependency: "direct main" description: @@ -989,6 +1021,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + verbose: + dependency: transitive + description: + name: verbose + sha256: "8e63580e35d58a15e4fca702fe91766430b1d28738c160c466e5cb10c373002a" + url: "https://pub.dev" + source: hosted + version: "0.1.1" vibration: dependency: "direct main" description: @@ -1009,10 +1049,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.5" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c634421..39221ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,8 @@ dev_dependencies: sdk: flutter flutter_lints: ^3.0.0 + commitlint_cli: ^0.7.1 + husky: ^0.1.7 flutter_native_splash: color: "#1A202C" From e795e2cbfc7e19ad5cd873bc1d617d137975981c Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 18:32:54 +0100 Subject: [PATCH 02/15] build: add commit message hook to lint commit messages --- .github/pull_request_template.md | 23 +++++++++++++ .github/workflows/release.yml | 58 ++++++++++++++++++++++++++++++++ .husky/commit-msg | 4 +++ commitlint.yaml | 1 + 4 files changed, 86 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/release.yml create mode 100755 .husky/commit-msg create mode 100644 commitlint.yaml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..c978ac4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,23 @@ + + +# Description + + +# Type of change + + +- [ ] πŸ’₯ Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] πŸ—οΈ Build configuration (CI configuration, scaffolding etc.) +- [ ] πŸ› Bug fix (non-breaking change which fixes an issue) +- [ ] πŸ“ Documentation update(s) +- [ ] πŸ“¦ Dependency update(s) +- [ ] πŸ‘©πŸ½β€πŸ’» Improve developer experience +- [ ] ⚑ Improve performance +- [ ] ✨ New feature (non-breaking change which adds functionality) +- [ ] β™» Refactor +- [ ] βͺ Revert changes +- [ ] πŸ§ͺ New tests or updates to existing tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..840433c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,58 @@ +name: "Release" + +on: + push: + branches: + - beta + - main + +jobs: + ## + # install + ## + + install: + name: "Install" + runs-on: ubuntu-latest + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + + ## + # release + ## + + release: + name: "Release" + needs: [install] + permissions: + contents: write # to be able to publish a github release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + runs-on: ubuntu-latest + environment: production + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ“¦ Install yq" + uses: ./.github/actions/install-yq + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + - name: "πŸ“ Create .env file" + uses: ./.github/actions/create-env-file + with: + posthog_api_host: ${{ secrets.POSTHOG_API_HOST }} + posthog_project_id: ${{ secrets.POSTHOG_PROJECT_ID }} + provider_id: ${{ vars.PROVIDER_ID }} + - name: "πŸ”– Release" + env: + # appears on the release commits + GIT_AUTHOR_NAME: agoralabs-bot + GIT_AUTHOR_EMAIL: tech@agoralabs.sh + GIT_COMMITTER_NAME: agoralabs-bot + GIT_COMMITTER_EMAIL: tech@agoralabs.sh + # used to push the release commit and create the tags + GITHUB_TOKEN: ${{ secrets.WRITE_REPOS_TOKEN }} + run: yarn semantic-release diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..48ebb93 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +dart run commitlint_cli --edit "$1" diff --git a/commitlint.yaml b/commitlint.yaml new file mode 100644 index 0000000..d087610 --- /dev/null +++ b/commitlint.yaml @@ -0,0 +1 @@ +include: package:commitlint_cli/commitlint.yaml From 984b271ad8ad55e560e40532844baa7df307c93f Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 19:00:06 +0100 Subject: [PATCH 03/15] ci: add pull request workflow --- .github/actions/use-dependencies/action.yml | 19 ++++++ .github/workflows/pull_request_checks.yml | 65 +++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 .github/actions/use-dependencies/action.yml create mode 100644 .github/workflows/pull_request_checks.yml diff --git a/.github/actions/use-dependencies/action.yml b/.github/actions/use-dependencies/action.yml new file mode 100644 index 0000000..98682c9 --- /dev/null +++ b/.github/actions/use-dependencies/action.yml @@ -0,0 +1,19 @@ +name: "Use Flutter Dependencies" + +description: "Installs the Flutter SDK and a project dependencies with caching." + +runs: + using: "composite" + steps: + - name: "πŸ”§ Setup" + uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + pub-cache-key: "flutter-pub:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache of dart pub get dependencies + pub-cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + - name: "πŸ“¦ Install" + run: flutter pub get + shell: bash diff --git a/.github/workflows/pull_request_checks.yml b/.github/workflows/pull_request_checks.yml new file mode 100644 index 0000000..7852ec6 --- /dev/null +++ b/.github/workflows/pull_request_checks.yml @@ -0,0 +1,65 @@ +name: "Pull Request Checks" + +on: + pull_request: + +jobs: + ## + # install + ## + + install: + name: "Install" + runs-on: ubuntu-latest + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + + ## + # validatation + ## + + validate_pr_title: + name: "Validate PR Title" + runs-on: ubuntu-latest + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + - name: "βœ… Validate" + run: echo ${{ github.event.pull_request.title }} | dart run commitlint_cli + + ## + # build + ## + + build_android: + name: "Build Android" + needs: [validate_pr_title] + runs-on: ubuntu-latest + environment: development + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + - name: "πŸ—οΈ Build APK" + run: flutter build apk + - name: "πŸ—οΈ Build AppBundle" + run: flutter build appbundle + + build_ios: + name: "Build iOS" + needs: [validate_pr_title] + runs-on: macos-latest + environment: development + steps: + - name: "πŸ›Ž Checkout" + uses: actions/checkout@v4 + - name: "πŸ”§ Setup" + uses: ./.github/actions/use-dependencies + - name: "πŸ—οΈ Build ios" + run: flutter build ios --release --no-codesign From 2de2a3b6f6d54860a82229cb7abe278048ce4fd4 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 19:01:42 +0100 Subject: [PATCH 04/15] docs: add contributing guide --- CONTRIBUTING.md | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8e91d80 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,178 @@ +# Contributing guide + +### Table of contents + +* [1. Commit messages](#1-commit-messages) + * [1.1. Type](#11-type) + * [1.2. Scope](#12-scope) + * [1.3. Subject](#13-subject) +* [2. Pull requests](#2-pull-requests) +* [3. Pre-releases](#3-pre-releases) + * [3.1. Working on a future release](#31-working-on-a-future-release) + * [3.2. Releasing a bug fix on the default distribution channel](#32-releasing-a-bug-fix-on-the-default-distribution-channel) + * [3.3. Publishing beta release to the default distribution channel](#33-publishing-beta-release-to-the-default-distribution-channel) + * [3.4. Working on a new future release](#34-working-on-a-new-future-release) + +## 1. Commit messages + +Commit messages lean heavily towards the convention set out by [conventional commits](https://www.conventionalcommits.org). + +Each commit message must be in the format that includes a **type**, an optional **scope** and a **subject**: +``` +type(scope?): subject #scope is optional +``` + +Limit the whole message to 72 characters or less! + +Example: + +``` +build(terraform): burn it all down +``` + +### 1.1. Type + +Must be one of the following: + +* **build**: Changes that affect the build system or external dependencies (example scopes: npm) +* **chore**: Changes that don't really fall under any other type +* **ci**: Changes to the CI configuration files and scripts +* **docs**: Documentation only changes +* **feat**: A new feature +* **fix**: A bug fix +* **perf**: A code change that improves performance +* **refactor**: A code change that neither fixes a bug nor adds a feature +* **revert**: Revert a previous commit +* **test**: Adding missing tests or correcting existing tests + +### 1.2. Scope + +A scope may be provided to a commit’s type, to provide additional contextual information and is contained within a parenthesis + +### 1.3. Subject + +The subject contains a succinct description of the change: + +* use the present tense ("Add feature" not "Added feature") +* use the imperative mood ("Move cursor to..." not "Moves cursor to...") +* don't capitalise the first letter +* don't use a fullstop (.) at the end. <- Not this + +[Back to top ^](#table-of-contents) + +## 2. Pull requests + +1. Create a branch from the `main` branch and use the convention: `/name-of-issue`. +2. Once the code is ready to be merged into `main`, open a pull request. +> ⚠️**NOTE:** The title must conform to the conventional commit message format outlined above. This is to ensure the merge commit to the main branch is picked up by the CI and creates an entry in the [CHANGELOG.md](./CHANGELOG.md). +3. To merge the PR, use the "Squash and merge" option. This is to keep the commit history clean and keep the commits on `main` with a 1:1 ratio with previous PRs. + +[Back to top ^](#table-of-contents) + +## 3. Pre-releases + +### 3.1. Working on a future release + +We now decide to work on a future major release, which will be composed of multiple features, some of them being breaking changes. We want to publish our package for each new feature developed for test purpose, however we do not want to increment our package version or make it available until all the features are developed and tested. + +To implement that workflow we can commit our first feature to the `beta` branch. When pushing that commit, **semantic-release** will publish the pre-release version `2.0.0-beta.1` on the dist-tag `@beta`. That allow us to install our module with `yarn add example-module@beta`. Others installing with `yarn add example-module` will still receive the version `1.0.0`. + +The Git history of the repository is now: + +``` +* feat: initial commit # => v1.0.0 on @latest +| \ +| * feat: first feature \n\n BREAKING CHANGE: it breaks something # => v2.0.0-beta.1 on @beta +``` + +We can continue to work on our future release by committing and pushing other features or bug fixes on the `beta` branch. With each push, **semantic-release** will publish a new pre-release on the dist-tag `@beta`. + +With another feature, the Git history of the repository is now: + +``` +* feat: initial commit # => v1.0.0 on @latest +| \ +| * feat: first feature \n\n BREAKING CHANGE: it breaks something # => v2.0.0-beta.1 on @beta +| * feat: second feature # => v2.0.0-beta.2 on @beta +``` + +[Back to top ^](#table-of-contents) + +## 3.2. Releasing a bug fix on the default distribution channel + +In the meantime we can also continue to commit changes and release updates to `1.0.0`. + +For example, we can commit a bug fix with the message `fix: a fix` to `main`. When pushing that commit, **semantic-release** will release the version `1.0.1` on the dist-tag `@latest`. + +The Git history of the repository is now: + +``` +* feat: initial commit # => v1.0.0 on @latest +| \ +| * feat: first feature \n\n BREAKING CHANGE: it breaks something # => v2.0.0-beta.1 on @beta +| * feat: second feature # => v2.0.0-beta.2 on @beta +| fix: a fix # => v1.0.1 on @latest +``` + +[Back to top ^](#table-of-contents) + +## 3.3. Publishing beta release to the default distribution channel + +Once we've developed and pushed all the features & fixes we want to include in the future version `2.0.0` in the `beta` branch, we can release it to the default distribution channel, or `@latest`. + +1. First, merge into `beta` any bug fixes: +```shell +git merge origin/main --ff-only +``` + +2. Next, checkout the `main` branch and pull the latest: +```shell +git checkout main +git pull +``` +3. Now, we want the `main` branch to mirror the commit history of `beta`, so we want to use Git's fast-forward option; so we use: +```shell +git merge origin/beta --ff-only +``` +> ⚠️**NOTE:** As `beta` and `main` branches may have diverged, this merge might require to resolve conflicts. + +Once beta branch has been rebased on to `main`, **semantic-release** will release the version `2.0.0` on the dist-tag `@latest`. + +The Git history of the repository is now: + +``` +* feat: initial commit # => v1.0.0 on @latest +| \ +| * feat: first feature \n\n BREAKING CHANGE: it breaks something # => v2.0.0-beta.1 on @beta +| * feat: second feature # => v2.0.0-beta.2 on @beta +| fix: a fix # => v1.0.1 on @latest +| / +| Merge branch beta into main # => v2.0.0 on @latest +``` + +[Back to top ^](#table-of-contents) + +## 3.4. Working on a new future release + +We can now start to work on a new future major release, version `3.0.0`, on the `@beta` distribution channel. + +To do so we first need to update the `beta` branch with all the changes from `main` (the commits `fix: a fix`). As `beta` and `main` branches have diverged, this merge might require to resolve conflicts. + +We can now commit our new feature on `beta`. When pushing that commit, **semantic-release** will publish the pre-release version `3.0.0-beta.1` on the dist-tag `@beta`. That allow us to run integration tests by installing our module with `yarn install example-module@beta`. Other users installing with `yarn install example-module` will still receive the version `3.0.0`. + +The Git history of the repository is now: + +``` +* feat: initial commit # => v1.0.0 on @latest +| \ +| * feat: first feature \n\n BREAKING CHANGE: it breaks something # => v2.0.0-beta.1 on @beta +| * feat: second feature # => v2.0.0-beta.2 on @beta +| fix: a fix # => v1.0.1 on @latest +| / +| Merge branch beta into main # => v2.0.0 on @latest +| \ +| | Merge branch main into beta +| | feat: new feature \n\n BREAKING CHANGE: it breaks another thing # => v3.0.0-beta.1 on @beta +``` + +[Back to top ^](#table-of-contents) From 73a44d62fe2941a2ad9fe528c1f1bbbd6e3133ac Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 19:41:39 +0100 Subject: [PATCH 05/15] chore: update gitignore --- .gitignore | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index db24dfc..4fd4e05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,161 @@ -# Miscellaneous +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Miscellaneous *.class *.log *.pyc *.swp -.DS_Store .atom/ .buildlog/ .history From 9086ae4a6dd16a7dc134763d4ccde601c330a311 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 19:42:34 +0100 Subject: [PATCH 06/15] ci: add release workflow that updates version in yaml --- .github/actions/install-yq/action.yml | 12 ++++++ .github/workflows/release.yml | 31 +++------------ .releaserc | 36 ++++++++++++++++++ pubspec.yaml | 14 +------ scripts/set_vars.sh | 7 ++++ scripts/update_version.sh | 55 +++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 .github/actions/install-yq/action.yml create mode 100644 .releaserc create mode 100755 scripts/set_vars.sh create mode 100755 scripts/update_version.sh diff --git a/.github/actions/install-yq/action.yml b/.github/actions/install-yq/action.yml new file mode 100644 index 0000000..6f54a17 --- /dev/null +++ b/.github/actions/install-yq/action.yml @@ -0,0 +1,12 @@ +name: "Install yq" + +description: "Downloads and installs yq" + +runs: + using: "composite" + steps: + - name: "πŸ“¦ Install yq" + run: | + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 840433c..7d61a17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,28 +7,10 @@ on: - main jobs: - ## - # install - ## - - install: - name: "Install" - runs-on: ubuntu-latest - steps: - - name: "πŸ›Ž Checkout" - uses: actions/checkout@v4 - - name: "πŸ”§ Setup" - uses: ./.github/actions/use-dependencies - - ## - # release - ## - release: name: "Release" - needs: [install] permissions: - contents: write # to be able to publish a github release + contents: write # to be able to publish a GitHub release issues: write # to be able to comment on released issues pull-requests: write # to be able to comment on released pull requests runs-on: ubuntu-latest @@ -39,13 +21,12 @@ jobs: - name: "πŸ“¦ Install yq" uses: ./.github/actions/install-yq - name: "πŸ”§ Setup" - uses: ./.github/actions/use-dependencies - - name: "πŸ“ Create .env file" - uses: ./.github/actions/create-env-file + uses: actions/setup-node@v4 with: - posthog_api_host: ${{ secrets.POSTHOG_API_HOST }} - posthog_project_id: ${{ secrets.POSTHOG_PROJECT_ID }} - provider_id: ${{ vars.PROVIDER_ID }} + node-version: 'lts/*' + - name: "πŸ“¦ Install" + run: | + yarn add semantic-release @semantic-release/{changelog,commit-analyzer,exec,git,github,release-notes-generator} - name: "πŸ”– Release" env: # appears on the release commits diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..9eab522 --- /dev/null +++ b/.releaserc @@ -0,0 +1,36 @@ +{ + "branches": [ + "main", + { + "name":"beta", + "prerelease": true + } + ], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/changelog", + [ + "@semantic-release/exec", + { + "prepareCmd": "./scripts/update_version.sh ${nextRelease.version}" + } + ], + [ + "@semantic-release/git", + { + "assets": [ + "CHANGELOG.md", + "pubspec.yaml" + ], + "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" + } + ], + [ + "@semantic-release/github", + { + "releasedLabels": ["πŸš€ released"] + } + ] + ] +} diff --git a/pubspec.yaml b/pubspec.yaml index 39221ec..5c54a08 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,11 +4,9 @@ publish_to: 'none' version: 0.2.0+3 environment: sdk: '>=3.3.1 <4.0.0' - dependencies: flutter: sdk: flutter - equatable: ^2.0.5 flutter_riverpod: ^2.3.6 go_router: ^13.2.2 @@ -40,25 +38,19 @@ dependencies: base32: ^2.1.3 connectivity_plus: ^6.0.5 flutter_expandable_fab: ^2.2.0 - dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^3.0.0 commitlint_cli: ^0.7.1 husky: ^0.1.7 - flutter_native_splash: color: "#1A202C" image: "assets/images/splash-logo.png" - android_12: # For Android 12 and later, the launcher icon will be used as the splash screen icon by default. image: "assets/images/splash-logo.png" color: "#1A202C" - - flutter_launcher_icons: android: "launcher_icon" ios: true @@ -76,23 +68,19 @@ flutter_launcher_icons: macos: generate: true image_path: "assets/icon/app_icon.png" - flutter: uses-material-design: true - assets: - assets/images/ - # fonts: # - family: Anonymous Pro # fonts: # - asset: assets/fonts/AnonymousPro-Regular.ttf # - asset: assets/fonts/AnonymousPro-Bold.ttf # weight: 700 - fonts: - family: SF Pro fonts: - asset: assets/fonts/SFPRODISPLAYREGULAR.OTF - asset: assets/fonts/SFPRODISPLAYBOLD.OTF - weight: 700 \ No newline at end of file + weight: 700 diff --git a/scripts/set_vars.sh b/scripts/set_vars.sh new file mode 100755 index 0000000..02f6ce8 --- /dev/null +++ b/scripts/set_vars.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +# Public: Convenience function that exports some common environment variables. +function set_vars() { + export ERROR_PREFIX='\033[0;31m[ERROR]\033[0m' + export INFO_PREFIX='\033[1;33m[INFO]\033[0m' +} diff --git a/scripts/update_version.sh b/scripts/update_version.sh new file mode 100755 index 0000000..d39b53e --- /dev/null +++ b/scripts/update_version.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$(dirname "${0}") + +source "${SCRIPT_DIR}/set_vars.sh" + +# Public: Updates the pubspec.yaml "version" with the release version. +# +# $1 - The version to bump. +# +# Examples +# +# ./scripts/update_version.sh "1.0.0" +# ./scripts/update_version.sh "1.2.0-beta.3" +# +# Returns exit code 0 if successful, or 1 if the semantic version is incorrectly formatted. +function main { + local build + + set_vars + + if [ -z "${1}" ]; then + printf "%b no version specified, use: ./scripts/update_version.sh [version] \n" "${ERROR_PREFIX}" + exit 1 + fi + + # check the input is in semantic version format + if [[ ! "${1}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then + printf "%b invalid semantic version, got '${1}', but should be in the format '1.0.0' \n" "${ERROR_PREFIX}" + exit 1 + fi + + # get the version without the pre-release + version=${1%-*} + + # if the input is a pre-release release, *-beta.xx is suffixed to the end of the semantic version + # and we want to use this as a build number + if [[ "${1}" =~ ^[0-9]+\.[0-9]+\.[0-9]-beta+ ]]; then + printf "%b pre-release version found \n" "${INFO_PREFIX}" + build="${1#*-beta.}" + fi + + # if there is a build number, add it to the version + if [[ -n "${build}" ]]; then + version="${version}+${build}" + fi + + printf "%b setting version '%s' to pubspec.yaml \n" "${INFO_PREFIX}" "${version}" + yq e ".version = \"${version}\"" -i "${PWD}/pubspec.yaml" + + exit 0 +} + +# and so, it begins... +main "$@" From 2c610ae61b44dd3e77c2fae8f24de7c8a0aa92cb Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Wed, 28 Aug 2024 21:41:32 +0100 Subject: [PATCH 07/15] feat: add nunito fints --- android/app/build.gradle | 2 +- assets/fonts/Nunito/Nunito-Bold.ttf | Bin 0 -> 132152 bytes assets/fonts/Nunito/Nunito-Regular.ttf | Bin 0 -> 132204 bytes assets/fonts/SFPRODISPLAYBOLD.OTF | Bin 334728 -> 0 bytes assets/fonts/SFPRODISPLAYREGULAR.OTF | Bin 298944 -> 0 bytes .../fonts/SFProDisplay/SFProDisplay-Bold.ttf | Bin 0 -> 435904 bytes .../SFProDisplay/SFProDisplay-Regular.ttf | Bin 0 -> 413924 bytes pubspec.lock | 6 +++--- pubspec.yaml | 17 +++++++++-------- 9 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 assets/fonts/Nunito/Nunito-Bold.ttf create mode 100644 assets/fonts/Nunito/Nunito-Regular.ttf delete mode 100644 assets/fonts/SFPRODISPLAYBOLD.OTF delete mode 100644 assets/fonts/SFPRODISPLAYREGULAR.OTF create mode 100644 assets/fonts/SFProDisplay/SFProDisplay-Bold.ttf create mode 100644 assets/fonts/SFProDisplay/SFProDisplay-Regular.ttf diff --git a/android/app/build.gradle b/android/app/build.gradle index 0430a81..623f1de 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,7 +51,7 @@ android { defaultConfig { applicationId "is.kibis.kibisis" - minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger() + minSdkVersion localProperties.getProperty('flutter.minSdkVersion') ? localProperties.getProperty('flutter.minSdkVersion').toInteger() : 29 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/assets/fonts/Nunito/Nunito-Bold.ttf b/assets/fonts/Nunito/Nunito-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..886134dcfa3c784be09217fe57bf3aac9f059bf2 GIT binary patch literal 132152 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