feat(aio): add API endpoint for notifying about PR updates

This commit adds an API endpoint for notifying the preview server about PR
updates (`/pr-updated`). According to the update, the preview server can take
several actions. Currently, it will only check and (if necessary) update the
PR's preview visibility (but more actions could be supported in the future).
The API can be used with an automatic trigger (e.g. a GitHub webhook) to
instantly update a PR's preview visibility when it changes.

Fixes #16526
This commit is contained in:
Georgios Kalpakas
2017-06-27 19:43:02 +03:00
committed by Pete Bacon Darwin
parent 5a417b8514
commit 20556346a3
12 changed files with 624 additions and 8 deletions

View File

@ -374,6 +374,181 @@ describe('upload-server (on HTTP)', () => {
});
describe(`${host}/pr-updated`, () => {
const url = `http://${host}/pr-updated`;
// Helpers
const curl = (payload?: {number: number, action?: string}) => {
const payloadStr = payload && JSON.stringify(payload) || '';
return `curl -iLX POST --header "Content-Type: application/json" --data '${payloadStr}' ${url}`;
};
it('should disallow non-POST requests', done => {
const bodyRegex = /^Unknown resource in request/;
Promise.all([
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(404, bodyRegex)),
]).then(done);
});
it('should respond with 400 for requests without a payload', done => {
const bodyRegex = /^Missing or empty 'number' field in request/;
h.runCmd(curl()).
then(h.verifyResponse(400, bodyRegex)).
then(done);
});
it('should respond with 400 for requests without a \'number\' field', done => {
const bodyRegex = /^Missing or empty 'number' field in request/;
Promise.all([
h.runCmd(curl({} as any)).then(h.verifyResponse(400, bodyRegex)),
h.runCmd(curl({number: null} as any)).then(h.verifyResponse(400, bodyRegex)),
]).then(done);
});
it('should reject requests for which checking the PR visibility fails', done => {
h.runCmd(curl({number: c.BV_getPrIsTrusted_error})).
then(h.verifyResponse(500, /Test/)).
then(done);
});
it('should respond with 404 for unknown paths', done => {
const mockPayload = JSON.stringify({number: +pr});
const cmdPrefix = `curl -iLX POST --data "${mockPayload}" http://${host}`;
Promise.all([
h.runCmd(`${cmdPrefix}/foo/pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foo-pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foonpr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated/foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated-foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updatednfoo`).then(h.verifyResponse(404)),
]).then(done);
});
it('should do nothing if PR\'s visibility is already up-to-date', done => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
const checkVisibilities = () => {
// Public build is already public.
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
// Hidden build is already hidden.
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
};
h.createDummyBuild(publicPr, sha9, true);
h.createDummyBuild(hiddenPr, sha9, false);
checkVisibilities();
Promise.
all([
h.runCmd(curl({number: +publicPr, action: 'foo'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'foo'})).then(h.verifyResponse(200)),
]).
// Visibilities should not have changed, because the specified action could not have triggered a change.
then(checkVisibilities).
then(done);
});
it('should do nothing if \'action\' implies no visibility change', done => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
const checkVisibilities = () => {
// Public build is hidden atm.
expect(h.buildExists(publicPr, '', false)).toBe(true);
expect(h.buildExists(publicPr, '', true)).toBe(false);
// Hidden build is public atm.
expect(h.buildExists(hiddenPr, '', false)).toBe(false);
expect(h.buildExists(hiddenPr, '', true)).toBe(true);
};
h.createDummyBuild(publicPr, sha9, false);
h.createDummyBuild(hiddenPr, sha9, true);
checkVisibilities();
Promise.
all([
h.runCmd(curl({number: +publicPr, action: 'foo'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'foo'})).then(h.verifyResponse(200)),
]).
// Visibilities should not have changed, because the specified action could not have triggered a change.
then(checkVisibilities).
then(done);
});
describe('when the visiblity has changed', () => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
beforeEach(() => {
// Create initial PR builds with opposite visibilities as the ones that will be reported:
// - The now public PR was previously hidden.
// - The now hidden PR was previously public.
h.createDummyBuild(publicPr, sha9, false);
h.createDummyBuild(hiddenPr, sha9, true);
expect(h.buildExists(publicPr, '', false)).toBe(true);
expect(h.buildExists(publicPr, '', true)).toBe(false);
expect(h.buildExists(hiddenPr, '', false)).toBe(false);
expect(h.buildExists(hiddenPr, '', true)).toBe(true);
});
afterEach(() => {
// Expect PRs' visibility to have been updated:
// - The public PR should be actually public (previously it was hidden).
// - The hidden PR should be actually hidden (previously it was public).
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
h.deletePrDir(publicPr, true);
h.deletePrDir(hiddenPr, false);
});
it('should update the PR\'s visibility (action: undefined)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr})).then(h.verifyResponse(200)),
]).then(done);
});
it('should update the PR\'s visibility (action: labeled)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr, action: 'labeled'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'labeled'})).then(h.verifyResponse(200)),
]).then(done);
});
it('should update the PR\'s visibility (action: unlabeled)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr, action: 'unlabeled'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'unlabeled'})).then(h.verifyResponse(200)),
]).then(done);
});
});
});
describe(`${host}/*`, () => {
it('should respond with 404 for requests to unknown URLs', done => {