Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
leoafarias committed Sep 22, 2023
1 parent 2344bae commit af21aea
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 58 deletions.
7 changes: 0 additions & 7 deletions .github/actions/prepare/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@ runs:
run: dart pub get
shell: bash

- run: dart pub global activate grinder
shell: bash

- name: Build version
run: dart pub global run grinder:grinder build-version
shell: bash

- name: Analyze
run: dart analyze --fatal-infos --fatal-warnings .
shell: bash
21 changes: 14 additions & 7 deletions .github/actions/test/action.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
name: "Test Step"
description: "Tests the project"
name: "Run tests"
description: "Grind tasks for testing"

inputs:
with-coverage:
description: "Generate coverage reports"
required: false
default: "false"

runs:
using: "composite"
steps:
- name: Generate git cache
run: ./bin/fvm.dart install master
- name: Run tests
run: dart pub run grinder test
shell: bash

- name: Run tests
run: dart pub global run grinder:grinder test
shell: bash
- name: Generate coverage report
run: dart pub run grinder coverage
shell: bash
if: ${{ inputs.with-coverage == 'true' }}
9 changes: 5 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ jobs:
- name: Prepare environment
uses: ./.github/actions/prepare

- name: Deploy Chocolatey (Windows)
run: dart pub run grinder pkg-chocolatey-deploy

# - name: Deploy Chocolatey (Windows)
# run: dart pub run grinder pkg-chocolatey-deploy

deploy-homebrew:
name: Deploy Homebrew
Expand All @@ -61,8 +62,8 @@ jobs:
- name: Prepare environment
uses: ./.github/actions/prepare

- name: Deploy to Homebrew
run: dart pub run grinder pkg-homebrew-update
# - name: Deploy to Homebrew
# run: dart pub run grinder pkg-homebrew-update

deploy-docker:
name: Docker Deploy (latest)
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ concurrency:

jobs:
test:
name: Test
name: Run tests with coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -37,6 +37,8 @@ jobs:

- name: Run tests
uses: ./.github/actions/test
with:
with-coverage: 'true'

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
Expand Down
9 changes: 9 additions & 0 deletions lib/src/utils/console_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ void switchLineMode(bool active, List<String> args) {
return;
}
}

Future<bool> isCommandAvailable(String command) async {
try {
final result = await Process.run(command, ['--version']);
return result.exitCode == 0;
} catch (e) {
return false;
}
}
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ packages:
source: hosted
version: "1.6.3"
crypto:
dependency: transitive
dependency: "direct dev"
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
Expand Down Expand Up @@ -194,7 +194,7 @@ packages:
source: hosted
version: "0.9.4"
http:
dependency: transitive
dependency: "direct dev"
description:
name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ dev_dependencies:
grinder: ^0.9.4
test: ^1.24.4
lints: ^2.1.1
crypto: ^3.0.3
http: ^1.1.0

23 changes: 23 additions & 0 deletions tool/fvm.template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Fvm < Formula
desc "Flutter Version Management: A CLI to manage Flutter SDK versions"
homepage "https://github.com/leoafarias/fvm"
version "{{VERSION}}"

on_macos do
if Hardware::CPU.arm?
url "{{MACOS_ARM64_URL}}"
sha256 "{{MACOS_ARM64_SHA256}}"
else
url "{{MACOS_X64_URL}}"
sha256 "{{MACOS_X64_SHA256}}"
end
end

def install
bin.install "fvm"
end

test do
assert_match "FVM #{version}", shell_output("#{bin}/fvm --version").strip
end
end
67 changes: 30 additions & 37 deletions tool/grind.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,38 @@ import 'package:pub_semver/pub_semver.dart';
import 'package:pubspec2/pubspec2.dart';

import '../test/testing_helpers/prepare_test_environment.dart';
import 'homebrew.dart';

const _packageName = 'fvm';
const owner = 'leoafarias';
const repo = 'fvm';

void main(List<String> args) {
pkg.name.value = 'fvm';
pkg.humanName.value = 'fvm';
pkg.githubUser.value = 'fluttertools';
pkg.name.value = _packageName;
pkg.humanName.value = _packageName;
pkg.githubUser.value = owner;
pkg.homebrewRepo.value = 'leoafarias/homebrew-fvm';

pkg.addAllTasks();
addTask(homebrewTask());

grind(args);
}

@Task('Builds the version file')
// Allows to pass a version argument
// Example: grind build-version --version 3.0.0
buildVersion() async {
TaskArgs args = context.invocation.arguments;

String? versionArg = args.getOption('version');
Future<void> buildVersion() async {
final args = context.invocation.arguments;
final versionArg = args.getOption('version');

// Get the pubspec file
final pubspec = await PubSpec.load(Directory.current);

// Get the version
Version? currentVersion = pubspec.version;

Version? version = pubspec.version;

if (versionArg != null) {
version = Version.parse(versionArg);
}

log(currentVersion.toString());

if (version != pubspec.version) {
// change the dependencies to a single path dependency on project 'foo'
var newPubSpec = pubspec.copy(
version: version,
);

// save it
var newPubSpec = pubspec.copy(version: version);
await newPubSpec.save(Directory.current);
}

Expand All @@ -60,11 +52,11 @@ buildVersion() async {
versionFile.createSync(recursive: true);
}

// Write the following:
// const packageVersion = '2.4.1';
versionFile.writeAsStringSync(
"const packageVersion = '$version';",
);
// Add comment on top of the const that this file is generated by this command
String fileContent = '// GENERATED CODE - DO NOT MODIFY BY HAND\n\n ';
fileContent += "const packageVersion = '$version';";

versionFile.writeAsStringSync(fileContent);

log('Version $version written to version.g.dart');
}
Expand Down Expand Up @@ -97,27 +89,27 @@ Future<void> getReleases() async {
}

@Task('Prepare test environment')
Future<void> prepareTest() async {
@Depends(buildVersion)
Future<void> testSetup() async {
final testDir = Directory(getTempTestDir());
if (testDir.existsSync()) {
testDir.deleteSync(recursive: true);
}

runDartScript('bin/fvm.dart', arguments: ['install', 'stable']);
}

@Task('Test')
@Depends(buildVersion, prepareTest)
@Task('Run tests')
@Depends(testSetup)
Future<void> test() async {
runDartScript('bin/fvm.dart', arguments: ['install', '2.2.0']);

await runAsync('dart', arguments: ['test', '--coverage=coverage']);
// Run collectCoverage within a grind task
await collectCoverage();
}

@Task('Gather coverage and generate report')
@Depends(test)
Future<void> collectCoverage() async {
@Task('Get coverage')
Future<void> coverage() async {
await runAsync('dart', arguments: ['pub', 'global', 'activate', 'coverage']);

// Format coverage
await runAsync(
'dart',
arguments: [
Expand All @@ -133,6 +125,7 @@ Future<void> collectCoverage() async {
],
);

// Generate html
await runAsync(
'genhtml',
arguments: ['coverage/lcov.info', '-o', 'coverage/html'],
Expand Down
95 changes: 95 additions & 0 deletions tool/homebrew.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:fvm/src/utils/http.dart';
import 'package:grinder/grinder.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;

import 'grind.dart';

GrinderTask homebrewTask() => GrinderTask(
'homebrew-formula',
taskFunction: _homebrewFormula,
);

Future<void> _homebrewFormula() async {
final githubToken = Platform.environment['GITHUB_TOKEN'] ?? '';
final args = context.invocation.arguments;
final versionArg = args.getOption('version');

if (versionArg == null) {
throw Exception('Version is required');
}

final url = Uri.parse(
'https://api.github.com/repos/$owner/$repo/releases/tags/$versionArg');
final headers = {
if (githubToken.isNotEmpty) 'Authorization': 'token $githubToken',
'Accept': 'application/vnd.github.v3+json',
};

final response = await fetch(url.toString(), headers: headers);

final Map<String, dynamic> release = json.decode(response);
final List<dynamic> assets = release['assets'];
final Map<String, dynamic> assetData = {};

for (final asset in assets) {
final assetUrl = Uri.parse(asset['browser_download_url']);
final filename = path.basename(assetUrl.path);

if (!filename.contains('macos-x64') && !filename.contains('macos-arm64')) {
continue;
}

final sha256Hash = await _downloadFile(assetUrl, filename, headers);

if (sha256Hash.isNotEmpty) {
assetData[filename] = {
'url': asset['browser_download_url'],
'sha256': sha256Hash,
};
}
}

final template = File('tool/fvm.template.rb').readAsStringSync();

final macosX64 = assetData['fvm-$versionArg-macos-x64.tar.gz'];
final macosArm64 = assetData['fvm-$versionArg-macos-arm64.tar.gz'];

final formula = template
.replaceAll('{{VERSION}}', versionArg)
.replaceAll('{{MACOS_X64_URL}}', macosX64['url'])
.replaceAll('{{MACOS_X64_SHA256}}', macosX64['sha256'])
.replaceAll('{{MACOS_ARM64_URL}}', macosArm64['url'])
.replaceAll(
'{{MACOS_ARM64_SHA256}}',
macosArm64['sha256'],
);

final file = File('fvm.rb');
file.writeAsStringSync(formula);
}

Future<String> _downloadFile(
Uri url,
String filename,
Map<String, String> headers,
) async {
final response = await http.get(url, headers: headers);
if (response.statusCode == 200) {
final bytes = response.bodyBytes;
await File(filename).writeAsBytes(bytes);
print('Downloaded: $filename');

// Calculate SHA-256 hash
final sha256Hash = sha256.convert(bytes).toString();
print('SHA-256 Hash: $sha256Hash');
return sha256Hash;
} else {
print('Failed to download $filename: ${response.statusCode}');
return '';
}
}

0 comments on commit af21aea

Please sign in to comment.