Skip to content

Commit

Permalink
Use Dart Sass and the embedded compiler from HEAD by default
Browse files Browse the repository at this point in the history
This matches the behavior of other CI tooling, and is low-risk since
the release process releases the versions from HEAD anyway. It also
eliminates the need to make empty version-only updates to the compiler
just to make logic in Dart Sass visible to the test infrastructure.

This also refactors the tool/ directory to move each individual
`getX()` function into its own file, rather than lumping them all
together in the ambiguously-named `utils.ts`. Any utils functions that
are only used in one file have been moved to that file.
  • Loading branch information
nex3 committed Dec 16, 2022
1 parent 9b5c807 commit b1d0f17
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 423 deletions.
38 changes: 10 additions & 28 deletions .github/workflows/ci.yml
Expand Up @@ -76,25 +76,17 @@ jobs:
with: {repo: sass/embedded-protocol, default-ref: null}

- name: Check out Dart Sass
id: clone-dart-sass
uses: sass/clone-linked-repo@v1
with: {repo: sass/dart-sass, default-ref: null}
with: {repo: sass/dart-sass}

- name: Check out the embedded compiler
uses: sass/clone-linked-repo@v1
with:
repo: sass/dart-sass-embedded
# If we check out a specific version of Dart Sass, always check out
# the embedded compiler as well so we can actually use that Dart Sass
# version.
default-ref: ${{ !steps.clone-dart-sass.skip && 'main' || null }}
with: {repo: sass/dart-sass-embedded}

- name: Link the embedded compiler to Dart Sass
run: |
if [[ -d dart-sass ]]; then
yq -i '.dependency_overrides.sass = {"path": "../dart-sass"}' \
dart-sass-embedded/pubspec.yaml
fi
yq -i '.dependency_overrides.sass = {"path": "../dart-sass"}' \
dart-sass-embedded/pubspec.yaml
- name: Check out the JS API definition
uses: sass/clone-linked-repo@v1
Expand All @@ -104,8 +96,7 @@ jobs:
- name: npm run init
run: |
if [[ -d embedded-protocol ]]; then args=--protocol-path=embedded-protocol; fi
if [[ -d dart-sass-embedded ]]; then args="$args --compiler-path=dart-sass-embedded"; fi
npm run init -- --api-path=language $args
npm run init -- --compiler-path=dart-sass-embedded --api-path=language $args
- run: npm run test

Expand Down Expand Up @@ -146,25 +137,17 @@ jobs:
with: {repo: sass/embedded-protocol, default-ref: null}

- name: Check out Dart Sass
id: clone-dart-sass
uses: sass/clone-linked-repo@v1
with: {repo: sass/dart-sass, default-ref: null}
with: {repo: sass/dart-sass}

- name: Check out the embedded compiler
uses: sass/clone-linked-repo@v1
with:
repo: sass/dart-sass-embedded
# If we check out a specific version of Dart Sass, always check out
# the embedded compiler as well so we can actually use that Dart Sass
# version.
default-ref: ${{ !steps.clone-dart-sass.skip && 'main' || null }}
with: {repo: sass/dart-sass-embedded}

- name: Link the embedded compiler to Dart Sass
run: |
if [[ -d dart-sass ]]; then
yq -i '.dependency_overrides.sass = {"path": "../dart-sass"}' \
dart-sass-embedded/pubspec.yaml
fi
yq -i '.dependency_overrides.sass = {"path": "../dart-sass"}' \
dart-sass-embedded/pubspec.yaml
- name: Check out the JS API definition
uses: sass/clone-linked-repo@v1
Expand All @@ -174,8 +157,7 @@ jobs:
- name: npm run init
run: |
if [[ -d embedded-protocol ]]; then args=--protocol-path=embedded-protocol; fi
if [[ -d dart-sass-embedded ]]; then args="$args --compiler-path=dart-sass-embedded"; fi
npm run init -- --api-path=language $args
npm run init -- --compiler-path=dart-sass-embedded --api-path=language $args
- name: Check out sass-spec
uses: sass/clone-linked-repo@v1
Expand Down
26 changes: 7 additions & 19 deletions CONTRIBUTING.md
Expand Up @@ -67,30 +67,18 @@ JS API):
* `--<type>-ref`: A Git reference for the GitHub repository of the package to
clone.

* `--<type>-version`: The released version of the package to use. This isn't
available for `api`, because the JS API definition doesn't have its own tagged
versions.

By default:

* This uses the version of the embedded protocol and compiler specified by
`protocol-version` and `compiler-version` in `package.json`, *unless* these
versions end in `-dev` in which case it checks out the latest revision on
GitHub.

* This uses the JS API definition from the latest revision on GitHub.

`npm run init` chooses the Dart Sass version as follows:

* If a released version of the embedded compiler was specified, it uses the
version of Dart Sass compiled into that release.
`protocol-version` in `package.json`, *unless* that version ends in `-dev` in
which case it checks out the latest revision on GitHub.

* If `--compiler-path` was specified, it uses the version of Dart Sass linked to
that compiler.
* This uses the embedded compiler version and JS API definition from the latest
revision on GitHub.

* If the embedded compiler was cloned from GitHub, it uses the version of Dart
Sass specified in its pubspec *unless* that version ends in `-dev`, in which
case it checks out the latest revision on GitHub.
* This uses the Dart Sass version from the latest revision on GitHub, unless the
embedded `--compiler-path` was passed in which case it uses whatever version
of Dart Sass that package references.

## Continuous Integration

Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -16,7 +16,7 @@
"node": ">=14.0.0"
},
"scripts": {
"init": "ts-node ./tool/prepare-dev-environment.ts",
"init": "ts-node ./tool/init.ts",
"check": "npm-run-all check:gts check:tsc",
"check:gts": "gts check",
"check:tsc": "tsc --noEmit",
Expand Down
50 changes: 11 additions & 39 deletions tool/prepare-dev-environment.ts → tool/init.ts
Expand Up @@ -4,13 +4,9 @@

import yargs from 'yargs';

import {
nodeArchToDartArch,
getDartSassEmbedded,
getEmbeddedProtocol,
getJSApi,
nodePlatformToDartPlatform,
} from './utils';
import {getEmbeddedCompiler} from './get-embedded-compiler';
import {getEmbeddedProtocol} from './get-embedded-protocol';
import {getJSApi} from './get-js-api';

const argv = yargs(process.argv.slice(2))
.option('compiler-path', {
Expand All @@ -22,10 +18,6 @@ const argv = yargs(process.argv.slice(2))
type: 'string',
description: 'Build the Embedded Dart Sass binary from this Git ref.',
})
.option('compiler-version', {
type: 'string',
description: 'Download this version of the Embedded Dart Sass binary.',
})
.option('skip-compiler', {
type: 'boolean',
description: "Don't Embedded Dart Sass at all.",
Expand All @@ -38,10 +30,6 @@ const argv = yargs(process.argv.slice(2))
type: 'string',
description: 'Build the Embedded Protocol from this Git ref.',
})
.option('protocol-version', {
type: 'string',
description: 'Build the Embedded Protocol from this release version.',
})
.option('api-path', {
type: 'string',
description: 'Use the JS API definitions from the source at this path.',
Expand All @@ -51,30 +39,18 @@ const argv = yargs(process.argv.slice(2))
description: 'Build the JS API definitions from this Git ref.',
})
.conflicts({
'compiler-path': ['compiler-ref', 'compiler-version', 'skip-compiler'],
'compiler-ref': ['compiler-version', 'skip-compiler'],
'compiler-version': 'skip-compiler',
'protocol-path': ['protocol-ref', 'protocol-version'],
'protocol-ref': 'protocol-version',
'compiler-path': ['compiler-ref', 'skip-compiler'],
'compiler-ref': ['skip-compiler'],
'protocol-path': ['protocol-ref'],
'api-path': 'api-ref',
})
.parseSync();

(async () => {
try {
const outPath = 'lib/src/vendor';
const platform = nodePlatformToDartPlatform(
process.env.npm_config_platform || process.platform
);
const arch = nodeArchToDartArch(
process.env.npm_config_arch || process.arch
);

if (argv['protocol-version']) {
await getEmbeddedProtocol(outPath, {
version: argv['protocol-version'],
});
} else if (argv['protocol-ref']) {
if (argv['protocol-ref']) {
await getEmbeddedProtocol(outPath, {
ref: argv['protocol-ref'],
});
Expand All @@ -87,20 +63,16 @@ const argv = yargs(process.argv.slice(2))
}

if (!argv['skip-compiler']) {
if (argv['compiler-version']) {
await getDartSassEmbedded(outPath, platform, arch, {
version: argv['compiler-version'],
});
} else if (argv['compiler-ref']) {
await getDartSassEmbedded(outPath, platform, arch, {
if (argv['compiler-ref']) {
await getEmbeddedCompiler(outPath, {
ref: argv['compiler-ref'],
});
} else if (argv['compiler-path']) {
await getDartSassEmbedded(outPath, platform, arch, {
await getEmbeddedCompiler(outPath, {
path: argv['compiler-path'],
});
} else {
await getDartSassEmbedded(outPath, platform, arch);
await getEmbeddedCompiler(outPath);
}
}

Expand Down
123 changes: 113 additions & 10 deletions tool/prepare-optional-release.ts
@@ -1,11 +1,15 @@
import extractZip = require('extract-zip');
import {promises as fs} from 'fs';
import fetch from 'node-fetch';
import * as p from 'path';
import {extract as extractTar} from 'tar';
import yargs from 'yargs';
import {
getDartSassEmbedded,
nodePlatformToDartPlatform,
nodeArchToDartArch,
} from './utils';

import * as pkg from '../package.json';
import * as utils from './utils';

export type DartPlatform = 'linux' | 'macos' | 'windows';
export type DartArch = 'ia32' | 'x64' | 'arm' | 'arm64';

const argv = yargs(process.argv.slice(2))
.option('package', {
Expand All @@ -19,13 +23,112 @@ const argv = yargs(process.argv.slice(2))
})
.parseSync();

// Converts a Node-style platform name as returned by `process.platform` into a
// name used by Dart Sass. Throws if the operating system is not supported by
// Dart Sass Embedded.
export function nodePlatformToDartPlatform(platform: string): DartPlatform {
switch (platform) {
case 'linux':
return 'linux';
case 'darwin':
return 'macos';
case 'win32':
return 'windows';
default:
throw Error(`Platform ${platform} is not supported.`);
}
}

// Converts a Node-style architecture name as returned by `process.arch` into a
// name used by Dart Sass. Throws if the architecture is not supported by Dart
// Sass Embedded.
export function nodeArchToDartArch(arch: string): DartArch {
switch (arch) {
case 'ia32':
return 'ia32';
case 'x86':
return 'ia32';
case 'x64':
return 'x64';
case 'arm':
return 'arm';
case 'arm64':
return 'arm64';
default:
throw Error(`Architecture ${arch} is not supported.`);
}
}

// Get the platform's file extension for archives.
function getArchiveExtension(platform: DartPlatform): '.zip' | '.tar.gz' {
return platform === 'windows' ? '.zip' : '.tar.gz';
}

// Downloads the release for `repo` located at `assetUrl`, then unzips it into
// `outPath`.
async function downloadRelease(options: {
repo: string;
assetUrl: string;
outPath: string;
}): Promise<void> {
console.log(`Downloading ${options.repo} release asset.`);
const response = await fetch(options.assetUrl, {
redirect: 'follow',
});
if (!response.ok) {
throw Error(
`Failed to download ${options.repo} release asset: ${response.statusText}`
);
}
const releaseAsset = await response.buffer();

console.log(`Unzipping ${options.repo} release asset to ${options.outPath}.`);
await utils.cleanDir(p.join(options.outPath, options.repo));

const archiveExtension = options.assetUrl.endsWith('.zip')
? '.zip'
: '.tar.gz';
const zippedAssetPath =
options.outPath + '/' + options.repo + archiveExtension;
await fs.writeFile(zippedAssetPath, releaseAsset);
if (archiveExtension === '.zip') {
await extractZip(zippedAssetPath, {
dir: p.join(process.cwd(), options.outPath),
});
} else {
extractTar({
file: zippedAssetPath,
cwd: options.outPath,
sync: true,
});
}
await fs.unlink(zippedAssetPath);
}

(async () => {
try {
const [platform, arch] = argv.package.split('-');
await getDartSassEmbedded(
`npm/${argv.package}`,
nodePlatformToDartPlatform(platform),
nodeArchToDartArch(arch)
const version = pkg['compiler-version'] as string;
if (version.endsWith('-dev')) {
throw Error(
"Can't release optional packages for a -dev compiler version."
);
}

const [nodePlatform, nodeArch] = argv.package.split('-');
const dartPlatform = nodePlatformToDartPlatform(nodePlatform);
const dartArch = nodeArchToDartArch(nodeArch);
const outPath = p.join('npm', argv.package);
await downloadRelease({
repo: 'dart-sass-embedded',
assetUrl:
'https://github.com/sass/dart-sass-embedded/releases/download/' +
`${version}/sass_embedded-${version}-` +
`${dartPlatform}-${dartArch}${getArchiveExtension(dartPlatform)}`,
outPath,
});
await fs.rename(
p.join(outPath, 'sass_embedded'),
p.join(outPath, 'dart-sass-embedded')
);
} catch (error) {
console.error(error);
Expand Down
5 changes: 2 additions & 3 deletions tool/prepare-release.ts
Expand Up @@ -6,9 +6,8 @@ import {promises as fs} from 'fs';
import * as shell from 'shelljs';

import * as pkg from '../package.json';
import {getEmbeddedProtocol, getJSApi} from './utils';

shell.config.fatal = true;
import {getEmbeddedProtocol} from './get-embedded-protocol';
import {getJSApi} from './get-js-api';

(async () => {
try {
Expand Down

0 comments on commit b1d0f17

Please sign in to comment.