From 04671efa1db1ed24016eb953762eba45b98181ad Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 14 Dec 2021 19:50:52 +0000 Subject: [PATCH] Add support for feature flagging via the GitHub API --- lib/database-upload.test.js | 41 ++----- lib/database-upload.test.js.map | 2 +- lib/feature-flags.js | 79 +++++++++++++ lib/feature-flags.js.map | 1 + lib/feature-flags.test.js | 145 +++++++++++++++++++++++ lib/feature-flags.test.js.map | 1 + lib/testing-utils.js | 26 +++- lib/testing-utils.js.map | 2 +- src/database-upload.test.ts | 37 +----- src/feature-flags.test.ts | 202 ++++++++++++++++++++++++++++++++ src/feature-flags.ts | 90 ++++++++++++++ src/testing-utils.ts | 30 +++++ 12 files changed, 590 insertions(+), 66 deletions(-) create mode 100644 lib/feature-flags.js create mode 100644 lib/feature-flags.js.map create mode 100644 lib/feature-flags.test.js create mode 100644 lib/feature-flags.test.js.map create mode 100644 src/feature-flags.test.ts create mode 100644 src/feature-flags.ts diff --git a/lib/database-upload.test.js b/lib/database-upload.test.js index 458a1199a..447ec24f8 100644 --- a/lib/database-upload.test.js +++ b/lib/database-upload.test.js @@ -58,29 +58,6 @@ function getTestConfig(tmpDir) { debugMode: false, }; } -function getRecordingLogger(messages) { - return { - debug: (message) => { - messages.push({ type: "debug", message }); - console.debug(message); - }, - info: (message) => { - messages.push({ type: "info", message }); - console.info(message); - }, - warning: (message) => { - messages.push({ type: "warning", message }); - console.warn(message); - }, - error: (message) => { - messages.push({ type: "error", message }); - console.error(message); - }, - isDebug: () => true, - startGroup: () => undefined, - endGroup: () => undefined, - }; -} function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatusCode) { // Passing an auth token is required, so we just use a dummy value const client = github.getOctokit("123"); @@ -122,7 +99,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus .returns("false"); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Database upload disabled in workflow. Skipping upload.") !== undefined); }); @@ -138,7 +115,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus const config = getTestConfig(tmpDir); config.gitHubVersion = { type: util_1.GitHubVariant.GHES, version: "3.0" }; const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, config, testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, config, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Not running against github.com. Skipping upload.") !== undefined); }); @@ -154,7 +131,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus const config = getTestConfig(tmpDir); config.gitHubVersion = { type: util_1.GitHubVariant.GHAE }; const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, config, testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, config, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Not running against github.com. Skipping upload.") !== undefined); }); @@ -168,7 +145,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus .returns("true"); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(false); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Not analyzing default branch. Skipping upload.") !== undefined); }); @@ -188,7 +165,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus }, }); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Repository is not opted in to database uploads. Skipping upload.") !== undefined); @@ -209,7 +186,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus }, }); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "info" && v.message === "Skipping database upload due to unknown error: Error: some error message") !== undefined); @@ -230,7 +207,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus }, }); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "warning" && v.message === "Failed to upload database for javascript: Error: some error message") !== undefined); @@ -251,7 +228,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus }, }); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Successfully uploaded database for javascript") !== undefined); }); @@ -271,7 +248,7 @@ function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatus }, }); const loggedMessages = []; - await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages)); + await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); t.assert(loggedMessages.find((v) => v.type === "debug" && v.message === "Successfully uploaded database for javascript") !== undefined); }); diff --git a/lib/database-upload.test.js.map b/lib/database-upload.test.js.map index 6b53e069a..8ca705c21 100644 --- a/lib/database-upload.test.js.map +++ b/lib/database-upload.test.js.map @@ -1 +1 @@ -{"version":3,"file":"database-upload.test.js","sourceRoot":"","sources":["../src/database-upload.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"database-upload.test.js","sourceRoot":"","sources":["../src/database-upload.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AAEzB,wDAA0C;AAC1C,8CAAuB;AACvB,6CAA+B;AAE/B,4DAA8C;AAE9C,wDAA0C;AAC1C,qCAAqC;AAErC,uDAAoD;AACpD,2CAAuC;AAEvC,mDAKyB;AACzB,iCAMgB;AAEhB,IAAA,0BAAU,EAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,UAAU,CAAC,GAAG,EAAE;IACnB,IAAA,4BAAqB,EAAC,WAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,YAAY,GAAkB,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AACzE,MAAM,cAAc,GAAqB;IACvC,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,oBAAoB;CAC1B,CAAC;AAEF,SAAS,aAAa,CAAC,MAAc;IACnC,OAAO;QACL,SAAS,EAAE,CAAC,oBAAQ,CAAC,UAAU,CAAC;QAChC,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,EAAE;QACf,KAAK,EAAE,EAAE;QACT,iBAAiB,EAAE,EAAE;QACrB,OAAO,EAAE,MAAM;QACf,YAAY,EAAE,MAAM;QACpB,SAAS,EAAE,KAAK;QAChB,aAAa,EAAE,EAAE,IAAI,EAAE,oBAAa,CAAC,MAAM,EAAE;QAC7C,UAAU,EAAE,MAAM;QAClB,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,eAAuB,EACvB,eAAyB,EACzB,wBAAiC;IAEjC,kEAAkE;IAClE,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAExC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEjD,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAClC,wDAAwD,CACzD,CAAC;IACF,IAAI,eAAe,GAAG,GAAG,EAAE;QACzB,QAAQ,CAAC,QAAQ,CAAC;YAChB,MAAM,EAAE,eAAe;YACvB,IAAI,EAAE;gBACJ,eAAe;aAChB;YACD,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,wDAAwD;SAC9D,CAAC,CAAC;KACJ;SAAM;QACL,QAAQ,CAAC,MAAM,CAAC,IAAI,gBAAS,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC,CAAC;KACvE;IAED,IAAI,wBAAwB,KAAK,SAAS,EAAE;QAC1C,MAAM,GAAG,GAAG,eAAe;YACzB,CAAC,CAAC,wGAAwG;YAC1G,CAAC,CAAC,kEAAkE,CAAC;QACvE,MAAM,iBAAiB,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,wBAAwB,GAAG,GAAG,EAAE;YAClC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;SACvC;aAAM;YACL,iBAAiB,CAAC,MAAM,CACtB,IAAI,gBAAS,CAAC,oBAAoB,EAAE,wBAAwB,CAAC,CAC9D,CAAC;SACH;KACF;IAED,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,IAAA,aAAI,EAAC,+DAA+D,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAChF,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,OAAO,CAAC,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAgB,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,wDAAwD,CACzE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,+CAA+C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAChE,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,oBAAa,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAEpE,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,MAAM,EACN,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAgB,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,kDAAkD,CACnE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,+CAA+C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAChE,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,oBAAa,CAAC,IAAI,EAAE,CAAC;QAEpD,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,MAAM,EACN,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAgB,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,kDAAkD,CACnE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,uDAAuD,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACxE,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEpE,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAgB,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,gDAAgD,CACjE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,qDAAqD,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACtE,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAEtB,IAAA,kBAAS,EAAC;YACR,KAAK,CAAC,cAAc;gBAClB,OAAO;YACT,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAgB,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO;gBACP,kEAAkE,CACvE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,6EAA6E,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC9F,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAEtB,IAAA,kBAAS,EAAC;YACR,KAAK,CAAC,cAAc;gBAClB,OAAO;YACT,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,EAAqB,CAAC;QAC7C,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,MAAM;YACjB,CAAC,CAAC,OAAO;gBACP,0EAA0E,CAC/E,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,2CAA2C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC5D,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,gBAAgB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAElC,IAAA,kBAAS,EAAC;YACR,KAAK,CAAC,cAAc,CAAC,CAAS,EAAE,cAAsB;gBACpD,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACvC,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,EAAqB,CAAC;QAC7C,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,CAAC,CAAC,OAAO;gBACP,qEAAqE,CAC1E,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,qDAAqD,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACtE,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,gBAAgB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAElC,IAAA,kBAAS,EAAC;YACR,KAAK,CAAC,cAAc,CAAC,CAAS,EAAE,cAAsB;gBACpD,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACvC,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,EAAqB,CAAC;QAC7C,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,+CAA+C,CAChE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,yDAAyD,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC1E,MAAM,IAAA,iBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,IAAA,gCAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK;aACF,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC;aACrC,QAAQ,CAAC,iBAAiB,CAAC;aAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEnE,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAEjC,IAAA,kBAAS,EAAC;YACR,KAAK,CAAC,cAAc,CAAC,CAAS,EAAE,cAAsB;gBACpD,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACvC,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,EAAqB,CAAC;QAC7C,MAAM,IAAA,iCAAe,EACnB,YAAY,EACZ,aAAa,CAAC,MAAM,CAAC,EACrB,cAAc,EACd,IAAA,kCAAkB,EAAC,cAAc,CAAC,CACnC,CAAC;QACF,CAAC,CAAC,MAAM,CACN,cAAc,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,OAAO,KAAK,+CAA+C,CAChE,KAAK,SAAS,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/lib/feature-flags.js b/lib/feature-flags.js new file mode 100644 index 000000000..d230f4e24 --- /dev/null +++ b/lib/feature-flags.js @@ -0,0 +1,79 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GitHubFeatureFlags = void 0; +const api_client_1 = require("./api-client"); +const repository_1 = require("./repository"); +const util = __importStar(require("./util")); +class GitHubFeatureFlags { + constructor(gitHubVersion, apiDetails, logger) { + this.gitHubVersion = gitHubVersion; + this.apiDetails = apiDetails; + this.logger = logger; + } + getDatabaseUploadsEnabled() { + return this.getFeatureFlag("database_uploads_enabled"); + } + getMlPoweredQueriesEnabled() { + return this.getFeatureFlag("ml_powered_queries_enabled"); + } + getUploadsDomainEnabled() { + return this.getFeatureFlag("uploads_domain_enabled"); + } + async preloadFeatureFlags() { + await this.getApiResponse(); + } + async getFeatureFlag(name) { + const response = (await this.getApiResponse())[name]; + if (response === undefined) { + this.logger.debug(`Feature flag '${name}' undefined in API response, considering it disabled.`); + } + return response || false; + } + async getApiResponse() { + const loadApiResponse = async () => { + // Do nothing when not running against github.com + if (this.gitHubVersion.type !== util.GitHubVariant.DOTCOM) { + this.logger.debug("Not running against github.com. Disabling all feature flags."); + return {}; + } + const client = (0, api_client_1.getApiClient)(this.apiDetails); + const repositoryNwo = (0, repository_1.parseRepositoryNwo)(util.getRequiredEnvParam("GITHUB_REPOSITORY")); + try { + const response = await client.request("GET /repos/:owner/:repo/code-scanning/codeql-action/features", { + owner: repositoryNwo.owner, + repo: repositoryNwo.repo, + }); + return response.data; + } + catch (e) { + console.log(e); + this.logger.info(`Disabling all feature flags due to unknown error: ${e}`); + return {}; + } + }; + const apiResponse = this.cachedApiResponse || (await loadApiResponse()); + this.cachedApiResponse = apiResponse; + return apiResponse; + } +} +exports.GitHubFeatureFlags = GitHubFeatureFlags; +//# sourceMappingURL=feature-flags.js.map \ No newline at end of file diff --git a/lib/feature-flags.js.map b/lib/feature-flags.js.map new file mode 100644 index 000000000..7b2b865b3 --- /dev/null +++ b/lib/feature-flags.js.map @@ -0,0 +1 @@ +{"version":3,"file":"feature-flags.js","sourceRoot":"","sources":["../src/feature-flags.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA8D;AAE9D,6CAAkD;AAClD,6CAA+B;AAgB/B,MAAa,kBAAkB;IAG7B,YACU,aAAiC,EACjC,UAA4B,EAC5B,MAAc;QAFd,kBAAa,GAAb,aAAa,CAAoB;QACjC,eAAU,GAAV,UAAU,CAAkB;QAC5B,WAAM,GAAN,MAAM,CAAQ;IACrB,CAAC;IAEJ,yBAAyB;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;IACzD,CAAC;IAED,0BAA0B;QACxB,OAAO,IAAI,CAAC,cAAc,CAAC,4BAA4B,CAAC,CAAC;IAC3D,CAAC;IAED,uBAAuB;QACrB,OAAO,IAAI,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAY;QACvC,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,QAAQ,KAAK,SAAS,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,iBAAiB,IAAI,uDAAuD,CAC7E,CAAC;SACH;QACD,OAAO,QAAQ,IAAI,KAAK,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,MAAM,eAAe,GAAG,KAAK,IAAI,EAAE;YACjC,iDAAiD;YACjD,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;gBACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,8DAA8D,CAC/D,CAAC;gBACF,OAAO,EAAE,CAAC;aACX;YACD,MAAM,MAAM,GAAG,IAAA,yBAAY,EAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,aAAa,GAAG,IAAA,+BAAkB,EACtC,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,CAC9C,CAAC;YACF,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CACnC,8DAA8D,EAC9D;oBACE,KAAK,EAAE,aAAa,CAAC,KAAK;oBAC1B,IAAI,EAAE,aAAa,CAAC,IAAI;iBACzB,CACF,CAAC;gBACF,OAAO,QAAQ,CAAC,IAAI,CAAC;aACtB;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,qDAAqD,CAAC,EAAE,CACzD,CAAC;gBACF,OAAO,EAAE,CAAC;aACX;QACH,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,IAAI,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC;QACrC,OAAO,WAAW,CAAC;IACrB,CAAC;CACF;AAtED,gDAsEC"} \ No newline at end of file diff --git a/lib/feature-flags.test.js b/lib/feature-flags.test.js new file mode 100644 index 000000000..1840a9912 --- /dev/null +++ b/lib/feature-flags.test.js @@ -0,0 +1,145 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const github = __importStar(require("@actions/github")); +const ava_1 = __importDefault(require("ava")); +const sinon = __importStar(require("sinon")); +const apiClient = __importStar(require("./api-client")); +const feature_flags_1 = require("./feature-flags"); +const testing_utils_1 = require("./testing-utils"); +const util = __importStar(require("./util")); +const util_1 = require("./util"); +(0, testing_utils_1.setupTests)(ava_1.default); +ava_1.default.beforeEach(() => { + (0, util_1.initializeEnvironment)(util_1.Mode.actions, "1.2.3"); + sinon + .stub(util, "getRequiredEnvParam") + .withArgs("GITHUB_REPOSITORY") + .returns("github/example"); +}); +const testApiDetails = { + auth: "1234", + url: "https://github.com", +}; +function mockHttpRequests(responseStatusCode, flags) { + // Passing an auth token is required, so we just use a dummy value + const client = github.getOctokit("123"); + const requestSpy = sinon.stub(client, "request"); + const optInSpy = requestSpy.withArgs("GET /repos/:owner/:repo/code-scanning/codeql-action/features"); + if (responseStatusCode < 300) { + optInSpy.resolves({ + status: responseStatusCode, + data: flags, + headers: {}, + url: "GET /repos/:owner/:repo/code-scanning/codeql-action/features", + }); + } + else { + optInSpy.throws(new util_1.HTTPError("some error message", responseStatusCode)); + } + sinon.stub(apiClient, "getApiClient").value(() => client); +} +const ALL_FEATURE_FLAGS_DISABLED_VARIANTS = [ + { + description: "GHES", + gitHubVersion: { type: util_1.GitHubVariant.GHES, version: "3.0.0" }, + }, + { description: "GHAE", gitHubVersion: { type: util_1.GitHubVariant.GHAE } }, +]; +for (const variant of ALL_FEATURE_FLAGS_DISABLED_VARIANTS) { + (0, ava_1.default)(`All feature flags are disabled if running against ${variant.description}`, async (t) => { + await (0, util_1.withTmpDir)(async (tmpDir) => { + (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); + const loggedMessages = []; + const featureFlags = new feature_flags_1.GitHubFeatureFlags(variant.gitHubVersion, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + t.assert(loggedMessages.find((v) => v.type === "debug" && + v.message === + "Not running against github.com. Disabling all feature flags.") !== undefined); + }); + }); +} +(0, ava_1.default)("Feature flags are disabled if they're not returned in API response", async (t) => { + await (0, util_1.withTmpDir)(async (tmpDir) => { + (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); + const loggedMessages = []; + const featureFlags = new feature_flags_1.GitHubFeatureFlags({ type: util_1.GitHubVariant.DOTCOM }, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); + mockHttpRequests(200, {}); + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + for (const featureFlag of [ + "database_uploads_enabled", + "ml_powered_queries_enabled", + "uploads_domain_enabled", + ]) { + t.assert(loggedMessages.find((v) => v.type === "debug" && + v.message === + `Feature flag '${featureFlag}' undefined in API response, considering it disabled.`) !== undefined); + } + }); +}); +(0, ava_1.default)("All feature flags are disabled if the API request errors", async (t) => { + await (0, util_1.withTmpDir)(async (tmpDir) => { + (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); + const loggedMessages = []; + const featureFlags = new feature_flags_1.GitHubFeatureFlags({ type: util_1.GitHubVariant.DOTCOM }, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); + mockHttpRequests(500, {}); + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + t.assert(loggedMessages.find((v) => v.type === "info" && + v.message === + "Disabling all feature flags due to unknown error: Error: some error message") !== undefined); + }); +}); +const FEATURE_FLAGS = [ + "database_uploads_enabled", + "ml_powered_queries_enabled", + "uploads_domain_enabled", +]; +for (const featureFlag of FEATURE_FLAGS) { + (0, ava_1.default)(`Feature flag '${featureFlag}' is enabled if enabled in the API response`, async (t) => { + await (0, util_1.withTmpDir)(async (tmpDir) => { + (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); + const loggedMessages = []; + const featureFlags = new feature_flags_1.GitHubFeatureFlags({ type: util_1.GitHubVariant.DOTCOM }, testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); + const expectedFeatureFlags = {}; + for (const f of FEATURE_FLAGS) { + expectedFeatureFlags[f] = false; + } + expectedFeatureFlags[featureFlag] = true; + mockHttpRequests(200, expectedFeatureFlags); + const actualFeatureFlags = { + database_uploads_enabled: await featureFlags.getDatabaseUploadsEnabled(), + ml_powered_queries_enabled: await featureFlags.getMlPoweredQueriesEnabled(), + uploads_domain_enabled: await featureFlags.getUploadsDomainEnabled(), + }; + t.deepEqual(actualFeatureFlags, expectedFeatureFlags); + }); + }); +} +//# sourceMappingURL=feature-flags.test.js.map \ No newline at end of file diff --git a/lib/feature-flags.test.js.map b/lib/feature-flags.test.js.map new file mode 100644 index 000000000..fa41d2510 --- /dev/null +++ b/lib/feature-flags.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"feature-flags.test.js","sourceRoot":"","sources":["../src/feature-flags.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/testing-utils.js b/lib/testing-utils.js index 7be20be04..441eee9a5 100644 --- a/lib/testing-utils.js +++ b/lib/testing-utils.js @@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.setupActionsVars = exports.setupTests = void 0; +exports.getRecordingLogger = exports.setupActionsVars = exports.setupTests = void 0; const sinon = __importStar(require("sinon")); const CodeQL = __importStar(require("./codeql")); function wrapOutput(context) { @@ -89,4 +89,28 @@ function setupActionsVars(tempDir, toolsDir) { process.env["RUNNER_TOOL_CACHE"] = toolsDir; } exports.setupActionsVars = setupActionsVars; +function getRecordingLogger(messages) { + return { + debug: (message) => { + messages.push({ type: "debug", message }); + console.debug(message); + }, + info: (message) => { + messages.push({ type: "info", message }); + console.info(message); + }, + warning: (message) => { + messages.push({ type: "warning", message }); + console.warn(message); + }, + error: (message) => { + messages.push({ type: "error", message }); + console.error(message); + }, + isDebug: () => true, + startGroup: () => undefined, + endGroup: () => undefined, + }; +} +exports.getRecordingLogger = getRecordingLogger; //# sourceMappingURL=testing-utils.js.map \ No newline at end of file diff --git a/lib/testing-utils.js.map b/lib/testing-utils.js.map index 208fd6fe8..964ebe1f8 100644 --- a/lib/testing-utils.js.map +++ b/lib/testing-utils.js.map @@ -1 +1 @@ -{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/database-upload.test.ts b/src/database-upload.test.ts index 16548f282..64be53bdf 100644 --- a/src/database-upload.test.ts +++ b/src/database-upload.test.ts @@ -11,9 +11,13 @@ import { setCodeQL } from "./codeql"; import { Config } from "./config-utils"; import { uploadDatabases } from "./database-upload"; import { Language } from "./languages"; -import { Logger } from "./logging"; import { RepositoryNwo } from "./repository"; -import { setupActionsVars, setupTests } from "./testing-utils"; +import { + getRecordingLogger, + LoggedMessage, + setupActionsVars, + setupTests, +} from "./testing-utils"; import { GitHubVariant, HTTPError, @@ -51,35 +55,6 @@ function getTestConfig(tmpDir: string): Config { }; } -interface LoggedMessage { - type: "debug" | "info" | "warning" | "error"; - message: string | Error; -} - -function getRecordingLogger(messages: LoggedMessage[]): Logger { - return { - debug: (message: string) => { - messages.push({ type: "debug", message }); - console.debug(message); - }, - info: (message: string) => { - messages.push({ type: "info", message }); - console.info(message); - }, - warning: (message: string | Error) => { - messages.push({ type: "warning", message }); - console.warn(message); - }, - error: (message: string | Error) => { - messages.push({ type: "error", message }); - console.error(message); - }, - isDebug: () => true, - startGroup: () => undefined, - endGroup: () => undefined, - }; -} - function mockHttpRequests( optInStatusCode: number, useUploadDomain?: boolean, diff --git a/src/feature-flags.test.ts b/src/feature-flags.test.ts new file mode 100644 index 000000000..fd3a9ff43 --- /dev/null +++ b/src/feature-flags.test.ts @@ -0,0 +1,202 @@ +import * as github from "@actions/github"; +import test from "ava"; +import * as sinon from "sinon"; + +import * as apiClient from "./api-client"; +import { GitHubApiDetails } from "./api-client"; +import { GitHubFeatureFlags } from "./feature-flags"; +import { + getRecordingLogger, + LoggedMessage, + setupActionsVars, + setupTests, +} from "./testing-utils"; +import * as util from "./util"; +import { + GitHubVariant, + HTTPError, + initializeEnvironment, + Mode, + withTmpDir, +} from "./util"; + +setupTests(test); + +test.beforeEach(() => { + initializeEnvironment(Mode.actions, "1.2.3"); + + sinon + .stub(util, "getRequiredEnvParam") + .withArgs("GITHUB_REPOSITORY") + .returns("github/example"); +}); + +const testApiDetails: GitHubApiDetails = { + auth: "1234", + url: "https://github.com", +}; + +function mockHttpRequests( + responseStatusCode: number, + flags: { [flagName: string]: boolean } +) { + // Passing an auth token is required, so we just use a dummy value + const client = github.getOctokit("123"); + + const requestSpy = sinon.stub(client, "request"); + + const optInSpy = requestSpy.withArgs( + "GET /repos/:owner/:repo/code-scanning/codeql-action/features" + ); + if (responseStatusCode < 300) { + optInSpy.resolves({ + status: responseStatusCode, + data: flags, + headers: {}, + url: "GET /repos/:owner/:repo/code-scanning/codeql-action/features", + }); + } else { + optInSpy.throws(new HTTPError("some error message", responseStatusCode)); + } + + sinon.stub(apiClient, "getApiClient").value(() => client); +} + +const ALL_FEATURE_FLAGS_DISABLED_VARIANTS: Array<{ + description: string; + gitHubVersion: util.GitHubVersion; +}> = [ + { + description: "GHES", + gitHubVersion: { type: GitHubVariant.GHES, version: "3.0.0" }, + }, + { description: "GHAE", gitHubVersion: { type: GitHubVariant.GHAE } }, +]; + +for (const variant of ALL_FEATURE_FLAGS_DISABLED_VARIANTS) { + test(`All feature flags are disabled if running against ${variant.description}`, async (t) => { + await withTmpDir(async (tmpDir) => { + setupActionsVars(tmpDir, tmpDir); + + const loggedMessages = []; + const featureFlags = new GitHubFeatureFlags( + variant.gitHubVersion, + testApiDetails, + getRecordingLogger(loggedMessages) + ); + + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + + t.assert( + loggedMessages.find( + (v: LoggedMessage) => + v.type === "debug" && + v.message === + "Not running against github.com. Disabling all feature flags." + ) !== undefined + ); + }); + }); +} + +test("Feature flags are disabled if they're not returned in API response", async (t) => { + await withTmpDir(async (tmpDir) => { + setupActionsVars(tmpDir, tmpDir); + + const loggedMessages = []; + const featureFlags = new GitHubFeatureFlags( + { type: GitHubVariant.DOTCOM }, + testApiDetails, + getRecordingLogger(loggedMessages) + ); + + mockHttpRequests(200, {}); + + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + + for (const featureFlag of [ + "database_uploads_enabled", + "ml_powered_queries_enabled", + "uploads_domain_enabled", + ]) { + t.assert( + loggedMessages.find( + (v: LoggedMessage) => + v.type === "debug" && + v.message === + `Feature flag '${featureFlag}' undefined in API response, considering it disabled.` + ) !== undefined + ); + } + }); +}); + +test("All feature flags are disabled if the API request errors", async (t) => { + await withTmpDir(async (tmpDir) => { + setupActionsVars(tmpDir, tmpDir); + + const loggedMessages = []; + const featureFlags = new GitHubFeatureFlags( + { type: GitHubVariant.DOTCOM }, + testApiDetails, + getRecordingLogger(loggedMessages) + ); + + mockHttpRequests(500, {}); + + t.assert((await featureFlags.getDatabaseUploadsEnabled()) === false); + t.assert((await featureFlags.getMlPoweredQueriesEnabled()) === false); + t.assert((await featureFlags.getUploadsDomainEnabled()) === false); + + t.assert( + loggedMessages.find( + (v: LoggedMessage) => + v.type === "info" && + v.message === + "Disabling all feature flags due to unknown error: Error: some error message" + ) !== undefined + ); + }); +}); + +const FEATURE_FLAGS = [ + "database_uploads_enabled", + "ml_powered_queries_enabled", + "uploads_domain_enabled", +]; + +for (const featureFlag of FEATURE_FLAGS) { + test(`Feature flag '${featureFlag}' is enabled if enabled in the API response`, async (t) => { + await withTmpDir(async (tmpDir) => { + setupActionsVars(tmpDir, tmpDir); + + const loggedMessages = []; + const featureFlags = new GitHubFeatureFlags( + { type: GitHubVariant.DOTCOM }, + testApiDetails, + getRecordingLogger(loggedMessages) + ); + + const expectedFeatureFlags = {}; + for (const f of FEATURE_FLAGS) { + expectedFeatureFlags[f] = false; + } + expectedFeatureFlags[featureFlag] = true; + mockHttpRequests(200, expectedFeatureFlags); + + const actualFeatureFlags = { + database_uploads_enabled: + await featureFlags.getDatabaseUploadsEnabled(), + ml_powered_queries_enabled: + await featureFlags.getMlPoweredQueriesEnabled(), + uploads_domain_enabled: await featureFlags.getUploadsDomainEnabled(), + }; + + t.deepEqual(actualFeatureFlags, expectedFeatureFlags); + }); + }); +} diff --git a/src/feature-flags.ts b/src/feature-flags.ts new file mode 100644 index 000000000..0f30c5ac9 --- /dev/null +++ b/src/feature-flags.ts @@ -0,0 +1,90 @@ +import { getApiClient, GitHubApiDetails } from "./api-client"; +import { Logger } from "./logging"; +import { parseRepositoryNwo } from "./repository"; +import * as util from "./util"; + +interface FeatureFlags { + getDatabaseUploadsEnabled(): Promise; + getMlPoweredQueriesEnabled(): Promise; + getUploadsDomainEnabled(): Promise; +} + +/** + * A response from the GitHub API that contains feature flag enablement information for the CodeQL + * Action. + * + * It maps feature flags to whether they are enabled or not. + */ +type FeatureFlagsApiResponse = { [flagName: string]: boolean }; + +export class GitHubFeatureFlags implements FeatureFlags { + private cachedApiResponse: FeatureFlagsApiResponse | undefined; + + constructor( + private gitHubVersion: util.GitHubVersion, + private apiDetails: GitHubApiDetails, + private logger: Logger + ) {} + + getDatabaseUploadsEnabled(): Promise { + return this.getFeatureFlag("database_uploads_enabled"); + } + + getMlPoweredQueriesEnabled(): Promise { + return this.getFeatureFlag("ml_powered_queries_enabled"); + } + + getUploadsDomainEnabled(): Promise { + return this.getFeatureFlag("uploads_domain_enabled"); + } + + async preloadFeatureFlags(): Promise { + await this.getApiResponse(); + } + + private async getFeatureFlag(name: string): Promise { + const response = (await this.getApiResponse())[name]; + if (response === undefined) { + this.logger.debug( + `Feature flag '${name}' undefined in API response, considering it disabled.` + ); + } + return response || false; + } + + private async getApiResponse(): Promise { + const loadApiResponse = async () => { + // Do nothing when not running against github.com + if (this.gitHubVersion.type !== util.GitHubVariant.DOTCOM) { + this.logger.debug( + "Not running against github.com. Disabling all feature flags." + ); + return {}; + } + const client = getApiClient(this.apiDetails); + const repositoryNwo = parseRepositoryNwo( + util.getRequiredEnvParam("GITHUB_REPOSITORY") + ); + try { + const response = await client.request( + "GET /repos/:owner/:repo/code-scanning/codeql-action/features", + { + owner: repositoryNwo.owner, + repo: repositoryNwo.repo, + } + ); + return response.data; + } catch (e) { + console.log(e); + this.logger.info( + `Disabling all feature flags due to unknown error: ${e}` + ); + return {}; + } + }; + + const apiResponse = this.cachedApiResponse || (await loadApiResponse()); + this.cachedApiResponse = apiResponse; + return apiResponse; + } +} diff --git a/src/testing-utils.ts b/src/testing-utils.ts index 867a12894..5efca2404 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -2,6 +2,7 @@ import { TestInterface } from "ava"; import * as sinon from "sinon"; import * as CodeQL from "./codeql"; +import { Logger } from "./logging"; type TestContext = { stdoutWrite: any; @@ -89,3 +90,32 @@ export function setupActionsVars(tempDir: string, toolsDir: string) { process.env["RUNNER_TEMP"] = tempDir; process.env["RUNNER_TOOL_CACHE"] = toolsDir; } + +export interface LoggedMessage { + type: "debug" | "info" | "warning" | "error"; + message: string | Error; +} + +export function getRecordingLogger(messages: LoggedMessage[]): Logger { + return { + debug: (message: string) => { + messages.push({ type: "debug", message }); + console.debug(message); + }, + info: (message: string) => { + messages.push({ type: "info", message }); + console.info(message); + }, + warning: (message: string | Error) => { + messages.push({ type: "warning", message }); + console.warn(message); + }, + error: (message: string | Error) => { + messages.push({ type: "error", message }); + console.error(message); + }, + isDebug: () => true, + startGroup: () => undefined, + endGroup: () => undefined, + }; +}