diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e48b7a9..ecf54ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,26 +1,31 @@ name: CI on: push jobs: - lint: + test: + name: Unit tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: goto-bus-stop/standard-action@v1 - with: - annotate: true - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install dependencies + run: npm install + - name: Run tests + run: npm test smoke-test: + name: Build test strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - zig-version: [0.5.0, master] + zig-version: [0.5.0, 0.7.0, master] runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 - - uses: goto-bus-stop/setup-zig@default + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install Zig + uses: goto-bus-stop/setup-zig@default with: version: ${{matrix.zig-version}} - - run: zig build test + - name: Run tests + run: zig build test working-directory: test diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8a6e4..4b796dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## 1.3.0 +* Support pinning to a specific commit of the zig compiler. ([@codehz](https://github.com/codehz) in [#14](https://github.com/goto-bus-stop/setup-zig/pull/14)) + ```yaml + uses: goto-bus-stop/setup-zig@v1 + with: + version: 0.6.0+4b48fccad + ``` +* Add tests for the version -> URL resolution code. + ## 1.2.5 * Update dependencies to fix #11. @@ -14,7 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). * Configure Actions to build releases automatically. ## 1.2.2 -* Update examples. (#7) +* Update examples. ([#7](https://github.com/goto-bus-stop/setup-zig/pull/7)) * Upgrade dependencies. * Recommend using @v1 instead of pinning to a version. diff --git a/README.md b/README.md index 46e3eeb..b8f42eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # setup-zig -Use the zig compiler in your Github Action +Use the zig compiler in your Github Actions workflows [Usage](#usage) - [License: Apache-2.0](#license) @@ -31,7 +31,7 @@ Optionally set a Zig version: ```yaml - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.4.0 # The default is 0.5.0 + version: 0.7.0 # The default is 0.5.0 ``` To use the nightly builds, set: @@ -41,7 +41,14 @@ To use the nightly builds, set: version: master ``` -If you are running Zig on Windows machines, you need to make sure that your .zig files use \n line endings and not \r\n. The `actions/checkout` action auto-converts line endings to \r\n, so add a `.gitattributes` file: +Or [pin to a specific commit](https://github.com/goto-bus-stop/setup-zig/issues/13) using `version+commithash` syntax: +```yaml +- uses: goto-bus-stop/setup-zig@v1 + with: + version: 0.6.0+4b48fccad +``` + +If you are running Zig on Windows machines, you need to make sure that your .zig files use \n line endings and not \r\n. The `actions/checkout` action auto-converts line endings to `\r\n` on Windows runners, so add a `.gitattributes` file: ``` *.zig text eol=lf ``` diff --git a/dist/index.js b/dist/index.js index 2637384..c1e8f1d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8,49 +8,22 @@ module.exports = const os = __webpack_require__(2087) const path = __webpack_require__(5622) const semver = __webpack_require__(1383) -const get = __webpack_require__(2522).concat const actions = __webpack_require__(2186) const cache = __webpack_require__(7784) +const { + extForPlatform, + resolveCommit, + resolveVersion +} = __webpack_require__(3470) -function getJSON (opts) { - return new Promise((resolve, reject) => { - get({ ...opts, json: true }, (err, req, data) => { - if (err) { - reject(err) - } else { - resolve(data) - } - }) - }) -} +async function downloadZig (platform, version) { + const ext = extForPlatform(platform) -async function downloadZig (version) { - const host = { - linux: 'x86_64-linux', - darwin: 'x86_64-macos', - win32: 'x86_64-windows' - }[os.platform()] || os.platform() - const ext = { - linux: 'tar.xz', - darwin: 'tar.xz', - win32: 'zip' - }[os.platform()] + const { downloadUrl, variantName } = version.includes('+') + ? resolveCommit(platform, version) + : await resolveVersion(platform, version) - const index = await getJSON({ url: 'https://ziglang.org/download/index.json' }) - - const availableVersions = Object.keys(index) - const useVersion = semver.valid(version) - ? semver.maxSatisfying(availableVersions.filter((v) => semver.valid(v)), version) - : null - - const meta = index[useVersion || version] - if (!meta || !meta[host]) { - throw new Error(`Could not find version ${version} for platform ${host}`) - } - - const variantName = path.basename(meta[host].tarball).replace(`.${ext}`, '') - - const downloadPath = await cache.downloadTool(meta[host].tarball) + const downloadPath = await cache.downloadTool(downloadUrl) const zigPath = ext === 'zip' ? await cache.extractZip(downloadPath) : await cache.extractTar(downloadPath, undefined, 'x') @@ -70,7 +43,7 @@ async function main () { let zigPath = cache.find('zig', version) if (!zigPath) { - zigPath = await downloadZig(version) + zigPath = await downloadZig(os.platform(), version) } // Add the `zig` binary to the $PATH @@ -1143,7 +1116,6 @@ class ExecState extends events.EventEmitter { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -const url = __webpack_require__(8835); const http = __webpack_require__(8605); const https = __webpack_require__(7211); const pm = __webpack_require__(6443); @@ -1192,7 +1164,7 @@ var MediaTypes; * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com */ function getProxyUrl(serverUrl) { - let proxyUrl = pm.getProxyUrl(url.parse(serverUrl)); + let proxyUrl = pm.getProxyUrl(new URL(serverUrl)); return proxyUrl ? proxyUrl.href : ''; } exports.getProxyUrl = getProxyUrl; @@ -1211,6 +1183,15 @@ const HttpResponseRetryCodes = [ const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; const ExponentialBackoffCeiling = 10; const ExponentialBackoffTimeSlice = 5; +class HttpClientError extends Error { + constructor(message, statusCode) { + super(message); + this.name = 'HttpClientError'; + this.statusCode = statusCode; + Object.setPrototypeOf(this, HttpClientError.prototype); + } +} +exports.HttpClientError = HttpClientError; class HttpClientResponse { constructor(message) { this.message = message; @@ -1229,7 +1210,7 @@ class HttpClientResponse { } exports.HttpClientResponse = HttpClientResponse; function isHttps(requestUrl) { - let parsedUrl = url.parse(requestUrl); + let parsedUrl = new URL(requestUrl); return parsedUrl.protocol === 'https:'; } exports.isHttps = isHttps; @@ -1334,7 +1315,7 @@ class HttpClient { if (this._disposed) { throw new Error('Client has already been disposed.'); } - let parsedUrl = url.parse(requestUrl); + let parsedUrl = new URL(requestUrl); let info = this._prepareRequest(verb, parsedUrl, headers); // Only perform retries on reads since writes may not be idempotent. let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1 @@ -1373,7 +1354,7 @@ class HttpClient { // if there's no location to redirect to, we won't break; } - let parsedRedirectUrl = url.parse(redirectUrl); + let parsedRedirectUrl = new URL(redirectUrl); if (parsedUrl.protocol == 'https:' && parsedUrl.protocol != parsedRedirectUrl.protocol && !this._allowRedirectDowngrade) { @@ -1489,7 +1470,7 @@ class HttpClient { * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com */ getAgent(serverUrl) { - let parsedUrl = url.parse(serverUrl); + let parsedUrl = new URL(serverUrl); return this._getAgent(parsedUrl); } _prepareRequest(method, requestUrl, headers) { @@ -1562,7 +1543,7 @@ class HttpClient { maxSockets: maxSockets, keepAlive: this._keepAlive, proxy: { - proxyAuth: proxyUrl.auth, + proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`, host: proxyUrl.hostname, port: proxyUrl.port } @@ -1657,12 +1638,8 @@ class HttpClient { else { msg = 'Failed request: (' + statusCode + ')'; } - let err = new Error(msg); - // attach statusCode and body obj (if available) to the error object - err['statusCode'] = statusCode; - if (response.result) { - err['result'] = response.result; - } + let err = new HttpClientError(msg, statusCode); + err.result = response.result; reject(err); } else { @@ -1677,12 +1654,11 @@ exports.HttpClient = HttpClient; /***/ }), /***/ 6443: -/***/ ((__unused_webpack_module, exports, __webpack_require__) => { +/***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -const url = __webpack_require__(8835); function getProxyUrl(reqUrl) { let usingSsl = reqUrl.protocol === 'https:'; let proxyUrl; @@ -1697,7 +1673,7 @@ function getProxyUrl(reqUrl) { proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY']; } if (proxyVar) { - proxyUrl = url.parse(proxyVar); + proxyUrl = new URL(proxyVar); } return proxyUrl; } @@ -2474,7 +2450,7 @@ class HTTPError extends Error { constructor(httpStatusCode) { super(`Unexpected HTTP response: ${httpStatusCode}`); this.httpStatusCode = httpStatusCode; - Object.setPrototypeOf(this, /* unsupported import.meta.prototype */ undefined); + Object.setPrototypeOf(this, new.target.prototype); } } exports.HTTPError = HTTPError; @@ -7522,13 +7498,89 @@ function wrappy (fn, cb) { } +/***/ }), + +/***/ 3470: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +const path = __webpack_require__(5622) +const get = __webpack_require__(2522).concat +const semver = __webpack_require__(1383) + +function extForPlatform (platform) { + return { + linux: 'tar.xz', + darwin: 'tar.xz', + win32: 'zip' + }[platform] +} + +function resolveCommit (platform, version) { + const ext = extForPlatform(platform) + const addrhost = { + linux: 'linux-x86_64', + darwin: 'macos-x86_64', + win32: 'windows-x86_64' + }[platform] + + const downloadUrl = `https://ziglang.org/builds/zig-${addrhost}-${version}.${ext}` + const variantName = `zig-${addrhost}-${version}` + + return { downloadUrl, variantName } +} + +function getJSON (opts) { + return new Promise((resolve, reject) => { + get({ ...opts, json: true }, (err, req, data) => { + if (err) { + reject(err) + } else { + resolve(data) + } + }) + }) +} + +async function resolveVersion (platform, version) { + const ext = extForPlatform(platform) + const host = { + linux: 'x86_64-linux', + darwin: 'x86_64-macos', + win32: 'x86_64-windows' + }[platform] || platform + + const index = await getJSON({ url: 'https://ziglang.org/download/index.json' }) + + const availableVersions = Object.keys(index) + const useVersion = semver.valid(version) + ? semver.maxSatisfying(availableVersions.filter((v) => semver.valid(v)), version) + : null + + const meta = index[useVersion || version] + if (!meta || !meta[host]) { + throw new Error(`Could not find version ${useVersion || version} for platform ${host}`) + } + + const downloadUrl = meta[host].tarball + const variantName = path.basename(meta[host].tarball).replace(`.${ext}`, '') + + return { downloadUrl, variantName } +} + +module.exports = { + extForPlatform, + resolveCommit, + resolveVersion +} + + /***/ }), /***/ 2357: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("assert");; /***/ }), @@ -7536,7 +7588,7 @@ module.exports = require("assert"); /***/ ((module) => { "use strict"; -module.exports = require("child_process"); +module.exports = require("child_process");; /***/ }), @@ -7544,7 +7596,7 @@ module.exports = require("child_process"); /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("crypto");; /***/ }), @@ -7552,7 +7604,7 @@ module.exports = require("crypto"); /***/ ((module) => { "use strict"; -module.exports = require("events"); +module.exports = require("events");; /***/ }), @@ -7560,7 +7612,7 @@ module.exports = require("events"); /***/ ((module) => { "use strict"; -module.exports = require("fs"); +module.exports = require("fs");; /***/ }), @@ -7568,7 +7620,7 @@ module.exports = require("fs"); /***/ ((module) => { "use strict"; -module.exports = require("http"); +module.exports = require("http");; /***/ }), @@ -7576,7 +7628,7 @@ module.exports = require("http"); /***/ ((module) => { "use strict"; -module.exports = require("https"); +module.exports = require("https");; /***/ }), @@ -7584,7 +7636,7 @@ module.exports = require("https"); /***/ ((module) => { "use strict"; -module.exports = require("net"); +module.exports = require("net");; /***/ }), @@ -7592,7 +7644,7 @@ module.exports = require("net"); /***/ ((module) => { "use strict"; -module.exports = require("os"); +module.exports = require("os");; /***/ }), @@ -7600,7 +7652,7 @@ module.exports = require("os"); /***/ ((module) => { "use strict"; -module.exports = require("path"); +module.exports = require("path");; /***/ }), @@ -7608,7 +7660,7 @@ module.exports = require("path"); /***/ ((module) => { "use strict"; -module.exports = require("querystring"); +module.exports = require("querystring");; /***/ }), @@ -7616,7 +7668,7 @@ module.exports = require("querystring"); /***/ ((module) => { "use strict"; -module.exports = require("stream"); +module.exports = require("stream");; /***/ }), @@ -7624,7 +7676,7 @@ module.exports = require("stream"); /***/ ((module) => { "use strict"; -module.exports = require("tls"); +module.exports = require("tls");; /***/ }), @@ -7632,7 +7684,7 @@ module.exports = require("tls"); /***/ ((module) => { "use strict"; -module.exports = require("url"); +module.exports = require("url");; /***/ }), @@ -7640,7 +7692,7 @@ module.exports = require("url"); /***/ ((module) => { "use strict"; -module.exports = require("util"); +module.exports = require("util");; /***/ }), @@ -7648,7 +7700,7 @@ module.exports = require("util"); /***/ ((module) => { "use strict"; -module.exports = require("zlib"); +module.exports = require("zlib");; /***/ }) diff --git a/index.js b/index.js index e2fe21f..b1753a2 100644 --- a/index.js +++ b/index.js @@ -1,49 +1,22 @@ const os = require('os') const path = require('path') const semver = require('semver') -const get = require('simple-get').concat const actions = require('@actions/core') const cache = require('@actions/tool-cache') +const { + extForPlatform, + resolveCommit, + resolveVersion +} = require('./versions') -function getJSON (opts) { - return new Promise((resolve, reject) => { - get({ ...opts, json: true }, (err, req, data) => { - if (err) { - reject(err) - } else { - resolve(data) - } - }) - }) -} +async function downloadZig (platform, version) { + const ext = extForPlatform(platform) -async function downloadZig (version) { - const host = { - linux: 'x86_64-linux', - darwin: 'x86_64-macos', - win32: 'x86_64-windows' - }[os.platform()] || os.platform() - const ext = { - linux: 'tar.xz', - darwin: 'tar.xz', - win32: 'zip' - }[os.platform()] + const { downloadUrl, variantName } = version.includes('+') + ? resolveCommit(platform, version) + : await resolveVersion(platform, version) - const index = await getJSON({ url: 'https://ziglang.org/download/index.json' }) - - const availableVersions = Object.keys(index) - const useVersion = semver.valid(version) - ? semver.maxSatisfying(availableVersions.filter((v) => semver.valid(v)), version) - : null - - const meta = index[useVersion || version] - if (!meta || !meta[host]) { - throw new Error(`Could not find version ${version} for platform ${host}`) - } - - const variantName = path.basename(meta[host].tarball).replace(`.${ext}`, '') - - const downloadPath = await cache.downloadTool(meta[host].tarball) + const downloadPath = await cache.downloadTool(downloadUrl) const zigPath = ext === 'zip' ? await cache.extractZip(downloadPath) : await cache.extractTar(downloadPath, undefined, 'x') @@ -63,7 +36,7 @@ async function main () { let zigPath = cache.find('zig', version) if (!zigPath) { - zigPath = await downloadZig(version) + zigPath = await downloadZig(os.platform(), version) } // Add the `zig` binary to the $PATH diff --git a/package.json b/package.json index da82412..84a9647 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "setup-zig", "description": "Use the zig compiler in your Github Action", - "version": "1.2.5", + "version": "1.3.0", "author": "Renée Kooi ", "bugs": { "url": "https://github.com/goto-bus-stop/setup-zig/issues" @@ -13,8 +13,8 @@ "simple-get": "^4.0.0" }, "devDependencies": { - "@vercel/ncc": "^0.24.1", - "standard": "^14.3.1" + "@vercel/ncc": "^0.25.0", + "standard": "^16.0.1" }, "homepage": "https://github.com/goto-bus-stop/setup-zig", "keywords": [ @@ -31,7 +31,7 @@ }, "scripts": { "prepare": "ncc build index.js -o dist", - "test": "standard" + "test": "standard && node test" }, "standard": { "ignore": [ diff --git a/test.js b/test.js new file mode 100644 index 0000000..3860a28 --- /dev/null +++ b/test.js @@ -0,0 +1,32 @@ +const assert = require('assert').strict +const { + resolveCommit, + resolveVersion +} = require('./versions') + +async function test () { + assert.deepEqual(resolveCommit('linux', '0.6.0+4b48fccad'), { + downloadUrl: 'https://ziglang.org/builds/zig-linux-x86_64-0.6.0+4b48fccad.tar.xz', + variantName: 'zig-linux-x86_64-0.6.0+4b48fccad' + }) + assert.deepEqual(resolveCommit('win32', '0.6.0+4b48fccad'), { + downloadUrl: 'https://ziglang.org/builds/zig-windows-x86_64-0.6.0+4b48fccad.zip', + variantName: 'zig-windows-x86_64-0.6.0+4b48fccad' + }) + + assert.deepEqual(await resolveVersion('linux', '0.7.0'), { + downloadUrl: 'https://ziglang.org/download/0.7.0/zig-linux-x86_64-0.7.0.tar.xz', + variantName: 'zig-linux-x86_64-0.7.0' + }) + assert.deepEqual(await resolveVersion('win32', '0.4.0'), { + downloadUrl: 'https://ziglang.org/download/0.4.0/zig-windows-x86_64-0.4.0.zip', + variantName: 'zig-windows-x86_64-0.4.0' + }) + await assert.doesNotReject(resolveVersion('linux', 'master')) + await assert.doesNotReject(resolveVersion('win32', 'master')) +} + +test().catch((error) => { + console.error(error.stack) + process.exit(1) +}) diff --git a/versions.js b/versions.js new file mode 100644 index 0000000..cd08c4f --- /dev/null +++ b/versions.js @@ -0,0 +1,69 @@ +const path = require('path') +const get = require('simple-get').concat +const semver = require('semver') + +function extForPlatform (platform) { + return { + linux: 'tar.xz', + darwin: 'tar.xz', + win32: 'zip' + }[platform] +} + +function resolveCommit (platform, version) { + const ext = extForPlatform(platform) + const addrhost = { + linux: 'linux-x86_64', + darwin: 'macos-x86_64', + win32: 'windows-x86_64' + }[platform] + + const downloadUrl = `https://ziglang.org/builds/zig-${addrhost}-${version}.${ext}` + const variantName = `zig-${addrhost}-${version}` + + return { downloadUrl, variantName } +} + +function getJSON (opts) { + return new Promise((resolve, reject) => { + get({ ...opts, json: true }, (err, req, data) => { + if (err) { + reject(err) + } else { + resolve(data) + } + }) + }) +} + +async function resolveVersion (platform, version) { + const ext = extForPlatform(platform) + const host = { + linux: 'x86_64-linux', + darwin: 'x86_64-macos', + win32: 'x86_64-windows' + }[platform] || platform + + const index = await getJSON({ url: 'https://ziglang.org/download/index.json' }) + + const availableVersions = Object.keys(index) + const useVersion = semver.valid(version) + ? semver.maxSatisfying(availableVersions.filter((v) => semver.valid(v)), version) + : null + + const meta = index[useVersion || version] + if (!meta || !meta[host]) { + throw new Error(`Could not find version ${useVersion || version} for platform ${host}`) + } + + const downloadUrl = meta[host].tarball + const variantName = path.basename(meta[host].tarball).replace(`.${ext}`, '') + + return { downloadUrl, variantName } +} + +module.exports = { + extForPlatform, + resolveCommit, + resolveVersion +}