diff --git a/.github/actions/latest-version/action.yml b/.github/actions/latest-version/action.yml new file mode 100644 index 0000000..0bc2b81 --- /dev/null +++ b/.github/actions/latest-version/action.yml @@ -0,0 +1,94 @@ +# This action is supposed to be used in setup-tarantool CI. +# +# It determines the latest tarantool version available in the +# repository defined by the input parameters. +# +# The output values represent the tarantool version in different +# forms for convenience. +# +# Usage example: +# +# - steps: +# - id: latest_version +# uses: ./.github/actions/latest-version +# with: +# tarantool-series: '1.10' # don't miss quotes! +# +# - run: echo ${{ steps.latest-version.outputs.package }} +# # ---> 1.10.13.0.g1d2c5aad5-1 +# - run: echo ${{ steps.latest-version.outputs.abc }} +# # ---> 1.10.13 +# - run: echo ${{ steps.latest-version.outputs.abcd }} +# # ---> 1.10.13.0 +# - run: echo ${{ steps.latest-version.outputs.abc-d }} +# # ---> 1.10.13-0 +# - run: echo ${{ steps.latest-version.outputs.git-describe }} +# # ---> 1.10.13-0-g1d2c5aad5 + +name: 'Latest tarantool version' +description: 'Get latest tarantool version of given release series' +inputs: + tarantool-series: + description: 'Tarantool release series' + required: true + nightly-build: + description: 'Whether to look into a repository with nightly builds' + required: false + default: false +outputs: + package: + description: 'Latest tarantool version in the Debian package format' + value: ${{ steps.get-latest-version.outputs.package }} + abc: + description: 'Latest tarantool version in the A.B.C form' + value: ${{ steps.get-latest-version.outputs.abc }} + abcd: + description: 'Latest tarantool version in the A.B.C.D form' + value: ${{ steps.get-latest-version.outputs.abcd }} + abc-d: + description: 'Latest tarantool version in the A.B.C-D form' + value: ${{ steps.get-latest-version.outputs.abc-d }} + git-describe: + description: 'Latest tarantool version in the A.B.C-D-gHHHHHHHHH form' + value: ${{ steps.get-latest-version.outputs.git-describe }} +runs: + using: 'composite' + steps: + - id: get-latest-version + run: | + node <<'SCRIPT' + process.env['INPUT_TARANTOOL-VERSION'] = '${{ inputs.tarantool-series }}' + process.env['INPUT_NIGHTLY-BUILD'] = '${{ inputs.nightly-build }}' + require('./dist/main').latest_version().then(v => { + console.log(`package: ${v}`) + console.log(`::set-output name=package::${v}`) + + /* + * 1.10.13.0.g1d2c5aad5-1 + * -> + * parts[0]: '1' + * parts[1]: '10' + * parts[2]: '13' + * parts[3]: '0' + * parts[4]: 'g1d2c5aad5' + * parts[5]: '1' + */ + var parts = v.split(/[.-]/) + + var abc = parts.slice(0, 3).join('.') + var abcd = `${abc}.${parts[3]}` + var abc_d = `${abc}-${parts[3]}` + var git_describe = `${abc_d}-${parts[4]}` + + console.log(`abc: ${abc}`) + console.log(`abcd: ${abcd}`) + console.log(`abc-d: ${abc_d}`) + console.log(`git-describe: ${git_describe}`) + + console.log(`::set-output name=abc::${abc}`) + console.log(`::set-output name=abcd::${abcd}`) + console.log(`::set-output name=abc-d::${abc_d}`) + console.log(`::set-output name=git-describe::${git_describe}`) + }) + SCRIPT + shell: bash diff --git a/.github/actions/verify-version/action.yml b/.github/actions/verify-version/action.yml new file mode 100644 index 0000000..f8aefcb --- /dev/null +++ b/.github/actions/verify-version/action.yml @@ -0,0 +1,49 @@ +# This action is supposed to be used in setup-tarantool CI. +# +# It verifies currently installed tarantool against two +# properties: +# +# 1. Tarantool version matches provided version prefix. +# 2. Tarantool is installed by apt-get/from cache. +# +# Usage example: +# +# - steps: +# - uses: ./.github/actions/verify-version +# with: +# tarantool-version: '1.10.12' # don't miss quotes! +# from-cache: false + +name: 'Verify tarantool version' +description: 'Verify that installed tarantool has given version' +inputs: + tarantool-version: + description: 'Expected tarantool version (version string prefix)' + required: true + from-cache: + description: 'Expect tarantool from cache or from apt-get (if omitted, does not perform the check)' + required: false + default: '' +runs: + using: 'composite' + steps: + - name: Verify tarantool version + run: | + tarantool -e "assert(_TARANTOOL:startswith('${{ inputs.tarantool-version }}'), _TARANTOOL)" + shell: bash + + - name: Verify that tarantool is installed from the cache + run: | + if dpkg --status tarantool; then + echo "Tarantool is installed by apt-get, but it is expected that" + echo "tarantool will be installed from the cache" + exit 1 + fi + if: inputs.from-cache == 'true' + shell: bash + + - name: Verify that tarantool is installed by apt-get (not from the cache) + run: | + dpkg --status tarantool + if: inputs.from-cache == 'false' + shell: bash diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ef700c4..c7ffec9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -90,3 +90,214 @@ jobs: uses: ./ with: tarantool-version: '1.10' + + # This test case performs basic test of the three digit version + # support. + # + # It performs the following steps and checks. + # + # - install 1.10.12 + # - checks: version, non-cached + # - uninstall tarantool + # - install 1.10.12 + # - checks: version, cached + # - install 1.10.LATEST + # - checks: version, non-cached + test-exact-version-basic: + runs-on: ubuntu-latest + env: + TARANTOOL_CACHE_KEY_SUFFIX: -C-${{ github.run_id }} + steps: + - uses: actions/checkout@v2 + + - id: latest-version + uses: ./.github/actions/latest-version + with: + tarantool-series: '1.10' + + - name: Install 1.10.12 (non-cached) + uses: ./ + with: + tarantool-version: '1.10.12' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '1.10.12-0' + from-cache: false + + - name: Uninstall tarantool + run: sudo apt-get -y remove tarantool tarantool-dev tarantool-common + + - name: Install 1.10.12 (cached) + uses: ./ + with: + tarantool-version: '1.10.12' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '1.10.12-0' + from-cache: true + + - name: Install 1.10.LATEST (non-cached) + uses: ./ + with: + tarantool-version: '${{ steps.latest-version.outputs.abc }}' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: false + + # This test case verifies that a two digit version is installed + # without any problem after a three digit version (not a latest + # one). + # + # - install 1.10.12 + # - checks: version, non-cached + # - uninstall tarantool + # - install 1.10 + # - checks: version, non-cached + test-exact-version-then-two-digit-version: + runs-on: ubuntu-latest + env: + TARANTOOL_CACHE_KEY_SUFFIX: -D-${{ github.run_id }} + steps: + - uses: actions/checkout@v2 + + - id: latest-version + uses: ./.github/actions/latest-version + with: + tarantool-series: '1.10' + + - name: Install 1.10.12 (non-cached) + uses: ./ + with: + tarantool-version: '1.10.12' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '1.10.12-0' + from-cache: false + + - name: Uninstall tarantool + run: sudo apt-get -y remove tarantool tarantool-dev tarantool-common + + - name: Install 1.10 (non-cached) + uses: ./ + with: + tarantool-version: '1.10' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: false + + # This test case verifies that a two digit version is installed + # without any problem after a three digit version (the latest + # one). + # + # - install 1.10.LATEST + # - checks: version, non-cached + # - uninstall tarantool + # - install 1.10 + # - checks: version, cached + test-exact-version-latest-then-two-digit-version: + runs-on: ubuntu-latest + env: + TARANTOOL_CACHE_KEY_SUFFIX: -E-${{ github.run_id }} + steps: + - uses: actions/checkout@v2 + + - id: latest-version + uses: ./.github/actions/latest-version + with: + tarantool-series: '1.10' + + - name: Install 1.10.LATEST (non-cached) + uses: ./ + with: + tarantool-version: '${{ steps.latest-version.outputs.abc }}' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: false + + - name: Uninstall tarantool + run: sudo apt-get -y remove tarantool tarantool-dev tarantool-common + + - name: Install 1.10 (cached) + uses: ./ + with: + tarantool-version: '1.10' + nightly-build: false + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: true + + # This test case performs basic test of four digit version + # support (for nightly repositories). + # + # - install 1.10.LATEST.LATEST (nightly) + # - checks: version, non-cached + # - uninstall tarantool + # - install 1.10.LATEST (nightly) + # - checks: version, cached + # - install 1.10 (nightly) + # - checks: version, cached + test-exact-version-nightly: + runs-on: ubuntu-latest + env: + TARANTOOL_CACHE_KEY_SUFFIX: -F-${{ github.run_id }} + steps: + - uses: actions/checkout@v2 + + - id: latest-version + uses: ./.github/actions/latest-version + with: + tarantool-series: '1.10' + nightly-build: true + + - name: Install 1.10.LATEST.LATEST (nightly, non-cached) + uses: ./ + with: + tarantool-version: '${{ steps.latest-version.outputs.abcd }}' + nightly-build: true + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: false + + - name: Uninstall tarantool + run: sudo apt-get -y remove tarantool tarantool-dev tarantool-common + + - name: Install 1.10.LATEST (nightly, cached) + uses: ./ + with: + tarantool-version: '1.10' + nightly-build: true + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: true + + - name: Install 1.10 (nightly, cached) + uses: ./ + with: + tarantool-version: '1.10' + nightly-build: true + + - uses: ./.github/actions/verify-version + with: + tarantool-version: '${{ steps.latest-version.outputs.git-describe }}' + from-cache: true diff --git a/README.md b/README.md index dd637cb..95fa16b 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,16 @@ steps: - run: .rocks/bin/luatest -v ``` +### Install an exact version + +``` +steps: + - uses: actions/checkout@v2 + - uses: tarantool/setup-tarantool@v1 + with: + tarantool-version: '2.6.1' +``` + ### Install a nightly build ```yaml @@ -31,7 +41,7 @@ steps: - uses: actions/checkout@v2 - uses: tarantool/setup-tarantool@v1 with: - tarantool-version: '2.6' + tarantool-version: '2.6' # or, say, '2.6.1.0' for exact version nightly-build: true ``` diff --git a/dist/main/index.js b/dist/main/index.js index 672faa6..01100cd 100644 --- a/dist/main/index.js +++ b/dist/main/index.js @@ -58023,9 +58023,11 @@ const io = __importStar(__nccwpck_require__(7436)); const path = __importStar(__nccwpck_require__(1017)); const fs = __importStar(__nccwpck_require__(7147)); const nightlyBuild = (core.getInput('nightly-build') || 'false').toUpperCase() === 'TRUE'; +const tarantool_version = core.getInput('tarantool-version', { required: true }); +const tarantool_series = tarantool_version.split('.', 2).join('.'); const baseUrl = 'https://download.tarantool.org/tarantool/' + (nightlyBuild ? '' : 'release/') + - core.getInput('tarantool-version', { required: true }); + tarantool_series; async function capture(cmd, options) { let output = ''; await exec.exec(cmd, [], { @@ -58079,8 +58081,10 @@ function semver_max(a, b) { return pa[i] >= pb[i] ? a : b; } } -async function latest_version() { +async function available_versions(version_prefix) { const repo = baseUrl + '/ubuntu/dists/' + (await lsb_release()); + // Don't return 1.10.10, when the version prefix is 1.10.1. + const prefix = version_prefix ? version_prefix + '.' : ''; return http_get(`${repo}/main/binary-amd64/Packages`) .then(response => { if (response.message.statusCode !== 200) { @@ -58089,16 +58093,29 @@ async function latest_version() { return response.readBody(); }) .then(output => { - let ret = ''; + let versions = new Array(); 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); + if (match) { + let v = match[1]; + if (!prefix || v.startsWith(prefix)) { + versions.push(v); + } + } + }); + return versions; + }); +} +async function latest_version(version_prefix) { + return available_versions(version_prefix).then(versions => { + let max = ''; + versions.forEach(v => { + max = semver_max(max, v); }); - return ret; + return max; }); } exports.latest_version = latest_version; @@ -58106,8 +58123,8 @@ async function run_linux() { try { const distro = await lsb_release(); const cache_dir = 'cache-tarantool'; - core.startGroup('Checking latest tarantool version'); - const version = await latest_version(); + core.startGroup(`Checking latest tarantool ${tarantool_version} version`); + const version = await latest_version(tarantool_version); core.info(`${version}`); core.endGroup(); if (core.getInput('cache-key')) { @@ -58143,7 +58160,7 @@ async function run_linux() { }); core.startGroup('Installing tarantool'); const dpkg_before = await dpkg_list(); - await exec.exec('sudo apt-get install -y tarantool tarantool-dev'); + await exec.exec(`sudo apt-get install -y tarantool=${version}* tarantool-dev=${version}*`); const dpkg_after = await dpkg_list(); const dpkg_diff = Array.from(dpkg_after.values()).filter(pkg => !dpkg_before.has(pkg)); core.endGroup(); diff --git a/src/main.ts b/src/main.ts index 759d878..34ba98b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,10 +9,12 @@ import * as fs from 'fs' const nightlyBuild = (core.getInput('nightly-build') || 'false').toUpperCase() === 'TRUE' +const tarantool_version = core.getInput('tarantool-version', {required: true}) +const tarantool_series = tarantool_version.split('.', 2).join('.') const baseUrl = 'https://download.tarantool.org/tarantool/' + (nightlyBuild ? '' : 'release/') + - core.getInput('tarantool-version', {required: true}) + tarantool_series interface CaptureOptions { /** optional. defaults to false */ @@ -76,8 +78,14 @@ function semver_max(a: string, b: string): string { } } -export async function latest_version(): Promise { +async function available_versions( + version_prefix: string +): Promise> { const repo = baseUrl + '/ubuntu/dists/' + (await lsb_release()) + + // Don't return 1.10.10, when the version prefix is 1.10.1. + const prefix = version_prefix ? version_prefix + '.' : '' + return http_get(`${repo}/main/binary-amd64/Packages`) .then(response => { if (response.message.statusCode !== 200) { @@ -86,17 +94,31 @@ export async function latest_version(): Promise { return response.readBody() }) .then(output => { - let ret = '' + let versions = new Array() 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) + if (match) { + let v = match[1] + if (!prefix || v.startsWith(prefix)) { + versions.push(v) + } + } }) - return ret + return versions + }) +} + +export async function latest_version(version_prefix: string): Promise { + return available_versions(version_prefix).then(versions => { + let max = '' + versions.forEach(v => { + max = semver_max(max, v) }) + return max + }) } async function run_linux(): Promise { @@ -104,11 +126,10 @@ async function run_linux(): Promise { const distro = await lsb_release() const cache_dir = 'cache-tarantool' - core.startGroup('Checking latest tarantool version') - const version = await latest_version() + core.startGroup(`Checking latest tarantool ${tarantool_version} version`) + const version = await latest_version(tarantool_version) core.info(`${version}`) core.endGroup() - if (core.getInput('cache-key')) { core.warning("Setup-tarantool input 'cache-key' is deprecated") } @@ -148,7 +169,9 @@ async function run_linux(): Promise { core.startGroup('Installing tarantool') const dpkg_before = await dpkg_list() - await exec.exec('sudo apt-get install -y tarantool tarantool-dev') + await exec.exec( + `sudo apt-get install -y tarantool=${version}* tarantool-dev=${version}*` + ) const dpkg_after = await dpkg_list() const dpkg_diff: Array = Array.from(dpkg_after.values()).filter(