Skip to content

Commit

Permalink
Test against real-world Sass frameworks
Browse files Browse the repository at this point in the history
In a future commit, I'll update these jobs to only run just before
release, since they're expected to be substantially less likely to
fail and we don't want to waste cycles. For now, I have them runnning
always to verify that they run successfully at least once.
  • Loading branch information
nex3 committed Sep 16, 2021
1 parent 30cc9dc commit 8114760
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 22 deletions.
62 changes: 62 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -142,6 +142,68 @@ jobs:
--errors ambiguous-doc-reference,broken-link,deprecated
--errors unknown-directive,unknown-macro,unresolved-doc-reference

bootstrap:
name: "Bootstrap ${{ matrix.bootstrap_version }}"
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
bootstrap_version: [4, 5]

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: dart pub run grinder fetch-bootstrap${{matrix.bootstrap_version}}
- name: Build
run: dart bin/sass.dart --quiet build/bootstrap/scss:build/bootstrap-output
env: {GITHUB_BEARER_TOKEN: "${{ secrets.GITHUB_TOKEN }}"}

bourbon:
name: Bourbon
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: dart pub run grinder fetch-bourbon
- name: Test
run: |
dart bin/sass.dart --quiet -I build/bourbon -I build/bourbon/spec/fixtures \
build/bourbon/spec/fixtures:build/bourbon-output
env: {GITHUB_BEARER_TOKEN: "${{ secrets.GITHUB_TOKEN }}"}

foundation:
name: Foundation
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: dart pub run grinder fetch-foundation
# TODO(nweiz): Foundation has proper Sass tests, but they're currently not
# compatible with Dart Sass. Once they are, we should run those rather
# than just building the CSS output.
- name: Build
run: dart bin/sass.dart --quiet build/foundation-sites/assets:build/foundation-output
env: {GITHUB_BEARER_TOKEN: "${{ secrets.GITHUB_TOKEN }}"}

bulma:
name: Bulma
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: dart pub run grinder fetch-bulma
- name: Build
run: dart bin/sass.dart --quiet build/bulma/bulma.sass build/bulma-output.css
env: {GITHUB_BEARER_TOKEN: "${{ secrets.GITHUB_TOKEN }}"}

sanity_checks:
name: Sanity checks
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Expand Up @@ -34,7 +34,7 @@ dependencies:
dev_dependencies:
analyzer: ^2.2.0
archive: ^3.1.2
cli_pkg: ^1.3.0
cli_pkg: ^1.7.0
crypto: ^3.0.0
dart_style: ^2.0.0
grinder: ^0.9.0
Expand Down
5 changes: 3 additions & 2 deletions tool/grind.dart
Expand Up @@ -15,6 +15,7 @@ import 'grind/synchronize.dart';

export 'grind/bazel.dart';
export 'grind/benchmark.dart';
export 'grind/frameworks.dart';
export 'grind/sanity_check.dart';
export 'grind/subpackages.dart';
export 'grind/synchronize.dart';
Expand All @@ -34,8 +35,8 @@ void main(List<String> args) {
as Map<String, dynamic>;
pkg.npmReadme.fn = () => _readAndResolveMarkdown("package/README.npm.md");
pkg.standaloneName.value = "dart-sass";
pkg.githubUser.fn = () => Platform.environment["GH_USER"]!;
pkg.githubPassword.fn = () => Platform.environment["GH_TOKEN"]!;
pkg.githubUser.fn = () => Platform.environment["GH_USER"];
pkg.githubPassword.fn = () => Platform.environment["GH_TOKEN"];

pkg.githubReleaseNotes.fn = () =>
"To install Sass ${pkg.version}, download one of the packages below "
Expand Down
71 changes: 71 additions & 0 deletions tool/grind/frameworks.dart
@@ -0,0 +1,71 @@
// Copyright 2021 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'dart:convert';

import 'package:grinder/grinder.dart';
import 'package:http/http.dart' as http;

import 'utils.dart';

@Task('Download Bootstrap 5.x for testing purposes.')
Future<void> fetchBootstrap5() => _getLatestRelease('twbs/bootstrap');

@Task('Download Bootstrap 4.x for testing purposes.')
Future<void> fetchBootstrap4() =>
_getLatestRelease('twbs/bootstrap', pattern: RegExp(r'^v4\.'));

@Task('Download Bourbon for testing purposes.')
Future<void> fetchBourbon() => _getLatestRelease('thoughtbot/bourbon');

@Task('Download Foundation for testing purposes.')
Future<void> fetchFoundation() =>
_getLatestRelease('foundation/foundation-sites');

@Task('Download Bulma for testing purposes.')
Future<void> fetchBulma() => _getLatestRelease('jgthms/bulma');

/// Clones the latest release of the given GitHub repository [slug].
///
/// If [pattern] is passed, this will clone the latest release that matches that
/// pattern.
Future<void> _getLatestRelease(String slug, {Pattern? pattern}) async {
await cloneOrCheckout('git://github.com/$slug',
await _findLatestRelease(slug, pattern: pattern));
}

/// Returns the tag name of the latest release for the given GitHub repository
/// [slug].
///
/// If [pattern] is passed, this will find the latest release that matches that
/// pattern.
Future<String> _findLatestRelease(String slug, {Pattern? pattern}) async {
var releases = await _fetchReleases(slug);
if (pattern == null) return releases[0]['tag_name'] as String;

var page = 1;
while (releases.isNotEmpty) {
for (var release in releases) {
var tagName = release['tag_name'] as String;
if (pattern.allMatches(tagName).isNotEmpty) return tagName;
}

page++;
releases = await _fetchReleases(slug, page: page);
}

fail("Couldn't find a release of $slug matching $pattern.");
}

/// Fetches the GitHub releases page for the repo at [slug].
Future<List<Map<String, dynamic>>> _fetchReleases(String slug,
{int page = 1}) async {
var result = json.decode(await http.read(
Uri.parse("https://api.github.com/repos/$slug/releases?page=$page"),
headers: {
"accept": "application/vnd.github.v3+json",
"authorization": githubAuthorization
})) as List<dynamic>;
return result.cast<Map<String, dynamic>>();
}
15 changes: 3 additions & 12 deletions tool/grind/subpackages.dart
Expand Up @@ -12,6 +12,8 @@ import 'package:path/path.dart' as p;
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:yaml/yaml.dart';

import 'utils.dart';

/// The path in which pub expects to find its credentials file.
final String _pubCredentialsPath = () {
// This follows the same logic as pub:
Expand All @@ -30,17 +32,6 @@ final String _pubCredentialsPath = () {
return p.join(cacheDir, 'credentials.json');
}();

/// Returns the HTTP basic authentication Authorization header from the
/// environment.
String get _githubAuthorization {
var bearerToken = pkg.githubBearerToken.value;
return bearerToken != null
? "Bearer $bearerToken"
: "Basic " +
base64.encode(utf8
.encode(pkg.githubUser.value + ':' + pkg.githubPassword.value));
}

@Task('Deploy sub-packages to pub.')
Future<void> deploySubPackages() async {
// Write pub credentials
Expand Down Expand Up @@ -86,7 +77,7 @@ Future<void> deploySubPackages() async {
headers: {
"accept": "application/vnd.github.v3+json",
"content-type": "application/json",
"authorization": _githubAuthorization
"authorization": githubAuthorization
},
body: jsonEncode({
"ref": "refs/tags/${pubspec.name}/${pubspec.version}",
Expand Down
30 changes: 23 additions & 7 deletions tool/grind/utils.dart
Expand Up @@ -3,6 +3,7 @@
// https://opensource.org/licenses/MIT.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:cli_pkg/cli_pkg.dart' as pkg;
Expand All @@ -17,6 +18,17 @@ final sassBotEnvironment = RunOptions(environment: {
"GIT_COMMITTER_EMAIL": pkg.botEmail.value
});

/// Returns the HTTP basic authentication Authorization header from the
/// environment.
String get githubAuthorization {
var bearerToken = pkg.githubBearerToken.value;
return bearerToken != null
? "Bearer $bearerToken"
: "Basic " +
base64.encode(utf8
.encode(pkg.githubUser.value + ':' + pkg.githubPassword.value));
}

/// Ensure that the `build/` directory exists.
void ensureBuild() {
Directory('build').createSync(recursive: true);
Expand Down Expand Up @@ -47,18 +59,22 @@ Future<String> cloneOrCheckout(String url, String ref) async {

var path = p.join("build", name);

if (Directory(p.join(path, '.git')).existsSync()) {
log("Updating $url");
await runAsync("git",
arguments: ["fetch", "origin"], workingDirectory: path);
} else {
if (!Directory(p.join(path, '.git')).existsSync()) {
delete(Directory(path));
await runAsync("git", arguments: ["clone", url, path]);
await runAsync("git", arguments: ["init", path]);
await runAsync("git",
arguments: ["config", "advice.detachedHead", "false"],
workingDirectory: path);
await runAsync("git",
arguments: ["remote", "add", "origin", url], workingDirectory: path);
} else {
log("Updating $url");
}
await runAsync("git", arguments: ["checkout", ref], workingDirectory: path);

await runAsync("git",
arguments: ["fetch", "origin", "--depth=1", ref], workingDirectory: path);
await runAsync("git",
arguments: ["checkout", "FETCH_HEAD"], workingDirectory: path);
log("");

return path;
Expand Down

0 comments on commit 8114760

Please sign in to comment.