CI: release on tag with Github Actions
This commit is contained in:
parent
0577e954b8
commit
3b31439c2e
8 changed files with 198 additions and 51 deletions
56
.github/workflows/main.yml
vendored
Normal file
56
.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
name: Release an APK and an App Bundle on tagging
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and release artifacts.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11.x'
|
||||
|
||||
- uses: subosito/flutter-action@v1
|
||||
with:
|
||||
channel: 'stable'
|
||||
|
||||
- name: Clone the repository.
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get packages for the Flutter project.
|
||||
run: flutter pub get
|
||||
|
||||
- name: Update the flutter version file.
|
||||
working-directory: ${{ github.workspace }}/scripts
|
||||
run: ./update_flutter_version.sh
|
||||
|
||||
- name: Run the unit tests.
|
||||
run: flutter test
|
||||
|
||||
- name: Build signed artifacts.
|
||||
# `KEY_JKS` should contain the result of:
|
||||
# gpg -c --armor keystore.jks
|
||||
# `KEY_JKS_PASSPHRASE` should contain the passphrase used for the command above
|
||||
run: |
|
||||
echo "${{ secrets.KEY_JKS }}" > release.keystore.asc
|
||||
gpg -d --passphrase "${{ secrets.KEY_JKS_PASSPHRASE }}" --batch release.keystore.asc > $AVES_STORE_FILE
|
||||
rm release.keystore.asc
|
||||
flutter build apk
|
||||
flutter build appbundle
|
||||
rm $AVES_STORE_FILE
|
||||
env:
|
||||
AVES_STORE_FILE: ${{ github.workspace }}/key.jks
|
||||
AVES_STORE_PASSWORD: ${{ secrets.AVES_STORE_PASSWORD }}
|
||||
AVES_KEY_ALIAS: ${{ secrets.AVES_KEY_ALIAS }}
|
||||
AVES_KEY_PASSWORD: ${{ secrets.AVES_KEY_PASSWORD }}
|
||||
AVES_GOOGLE_API_KEY: ${{ secrets.AVES_GOOGLE_API_KEY }}
|
||||
|
||||
- name: Create a release with the APK and App Bundle.
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "build/app/outputs/apk/release/*.apk,build/app/outputs/bundle/release/*.aab"
|
||||
token: ${{ secrets.RELEASE_WORKFLOW_TOKEN }}
|
|
@ -27,7 +27,17 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
|||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
// for release using credentials stored in a local file
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
} else {
|
||||
// for release using credentials in environment variables set up by Github Actions
|
||||
// warning: in property file, single quotes should be escaped with a backslash
|
||||
// but they should not be escaped when stored in env variables
|
||||
keystoreProperties['storeFile'] = System.getenv('AVES_STORE_FILE')
|
||||
keystoreProperties['storePassword'] = System.getenv('AVES_STORE_PASSWORD')
|
||||
keystoreProperties['keyAlias'] = System.getenv('AVES_KEY_ALIAS')
|
||||
keystoreProperties['keyPassword'] = System.getenv('AVES_KEY_PASSWORD')
|
||||
keystoreProperties['googleApiKey'] = System.getenv('AVES_GOOGLE_API_KEY')
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
10
lib/flutter_version.dart
Normal file
10
lib/flutter_version.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
// run `scripts/update_flutter_version.sh` to update with the content of `flutter --version --machine`
|
||||
const Map<String, String> version = {
|
||||
'channel': 'unknown',
|
||||
'dartSdkVersion': 'unknown',
|
||||
'engineRevision': 'unknown',
|
||||
'frameworkCommitDate': 'unknown',
|
||||
'frameworkRevision': 'unknown',
|
||||
'frameworkVersion': 'unknown',
|
||||
'repositoryUrl': 'unknown',
|
||||
};
|
|
@ -1,7 +1,10 @@
|
|||
import 'package:aves/flutter_version.dart';
|
||||
import 'package:aves/widgets/about/licenses.dart';
|
||||
import 'package:aves/widgets/common/aves_logo.dart';
|
||||
import 'package:aves/widgets/common/link_chip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
class AboutPage extends StatelessWidget {
|
||||
@override
|
||||
|
@ -19,31 +22,8 @@ class AboutPage extends StatelessWidget {
|
|||
sliver: SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
const TextSpan(text: 'Made with ❤️ and '),
|
||||
WidgetSpan(
|
||||
child: FlutterLogo(
|
||||
size: Theme.of(context).textTheme.bodyText2.fontSize * 1.25,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const LinkChip(
|
||||
text: 'Sources',
|
||||
url: 'https://github.com/deckerst/aves',
|
||||
textStyle: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
AppReference(),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
|
@ -57,3 +37,71 @@ class AboutPage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppReference extends StatefulWidget {
|
||||
@override
|
||||
_AppReferenceState createState() => _AppReferenceState();
|
||||
}
|
||||
|
||||
class _AppReferenceState extends State<AppReference> {
|
||||
Future<PackageInfo> packageInfoLoader;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
packageInfoLoader = PackageInfo.fromPlatform();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
_buildAvesLine(),
|
||||
_buildFlutterLine(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvesLine() {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final style = textTheme.headline6.copyWith(fontWeight: FontWeight.bold);
|
||||
|
||||
return FutureBuilder<PackageInfo>(
|
||||
future: packageInfoLoader,
|
||||
builder: (context, snapshot) {
|
||||
return LinkChip(
|
||||
leading: AvesLogo(
|
||||
size: style.fontSize * 1.25,
|
||||
),
|
||||
text: 'Aves ${snapshot.data?.version}',
|
||||
url: 'https://github.com/deckerst/aves',
|
||||
textStyle: style,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFlutterLine() {
|
||||
final style = DefaultTextStyle.of(context).style;
|
||||
final subColor = style.color.withOpacity(.6);
|
||||
|
||||
return Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4),
|
||||
child: FlutterLogo(
|
||||
size: style.fontSize * 1.25,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(text: 'Flutter ${version['frameworkVersion']}'),
|
||||
],
|
||||
),
|
||||
style: TextStyle(color: subColor),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class LinkChip extends StatelessWidget {
|
||||
final Widget leading;
|
||||
final String text;
|
||||
final String url;
|
||||
final Color color;
|
||||
|
@ -12,6 +13,7 @@ class LinkChip extends StatelessWidget {
|
|||
|
||||
const LinkChip({
|
||||
Key key,
|
||||
this.leading,
|
||||
@required this.text,
|
||||
@required this.url,
|
||||
this.color,
|
||||
|
@ -20,32 +22,35 @@ class LinkChip extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveTextStyle = (textStyle ?? DefaultTextStyle.of(context).style).copyWith(
|
||||
color: color,
|
||||
);
|
||||
return InkWell(
|
||||
borderRadius: borderRadius,
|
||||
onTap: () async {
|
||||
if (await canLaunch(url)) {
|
||||
await launch(url);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
text,
|
||||
style: effectiveTextStyle,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
AIcons.openInNew,
|
||||
size: Theme.of(context).textTheme.bodyText2.fontSize,
|
||||
color: color,
|
||||
)
|
||||
],
|
||||
return DefaultTextStyle.merge(
|
||||
style: (textStyle ?? const TextStyle()).copyWith(color: color),
|
||||
child: InkWell(
|
||||
borderRadius: borderRadius,
|
||||
onTap: () async {
|
||||
if (await canLaunch(url)) {
|
||||
await launch(url);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (leading != null) ...[
|
||||
leading,
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Text(text),
|
||||
const SizedBox(width: 8),
|
||||
Builder(
|
||||
builder: (context) => Icon(
|
||||
AIcons.openInNew,
|
||||
size: DefaultTextStyle.of(context).style.fontSize,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -260,6 +260,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
package_info:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.1"
|
||||
palette_generator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -57,6 +57,7 @@ dependencies:
|
|||
google_maps_flutter:
|
||||
intl:
|
||||
outline_material_icons:
|
||||
package_info:
|
||||
palette_generator:
|
||||
pdf:
|
||||
pedantic:
|
||||
|
|
10
scripts/update_flutter_version.sh
Executable file
10
scripts/update_flutter_version.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
FILE_PATH="../lib/flutter_version.dart"
|
||||
rm "$FILE_PATH"
|
||||
echo "Updating flutter_version.dart:"
|
||||
{
|
||||
echo "const Map<String, String> version = "
|
||||
flutter --version --machine
|
||||
echo ";"
|
||||
} >> "$FILE_PATH"
|
||||
cat "$FILE_PATH"
|
Loading…
Reference in a new issue