diff --git a/packages/snippet-bot/README.md b/packages/snippet-bot/README.md index ee7092e1f62..94f3b87528b 100644 --- a/packages/snippet-bot/README.md +++ b/packages/snippet-bot/README.md @@ -2,7 +2,9 @@ Instructions are provided in [googleapis/repo-automation-bots](https://github.com/googleapis/repo-automation-bots/blob/master/README.md) for deploying and testing your bots. -This bot needs read/write permissions on PRs and Checks. +This bot needs read/write permissions on PRs and Checks. Also make sure that the bot is listening to webhooks for PRs. + +After installing the bot, you have to have `.github/snippet-bot.yml` for actually enabling it. This bot uses nock for mocking requests to GitHub, and snap-shot-it for capturing responses; This allows updates to the API surface to be treated as a visual diff, rather than tediously asserting against each field. diff --git a/packages/snippet-bot/__snapshots__/snippet-bot.js b/packages/snippet-bot/__snapshots__/snippet-bot.js index 0434ba78d66..e8aa9065e4c 100644 --- a/packages/snippet-bot/__snapshots__/snippet-bot.js +++ b/packages/snippet-bot/__snapshots__/snippet-bot.js @@ -10,20 +10,6 @@ exports['snippet-bot responds to PR sets a "failure" context on PR 1'] = { }, }; -exports[ - 'snippet-bot responds to PR sets a "failure" context on PR even when it failed to read the config 1' -] = { - name: 'Mismatched region tag', - conclusion: 'failure', - head_sha: 'ce03c1b7977aadefb5f6afc09901f106ee6ece6a', - output: { - title: 'Mismatched region tag detected.', - summary: 'Some new files have mismatched region tag', - text: - "test.py:5, tag `hello` has already started\ntest.py:10, tag `lol` doesn't have a matching start tag\ntest.py:8, tag `world` doesn't have a matching end tag", - }, -}; - exports[ 'snippet-bot responds to PR sets a "success" context on PR by ignoreFile 1' ] = { diff --git a/packages/snippet-bot/package-lock.json b/packages/snippet-bot/package-lock.json index 3959c5959db..25b596509cd 100644 --- a/packages/snippet-bot/package-lock.json +++ b/packages/snippet-bot/package-lock.json @@ -248,19 +248,6 @@ "@octokit/types": "^5.0.0" } }, - "@octokit/core": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.1.2.tgz", - "integrity": "sha512-AInOFULmwOa7+NFi9F8DlDkm5qtZVmDQayi7TUgChE3yeIGPq0Y+6cAEXPexQ3Ea+uZy66hKEazR7DJyU+4wfw==", - "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/graphql": "^4.3.1", - "@octokit/request": "^5.4.0", - "@octokit/types": "^5.0.0", - "before-after-hook": "^2.1.0", - "universal-user-agent": "^6.0.0" - } - }, "@octokit/endpoint": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.5.tgz", @@ -291,11 +278,21 @@ } }, "@octokit/plugin-paginate-rest": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.3.0.tgz", - "integrity": "sha512-Ye2ZJreP0ZlqJQz8fz+hXvrEAEYK4ay7br1eDpWzr6j76VXs/gKqxFcH8qRzkB3fo/2xh4Vy9VtGii4ZDc9qlA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", + "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", "requires": { - "@octokit/types": "^5.2.0" + "@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": { @@ -304,12 +301,22 @@ "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==" }, "@octokit/plugin-rest-endpoint-methods": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.2.tgz", - "integrity": "sha512-PTI7wpbGEZ2IR87TVh+TNWaLcgX/RsZQalFbQCq8XxYUrQ36RHyERrHSNXFy5gkWpspUAOYRSV707JJv6BhqJA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", + "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", "requires": { - "@octokit/types": "^5.1.1", + "@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/plugin-retry": { @@ -356,14 +363,54 @@ } }, "@octokit/rest": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.3.tgz", - "integrity": "sha512-GubgemnLvUJlkhouTM2BtX+g/voYT/Mqh0SASGwTnLvSkW1irjt14N911/ABb6m1Hru0TwScOgFgMFggp3igfQ==", + "version": "16.43.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", "requires": { - "@octokit/core": "^3.0.0", - "@octokit/plugin-paginate-rest": "^2.2.0", + "@octokit/auth-token": "^2.4.0", + "@octokit/plugin-paginate-rest": "^1.1.1", "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "4.1.2" + "@octokit/plugin-rest-endpoint-methods": "2.4.0", + "@octokit/request": "^5.2.0", + "@octokit/request-error": "^1.0.2", + "atob-lite": "^2.0.0", + "before-after-hook": "^2.0.0", + "btoa-lite": "^1.0.0", + "deprecation": "^2.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + }, + "dependencies": { + "@octokit/request-error": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", + "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", + "requires": { + "@octokit/types": "^2.0.0", + "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": { @@ -615,6 +662,12 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", @@ -639,8 +692,7 @@ "@types/node": { "version": "12.12.54", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", - "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", - "dev": true + "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==" }, "@types/normalize-package-data": { "version": "2.4.0", diff --git a/packages/snippet-bot/src/snippet-bot.ts b/packages/snippet-bot/src/snippet-bot.ts index d0c157bf4e2..7973969f53c 100644 --- a/packages/snippet-bot/src/snippet-bot.ts +++ b/packages/snippet-bot/src/snippet-bot.ts @@ -58,21 +58,28 @@ class Configuration { export = (app: Application) => { app.on('pull_request', async context => { + const repoUrl = context.payload.repository.full_name; let configOptions!: ConfigurationOptions | null; try { - configOptions = await context.config( - CONFIGURATION_FILE_PATH, - DEFAULT_CONFIGURATION + configOptions = await context.config( + CONFIGURATION_FILE_PATH ); } catch (err) { err.message = `Error reading configuration: ${err.message}`; logger.error(err); - // Falling back to default. - configOptions = DEFAULT_CONFIGURATION; + // Now this bot is only enabled if it finds the configuration file. + // Exiting. + return; } - const configuration = new Configuration( - configOptions as ConfigurationOptions - ); + + if (configOptions === null) { + logger.info(`snippet-bot is not configured for ${repoUrl}.`); + return; + } + const configuration = new Configuration({ + ...DEFAULT_CONFIGURATION, + ...configOptions, + }); logger.info({config: configuration}); // List pull request files for the given PR diff --git a/packages/snippet-bot/test/snippet-bot.ts b/packages/snippet-bot/test/snippet-bot.ts index 6ee36eed64f..a029fe9df1e 100644 --- a/packages/snippet-bot/test/snippet-bot.ts +++ b/packages/snippet-bot/test/snippet-bot.ts @@ -110,28 +110,15 @@ describe('snippet-bot', () => { requests.done(); }); - it('sets a "failure" context on PR even when it failed to read the config', async () => { + it('exits early when it failed to read the config', async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires - const changedFiles = require(resolve(fixturesPath, './pr_files_added')); const payload = require(resolve(fixturesPath, './pr_event')); - const blob = require(resolve(fixturesPath, './failure_blob')); const requests = nock('https://api.github.com') .get( '/repos/tmatsuo/repo-automation-bots/contents/.github/snippet-bot.yml' ) - .reply(403, {content: 'Permission denied'}) - .get('/repos/tmatsuo/repo-automation-bots/pulls/14/files?per_page=100') - .reply(200, changedFiles) - .get( - '/repos/tmatsuo/repo-automation-bots/git/blobs/223828dbd668486411b475665ab60855ba9898f3' - ) - .reply(200, blob) - .post('/repos/tmatsuo/repo-automation-bots/check-runs', body => { - snapshot(body); - return true; - }) - .reply(200); + .reply(403, {content: 'Permission denied'}); await probot.receive({ name: 'pull_request', @@ -199,5 +186,27 @@ describe('snippet-bot', () => { requests.done(); }); + + it('quits early if there is no config file', async () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const payload = require(resolve(fixturesPath, './pr_event')); + + // probot tries to fetch the org's config too. + const requests = nock('https://api.github.com') + .get( + '/repos/tmatsuo/repo-automation-bots/contents/.github/snippet-bot.yml' + ) + .reply(404, {content: 'Not Found'}) + .get('/repos/tmatsuo/.github/contents/.github/snippet-bot.yml') + .reply(404, {content: 'Not Found'}); + + await probot.receive({ + name: 'pull_request', + payload, + id: 'abc123', + }); + + requests.done(); + }); }); });