diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0cd529128..0b795c9cd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -91,6 +91,67 @@ jobs: cache: true tag_names: true + + - name: Publish CML cloud runner docker image + if: github.event_name == 'push' && (contains(github.ref, 'tags') || github.ref == 'refs/heads/master') + uses: elgohr/Publish-Docker-Github-Action@master + env: + DOCKER_FROM: cml + with: + name: dvcorg/cml-cloud-runner + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + dockerfile: ./docker/Dockerfile-cloud-runner + context: ./ + cache: true + tag_names: true + buildargs: DOCKER_FROM + + - name: Publish cml-py3 cloud runner docker image + if: github.event_name == 'push' && (contains(github.ref, 'tags') || github.ref == 'refs/heads/master') + uses: elgohr/Publish-Docker-Github-Action@master + env: + DOCKER_FROM: cml-py3 + with: + name: dvcorg/cml-py3-cloud-runner + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + dockerfile: ./docker/Dockerfile-cloud-runner + context: ./ + cache: true + tag_names: true + buildargs: DOCKER_FROM + + - name: Publish cml-gpu cloud runner docker image + if: github.event_name == 'push' && (contains(github.ref, 'tags') || github.ref == 'refs/heads/master') + uses: elgohr/Publish-Docker-Github-Action@master + env: + DOCKER_FROM: cml-gpu + with: + name: dvcorg/cml-gpu-cloud-runner + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + dockerfile: ./docker/Dockerfile-cloud-runner + context: ./ + cache: true + tag_names: true + buildargs: DOCKER_FROM + + - name: Publish cml-gpu-py3 cloud runner docker image + if: github.event_name == 'push' && (contains(github.ref, 'tags') || github.ref == 'refs/heads/master') + uses: elgohr/Publish-Docker-Github-Action@master + env: + DOCKER_FROM: cml-gpu-py3 + with: + name: dvcorg/cml-gpu-py3-cloud-runner + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + dockerfile: ./docker/Dockerfile-cloud-runner + context: ./ + cache: true + tag_names: true + buildargs: DOCKER_FROM + - name: Publish to NPM if: github.event_name == 'push' && (contains(github.ref, 'tags') || github.ref == 'refs/heads/master') run: | diff --git a/bin/cml-cloud-runner-entrypoint.js b/bin/cml-cloud-runner-entrypoint.js new file mode 100644 index 000000000..b99a86df1 --- /dev/null +++ b/bin/cml-cloud-runner-entrypoint.js @@ -0,0 +1,170 @@ +#!/usr/bin/env node + +const { spawn } = require('child_process'); +const { exec, randid } = require('../src/utils'); +const { URL } = require('url'); + +const { + RUNNER_PATH, + + DOCKER_MACHINE, + RUNNER_REPO, + RUNNER_IDLE_TIMEOUT = 5 * 60, + RUNNER_LABELS = '', + RUNNER_NAME = randid(), + RUNNER_EXECUTOR = 'shell', + RUNNER_RUNTIME = '', + RUNNER_IMAGE = 'dvcorg/cml:latest' +} = process.env; + +const { protocol, host, pathname } = new URL(RUNNER_REPO); +const RUNNER_REPO_ORIGIN = `${protocol}//${host}`; +process.env.GITHUB_REPOSITORY = process.env.CI_PROJECT_PATH = pathname.substring( + 1 +); +process.env.CI_API_V4_URL = `${RUNNER_REPO_ORIGIN}/api/v4/`; + +const IS_GITHUB = RUNNER_REPO_ORIGIN === 'https://github.com'; +let TIMEOUT_TIMER = 0; +let JOB_RUNNING = false; +let RUNNER_TOKEN; +let GITLAB_CI_TOKEN; + +const { get_runner_token, register_runner } = IS_GITHUB + ? require('../src/github') + : require('../src/gitlab'); + +const shutdown_docker_machine = async () => { + console.log('Shutting down docker machine'); + try { + DOCKER_MACHINE && + console.log(await exec(`echo y | docker-machine rm ${DOCKER_MACHINE}`)); + } catch (err) { + console.log(err.message); + } +}; + +const shutdown = async error => { + try { + console.log('Unregistering runner'); + + try { + if (IS_GITHUB) { + console.log( + await exec( + `${RUNNER_PATH}/config.sh remove --token "${RUNNER_TOKEN}"` + ) + ); + } else { + console.log(await exec(`gitlab-runner verify --delete`)); + console.log( + await exec( + `gitlab-runner unregister --url "${RUNNER_REPO_ORIGIN}" --token "${GITLAB_CI_TOKEN}" ` + ) + ); + } + } catch (err) {} + + await shutdown_docker_machine(); + + if (error) throw error; + + return process.exit(0); + } catch (err) { + console.error(err); + return process.exit(1); + } +}; + +process.on('SIGTERM', shutdown); +process.on('SIGINT', shutdown); +process.on('SIGQUIT', shutdown); + +const run = async () => { + RUNNER_TOKEN = await get_runner_token(); + if (!RUNNER_TOKEN) { + throw new Error( + 'RUNNER_TOKEN is needed to start the runner. Are you setting a runner?' + ); + } + + if (IS_GITHUB && RUNNER_EXECUTOR !== 'shell') { + throw new Error('Github only supports shell executor'); + } + + console.log(`Starting runner with ${RUNNER_EXECUTOR} executor`); + + let command; + if (IS_GITHUB) { + console.log('Registering Github runner'); + console.log( + await exec( + `${RUNNER_PATH}/config.sh --url "${RUNNER_REPO}" --token "${RUNNER_TOKEN}" --name "${RUNNER_NAME}" --labels "${RUNNER_LABELS}" --work "_work"` + ) + ); + + command = `${RUNNER_PATH}/run.sh`; + } else { + console.log('Registering Gitlab runner'); + const runner = await register_runner({ + tags: RUNNER_LABELS, + token: RUNNER_TOKEN + }); + + GITLAB_CI_TOKEN = runner.token; + + command = `gitlab-runner --log-format="json" run-single \ + --url "https://gitlab.com/" \ + --token "${runner.token}" \ + --executor "${RUNNER_EXECUTOR}" \ + --docker-runtime "${RUNNER_RUNTIME}" \ + --docker-image "${RUNNER_IMAGE}" \ + --wait-timeout ${RUNNER_IDLE_TIMEOUT} \ + --name "${RUNNER_NAME}" \ + --request-concurrency 1 \ + --limit 1`; + } + + const proc = spawn(command, { shell: true }); + + proc.stderr.on('data', data => { + data && console.log(data.toString('utf8')); + + if (data && !IS_GITHUB) { + try { + const { msg } = JSON.parse(data); + msg.includes('runner has not received a job') && shutdown(); + } catch (err) {} + } + }); + + proc.stdout.on('data', async data => { + data && console.log(data.toString('utf8')); + + if (data && IS_GITHUB && data.includes('Running job')) { + JOB_RUNNING = true; + TIMEOUT_TIMER = 0; + } + + if ( + data && + IS_GITHUB && + data.includes('Job') && + data.includes('completed with result') + ) { + JOB_RUNNING = false; + } + }); + + const watcher = setInterval(() => { + IS_GITHUB && + TIMEOUT_TIMER >= RUNNER_IDLE_TIMEOUT && + shutdown() && + clearInterval(watcher); + if (!JOB_RUNNING) TIMEOUT_TIMER++; + }, 1000); +}; + +run().catch(err => { + shutdown(err); +}); diff --git a/docker/Dockerfile-cloud-runner b/docker/Dockerfile-cloud-runner new file mode 100644 index 000000000..5bc628734 --- /dev/null +++ b/docker/Dockerfile-cloud-runner @@ -0,0 +1,27 @@ +ARG DOCKER_FROM=cml + +FROM dvcorg/${DOCKER_FROM}:latest as base + +LABEL maintainer="dvc.org" + +# DOCKER, DOCKER MACHINE, GITLAB RUNNER AND GITHUB RUNNER +ENV RUNNER_PATH=/home/runner +ENV RUNNER_ALLOW_RUNASROOT=1 + +RUN mkdir ${RUNNER_PATH} +WORKDIR ${RUNNER_PATH} + +RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && \ + curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \ + chmod +x /usr/local/bin/docker-compose && \ + curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine && \ + chmod +x /tmp/docker-machine && mv /tmp/docker-machine /usr/local/bin/docker-machine && \ + wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64 && \ + chmod +x /usr/local/bin/gitlab-runner && \ + gitlab-runner install --user=root --working-directory=${RUNNER_PATH} && \ + wget https://github.com/actions/runner/releases/download/v2.263.0/actions-runner-linux-x64-2.263.0.tar.gz && \ + tar xzf actions-runner-linux-x64-2.263.0.tar.gz && \ + ./bin/installdependencies.sh && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +CMD ["cml-cloud-runner-entrypoint"] diff --git a/package-lock.json b/package-lock.json index 58bf0ba25..4fc7ed34f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dvcorg/cml", - "version": "0.1.8", + "version": "0.1.9", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10,9 +10,9 @@ "integrity": "sha512-Wp4xnyokakM45Uuj4WLUxdsa8fJjKVl1fDTsPbTEcTcuu0Nb26IPQbOtjmnfaCPGcaoPOOqId8H9NapZ8gii4w==" }, "@actions/github": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-2.1.1.tgz", - "integrity": "sha512-kAgTGUx7yf5KQCndVeHSwCNZuDBvPyxm5xKTswW2lofugeuC1AZX73nUUVDNaysnM9aKFMHv9YCdVJbg7syEyA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-2.2.0.tgz", + "integrity": "sha512-9UAZqn8ywdR70n3GwVle4N8ALosQs4z50N7XMXrSTUVOmVpaBC5kE3TRTT7qQdi3OaQV24mjGuJZsHUmhD+ZXw==", "requires": { "@actions/http-client": "^1.0.3", "@octokit/graphql": "^4.3.1", @@ -570,41 +570,31 @@ } }, "@octokit/auth-token": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz", - "integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.1.tgz", + "integrity": "sha512-NB81O5h39KfHYGtgfWr2booRxp2bWOJoqbWwbyUg2hw6h35ArWYlAST5B3XwAkbdcx13yt84hFXyFP5X0QToWA==", "requires": { - "@octokit/types": "^2.0.0" + "@octokit/types": "^4.0.1" } }, "@octokit/endpoint": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.1.tgz", - "integrity": "sha512-pOPHaSz57SFT/m3R5P8MUu4wLPszokn5pXcB/pzavLTQf2jbU+6iayTvzaY6/BiotuRS0qyEUkx3QglT4U958A==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.2.tgz", + "integrity": "sha512-xs1mmCEZ2y4shXCpFjNq3UbmNR+bLzxtZim2L0zfEtj9R6O6kc4qLDvYw66hvO6lUsYzPTM5hMkltbuNAbRAcQ==", "requires": { - "@octokit/types": "^2.11.1", + "@octokit/types": "^4.0.1", "is-plain-object": "^3.0.0", "universal-user-agent": "^5.0.0" - }, - "dependencies": { - "universal-user-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", - "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", - "requires": { - "os-name": "^3.1.0" - } - } } }, "@octokit/graphql": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz", - "integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.0.tgz", + "integrity": "sha512-StJWfn0M1QfhL3NKBz31e1TdDNZrHLLS57J2hin92SIfzlOVBuUaRkp31AGkGOAFOAVtyEX6ZiZcsjcJDjeb5g==", "requires": { "@octokit/request": "^5.3.0", - "@octokit/types": "^2.0.0", - "universal-user-agent": "^4.0.0" + "@octokit/types": "^4.0.1", + "universal-user-agent": "^5.0.0" } }, "@octokit/plugin-paginate-rest": { @@ -613,6 +603,16 @@ "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", "requires": { "@octokit/types": "^2.0.1" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "requires": { + "@types/node": ">= 8" + } + } } }, "@octokit/plugin-request-log": { @@ -627,39 +627,39 @@ "requires": { "@octokit/types": "^2.0.1", "deprecation": "^2.3.1" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "requires": { + "@types/node": ">= 8" + } + } } }, "@octokit/request": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.2.tgz", - "integrity": "sha512-zKdnGuQ2TQ2vFk9VU8awFT4+EYf92Z/v3OlzRaSh4RIP0H6cvW1BFPXq4XYvNez+TPQjqN+0uSkCYnMFFhcFrw==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.4.tgz", + "integrity": "sha512-vqv1lz41c6VTxUvF9nM+a6U+vvP3vGk7drDpr0DVQg4zyqlOiKVrY17DLD6de5okj+YLHKcoqaUZTBtlNZ1BtQ==", "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", - "@octokit/types": "^2.11.1", + "@octokit/types": "^4.0.1", "deprecation": "^2.0.0", "is-plain-object": "^3.0.0", "node-fetch": "^2.3.0", "once": "^1.4.0", "universal-user-agent": "^5.0.0" - }, - "dependencies": { - "universal-user-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", - "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", - "requires": { - "os-name": "^3.1.0" - } - } } }, "@octokit/request-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.0.tgz", - "integrity": "sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.1.tgz", + "integrity": "sha512-5lqBDJ9/TOehK82VvomQ6zFiZjPeSom8fLkFVLuYL3sKiIb5RB8iN/lenLkY7oBmyQcGP7FBMGiIZTO8jufaRQ==", "requires": { - "@octokit/types": "^2.0.0", + "@octokit/types": "^4.0.1", "deprecation": "^2.0.0", "once": "^1.4.0" } @@ -696,13 +696,29 @@ "deprecation": "^2.0.0", "once": "^1.4.0" } + }, + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "requires": { + "@types/node": ">= 8" + } + }, + "universal-user-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", + "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", + "requires": { + "os-name": "^3.1.0" + } } } }, "@octokit/types": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.12.2.tgz", - "integrity": "sha512-1GHLI/Jll3j6F0GbYyZPFTcHZMGjAiRfkTEoRUyaVVk2IWbDdwEiClAJvXzfXCDayuGSNCqAUH8lpjZtqW9GDw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.0.2.tgz", + "integrity": "sha512-+4X6qfhT/fk/5FD66395NrFLxCzD6FsGlpPwfwvnukdyfYbhiZB/FJltiT1XM5Q63rGGBSf9FPaNV3WpNHm54A==", "requires": { "@types/node": ">= 8" } @@ -808,9 +824,9 @@ } }, "@types/node": { - "version": "13.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", - "integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==" + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", + "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==" }, "@types/parse-json": { "version": "4.0.0", @@ -7776,9 +7792,9 @@ } }, "universal-user-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", - "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", + "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", "requires": { "os-name": "^3.1.0" } diff --git a/package.json b/package.json index 2c5342827..03b10d012 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dvcorg/cml", - "version": "0.1.8", + "version": "0.1.9", "author": { "name": "DVC", "url": "http://dvc.org" @@ -19,7 +19,8 @@ "cml-send-comment": "./bin/cml-send-comment.js", "cml-send-github-check": "./bin/cml-send-github-check.js", "cml-publish": "./bin/cml-publish.js", - "cml-tensorboard-dev": "./bin/cml-tensorboard-dev.js" + "cml-tensorboard-dev": "./bin/cml-tensorboard-dev.js", + "cml-cloud-runner-entrypoint": "./bin/cml-cloud-runner-entrypoint.js" }, "scripts": { "lintfix": "eslint --fix ./", @@ -42,7 +43,7 @@ }, "dependencies": { "@actions/core": "^1.2.0", - "@actions/github": "^2.0.0", + "@actions/github": "^2.2.0", "canvas": "^2.6.1", "file-type": "^14.2.0", "json-to-markdown-table2": "^1.0.1", diff --git a/src/github.js b/src/github.js index 549454e08..513c0a847 100644 --- a/src/github.js +++ b/src/github.js @@ -88,6 +88,21 @@ const comment = async opts => { ); }; +const get_runner_token = async () => { + const { + data: { token } + } = await octokit.actions.createRegistrationToken({ + owner, + repo + }); + + return token; +}; + +const register_runner = async opts => { + throw new Error('not yet implemented'); +}; + const handle_error = e => { core.setFailed(e.message); }; @@ -103,4 +118,6 @@ exports.ref_parser = ref_parser; exports.check_ran_ref = check_ran_ref; exports.create_check_report = create_check_report; exports.comment = comment; +exports.get_runner_token = get_runner_token; +exports.register_runner = register_runner; exports.handle_error = handle_error; diff --git a/src/gitlab.js b/src/gitlab.js index f53b8476d..e7b7185fe 100644 --- a/src/gitlab.js +++ b/src/gitlab.js @@ -63,6 +63,34 @@ const comment = async opts => { await fetch(endpoint, { method: 'POST', headers, body }); }; +const get_runner_token = async () => { + const endpoint = `${CI_API_V4_URL}/projects/${owner}%2F${repo}`; + const headers = { 'PRIVATE-TOKEN': TOKEN, Accept: 'application/json' }; + const response = await fetch(endpoint, { method: 'GET', headers }); + const project = await response.json(); + + return project.runners_token; +}; + +const register_runner = async opts => { + const endpoint = `${CI_API_V4_URL}/runners`; + + console.log(endpoint); + const headers = { 'PRIVATE-TOKEN': TOKEN, Accept: 'application/json' }; + + const body = new URLSearchParams(); + body.append('token', opts.token); + body.append('locked', 'true'); + body.append('run_untagged', 'true'); + body.append('access_level', 'not_protected'); + body.append('tag_list', opts.tags); + + const response = await fetch(endpoint, { method: 'POST', headers, body }); + const runner = await response.json(); + + return runner; +}; + const handle_error = e => { console.log(e.message); process.exit(1); @@ -79,4 +107,6 @@ exports.ref_parser = ref_parser; exports.project_jobs = project_jobs; exports.check_ran_ref = check_ran_ref; exports.comment = comment; +exports.get_runner_token = get_runner_token; +exports.register_runner = register_runner; exports.handle_error = handle_error; diff --git a/src/utils.js b/src/utils.js index 64b83b82a..abb2a5e20 100644 --- a/src/utils.js +++ b/src/utils.js @@ -52,6 +52,18 @@ const upload = async opts => { return { mime, size, uri }; }; +const randid = () => { + return ( + Math.random() + .toString(36) + .substring(2, 7) + + Math.random() + .toString(36) + .substring(2, 7) + ); +}; + exports.exec = exec; exports.upload = upload; +exports.randid = randid; exports.git = git('./');