From 7e981be58a7988f69a7a1a14580bc08aae9b5e64 Mon Sep 17 00:00:00 2001 From: rs-- Date: Fri, 29 May 2020 21:34:19 -0700 Subject: [PATCH] Create 'Bors try' monitor - Post 'bors try' to a Github PR until a certain number of consecutive passes occur Signed-off-by: Rob Sanchez --- src/bors-retry/Dockerfile | 10 + src/bors-retry/README.md | 111 +++++++++++ src/bors-retry/index.js | 196 +++++++++++++++++++ src/bors-retry/package-lock.json | 316 +++++++++++++++++++++++++++++++ src/bors-retry/package.json | 16 ++ 5 files changed, 649 insertions(+) create mode 100644 src/bors-retry/Dockerfile create mode 100644 src/bors-retry/README.md create mode 100644 src/bors-retry/index.js create mode 100644 src/bors-retry/package-lock.json create mode 100644 src/bors-retry/package.json diff --git a/src/bors-retry/Dockerfile b/src/bors-retry/Dockerfile new file mode 100644 index 0000000..6a9e230 --- /dev/null +++ b/src/bors-retry/Dockerfile @@ -0,0 +1,10 @@ +FROM node:12-alpine + +WORKDIR /usr/src/app +COPY package.json . + +RUN npm install +COPY . . + +EXPOSE 8080 +CMD [ "npm", "start" ] diff --git a/src/bors-retry/README.md b/src/bors-retry/README.md new file mode 100644 index 0000000..f86eeee --- /dev/null +++ b/src/bors-retry/README.md @@ -0,0 +1,111 @@ +Bors Retry Monitor +================= + +Instructions +------------ + +Monitors GitHub pull requests, initiating Bors builds until the desired number of consecutive successful runs (TARGET_RUNS) has been met. + +1. Build the docker container: +``` +docker build -t bors-retry +``` + +2. Run the docker container with the appropriate environment variables: +``` +docker run \ + -e TARGET_RUNS \ + -e SHOULD_START \ + -e GITHUB_AUTH \ + -e GITHUB_ISSUE \ + bors-retry +``` + +The monitor could also be ran as a NodeJS app by setting the appropriate environment variables, and the command `npm start`. + +Required Arguments +----------------- + +GITHUB_AUTH - Personal GitHub access token [(tutorial)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) + +GITHUB_ISSUE - Issue number to monitor + +Optional Arguments +----------------- +TARGET_RUNS - Target # of consecutive successful runs (default: 5) + +SHOULD_START - Start a new monitoring cycle, if previous one is already finished (default: false) + +Monitoring Output +---------------- +``` +{ + date: <[string] timestamp of the monitoring sample>, + issue: <[number] GitHub PR being monitored>, + target: <[number] corresponds with the TARGET_RUNS env variable>, + streak: <[number] number of consecutive success (streak > 0) or failures (streak < 0)> + pending: <[array - string] date of the latest `bors try` request>, + success: <[array - run information] all successful Bors runs>, + failed: , + runs: <[array - run information] all Bors runs>, + completedCycles: <[number] number of completed Bors cycles (a cycle is reaching the targetted number of runs)>, + actions: <[array - string] pending actions for a given monitoring sample>, + monitoringComplete: <[boolean] end of a cycle detected> +} +``` + +Run Information: +``` +{ + start: <[string] timestamp of Bors try request>, + end: <[string] timestamp of completion of Bors try>, + duration: <[number] duration of Bors build in minutes>, + result: <[string] result of the build: 'success' or 'failed'> +} +``` + +Actions: +``` +monitorStart - initiating a cycle +borsTry - initiating a Bors run +``` + +Sample monitoring output: +``` +{ + date: '2020/05/31 06:40:35', + issue: '3083', + target: '5', + pending: [ '2020/05/31 06:11:39' ], + sucess: [ + { + start: '2020/05/30 05:41:09', + end: '2020/05/30 06:18:08', + duration: 36, + result: 'success' + }, + ... + ], + failed: [ + { + start: '2020/05/30 02:21:29', + end: '2020/05/30 03:41:39', + duration: 80, + result: 'failed' + }, + ... + ], + runs: [ + { + start: '2020/05/30 02:21:29', + end: '2020/05/30 03:41:39', + duration: 80, + result: 'failed' + }, + ... + ], + completedCycles: 2, + actions: [], + monitoringComplete: false +} +``` diff --git a/src/bors-retry/index.js b/src/bors-retry/index.js new file mode 100644 index 0000000..2ecae2b --- /dev/null +++ b/src/bors-retry/index.js @@ -0,0 +1,196 @@ +if (!process.env.GITHUB_AUTH || !process.env.GITHUB_ISSUE) { + throw "REQUIRED ENV: GITHUB_AUTH, GITHUB_ISSUE" +} + +const target = process.env.TARGET_RUNS || 5 + shouldStart = process.env.SHOULD_START || false, + githubAuth = process.env.GITHUB_AUTH, + githubIssue = process.env.GITHUB_ISSUE, + pollInterval = 60*1000, + staleBorsRequest = 4, + dateFormat = "YYYY/MM/DD HH:mm:ss"; + +const { Octokit } = require("@octokit/rest"), + moment = require("moment"), + github = new Octokit({ + auth: githubAuth + }); + +const githubActions = { + monitorStart: "===== Bors Monitoring Start =====", + monitorEnd: "===== Bors Monitoring End =====", + borsTry: "bors try" +} + +const writeComment = (comment) => { + const body = githubActions[comment] + console.log(`[Bors Monitor] Commenting: ${body}`); + github.issues.createComment({ + owner: "openenclave", + repo: "openenclave", + issue_number: githubIssue, + body + }); +} + +const monitor = async (targetRuns = 5, createNew = false) => { + + try { + + const data = [], + actions = []; + let page = 1; + while(1) { + const res = await github.issues.listComments({ + owner: "openenclave", + repo: "openenclave", + issue_number: githubIssue, + page + }); + if (res.data.length > 0) { + data.push(...res.data); + } else { + break; + } + page++; + } + + let start = 0, + streak = 0, + end = 0, + allRuns = [], + previousRequests = [], + successfulRuns = [], + failedRuns = []; + + const reset = () => { + streak = 0; + allRuns = []; + previousRequests = []; + successfulRuns = []; + failedRuns = []; + } + const comments = data.map((comment) => { + + const { body, user, created_at } = comment, + { monitorStart, monitorEnd, borsTry } = githubActions, + text = body.trim(), + commentDate = moment(created_at); + + if (text === monitorStart) { + start++; + } else if (text === monitorEnd) { + end++; + if (start === end) { + reset(); + } + } + + if (start > end) { + if (text === borsTry) { + previousRequests.push(commentDate); + } else if (text === "bors try-" && previousRequests.length > 0) { + previousRequests.shift(); + } else if (user.login === "bors[bot]") { + + if (text.includes("Already running a review")) { + previousRequests.shift(); + } else if (previousRequests.length > 0) { + + const prev = previousRequests.shift(), + duration = commentDate.diff(prev,"minutes"), + runDetails = { + start: prev.format(dateFormat), + end: commentDate.format(dateFormat), + duration + }; + + if (text.includes("Build succeeded")) { + runDetails.result = "success"; + successfulRuns.push(runDetails); + allRuns.push(runDetails); + streak = streak > 0 ? streak+1 : 1; + } else if (text.includes("Build failed")) { + runDetails.result = "failed"; + failedRuns.push(runDetails); + allRuns.push(runDetails); + streak = streak < 0 ? streak-1 : -1; + } else { + previousRequests.unshift(prev); + } + } + } + } + + return comment; + }) + + if (start === end) { + if (start === 0 || createNew) { + actions.push("monitorStart"); + start++; + successfulRuns = []; + } else { + console.log("\tMonitoring exiting - SHOULD_START=false"); + return; + } + } + + const pending = previousRequests.length, + totalRuns = allRuns.length, + success = successfulRuns.length, + failed = failedRuns.length, + isCycleRunning = start - end > 0, + noCurrentRuns = pending === 0; + + //console.log(isCycleRunning, noCurrentRuns, success, failed, targetRuns, pending, totalRuns) + if (isCycleRunning && noCurrentRuns && streak < targetRuns) { + actions.push("borsTry"); + } + + const monitoringComplete = streak === targetRuns, + requestDate = moment(), + monitorStatus = { + date: requestDate.format(dateFormat), + issue: githubIssue, + target: targetRuns, + streak, + pending: previousRequests.map((prev) => {return prev.format(dateFormat)}), + sucess: successfulRuns, + failed: failedRuns, + runs: allRuns, + completedCycles: end, + actions, + monitoringComplete + } + + if (pending - totalRuns > 0 && previousRequests.length > 0) { + const lastRequestDate = new moment(previousRequests[0]) + + monitorStatus["lastRequestDate"] = lastRequestDate.format(dateFormat); + monitorStatus["sinceLastRequest"] = requestDate.diff(lastRequestDate,"minutes"); + } + + console.log(monitorStatus) + + if (actions.length > 0) { + actions.forEach((action) => { + writeComment(action); + }); + } + + if (monitoringComplete) { + console.log(`\tMonitoring complete - ${success}/${totalRuns} runs succeeded`); + writeComment(monitorEnd); + return; + } + + setTimeout(() => {monitor(targetRuns)}, pollInterval); + + } catch(e) { + console.log("error:",e); + } + +} + +monitor(target,shouldStart); diff --git a/src/bors-retry/package-lock.json b/src/bors-retry/package-lock.json new file mode 100644 index 0000000..0cc5f59 --- /dev/null +++ b/src/bors-retry/package-lock.json @@ -0,0 +1,316 @@ +{ + "name": "bors-retry", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@octokit/auth-token": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.1.tgz", + "integrity": "sha512-NB81O5h39KfHYGtgfWr2booRxp2bWOJoqbWwbyUg2hw6h35ArWYlAST5B3XwAkbdcx13yt84hFXyFP5X0QToWA==", + "requires": { + "@octokit/types": "^4.0.1" + } + }, + "@octokit/core": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.3.tgz", + "integrity": "sha512-23AHK9xBW0v79Ck8h5U+5iA4MW7aosqv+Yr6uZXolVGNzzHwryNH5wM386/6+etiKUTwLFZTqyMU9oQpIBZcFA==", + "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/graphql": "^4.3.1", + "@octokit/request": "^5.4.0", + "@octokit/types": "^4.0.1", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^5.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.2.tgz", + "integrity": "sha512-xs1mmCEZ2y4shXCpFjNq3UbmNR+bLzxtZim2L0zfEtj9R6O6kc4qLDvYw66hvO6lUsYzPTM5hMkltbuNAbRAcQ==", + "requires": { + "@octokit/types": "^4.0.1", + "is-plain-object": "^3.0.0", + "universal-user-agent": "^5.0.0" + } + }, + "@octokit/graphql": { + "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": "^4.0.1", + "universal-user-agent": "^5.0.0" + } + }, + "@octokit/plugin-paginate-rest": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.1.tgz", + "integrity": "sha512-/tHpIF2XpN40AyhIq295YRjb4g7Q5eKob0qM3thYJ0Z+CgmNsWKM/fWse/SUR8+LdprP1O4ZzSKQE+71TCwK+w==", + "requires": { + "@octokit/types": "^4.0.1" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", + "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==" + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "3.12.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.12.3.tgz", + "integrity": "sha512-9nrVDP1tBd7EtobGr5hZcYGTM0kBNmIvPJazrUd5OJO0NZWiQaQOqAnzApmC9cZ4o7RempV21ScpWkKGhrT51A==", + "requires": { + "@octokit/types": "^4.0.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "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": "^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" + } + }, + "@octokit/request-error": { + "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": "^4.0.1", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "17.9.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-17.9.2.tgz", + "integrity": "sha512-UXxiE0HhGQAPB3WDHTEu7lYMHH2uRcs/9f26XyHpGGiiXht8hgHWEk6fA7WglwwEvnj8V7mkJOgIntnij132UA==", + "requires": { + "@octokit/core": "^2.4.3", + "@octokit/plugin-paginate-rest": "^2.2.0", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "^3.12.2" + } + }, + "@octokit/types": { + "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" + } + }, + "@types/node": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", + "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==" + }, + "before-after-hook": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==" + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "is-plain-object": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "requires": { + "isobject": "^4.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==" + }, + "macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==" + }, + "moment": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", + "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "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" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "windows-release": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.0.tgz", + "integrity": "sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==", + "requires": { + "execa": "^1.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/src/bors-retry/package.json b/src/bors-retry/package.json new file mode 100644 index 0000000..33e0edb --- /dev/null +++ b/src/bors-retry/package.json @@ -0,0 +1,16 @@ +{ + "name": "bors-retry", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@octokit/rest": "^17.9.2", + "moment": "^2.26.0" + } +}