const core = require("@actions/core"); const path = require("path"); const fs = require("fs"); const github = require("@actions/github"); const glob = require("glob"); function sleep(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds)); } async function runOnce() { // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*` const files = core.getInput("files"); const name = core.getInput("name"); const token = core.getInput("token"); const slug = process.env.GITHUB_REPOSITORY; const owner = slug.split("/")[0]; const repo = slug.split("/")[1]; const sha = process.env.HEAD_SHA; core.info(`files: ${files}`); core.info(`name: ${name}`); const options = { request: { timeout: 30000, }, }; const octokit = github.getOctokit(token, options); // Delete the previous release since we can't overwrite one. This may happen // due to retrying an upload or it may happen because we're doing the dev // release. const releases = await octokit.paginate("GET /repos/:owner/:repo/releases", { owner, repo }); for (const release of releases) { if (release.tag_name !== name) { continue; } const release_id = release.id; core.info(`deleting release ${release_id}`); await octokit.rest.repos.deleteRelease({ owner, repo, release_id }); } // We also need to update the `dev` tag while we're at it on the `dev` branch. if (name == "nightly") { try { core.info(`updating nightly tag`); await octokit.rest.git.updateRef({ owner, repo, ref: "tags/nightly", sha, force: true, }); } catch (e) { core.error(e); core.info(`creating nightly tag`); await octokit.rest.git.createTag({ owner, repo, tag: "nightly", message: "nightly release", object: sha, type: "commit", }); } } // Creates an official GitHub release for this `tag`, and if this is `dev` // then we know that from the previous block this should be a fresh release. core.info(`creating a release`); const release = await octokit.rest.repos.createRelease({ owner, repo, name, tag_name: name, target_commitish: sha, prerelease: name === "nightly", }); const release_id = release.data.id; // Upload all the relevant assets for this release as just general blobs. for (const file of glob.sync(files)) { const size = fs.statSync(file).size; const name = path.basename(file); await runWithRetry(async function () { // We can't overwrite assets, so remove existing ones from a previous try. let assets = await octokit.rest.repos.listReleaseAssets({ owner, repo, release_id, }); for (const asset of assets.data) { if (asset.name === name) { core.info(`delete asset ${name}`); const asset_id = asset.id; await octokit.rest.repos.deleteReleaseAsset({ owner, repo, asset_id }); } } core.info(`upload ${file}`); const headers = { "content-length": size, "content-type": "application/octet-stream" }; const data = fs.createReadStream(file); await octokit.rest.repos.uploadReleaseAsset({ data, headers, name, url: release.data.upload_url, }); }); } } async function runWithRetry(f) { const retries = 10; const maxDelay = 4000; let delay = 1000; for (let i = 0; i < retries; i++) { try { await f(); break; } catch (e) { if (i === retries - 1) throw e; core.error(e); const currentDelay = Math.round(Math.random() * delay); core.info(`sleeping ${currentDelay} ms`); await sleep(currentDelay); delay = Math.min(delay * 2, maxDelay); } } } async function run() { await runWithRetry(runOnce); } run().catch((err) => { core.error(err); core.setFailed(err.message); });