diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de32930..ccc0b46 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,19 +9,41 @@ jobs: fail-fast: false matrix: runs-on: [ubuntu-20.04] - tarantool: ['1.10', '2.4', '2.5', '2.6', '2.7'] + tarantool: + - '1.10' + - '2.4' + - '2.5' + - '2.6' + - '2.7' + - '2.8' include: - {runs-on: ubuntu-18.04, tarantool: '1.10'} - {runs-on: ubuntu-16.04, tarantool: '1.10'} runs-on: ${{ matrix.runs-on }} + env: + TARANTOOL_CACHE_KEY_SUFFIX: -${{ github.run_id }} steps: - uses: actions/checkout@v2 + - id: get-latest + run: | + node <<'SCRIPT' + process.env["INPUT_TARANTOOL-VERSION"] = "${{ matrix.tarantool }}" + require("./dist/main").latest_version().then(v => { + console.log(v) + console.log(`::set-output name=version::${v}`) + }) + SCRIPT + - name: Setup from scratch uses: ./ with: tarantool-version: ${{ matrix.tarantool }} - cache-key: tarantool-${{ matrix.tarantool }}-${{ matrix.runs-on }}-${{ github.run_id }} + + - name: Check precise version + run: | + dpkg -s tarantool | grep '^Version: ${{ steps.get-latest.outputs.version }}' + # It'll also fail if tarantool is installed from cache but not from apt-get - name: Uninstall tarantool run: sudo apt-get -y remove tarantool tarantool-dev tarantool-common @@ -30,9 +52,8 @@ jobs: uses: ./ with: tarantool-version: ${{ matrix.tarantool }} - cache-key: tarantool-${{ matrix.tarantool }}-${{ matrix.runs-on }}-${{ github.run_id }} - - name: Check version + - name: Check branch version run: | T=$(tarantool -e 'print(_TARANTOOL:match("%d+%.%d+")); os.exit()') if [ "$T" != "${{ matrix.tarantool }}" ]; then @@ -48,10 +69,11 @@ jobs: matrix: runs-on: [ubuntu-20.04, ubuntu-20.04, ubuntu-20.04] runs-on: ${{ matrix.runs-on }} + env: + TARANTOOL_CACHE_KEY_SUFFIX: -${{ github.run_id }} steps: - uses: actions/checkout@v2 - name: Setup Tarantool uses: ./ with: tarantool-version: '1.10' - cache-key: test-concurrency-${{ github.run_id }} diff --git a/README.md b/README.md index c4d5e4f..2b33b18 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This action will set up [Tarantool](https://www.tarantool.io) environment and ** - When cached, it takes \~1-2s to finish. - The first run takes \~40s. - Cache size is \~20MB. -- Runs on `ubuntu-*` only. +- Runs on GitHub-hosted `ubuntu-*` runners only. # Usage @@ -18,28 +18,12 @@ steps: - uses: actions/checkout@v2 - uses: tarantool/setup-tarantool@v1 with: - tarantool-version: '2.5' + tarantool-version: '2.6' - run: tarantoolctl rocks install luatest - run: tarantoolctl rocks make - run: .rocks/bin/luatest -v ``` -### Custom cache key - -By default, the action caches installed apt packages with the key: - -```tarantool-setup-${tarantool-version}-${ubuntu-version}``` - -If you need to drop the cache, it's customizable: - -```yaml -steps: - - uses: tarantool/setup-tarantool@v1 - with: - tarantool-version: 2.5 - cache-key: some-other-key -``` - # License The scripts and documentation in this project are released under the [MIT License](LICENSE). diff --git a/action.yml b/action.yml index 537004d..ea0529a 100644 --- a/action.yml +++ b/action.yml @@ -7,8 +7,8 @@ inputs: tarantool-version: description: Tarantool version cache-key: - description: Custom key used for APT packages caching + description: Deprecated. Custom key used for APT packages caching required: false runs: using: 'node12' - main: dist/main/index.js + main: dist/index.js diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..d2ac215 --- /dev/null +++ b/dist/index.js @@ -0,0 +1 @@ +require("./main").run() diff --git a/dist/main/index.js b/dist/main/index.js index 0751e2c..c9bfd90 100644 --- a/dist/main/index.js +++ b/dist/main/index.js @@ -3392,6 +3392,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.run = exports.latest_version = void 0; const httpm = __importStar(__webpack_require__(539)); const cache = __importStar(__webpack_require__(692)); const core = __importStar(__webpack_require__(470)); @@ -3399,6 +3400,8 @@ const exec = __importStar(__webpack_require__(986)); const io = __importStar(__webpack_require__(1)); const path = __importStar(__webpack_require__(622)); const fs = __importStar(__webpack_require__(747)); +const baseUrl = 'https://download.tarantool.org/tarantool/release/' + + core.getInput('tarantool-version', { required: true }); async function capture(cmd, options) { let output = ''; await exec.exec(cmd, [], { @@ -3411,6 +3414,21 @@ async function capture(cmd, options) { }); return output.trim(); } +let _lsb_release; +async function lsb_release() { + if (!_lsb_release) { + _lsb_release = capture('lsb_release -c -s', { silent: true }); + } + return _lsb_release; +} +let _httpc; +async function http_get(url) { + if (!_httpc) { + _httpc = new httpm.HttpClient('httpc'); + } + core.info('HTTP GET ' + url); + return _httpc.get(url); +} async function dpkg_list() { const cmd = 'sudo dpkg-query -W -f "${binary:Package}\\n"'; const output = await capture(cmd, { silent: true }); @@ -3418,14 +3436,62 @@ async function dpkg_list() { output.split('\n').forEach(l => ret.add(l)); return ret; } +function semver_max(a, b) { + const re = /[.-]/; + var pa = a.split(re); + var pb = b.split(re); + for (var i = 0;; i++) { + var na = Number(pa[i]); + var nb = Number(pb[i]); + if (na > nb) + return a; + if (nb > na) + return b; + if (!isNaN(na) && isNaN(nb)) + return a; + if (isNaN(na) && !isNaN(nb)) + return b; + if (isNaN(na) && isNaN(nb)) + return pa[i] >= pb[i] ? a : b; + } +} +async function latest_version() { + const repo = baseUrl + '/ubuntu/dists/' + (await lsb_release()); + return http_get(`${repo}/main/binary-amd64/Packages`) + .then(response => { + if (response.message.statusCode !== 200) { + throw new Error(`server replied ${response.message.statusCode}`); + } + return response.readBody(); + }) + .then(output => { + let ret = ''; + output + .split('\n\n') + .filter(paragraph => paragraph.startsWith('Package: tarantool\n')) + .forEach(paragraph => { + const match = paragraph.match(/^Version: (.+)$/m); + const version = match ? match[1] : ret; + ret = semver_max(ret, version); + }); + return ret; + }); +} +exports.latest_version = latest_version; async function run_linux() { try { - const httpc = new httpm.HttpClient('httpc'); - const t_version = core.getInput('tarantool-version', { required: true }); - const lsb_release = await capture('lsb_release -c -s', { silent: true }); + const distro = await lsb_release(); const cache_dir = 'cache-tarantool'; - const cache_key = core.getInput('cache-key') || - `tarantool-setup-${t_version}-${lsb_release}`; + core.startGroup('Checking latest tarantool version'); + const version = await latest_version(); + core.info(`${version}`); + core.endGroup(); + if (core.getInput('cache-key')) { + core.warning("Setup-tarantool input 'cache-key' is deprecated"); + } + let cache_key = `tarantool-setup-${distro}-${version}`; + // This for testing only + cache_key += process.env['TARANTOOL_CACHE_KEY_SUFFIX'] || ''; if (await cache.restoreCache([cache_dir], cache_key)) { core.info(`Cache restored from key: ${cache_key}`); await exec.exec(`sudo rsync -aK "${cache_dir}/" /`); @@ -3435,20 +3501,17 @@ async function run_linux() { else { core.info(`Cache not found for input key: ${cache_key}`); } - const baseUrl = 'https://download.tarantool.org/tarantool/release/' + t_version; await core.group('Adding gpg key', async () => { - const url = baseUrl + '/gpgkey'; - core.info('curl ' + url); - const response = await httpc.get(url); + const response = await http_get(baseUrl + '/gpgkey'); if (response.message.statusCode !== 200) { - throw new Error('server replied ${response.message.statusCode}'); + throw new Error(`server replied ${response.message.statusCode}`); } const gpgkey = Buffer.from(await response.readBody()); await exec.exec('sudo apt-key add - ', [], { input: gpgkey }); }); await core.group('Setting up repository', async () => { await exec.exec('sudo tee /etc/apt/sources.list.d/tarantool.list', [], { - input: Buffer.from(`deb ${baseUrl}/ubuntu/ ${lsb_release} main\n`) + input: Buffer.from(`deb ${baseUrl}/ubuntu/ ${distro} main\n`) }); }); await core.group('Running apt-get update', async () => { @@ -3495,8 +3558,7 @@ async function run() { } await exec.exec('tarantool --version'); } -run(); -exports.default = run; +exports.run = run; /***/ }), diff --git a/src/main.ts b/src/main.ts index eb4e12d..7319819 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,10 @@ import * as io from '@actions/io' import * as path from 'path' import * as fs from 'fs' +const baseUrl = + 'https://download.tarantool.org/tarantool/release/' + + core.getInput('tarantool-version', {required: true}) + interface CaptureOptions { /** optional. defaults to false */ silent?: boolean @@ -27,6 +31,24 @@ async function capture(cmd: string, options?: CaptureOptions): Promise { return output.trim() } +let _lsb_release: Promise +async function lsb_release(): Promise { + if (!_lsb_release) { + _lsb_release = capture('lsb_release -c -s', {silent: true}) + } + + return _lsb_release +} + +let _httpc: httpm.HttpClient +async function http_get(url: string): Promise { + if (!_httpc) { + _httpc = new httpm.HttpClient('httpc') + } + core.info('HTTP GET ' + url) + return _httpc.get(url) +} + async function dpkg_list(): Promise> { const cmd = 'sudo dpkg-query -W -f "${binary:Package}\\n"' const output: string = await capture(cmd, {silent: true}) @@ -36,15 +58,60 @@ async function dpkg_list(): Promise> { return ret } +function semver_max(a: string, b: string): string { + const re = /[.-]/ + var pa = a.split(re) + var pb = b.split(re) + for (var i = 0; ; i++) { + var na = Number(pa[i]) + var nb = Number(pb[i]) + if (na > nb) return a + if (nb > na) return b + if (!isNaN(na) && isNaN(nb)) return a + if (isNaN(na) && !isNaN(nb)) return b + if (isNaN(na) && isNaN(nb)) return pa[i] >= pb[i] ? a : b + } +} + +export async function latest_version(): Promise { + const repo = baseUrl + '/ubuntu/dists/' + (await lsb_release()) + return http_get(`${repo}/main/binary-amd64/Packages`) + .then(response => { + if (response.message.statusCode !== 200) { + throw new Error(`server replied ${response.message.statusCode}`) + } + return response.readBody() + }) + .then(output => { + let ret = '' + output + .split('\n\n') + .filter(paragraph => paragraph.startsWith('Package: tarantool\n')) + .forEach(paragraph => { + const match = paragraph.match(/^Version: (.+)$/m) + const version = match ? match[1] : ret + ret = semver_max(ret, version) + }) + return ret + }) +} + async function run_linux(): Promise { try { - const httpc = new httpm.HttpClient('httpc') - const t_version = core.getInput('tarantool-version', {required: true}) - const lsb_release = await capture('lsb_release -c -s', {silent: true}) + const distro = await lsb_release() const cache_dir = 'cache-tarantool' - const cache_key = - core.getInput('cache-key') || - `tarantool-setup-${t_version}-${lsb_release}` + + core.startGroup('Checking latest tarantool version') + const version = await latest_version() + core.info(`${version}`) + core.endGroup() + + if (core.getInput('cache-key')) { + core.warning("Setup-tarantool input 'cache-key' is deprecated") + } + let cache_key = `tarantool-setup-${distro}-${version}` + // This for testing only + cache_key += process.env['TARANTOOL_CACHE_KEY_SUFFIX'] || '' if (await cache.restoreCache([cache_dir], cache_key)) { core.info(`Cache restored from key: ${cache_key}`) @@ -55,16 +122,10 @@ async function run_linux(): Promise { core.info(`Cache not found for input key: ${cache_key}`) } - const baseUrl = - 'https://download.tarantool.org/tarantool/release/' + t_version - await core.group('Adding gpg key', async () => { - const url = baseUrl + '/gpgkey' - core.info('curl ' + url) - - const response = await httpc.get(url) + const response = await http_get(baseUrl + '/gpgkey') if (response.message.statusCode !== 200) { - throw new Error('server replied ${response.message.statusCode}') + throw new Error(`server replied ${response.message.statusCode}`) } const gpgkey = Buffer.from(await response.readBody()) @@ -73,7 +134,7 @@ async function run_linux(): Promise { await core.group('Setting up repository', async () => { await exec.exec('sudo tee /etc/apt/sources.list.d/tarantool.list', [], { - input: Buffer.from(`deb ${baseUrl}/ubuntu/ ${lsb_release} main\n`) + input: Buffer.from(`deb ${baseUrl}/ubuntu/ ${distro} main\n`) }) }) @@ -121,7 +182,7 @@ async function run_linux(): Promise { } } -async function run(): Promise { +export async function run(): Promise { if (process.platform === 'linux') { await run_linux() } else { @@ -130,7 +191,3 @@ async function run(): Promise { await exec.exec('tarantool --version') } - -run() - -export default run