From 7e07c1c83108219d9d2feda6af74db9a29a73c75 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 18 Nov 2020 17:06:48 -0500 Subject: [PATCH 01/16] Add build-changelog script, load schemas and create a diff --- package-lock.json | 516 +++++++++++++++++++++++++++++- package.json | 3 + script/graphql/build-changelog.js | 84 +++++ 3 files changed, 601 insertions(+), 2 deletions(-) create mode 100644 script/graphql/build-changelog.js diff --git a/package-lock.json b/package-lock.json index 55b713a58e..9ef31427f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,21 @@ "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==", "dev": true }, + "@ardatan/aggregate-error": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@ardatan/aggregate-error/-/aggregate-error-0.0.6.tgz", + "integrity": "sha512-vyrkEHG1jrukmzTPtyWB4NLPauUw5bQeg4uhn8f+1SSynmrOcyvlb1GKQjjgoBzElLdfXCRYX8UnBlhklOHYRQ==", + "requires": { + "tslib": "~2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -1217,6 +1232,447 @@ "resolved": "https://registry.npmjs.org/@github/rest-api-operations/-/rest-api-operations-3.7.1.tgz", "integrity": "sha512-ppNyeJAOgCpMqmkBBbSwj2JPfzfpN9ST4xe1G3sLl9OsYSasHTb39s1ZiHAIdIaVAtyeRnGL/3wp8dUqrX6G4A==" }, + "@graphql-inspector/core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@graphql-inspector/core/-/core-2.3.0.tgz", + "integrity": "sha512-bxYqAvVK7vDQ0O/ygZ/JNs5XCxSe+DtKwkCsov7RMPoSkkFuHyyC9BDTm6eN57wPwVk5AJ5b5s32oYVTphvELA==", + "requires": { + "dependency-graph": "0.9.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/github-loader": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-6.2.5.tgz", + "integrity": "sha512-DLuQmYeNNdPo8oWus8EePxWCfCAyUXPZ/p1PWqjrX/NGPyH2ZObdqtDAfRHztljt0F/qkBHbGHCEk2TKbRZTRw==", + "requires": { + "@graphql-tools/graphql-tag-pluck": "^6.2.6", + "@graphql-tools/utils": "^7.0.0", + "cross-fetch": "3.0.6", + "tslib": "~2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/graphql-tag-pluck": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-6.3.0.tgz", + "integrity": "sha512-wdXE6iKTD/ePvhPaukhXm6M8FcsiR9rrwFvkYN96sx2UjDjXzU6vS1QUniNuwjRPaQuSe635vqfaUSN9JuNHvA==", + "requires": { + "@babel/parser": "7.11.5", + "@babel/traverse": "7.12.1", + "@babel/types": "7.12.1", + "@graphql-tools/utils": "^7.0.0", + "tslib": "~2.0.1", + "vue-template-compiler": "^2.6.12" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "requires": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==" + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz", + "integrity": "sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.1", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.1", + "@babel/types": "^7.12.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/parser": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==" + } + } + }, + "@babel/types": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", + "integrity": "sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/load": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-6.2.5.tgz", + "integrity": "sha512-TpDgp+id0hhD1iMhdFSgWgWumdI/IpFWwouJeaEhEEAEBkdvH4W9gbBiJBSbPQwMPRNWx8/AZtry0cYKLW4lHg==", + "requires": { + "@graphql-tools/merge": "^6.2.5", + "@graphql-tools/utils": "^7.0.0", + "globby": "11.0.1", + "import-from": "3.0.0", + "is-glob": "4.0.1", + "p-limit": "3.0.2", + "tslib": "~2.0.1", + "unixify": "1.0.0", + "valid-url": "1.0.9" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "requires": { + "p-try": "^2.0.0" + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/merge": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-6.2.5.tgz", + "integrity": "sha512-T2UEm7L5MeS1ggbGKBkdV9kTqLqSHQM13RrjPzIAYzkFL/mK837sf+oq8h2+R8B+senuHX8akUhMTcU85kcMvw==", + "requires": { + "@graphql-tools/schema": "^7.0.0", + "@graphql-tools/utils": "^7.0.0", + "tslib": "~2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/schema": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-7.0.0.tgz", + "integrity": "sha512-yDKgoT2+Uf3cdLYmiFB9lRIGsB6lZhILtCXHgZigYgURExrEPmfj3ZyszfEpPKYcPmKaO9FI4coDhIN0Toxl3w==", + "requires": { + "@graphql-tools/utils": "^7.0.0", + "tslib": "~2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "@graphql-tools/utils": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-VQQ7krHeoXO0FS3qbWsb/vZb8c8oyiCYPIH4RSgeK9SKOUpatWYt3DW4jmLmyHZLVVMk0yjUbsOhKTBEMejKSA==", + "requires": { + "@ardatan/aggregate-error": "0.0.6", + "camel-case": "4.1.1", + "tslib": "~2.0.1" + }, + "dependencies": { + "camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "requires": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "lower-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "requires": { + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "no-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "requires": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "pascal-case": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -5583,6 +6039,14 @@ "cross-spawn": "^7.0.1" } }, + "cross-fetch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", + "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", + "requires": { + "node-fetch": "2.6.1" + } + }, "cross-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", @@ -5914,6 +6378,12 @@ "resolved": "https://registry.npmjs.org/dateutil/-/dateutil-0.1.0.tgz", "integrity": "sha1-9MAkKeA/knwcnh4hu+KzeDNHfrA=" }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "optional": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6206,6 +6676,11 @@ } } }, + "dependency-graph": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz", + "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==" + }, "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", @@ -9697,8 +10172,7 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "header-case": { "version": "1.0.1", @@ -10176,6 +10650,21 @@ "resolve-from": "^4.0.0" } }, + "import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -20087,6 +20576,14 @@ "nan": "^2.13.2" } }, + "unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA=", + "requires": { + "normalize-path": "^2.1.1" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -20332,6 +20829,11 @@ } } }, + "valid-url": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", + "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", @@ -20408,6 +20910,16 @@ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, + "vue-template-compiler": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz", + "integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==", + "optional": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index bdbaab89c1..b37ef08576 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,9 @@ "@github-docs/frontmatter": "^1.3.1", "@github-docs/render-content": "^5.2.0", "@github/rest-api-operations": "^3.7.1", + "@graphql-inspector/core": "^2.3.0", + "@graphql-tools/github-loader": "^6.2.5", + "@graphql-tools/load": "^6.2.5", "@octokit/rest": "^16.38.1", "@primer/css": "^15.1.0", "@primer/octicons": "^11.0.0", diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js new file mode 100644 index 0000000000..2a7950a36a --- /dev/null +++ b/script/graphql/build-changelog.js @@ -0,0 +1,84 @@ +const { diff } = require('@graphql-inspector/core') +const { loadSchema } = require('@graphql-tools/load') +const git = require('../../lib/git-utils') +const fs = require('fs') +// check for required PAT +if (!process.env.GITHUB_TOKEN) { + console.error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.') + process.exit(1) +} + +main() + +async function main () { + // Load the previous schema from this repo + // TODO -- how to make sure that this script runs _before_ this artifact is updated? + // Maybe hook into the existing `update-files` script instead of being a stand-alone script. + const oldSchemaString = fs.readFileSync('data/graphql/schema.docs.graphql').toString() + + // Load the latest schema from github/github + const tree = await git.getTree('github', 'github', 'heads/master') + const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob') + const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob) + + // Create schema objects out of the strings + const oldSchema = await loadSchema(oldSchemaString) + const newSchema = await loadSchema(newSchemaBuffer.toString()) + + // Generate changes between the two schemas + const changes = diff(oldSchema, newSchema) + console.log(changes) + + // If there were any changes, create a changelog entry + if (changes.length > 0) { + const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json') + const previousChangelog = JSON.parse(previousChangelogString) + + // Build a `yyyy-mm-dd`-formatted date string + const today = new Date() + const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0') + + // TODO format `changes` into strings + const formattedChanges = [] + + // TODO how are these populated? + // { + // "title": "The [Checks preview](/graphql/overview/schema-previews#checks-preview) includes these changes:", + // "changes": [ + // "Enum value `STALE` was added to enum `CheckConclusionState`", + // "Enum value `SKIPPED` was added to enum `CheckConclusionState`" + // ] + // } + const previewChanges = [] + + // TODO how are these populated? + // "upcomingChanges": [ + // { + // "title": "The following changes will be made to the schema:", + // "changes": [ + // "On member `Issue.timeline`: `timeline` will be removed. Use Issue.timelineItems instead. **Effective 2020-10-01**.", + // "On member `PullRequest.timeline`: `timeline` will be removed. Use PullRequest.timelineItems instead. **Effective 2020-10-01**." + // ] + // } + // ] + const upcomingChanges = [] + + // add a new entry to the changelog data + previousChangelog.unshift( + { + date: todayString, + schemaChanges: [ + { + title: 'The GraphQL schema includes these changes:', + changes: formattedChanges + } + ], + previewChanges: previewChanges, + upcomingChanges: upcomingChanges + } + ) + + // rewrite the updated changelog + fs.writeFileSync('lib/graphql/static/changelog.json', JSON.stringify(previousChangelog, null, 2)) + } +} From 96e4ea94997a4ac73be8aa06c934a4070674b349 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 20 Nov 2020 17:02:21 -0500 Subject: [PATCH 02/16] Set up tests, start formatting messages --- script/graphql/build-changelog.js | 146 ++++++++++++++---- .../build-changelog-test.js.snap | 21 +++ tests/graphql/build-changelog-test.js | 42 +++++ 3 files changed, 180 insertions(+), 29 deletions(-) create mode 100644 tests/graphql/__snapshots__/build-changelog-test.js.snap create mode 100644 tests/graphql/build-changelog-test.js diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index 2a7950a36a..f08e6bc134 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -1,4 +1,4 @@ -const { diff } = require('@graphql-inspector/core') +const { diff, ChangeType } = require('@graphql-inspector/core') const { loadSchema } = require('@graphql-tools/load') const git = require('../../lib/git-utils') const fs = require('fs') @@ -8,9 +8,9 @@ if (!process.env.GITHUB_TOKEN) { process.exit(1) } -main() +// main() -async function main () { +async function main() { // Load the previous schema from this repo // TODO -- how to make sure that this script runs _before_ this artifact is updated? // Maybe hook into the existing `update-files` script instead of being a stand-alone script. @@ -20,26 +20,59 @@ async function main () { const tree = await git.getTree('github', 'github', 'heads/master') const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob') const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob) + const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString()) + if (changelogEntry) { + const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json') + const previousChangelog = JSON.parse(previousChangelogString) + // add a new entry to the changelog data + previousChangelog.unshift(changelogEntry) + // rewrite the updated changelog + fs.writeFileSync('lib/graphql/static/changelog.json', JSON.stringify(previousChangelog, null, 2)) + } +} + +// Compare `oldSchemaString` to `newSchemaString`, and if there are any +// changes that warrant a changelog entry, return a changelog entry. +// Otherwise, return null. +async function createChangelogEntry(oldSchemaString, newSchemaString) { // Create schema objects out of the strings const oldSchema = await loadSchema(oldSchemaString) - const newSchema = await loadSchema(newSchemaBuffer.toString()) + const newSchema = await loadSchema(newSchemaString) // Generate changes between the two schemas const changes = diff(oldSchema, newSchema) - console.log(changes) + const changesToReport = [] + changes.forEach(function (change) { + if (CHANGES_TO_REPORT.includes(change.type)) { + changesToReport.push(change) + } else if (CHANGES_TO_IGNORE.includes(change.type)) { + // Do nothing + } else { + throw "This change type should be added to CHANGES_TO_REPORT or CHANGES_TO_IGNORE: " + change.type + } + }) + const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport) // If there were any changes, create a changelog entry - if (changes.length > 0) { - const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json') - const previousChangelog = JSON.parse(previousChangelogString) - + if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0) { // Build a `yyyy-mm-dd`-formatted date string const today = new Date() const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0') - // TODO format `changes` into strings - const formattedChanges = [] + const changelogEntry = { + date: todayString, + schemaChanges: [], + previewChanges: [], + upcomingChanges: [], + } + + const schemaChange = { + title: 'The GraphQL schema includes these changes:', + // Replace single quotes which wrap field/argument/type names with backticks + changes: changesToReport.map(function (change) { return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`') }) + } + changelogEntry.schemaChanges.push(schemaChange) // TODO how are these populated? // { @@ -62,23 +95,78 @@ async function main () { // } // ] const upcomingChanges = [] - - // add a new entry to the changelog data - previousChangelog.unshift( - { - date: todayString, - schemaChanges: [ - { - title: 'The GraphQL schema includes these changes:', - changes: formattedChanges - } - ], - previewChanges: previewChanges, - upcomingChanges: upcomingChanges - } - ) - - // rewrite the updated changelog - fs.writeFileSync('lib/graphql/static/changelog.json', JSON.stringify(previousChangelog, null, 2)) + return changelogEntry + } else { + return null } } + +function segmentPreviewChanges(changesToReport) { + // TODO: read the previews yaml file and + // split the list of changes based on whether the change's path + // (or any "parents" in the change's path) are in a preview. + // See: https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L230 + return { schemaChangesToReport: changesToReport, previewChangesToReport: [] } +} + +const CHANGES_TO_REPORT = [ + ChangeType.FieldArgumentDefaultChanged, + ChangeType.FieldArgumentTypeChanged, + ChangeType.EnumValueRemoved, + ChangeType.EnumValueAdded, + ChangeType.FieldRemoved, + ChangeType.FieldAdded, + ChangeType.FieldTypeChanged, + ChangeType.FieldArgumentAdded, + ChangeType.FieldArgumentRemoved, + ChangeType.ObjectTypeInterfaceAdded, + ChangeType.ObjectTypeInterfaceRemoved, + ChangeType.InputFieldRemoved, + ChangeType.InputFieldAdded, + ChangeType.InputFieldDefaultValueChanged, + ChangeType.InputFieldTypeChanged, + ChangeType.TypeRemoved, + ChangeType.TypeAdded, + ChangeType.TypeKindChanged, + ChangeType.UnionMemberRemoved, + ChangeType.UnionMemberAdded, + ChangeType.SchemaQueryTypeChanged, + ChangeType.SchemaMutationTypeChanged, + ChangeType.SchemaSubscriptionTypeChanged, +] + +const CHANGES_TO_IGNORE = [ + ChangeType.FieldArgumentDescriptionChanged, + ChangeType.DirectiveRemoved, + ChangeType.DirectiveAdded, + ChangeType.DirectiveDescriptionChanged, + ChangeType.DirectiveLocationAdded, + ChangeType.DirectiveLocationRemoved, + ChangeType.DirectiveArgumentAdded, + ChangeType.DirectiveArgumentRemoved, + ChangeType.DirectiveArgumentDescriptionChanged, + ChangeType.DirectiveArgumentDefaultValueChanged, + ChangeType.DirectiveArgumentTypeChanged, + ChangeType.EnumValueDescriptionChanged, + ChangeType.EnumValueDeprecationReasonChanged, + ChangeType.EnumValueDeprecationReasonAdded, + ChangeType.EnumValueDeprecationReasonRemoved, + ChangeType.FieldDescriptionChanged, + ChangeType.FieldDescriptionAdded, + ChangeType.FieldDescriptionRemoved, + ChangeType.FieldDeprecationAdded, + ChangeType.FieldDeprecationRemoved, + ChangeType.FieldDeprecationReasonChanged, + ChangeType.FieldDeprecationReasonAdded, + ChangeType.FieldDeprecationReasonRemoved, + ChangeType.InputFieldDescriptionAdded, + ChangeType.InputFieldDescriptionRemoved, + ChangeType.InputFieldDescriptionChanged, + ChangeType.TypeDescriptionChanged, + ChangeType.TypeDescriptionRemoved, + ChangeType.TypeDescriptionAdded, +] + + + +module.exports = { createChangelogEntry } diff --git a/tests/graphql/__snapshots__/build-changelog-test.js.snap b/tests/graphql/__snapshots__/build-changelog-test.js.snap new file mode 100644 index 0000000000..58fa533eb9 --- /dev/null +++ b/tests/graphql/__snapshots__/build-changelog-test.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`creating a changelog from old schema and new schema finds a diff of schema changes, upcoming changes, and preview changes 1`] = ` +Object { + "date": "2020-11-20", + "previewChanges": Array [], + "schemaChanges": Array [ + Object { + "changes": Array [ + "Field \`removedField\` was removed from object type \`Query\`", + "Type for argument \`argumentMadeRequired\` on field \`Query.argumentsField\` changed from \`Int\` to \`Int!\`", + "Type for argument \`argumentMadeOptional\` on field \`Query.argumentsField\` changed from \`Int!\` to \`Int\`", + "Argument \`removedRequiredArgument: Int!\` was removed from field \`Query.argumentsField\`", + "Argument \`removedOptionalArgument: Int!\` was removed from field \`Query.argumentsField\`", + ], + "title": "The GraphQL schema includes these changes:", + }, + ], + "upcomingChanges": Array [], +} +`; diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js new file mode 100644 index 0000000000..0acbf68dd3 --- /dev/null +++ b/tests/graphql/build-changelog-test.js @@ -0,0 +1,42 @@ +const { createChangelogEntry } = require('../../script/graphql/build-changelog') + +describe('creating a changelog from old schema and new schema', () => { + it('finds a diff of schema changes, upcoming changes, and preview changes', async () => { + const oldSchemaString = ` + type Query { + stableField: String + removedField: Boolean + argumentsField( + removedRequiredArgument: Int! + removedOptionalArgument: Int! + argumentMadeRequired: Int + argumentMadeOptional: Int! + ): String + } + ` + + const newSchemaString = ` + type Query { + stableField: String + argumentsField( + argumentMadeRequired: Int! + argumentMadeOptional: Int + ): String + } + ` + + + const entry = await createChangelogEntry(oldSchemaString, newSchemaString) + expect(entry).toMatchSnapshot() + }) + + it('returns null when there isnt any difference', async () => { + const schemaString = ` + type Query { + i: Int! + }` + + const nullEntry = await createChangelogEntry(schemaString, schemaString) + expect(nullEntry).toBeNull() + }) +}) From 9d5af1f98dcc7d8070fcbc8f8d4b05f73c0dad96 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 07:15:22 -0500 Subject: [PATCH 03/16] Create preview changes entries --- script/graphql/build-changelog.js | 121 ++++++++++++++---- .../build-changelog-test.js.snap | 11 +- tests/graphql/build-changelog-test.js | 46 ++++++- 3 files changed, 148 insertions(+), 30 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index f08e6bc134..7373bc5272 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -2,6 +2,8 @@ const { diff, ChangeType } = require('@graphql-inspector/core') const { loadSchema } = require('@graphql-tools/load') const git = require('../../lib/git-utils') const fs = require('fs') +const yaml = require('js-yaml') + // check for required PAT if (!process.env.GITHUB_TOKEN) { console.error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.') @@ -20,8 +22,18 @@ async function main() { const tree = await git.getTree('github', 'github', 'heads/master') const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob') const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob) - const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString()) + + const previewsString = fs.readFileSync('data/graphql/graphql_previews.yml') + const previews = yaml.safeLoad(previewsString) + + const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString(), previews) if (changelogEntry) { + // Build a `yyyy-mm-dd`-formatted date string + // and tag the changelog entry with it + const today = new Date() + const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0') + changelogEntry.date = todayString + const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json') const previousChangelog = JSON.parse(previousChangelogString) // add a new entry to the changelog data @@ -35,7 +47,7 @@ async function main() { // Compare `oldSchemaString` to `newSchemaString`, and if there are any // changes that warrant a changelog entry, return a changelog entry. // Otherwise, return null. -async function createChangelogEntry(oldSchemaString, newSchemaString) { +async function createChangelogEntry(oldSchemaString, newSchemaString, previews) { // Create schema objects out of the strings const oldSchema = await loadSchema(oldSchemaString) const newSchema = await loadSchema(newSchemaString) @@ -53,15 +65,10 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) { } }) - const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport) + const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport, previews) // If there were any changes, create a changelog entry if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0) { - // Build a `yyyy-mm-dd`-formatted date string - const today = new Date() - const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0') - const changelogEntry = { - date: todayString, schemaChanges: [], previewChanges: [], upcomingChanges: [], @@ -70,19 +77,19 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) { const schemaChange = { title: 'The GraphQL schema includes these changes:', // Replace single quotes which wrap field/argument/type names with backticks - changes: changesToReport.map(function (change) { return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`') }) + changes: cleanMessagesFromChanges(schemaChangesToReport) } changelogEntry.schemaChanges.push(schemaChange) - // TODO how are these populated? - // { - // "title": "The [Checks preview](/graphql/overview/schema-previews#checks-preview) includes these changes:", - // "changes": [ - // "Enum value `STALE` was added to enum `CheckConclusionState`", - // "Enum value `SKIPPED` was added to enum `CheckConclusionState`" - // ] - // } - const previewChanges = [] + for (const previewTitle in previewChangesToReport) { + let previewChanges = previewChangesToReport[previewTitle] + let cleanTitle = cleanPreviewTitle(previewTitle) + let entryTitle = "The [" + cleanTitle + "](/graphql/overview/schema-previews#" + previewAnchor(cleanTitle) + ") includes these changes:" + changelogEntry.previewChanges.push({ + title: entryTitle, + changes: cleanMessagesFromChanges(previewChanges.changes), + }) + } // TODO how are these populated? // "upcomingChanges": [ @@ -101,12 +108,76 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) { } } -function segmentPreviewChanges(changesToReport) { - // TODO: read the previews yaml file and - // split the list of changes based on whether the change's path - // (or any "parents" in the change's path) are in a preview. - // See: https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L230 - return { schemaChangesToReport: changesToReport, previewChangesToReport: [] } +// prepare the preview title from github/github source for the docs. +// ported from build-changelog-from-markdown +function cleanPreviewTitle(title) { + if (title == "UpdateRefsPreview") { + title = "Update refs preview" + } else if (title == "MergeInfoPreview") { + title = "Merge info preview" + } else if (!title.endsWith("preview")) { + title = title + " preview" + } + return title +} + +/** + * @param {string} [previewTitle] + * @return {string} +*/ +function previewAnchor(previewTitle) { + // ported from https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L281 + return previewTitle + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, '') +} + +function cleanMessagesFromChanges(changes) { + return changes.map(function (change) { + // replace single quotes around graphql names with backticks, + // to match previous behavior from graphql-schema-comparator + return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`') + }) +} + +function segmentPreviewChanges(changesToReport, previews) { + // Build a map of `{ path => previewTitle` } + // for easier lookup of change to preview + const pathToPreview = {} + previews.forEach(function (preview) { + preview.toggled_on.forEach(function (path) { + pathToPreview[path] = preview.title + }) + }) + const schemaChanges = [] + const changesByPreview = {} + + changesToReport.forEach(function (change) { + // For each change, see if its path _or_ one of its ancestors + // is covered by a preview. If it is, mark this change as belonging to a preview + const pathParts = change.path.split(".") + let testPath = null + let previewTitle = null + let previewChanges = null + while (pathParts.length > 0 && !previewTitle) { + testPath = pathParts.join(".") + previewTitle = pathToPreview[testPath] + // If that path didn't find a match, then we'll + // check the next ancestor. + pathParts.pop() + } + if (previewTitle) { + previewChanges = changesByPreview[previewTitle] || (changesByPreview[previewTitle] = { + title: previewTitle, + changes: [] + }) + previewChanges.changes.push(change) + } else { + schemaChanges.push(change) + } + }) + return { schemaChangesToReport: schemaChanges, previewChangesToReport: changesByPreview } } const CHANGES_TO_REPORT = [ @@ -169,4 +240,4 @@ const CHANGES_TO_IGNORE = [ -module.exports = { createChangelogEntry } +module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor } diff --git a/tests/graphql/__snapshots__/build-changelog-test.js.snap b/tests/graphql/__snapshots__/build-changelog-test.js.snap index 58fa533eb9..99c273b195 100644 --- a/tests/graphql/__snapshots__/build-changelog-test.js.snap +++ b/tests/graphql/__snapshots__/build-changelog-test.js.snap @@ -2,8 +2,15 @@ exports[`creating a changelog from old schema and new schema finds a diff of schema changes, upcoming changes, and preview changes 1`] = ` Object { - "date": "2020-11-20", - "previewChanges": Array [], + "previewChanges": Array [ + Object { + "changes": Array [ + "Field \`Query.previewField\` changed type from \`PreviewType\` to \`PreviewType!\`", + "Type for argument \`changeTypeArgument\` on field 'PreviewType.field1\` changed from \`Int\` to \`Float'", + ], + "title": "The [Test preview](/graphql/overview/schema-previews#test-preview) includes these changes:", + }, + ], "schemaChanges": Array [ Object { "changes": Array [ diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 0acbf68dd3..373c336363 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -1,8 +1,13 @@ -const { createChangelogEntry } = require('../../script/graphql/build-changelog') +const yaml = require("js-yaml") +const { createChangelogEntry, cleanPreviewTitle, previewAnchor } = require('../../script/graphql/build-changelog') describe('creating a changelog from old schema and new schema', () => { it('finds a diff of schema changes, upcoming changes, and preview changes', async () => { const oldSchemaString = ` + type PreviewType { + field1(changeTypeArgument: Int): Int + } + type Query { stableField: String removedField: Boolean @@ -12,21 +17,39 @@ describe('creating a changelog from old schema and new schema', () => { argumentMadeRequired: Int argumentMadeOptional: Int! ): String + previewField: PreviewType } ` const newSchemaString = ` + type PreviewType { + field1(changeTypeArgument: Float): Int + } + type Query { stableField: String argumentsField( argumentMadeRequired: Int! argumentMadeOptional: Int ): String + previewField: PreviewType! } ` + previews = yaml.safeLoad(` +- title: Test preview + description: This preview is just for test + toggled_by: ':test_preview' + announcement: null + updates: null + toggled_on: + - PreviewType + - Query.previewField + owning_teams: + - '@github/engineering' +`) - const entry = await createChangelogEntry(oldSchemaString, newSchemaString) + const entry = await createChangelogEntry(oldSchemaString, newSchemaString, previews) expect(entry).toMatchSnapshot() }) @@ -36,7 +59,24 @@ describe('creating a changelog from old schema and new schema', () => { i: Int! }` - const nullEntry = await createChangelogEntry(schemaString, schemaString) + const nullEntry = await createChangelogEntry(schemaString, schemaString, []) expect(nullEntry).toBeNull() }) }) + +describe("Preparing preview links", () => { + it("fixes preview names", () => { + // These two are special cases + expect(cleanPreviewTitle("UpdateRefsPreview")).toEqual("Update refs preview") + expect(cleanPreviewTitle("MergeInfoPreview")).toEqual("Merge info preview") + // Previews that don't end in " preview" have it added + expect(cleanPreviewTitle("something interesting")).toEqual("something interesting preview") + // Other things are left as-is + expect(cleanPreviewTitle("nice preview")).toEqual("nice preview") + }) + + it("creates anchors from preview titles", () => { + expect(previewAnchor("Merge info preview")).toEqual("merge-info-preview") + expect(previewAnchor("some.punct123 preview")).toEqual("somepunct123-preview") + }) +}) From 7b7ae0b5e41b65aa5a0746cce2939a44933e09dc Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 07:26:20 -0500 Subject: [PATCH 04/16] Add docs --- script/graphql/build-changelog.js | 41 ++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index 7373bc5272..de508b9a59 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -43,10 +43,16 @@ async function main() { } } - -// Compare `oldSchemaString` to `newSchemaString`, and if there are any -// changes that warrant a changelog entry, return a changelog entry. -// Otherwise, return null. +/** + * Compare `oldSchemaString` to `newSchemaString`, and if there are any + * changes that warrant a changelog entry, return a changelog entry. + * Based on the parsed `previews`, identify changes that are under a preview. + * Otherwise, return null. + * @param {string} [oldSchemaString] + * @param {string} [newSchemaString] + * @param {object} [previews] + * @return {object?} + */ async function createChangelogEntry(oldSchemaString, newSchemaString, previews) { // Create schema objects out of the strings const oldSchema = await loadSchema(oldSchemaString) @@ -108,8 +114,12 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews) } } -// prepare the preview title from github/github source for the docs. -// ported from build-changelog-from-markdown +/** + * Prepare the preview title from github/github source for the docs. + * (ported from build-changelog-from-markdown) + * @param {string} title + * @return {string} + */ function cleanPreviewTitle(title) { if (title == "UpdateRefsPreview") { title = "Update refs preview" @@ -122,17 +132,23 @@ function cleanPreviewTitle(title) { } /** + * Turn the given title into an HTML-ready anchor. + * (ported from https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L281) * @param {string} [previewTitle] * @return {string} */ function previewAnchor(previewTitle) { - // ported from https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L281 return previewTitle .toLowerCase() .replace(/ /g, '-') .replace(/[^\w-]/g, '') } +/** + * Turn changes from graphql-inspector into messages for the HTML changelog. + * @param {Array} changes + * @return {Array} + */ function cleanMessagesFromChanges(changes) { return changes.map(function (change) { // replace single quotes around graphql names with backticks, @@ -141,6 +157,15 @@ function cleanMessagesFromChanges(changes) { }) } +/** + * Split `changesToReport` into two parts, + * one for changes in the main schema, + * and another for changes that are under preview. + * (Ported from https://github.com/github/graphql-docs/blob/7e6a5ccbf13cc7d875fee65527b25bc49e886b41/lib/graphql_docs/update_internal_developer/change_log.rb#L230) + * @param {Array} changesToReport + * @param {object} previews + * @return {object} + */ function segmentPreviewChanges(changesToReport, previews) { // Build a map of `{ path => previewTitle` } // for easier lookup of change to preview @@ -238,6 +263,4 @@ const CHANGES_TO_IGNORE = [ ChangeType.TypeDescriptionAdded, ] - - module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor } From 360c517a7d69adf9eb5bd69b97a1eded0b4a5c63 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:08:00 -0500 Subject: [PATCH 05/16] Add upcoming changes to build-changelog --- script/graphql/build-changelog.js | 88 +++++++++++++------ .../build-changelog-test.js.snap | 9 +- tests/graphql/build-changelog-test.js | 21 ++++- 3 files changed, 88 insertions(+), 30 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index de508b9a59..6492264d32 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -26,23 +26,42 @@ async function main() { const previewsString = fs.readFileSync('data/graphql/graphql_previews.yml') const previews = yaml.safeLoad(previewsString) - const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString(), previews) - if (changelogEntry) { - // Build a `yyyy-mm-dd`-formatted date string - // and tag the changelog entry with it - const today = new Date() - const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0') - changelogEntry.date = todayString + // TODO how to make sure to get these before the file is updated? + const oldUpcomingChangesString = fs.readFileSync('data/graphql/graphql_upcoming_changes_public.yml') + const oldUpcomingChanges = yaml.safeLoad(oldUpcomingChangesString).upcoming_changes + // TODO actually get different changes here + const newUpcomingChanges = oldUpcomingChanges - const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json') - const previousChangelog = JSON.parse(previousChangelogString) - // add a new entry to the changelog data - previousChangelog.unshift(changelogEntry) - // rewrite the updated changelog - fs.writeFileSync('lib/graphql/static/changelog.json', JSON.stringify(previousChangelog, null, 2)) + const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString(), previews, oldUpcomingChanges, newUpcomingChanges) + if (changelogEntry) { + prependDatedEntry(changelogEntry, 'lib/graphql/static/changelog.json') } } +/** + * Tag `changelogEntry` with `date: YYYY-mm-dd`, then prepend it to the JSON + * structure written to `targetPath`. (`changelogEntry` and that file are modified in place.) + * @param {object} changelogEntry + * @param {string} targetPath + * @return {void} + */ +function prependDatedEntry(changelogEntry, targetPath) { + // Build a `yyyy-mm-dd`-formatted date string + // and tag the changelog entry with it + const today = new Date() + const todayString = String(today.getFullYear()) + '-' + + String(today.getMonth() + 1).padStart(2, '0') + '-' + + String(today.getDate()).padStart(2, '0') + changelogEntry.date = todayString + + const previousChangelogString = fs.readFileSync(targetPath) + const previousChangelog = JSON.parse(previousChangelogString) + // add a new entry to the changelog data + previousChangelog.unshift(changelogEntry) + // rewrite the updated changelog + fs.writeFileSync(targetPath, JSON.stringify(previousChangelog, null, 2)) +} + /** * Compare `oldSchemaString` to `newSchemaString`, and if there are any * changes that warrant a changelog entry, return a changelog entry. @@ -50,10 +69,12 @@ async function main() { * Otherwise, return null. * @param {string} [oldSchemaString] * @param {string} [newSchemaString] - * @param {object} [previews] + * @param {Array} [previews] + * @param {Array} [oldUpcomingChanges] + * @param {Array} [newUpcomingChanges] * @return {object?} */ -async function createChangelogEntry(oldSchemaString, newSchemaString, previews) { +async function createChangelogEntry(oldSchemaString, newSchemaString, previews, oldUpcomingChanges, newUpcomingChanges) { // Create schema objects out of the strings const oldSchema = await loadSchema(oldSchemaString) const newSchema = await loadSchema(newSchemaString) @@ -72,8 +93,20 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews) }) const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport, previews) + + const addedUpcomingChanges = newUpcomingChanges.filter(function (change) { + // Manually check each of `newUpcomingChanges` for an equivalent entry + // in `oldUpcomingChanges`. + return !oldUpcomingChanges.find(function (oldChange) { + return (oldChange.location == change.location && + oldChange.date == change.date && + oldChange.description == change.description + ) + }) + }) + // If there were any changes, create a changelog entry - if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0) { + if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0 || addedUpcomingChanges.length > 0) { const changelogEntry = { schemaChanges: [], previewChanges: [], @@ -97,17 +130,18 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews) }) } - // TODO how are these populated? - // "upcomingChanges": [ - // { - // "title": "The following changes will be made to the schema:", - // "changes": [ - // "On member `Issue.timeline`: `timeline` will be removed. Use Issue.timelineItems instead. **Effective 2020-10-01**.", - // "On member `PullRequest.timeline`: `timeline` will be removed. Use PullRequest.timelineItems instead. **Effective 2020-10-01**." - // ] - // } - // ] - const upcomingChanges = [] + if (addedUpcomingChanges.length > 0) { + changelogEntry.upcomingChanges.push({ + title: "The following changes will be made to the schema:", + changes: addedUpcomingChanges.map(function (change) { + const location = change.location + const description = change.description + const date = change.date.split("T")[0] + return "On member `" + location + "`:" + description + " **Effective " + date + "**." + }) + }) + } + return changelogEntry } else { return null diff --git a/tests/graphql/__snapshots__/build-changelog-test.js.snap b/tests/graphql/__snapshots__/build-changelog-test.js.snap index 99c273b195..e78af680b9 100644 --- a/tests/graphql/__snapshots__/build-changelog-test.js.snap +++ b/tests/graphql/__snapshots__/build-changelog-test.js.snap @@ -23,6 +23,13 @@ Object { "title": "The GraphQL schema includes these changes:", }, ], - "upcomingChanges": Array [], + "upcomingChanges": Array [ + Object { + "changes": Array [ + "On member \`Query.stableField\`:\`stableField\` will be removed. **Effective 2021-06-01**.", + ], + "title": "The following changes will be made to the schema:", + }, + ], } `; diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 373c336363..6ea7b129a7 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -49,7 +49,24 @@ describe('creating a changelog from old schema and new schema', () => { - '@github/engineering' `) - const entry = await createChangelogEntry(oldSchemaString, newSchemaString, previews) + oldUpcomingChanges = yaml.safeLoad(` +upcoming_changes: + - location: EnterprisePendingCollaboratorEdge.isUnlicensed + description: '\`isUnlicensed\` will be removed.' + date: '2021-01-01T00:00:00+00:00' +`).upcoming_changes + + newUpcomingChanges = yaml.safeLoad(` +upcoming_changes: + - location: Query.stableField + description: '\`stableField\` will be removed.' + date: '2021-06-01T00:00:00+00:00' + - location: EnterprisePendingCollaboratorEdge.isUnlicensed + description: '\`isUnlicensed\` will be removed.' + date: '2021-01-01T00:00:00+00:00' +`).upcoming_changes + + const entry = await createChangelogEntry(oldSchemaString, newSchemaString, previews, oldUpcomingChanges, newUpcomingChanges) expect(entry).toMatchSnapshot() }) @@ -59,7 +76,7 @@ describe('creating a changelog from old schema and new schema', () => { i: Int! }` - const nullEntry = await createChangelogEntry(schemaString, schemaString, []) + const nullEntry = await createChangelogEntry(schemaString, schemaString, [], [], []) expect(nullEntry).toBeNull() }) }) From f2119bc61907b5465841f107c1689f6fe804b0c5 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:17:40 -0500 Subject: [PATCH 06/16] Add a test for updating the changelog file on disk --- script/graphql/build-changelog.js | 2 +- .../build-changelog-test.js.snap | 15 ++++++++++++++ tests/graphql/build-changelog-test.js | 20 ++++++++++++++++++- tests/graphql/example_changelog.json | 8 ++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/graphql/example_changelog.json diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index 6492264d32..dae47e8f22 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -297,4 +297,4 @@ const CHANGES_TO_IGNORE = [ ChangeType.TypeDescriptionAdded, ] -module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor } +module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } diff --git a/tests/graphql/__snapshots__/build-changelog-test.js.snap b/tests/graphql/__snapshots__/build-changelog-test.js.snap index e78af680b9..bcf7b6d289 100644 --- a/tests/graphql/__snapshots__/build-changelog-test.js.snap +++ b/tests/graphql/__snapshots__/build-changelog-test.js.snap @@ -33,3 +33,18 @@ Object { ], } `; + +exports[`updating the changelog file modifies the entry object and the file on disk 1`] = ` +"[ + { + \\"someStuff\\": true, + \\"date\\": \\"2020-11-23\\" + }, + { + \\"previous_entry\\": \\"...\\" + }, + { + \\"another_previous_entry\\": \\"...\\" + } +]" +`; diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 6ea7b129a7..5d44c76e14 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -1,5 +1,6 @@ const yaml = require("js-yaml") -const { createChangelogEntry, cleanPreviewTitle, previewAnchor } = require('../../script/graphql/build-changelog') +const { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } = require('../../script/graphql/build-changelog') +const fs = require("fs") describe('creating a changelog from old schema and new schema', () => { it('finds a diff of schema changes, upcoming changes, and preview changes', async () => { @@ -97,3 +98,20 @@ describe("Preparing preview links", () => { expect(previewAnchor("some.punct123 preview")).toEqual("somepunct123-preview") }) }) + +describe("updating the changelog file", () => { + it("modifies the entry object and the file on disk", () => { + const testTargetPath = "tests/graphql/example_changelog.json" + const previousContents = fs.readFileSync(testTargetPath) + + const exampleEntry = { someStuff: true } + prependDatedEntry(exampleEntry, testTargetPath) + const newContents = fs.readFileSync(testTargetPath).toString() + // reset the file: + fs.writeFileSync(testTargetPath, previousContents) + + const expectedDate = (new Date).toISOString().split("T")[0] + expect(exampleEntry).toEqual({ someStuff: true, date: expectedDate }) + expect(newContents).toMatchSnapshot() + }) +}) diff --git a/tests/graphql/example_changelog.json b/tests/graphql/example_changelog.json new file mode 100644 index 0000000000..a132be4304 --- /dev/null +++ b/tests/graphql/example_changelog.json @@ -0,0 +1,8 @@ +[ + { + "previous_entry": "..." + }, + { + "another_previous_entry": "..." + } +] From ab06aadf82a3ea73f9fd9b0cede6ddd36b646471 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:42:12 -0500 Subject: [PATCH 07/16] Add changelog creation to update-files.js --- script/graphql/build-changelog.js | 35 --------------------------- script/graphql/update-files.js | 23 ++++++++++++++++++ tests/graphql/build-changelog-test.js | 2 +- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index dae47e8f22..a58a4a7508 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -1,43 +1,8 @@ const { diff, ChangeType } = require('@graphql-inspector/core') const { loadSchema } = require('@graphql-tools/load') -const git = require('../../lib/git-utils') const fs = require('fs') const yaml = require('js-yaml') -// check for required PAT -if (!process.env.GITHUB_TOKEN) { - console.error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.') - process.exit(1) -} - -// main() - -async function main() { - // Load the previous schema from this repo - // TODO -- how to make sure that this script runs _before_ this artifact is updated? - // Maybe hook into the existing `update-files` script instead of being a stand-alone script. - const oldSchemaString = fs.readFileSync('data/graphql/schema.docs.graphql').toString() - - // Load the latest schema from github/github - const tree = await git.getTree('github', 'github', 'heads/master') - const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob') - const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob) - - const previewsString = fs.readFileSync('data/graphql/graphql_previews.yml') - const previews = yaml.safeLoad(previewsString) - - // TODO how to make sure to get these before the file is updated? - const oldUpcomingChangesString = fs.readFileSync('data/graphql/graphql_upcoming_changes_public.yml') - const oldUpcomingChanges = yaml.safeLoad(oldUpcomingChangesString).upcoming_changes - // TODO actually get different changes here - const newUpcomingChanges = oldUpcomingChanges - - const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString(), previews, oldUpcomingChanges, newUpcomingChanges) - if (changelogEntry) { - prependDatedEntry(changelogEntry, 'lib/graphql/static/changelog.json') - } -} - /** * Tag `changelogEntry` with `date: YYYY-mm-dd`, then prepend it to the JSON * structure written to `targetPath`. (`changelogEntry` and that file are modified in place.) diff --git a/script/graphql/update-files.js b/script/graphql/update-files.js index ed51b443b5..1bb806ccc7 100755 --- a/script/graphql/update-files.js +++ b/script/graphql/update-files.js @@ -14,6 +14,7 @@ const processPreviews = require('./utils/process-previews') const processUpcomingChanges = require('./utils/process-upcoming-changes') const processSchemas = require('./utils/process-schemas') const prerenderObjects = require('./utils/prerender-objects') +const { prependDatedEntry, createChangelogEntry } = require("./build-changelog") // check for required PAT if (!process.env.GITHUB_TOKEN) { @@ -57,6 +58,10 @@ async function main () { // 2. UPDATE UPCOMING CHANGES const upcomingChangesPath = getDataFilepath('upcomingChanges', graphqlVersion) + let previousUpcomingChanges = null + if (fs.existsSync(upcomingChangesPath)) { + previousUpcomingChanges = yaml.safeLoad(fs.readFileSync(upcomingChangesPath, "utf8")) + } const safeForPublicChanges = await getRemoteRawContent(upcomingChangesPath, graphqlVersion) updateFile(upcomingChangesPath, safeForPublicChanges) upcomingChangesJson[graphqlVersion] = await processUpcomingChanges(safeForPublicChanges) @@ -64,6 +69,10 @@ async function main () { // 3. UPDATE SCHEMAS // note: schemas live in separate files per version const schemaPath = getDataFilepath('schemas', graphqlVersion) + let previousSchemaString = null + if (fs.existsSync(upcomingChangesPath)) { + previousSchemaString = fs.readFileSync(schemaPath, "utf8") + } const latestSchema = await getRemoteRawContent(schemaPath, graphqlVersion) const safeForPublicSchema = removeHiddenMembers(schemaPath, latestSchema) updateFile(schemaPath, safeForPublicSchema) @@ -73,6 +82,20 @@ async function main () { // 4. PRERENDER OBJECTS HTML // because the objects page is too big to render on page load prerenderedObjects[graphqlVersion] = await prerenderObjects(schemaJsonPerVersion) + + if (allVersions[version].nonEnterpriseDefault) { + // The Changelog is only build for free-pro-team@latest + const changelogEntry = createChangelogEntry( + previousSchemaString, + safeForPublicSchema, + safeForPublicPreviews, + previousUpcomingChanges.upcoming_changes, + yaml.safeLoad(safeForPublicChanges).upcoming_changes, + ) + if (changelogEntry) { + prependDatedEntry(changelogEntry, path.join(process.cwd(), 'lib/graphql/static/changelog.json')) + } + } } updateStaticFile(previewsJson, path.join(graphqlStaticDir, 'previews.json')) diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 5d44c76e14..7228b46cf1 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -106,7 +106,7 @@ describe("updating the changelog file", () => { const exampleEntry = { someStuff: true } prependDatedEntry(exampleEntry, testTargetPath) - const newContents = fs.readFileSync(testTargetPath).toString() + const newContents = fs.readFileSync(testTargetPath, "utf8") // reset the file: fs.writeFileSync(testTargetPath, previousContents) From 3ad453e28bda01b639388f4180c5b07d8ded5c4c Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:45:07 -0500 Subject: [PATCH 08/16] remove needless package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index bf5d6783b0..067dc8fcd4 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "@github-docs/render-content": "^5.2.0", "@github/rest-api-operations": "^3.7.3", "@graphql-inspector/core": "^2.3.0", - "@graphql-tools/github-loader": "^6.2.5", "@graphql-tools/load": "^6.2.5", "@octokit/rest": "^16.38.1", "@primer/css": "^15.1.0", From 615561cb56fe390a72dbd24f764027364d41d87d Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:45:52 -0500 Subject: [PATCH 09/16] oops, update lockfile --- package-lock.json | 230 ++-------------------------------------------- 1 file changed, 8 insertions(+), 222 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70528b7c4b..fe4a5a67b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1248,197 +1248,6 @@ } } }, - "@graphql-tools/github-loader": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-6.2.5.tgz", - "integrity": "sha512-DLuQmYeNNdPo8oWus8EePxWCfCAyUXPZ/p1PWqjrX/NGPyH2ZObdqtDAfRHztljt0F/qkBHbGHCEk2TKbRZTRw==", - "requires": { - "@graphql-tools/graphql-tag-pluck": "^6.2.6", - "@graphql-tools/utils": "^7.0.0", - "cross-fetch": "3.0.6", - "tslib": "~2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" - } - } - }, - "@graphql-tools/graphql-tag-pluck": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-6.3.0.tgz", - "integrity": "sha512-wdXE6iKTD/ePvhPaukhXm6M8FcsiR9rrwFvkYN96sx2UjDjXzU6vS1QUniNuwjRPaQuSe635vqfaUSN9JuNHvA==", - "requires": { - "@babel/parser": "7.11.5", - "@babel/traverse": "7.12.1", - "@babel/types": "7.12.1", - "@graphql-tools/utils": "^7.0.0", - "tslib": "~2.0.1", - "vue-template-compiler": "^2.6.12" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", - "requires": { - "@babel/types": "^7.12.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.12.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", - "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", - "requires": { - "@babel/types": "^7.11.0" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.11.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", - "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==" - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz", - "integrity": "sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.1", - "@babel/types": "^7.12.1", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/parser": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", - "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==" - } - } - }, - "@babel/types": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", - "integrity": "sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" - } - } - }, "@graphql-tools/load": { "version": "6.2.5", "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-6.2.5.tgz", @@ -3699,7 +3508,7 @@ }, "agentkeepalive": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", + "resolved": "http://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" }, "aggregate-error": { @@ -3847,7 +3656,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "requires": { "sprintf-js": "~1.0.2" } @@ -4596,7 +4405,7 @@ }, "brfs": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "resolved": "http://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", "requires": { "quote-stream": "^1.0.1", @@ -6039,14 +5848,6 @@ "cross-spawn": "^7.0.1" } }, - "cross-fetch": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", - "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", - "requires": { - "node-fetch": "2.6.1" - } - }, "cross-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", @@ -6378,12 +6179,6 @@ "resolved": "https://registry.npmjs.org/dateutil/-/dateutil-0.1.0.tgz", "integrity": "sha1-9MAkKeA/knwcnh4hu+KzeDNHfrA=" }, - "de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "optional": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7188,7 +6983,7 @@ "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", "requires": { "is-arrayish": "^0.2.1" } @@ -10240,7 +10035,8 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, "header-case": { "version": "1.0.1", @@ -10342,7 +10138,7 @@ "dependencies": { "mkdirp": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" }, "nopt": { @@ -15451,7 +15247,7 @@ }, "magic-string": { "version": "0.22.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "requires": { "vlq": "^0.2.2" @@ -20984,16 +20780,6 @@ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, - "vue-template-compiler": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz", - "integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==", - "optional": true, - "requires": { - "de-indent": "^1.0.2", - "he": "^1.1.0" - } - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", From b87ca3b3e3eb9124e6edee8a896be073a37a6698 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Mon, 23 Nov 2020 08:55:05 -0500 Subject: [PATCH 10/16] Fix lint errors --- script/graphql/build-changelog.js | 59 +++++++++++++-------------- script/graphql/update-files.js | 8 ++-- tests/graphql/build-changelog-test.js | 38 ++++++++--------- 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index a58a4a7508..b210bc1d2c 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -1,7 +1,6 @@ const { diff, ChangeType } = require('@graphql-inspector/core') const { loadSchema } = require('@graphql-tools/load') const fs = require('fs') -const yaml = require('js-yaml') /** * Tag `changelogEntry` with `date: YYYY-mm-dd`, then prepend it to the JSON @@ -10,7 +9,7 @@ const yaml = require('js-yaml') * @param {string} targetPath * @return {void} */ -function prependDatedEntry(changelogEntry, targetPath) { +function prependDatedEntry (changelogEntry, targetPath) { // Build a `yyyy-mm-dd`-formatted date string // and tag the changelog entry with it const today = new Date() @@ -39,7 +38,7 @@ function prependDatedEntry(changelogEntry, targetPath) { * @param {Array} [newUpcomingChanges] * @return {object?} */ -async function createChangelogEntry(oldSchemaString, newSchemaString, previews, oldUpcomingChanges, newUpcomingChanges) { +async function createChangelogEntry (oldSchemaString, newSchemaString, previews, oldUpcomingChanges, newUpcomingChanges) { // Create schema objects out of the strings const oldSchema = await loadSchema(oldSchemaString) const newSchema = await loadSchema(newSchemaString) @@ -53,7 +52,7 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews, } else if (CHANGES_TO_IGNORE.includes(change.type)) { // Do nothing } else { - throw "This change type should be added to CHANGES_TO_REPORT or CHANGES_TO_IGNORE: " + change.type + throw new Error('This change type should be added to CHANGES_TO_REPORT or CHANGES_TO_IGNORE: ' + change.type) } }) @@ -63,9 +62,9 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews, // Manually check each of `newUpcomingChanges` for an equivalent entry // in `oldUpcomingChanges`. return !oldUpcomingChanges.find(function (oldChange) { - return (oldChange.location == change.location && - oldChange.date == change.date && - oldChange.description == change.description + return (oldChange.location === change.location && + oldChange.date === change.date && + oldChange.description === change.description ) }) }) @@ -75,7 +74,7 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews, const changelogEntry = { schemaChanges: [], previewChanges: [], - upcomingChanges: [], + upcomingChanges: [] } const schemaChange = { @@ -86,23 +85,23 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews, changelogEntry.schemaChanges.push(schemaChange) for (const previewTitle in previewChangesToReport) { - let previewChanges = previewChangesToReport[previewTitle] - let cleanTitle = cleanPreviewTitle(previewTitle) - let entryTitle = "The [" + cleanTitle + "](/graphql/overview/schema-previews#" + previewAnchor(cleanTitle) + ") includes these changes:" + const previewChanges = previewChangesToReport[previewTitle] + const cleanTitle = cleanPreviewTitle(previewTitle) + const entryTitle = 'The [' + cleanTitle + '](/graphql/overview/schema-previews#' + previewAnchor(cleanTitle) + ') includes these changes:' changelogEntry.previewChanges.push({ title: entryTitle, - changes: cleanMessagesFromChanges(previewChanges.changes), + changes: cleanMessagesFromChanges(previewChanges.changes) }) } if (addedUpcomingChanges.length > 0) { changelogEntry.upcomingChanges.push({ - title: "The following changes will be made to the schema:", + title: 'The following changes will be made to the schema:', changes: addedUpcomingChanges.map(function (change) { const location = change.location const description = change.description - const date = change.date.split("T")[0] - return "On member `" + location + "`:" + description + " **Effective " + date + "**." + const date = change.date.split('T')[0] + return 'On member `' + location + '`:' + description + ' **Effective ' + date + '**.' }) }) } @@ -119,13 +118,13 @@ async function createChangelogEntry(oldSchemaString, newSchemaString, previews, * @param {string} title * @return {string} */ -function cleanPreviewTitle(title) { - if (title == "UpdateRefsPreview") { - title = "Update refs preview" - } else if (title == "MergeInfoPreview") { - title = "Merge info preview" - } else if (!title.endsWith("preview")) { - title = title + " preview" +function cleanPreviewTitle (title) { + if (title === 'UpdateRefsPreview') { + title = 'Update refs preview' + } else if (title === 'MergeInfoPreview') { + title = 'Merge info preview' + } else if (!title.endsWith('preview')) { + title = title + ' preview' } return title } @@ -136,7 +135,7 @@ function cleanPreviewTitle(title) { * @param {string} [previewTitle] * @return {string} */ -function previewAnchor(previewTitle) { +function previewAnchor (previewTitle) { return previewTitle .toLowerCase() .replace(/ /g, '-') @@ -148,11 +147,11 @@ function previewAnchor(previewTitle) { * @param {Array} changes * @return {Array} */ -function cleanMessagesFromChanges(changes) { +function cleanMessagesFromChanges (changes) { return changes.map(function (change) { // replace single quotes around graphql names with backticks, // to match previous behavior from graphql-schema-comparator - return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`') + return change.message.replace(/'([a-zA-Z. :!]+)'/g, '`$1`') }) } @@ -165,7 +164,7 @@ function cleanMessagesFromChanges(changes) { * @param {object} previews * @return {object} */ -function segmentPreviewChanges(changesToReport, previews) { +function segmentPreviewChanges (changesToReport, previews) { // Build a map of `{ path => previewTitle` } // for easier lookup of change to preview const pathToPreview = {} @@ -180,12 +179,12 @@ function segmentPreviewChanges(changesToReport, previews) { changesToReport.forEach(function (change) { // For each change, see if its path _or_ one of its ancestors // is covered by a preview. If it is, mark this change as belonging to a preview - const pathParts = change.path.split(".") + const pathParts = change.path.split('.') let testPath = null let previewTitle = null let previewChanges = null while (pathParts.length > 0 && !previewTitle) { - testPath = pathParts.join(".") + testPath = pathParts.join('.') previewTitle = pathToPreview[testPath] // If that path didn't find a match, then we'll // check the next ancestor. @@ -227,7 +226,7 @@ const CHANGES_TO_REPORT = [ ChangeType.UnionMemberAdded, ChangeType.SchemaQueryTypeChanged, ChangeType.SchemaMutationTypeChanged, - ChangeType.SchemaSubscriptionTypeChanged, + ChangeType.SchemaSubscriptionTypeChanged ] const CHANGES_TO_IGNORE = [ @@ -259,7 +258,7 @@ const CHANGES_TO_IGNORE = [ ChangeType.InputFieldDescriptionChanged, ChangeType.TypeDescriptionChanged, ChangeType.TypeDescriptionRemoved, - ChangeType.TypeDescriptionAdded, + ChangeType.TypeDescriptionAdded ] module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } diff --git a/script/graphql/update-files.js b/script/graphql/update-files.js index 8b0efc3178..c5d83294b0 100755 --- a/script/graphql/update-files.js +++ b/script/graphql/update-files.js @@ -14,7 +14,7 @@ const processPreviews = require('./utils/process-previews') const processUpcomingChanges = require('./utils/process-upcoming-changes') const processSchemas = require('./utils/process-schemas') const prerenderObjects = require('./utils/prerender-objects') -const { prependDatedEntry, createChangelogEntry } = require("./build-changelog") +const { prependDatedEntry, createChangelogEntry } = require('./build-changelog') // check for required PAT if (!process.env.GITHUB_TOKEN) { @@ -60,7 +60,7 @@ async function main () { const upcomingChangesPath = getDataFilepath('upcomingChanges', graphqlVersion) let previousUpcomingChanges = null if (fs.existsSync(upcomingChangesPath)) { - previousUpcomingChanges = yaml.safeLoad(fs.readFileSync(upcomingChangesPath, "utf8")) + previousUpcomingChanges = yaml.safeLoad(fs.readFileSync(upcomingChangesPath, 'utf8')) } const safeForPublicChanges = await getRemoteRawContent(upcomingChangesPath, graphqlVersion) updateFile(upcomingChangesPath, safeForPublicChanges) @@ -71,7 +71,7 @@ async function main () { const schemaPath = getDataFilepath('schemas', graphqlVersion) let previousSchemaString = null if (fs.existsSync(upcomingChangesPath)) { - previousSchemaString = fs.readFileSync(schemaPath, "utf8") + previousSchemaString = fs.readFileSync(schemaPath, 'utf8') } const latestSchema = await getRemoteRawContent(schemaPath, graphqlVersion) const safeForPublicSchema = removeHiddenMembers(schemaPath, latestSchema) @@ -90,7 +90,7 @@ async function main () { safeForPublicSchema, safeForPublicPreviews, previousUpcomingChanges.upcoming_changes, - yaml.safeLoad(safeForPublicChanges).upcoming_changes, + yaml.safeLoad(safeForPublicChanges).upcoming_changes ) if (changelogEntry) { prependDatedEntry(changelogEntry, path.join(process.cwd(), 'lib/graphql/static/changelog.json')) diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 7228b46cf1..35342eb6b4 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -1,6 +1,6 @@ -const yaml = require("js-yaml") +const yaml = require('js-yaml') const { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } = require('../../script/graphql/build-changelog') -const fs = require("fs") +const fs = require('fs') describe('creating a changelog from old schema and new schema', () => { it('finds a diff of schema changes, upcoming changes, and preview changes', async () => { @@ -37,7 +37,7 @@ describe('creating a changelog from old schema and new schema', () => { } ` - previews = yaml.safeLoad(` + const previews = yaml.safeLoad(` - title: Test preview description: This preview is just for test toggled_by: ':test_preview' @@ -50,14 +50,14 @@ describe('creating a changelog from old schema and new schema', () => { - '@github/engineering' `) - oldUpcomingChanges = yaml.safeLoad(` + const oldUpcomingChanges = yaml.safeLoad(` upcoming_changes: - location: EnterprisePendingCollaboratorEdge.isUnlicensed description: '\`isUnlicensed\` will be removed.' date: '2021-01-01T00:00:00+00:00' `).upcoming_changes - newUpcomingChanges = yaml.safeLoad(` + const newUpcomingChanges = yaml.safeLoad(` upcoming_changes: - location: Query.stableField description: '\`stableField\` will be removed.' @@ -82,35 +82,35 @@ upcoming_changes: }) }) -describe("Preparing preview links", () => { - it("fixes preview names", () => { +describe('Preparing preview links', () => { + it('fixes preview names', () => { // These two are special cases - expect(cleanPreviewTitle("UpdateRefsPreview")).toEqual("Update refs preview") - expect(cleanPreviewTitle("MergeInfoPreview")).toEqual("Merge info preview") + expect(cleanPreviewTitle('UpdateRefsPreview')).toEqual('Update refs preview') + expect(cleanPreviewTitle('MergeInfoPreview')).toEqual('Merge info preview') // Previews that don't end in " preview" have it added - expect(cleanPreviewTitle("something interesting")).toEqual("something interesting preview") + expect(cleanPreviewTitle('something interesting')).toEqual('something interesting preview') // Other things are left as-is - expect(cleanPreviewTitle("nice preview")).toEqual("nice preview") + expect(cleanPreviewTitle('nice preview')).toEqual('nice preview') }) - it("creates anchors from preview titles", () => { - expect(previewAnchor("Merge info preview")).toEqual("merge-info-preview") - expect(previewAnchor("some.punct123 preview")).toEqual("somepunct123-preview") + it('creates anchors from preview titles', () => { + expect(previewAnchor('Merge info preview')).toEqual('merge-info-preview') + expect(previewAnchor('some.punct123 preview')).toEqual('somepunct123-preview') }) }) -describe("updating the changelog file", () => { - it("modifies the entry object and the file on disk", () => { - const testTargetPath = "tests/graphql/example_changelog.json" +describe('updating the changelog file', () => { + it('modifies the entry object and the file on disk', () => { + const testTargetPath = 'tests/graphql/example_changelog.json' const previousContents = fs.readFileSync(testTargetPath) const exampleEntry = { someStuff: true } prependDatedEntry(exampleEntry, testTargetPath) - const newContents = fs.readFileSync(testTargetPath, "utf8") + const newContents = fs.readFileSync(testTargetPath, 'utf8') // reset the file: fs.writeFileSync(testTargetPath, previousContents) - const expectedDate = (new Date).toISOString().split("T")[0] + const expectedDate = (new Date()).toISOString().split('T')[0] expect(exampleEntry).toEqual({ someStuff: true, date: expectedDate }) expect(newContents).toMatchSnapshot() }) From 15dbbeeb7cd0b8b7d882c73a2647f5f0fb4e23a8 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 25 Nov 2020 10:48:21 -0500 Subject: [PATCH 11/16] Apply suggestions from code review Co-authored-by: Sarah Schneider --- script/graphql/build-changelog.js | 5 +---- script/graphql/update-files.js | 13 ++++--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index b210bc1d2c..a3614a833b 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -12,10 +12,7 @@ const fs = require('fs') function prependDatedEntry (changelogEntry, targetPath) { // Build a `yyyy-mm-dd`-formatted date string // and tag the changelog entry with it - const today = new Date() - const todayString = String(today.getFullYear()) + '-' + - String(today.getMonth() + 1).padStart(2, '0') + '-' + - String(today.getDate()).padStart(2, '0') + const today = new Date().toISOString().slice(0, 10) changelogEntry.date = todayString const previousChangelogString = fs.readFileSync(targetPath) diff --git a/script/graphql/update-files.js b/script/graphql/update-files.js index c5d83294b0..03877bd164 100755 --- a/script/graphql/update-files.js +++ b/script/graphql/update-files.js @@ -58,10 +58,7 @@ async function main () { // 2. UPDATE UPCOMING CHANGES const upcomingChangesPath = getDataFilepath('upcomingChanges', graphqlVersion) - let previousUpcomingChanges = null - if (fs.existsSync(upcomingChangesPath)) { - previousUpcomingChanges = yaml.safeLoad(fs.readFileSync(upcomingChangesPath, 'utf8')) - } + const previousUpcomingChanges = yaml.safeLoad(fs.readFileSync(upcomingChangesPath, 'utf8')) const safeForPublicChanges = await getRemoteRawContent(upcomingChangesPath, graphqlVersion) updateFile(upcomingChangesPath, safeForPublicChanges) upcomingChangesJson[graphqlVersion] = await processUpcomingChanges(safeForPublicChanges) @@ -69,10 +66,7 @@ async function main () { // 3. UPDATE SCHEMAS // note: schemas live in separate files per version const schemaPath = getDataFilepath('schemas', graphqlVersion) - let previousSchemaString = null - if (fs.existsSync(upcomingChangesPath)) { - previousSchemaString = fs.readFileSync(schemaPath, 'utf8') - } + const previousSchemaString = fs.readFileSync(schemaPath, 'utf8') const latestSchema = await getRemoteRawContent(schemaPath, graphqlVersion) const safeForPublicSchema = removeHiddenMembers(schemaPath, latestSchema) updateFile(schemaPath, safeForPublicSchema) @@ -83,9 +77,10 @@ async function main () { // because the objects page is too big to render on page load prerenderedObjects[graphqlVersion] = await prerenderObjects(schemaJsonPerVersion) + // 5. UPDATE CHANGELOG if (allVersions[version].nonEnterpriseDefault) { // The Changelog is only build for free-pro-team@latest - const changelogEntry = createChangelogEntry( + const changelogEntry = await createChangelogEntry( previousSchemaString, safeForPublicSchema, safeForPublicPreviews, From 84153b4d039e4259addf05428038a21b045bd61e Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 25 Nov 2020 11:01:15 -0500 Subject: [PATCH 12/16] Add a description to CHANGES_TO_REPORT --- script/graphql/build-changelog.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index a3614a833b..0fb281fa9a 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -12,7 +12,7 @@ const fs = require('fs') function prependDatedEntry (changelogEntry, targetPath) { // Build a `yyyy-mm-dd`-formatted date string // and tag the changelog entry with it - const today = new Date().toISOString().slice(0, 10) + const todayString = new Date().toISOString().slice(0, 10) changelogEntry.date = todayString const previousChangelogString = fs.readFileSync(targetPath) @@ -200,6 +200,11 @@ function segmentPreviewChanges (changesToReport, previews) { return { schemaChangesToReport: schemaChanges, previewChangesToReport: changesByPreview } } +// We only want to report changes to schema structure. +// Deprecations are covered by "upcoming changes." +// By listing the changes explicitly here, we can make sure that, +// if the library changes, we don't miss publishing anything that we mean to. +// This was originally ported from https://github.com/github/graphql-docs/blob/7e6a5ccbf13cc7d875fee65527b25bc49e886b41/lib/graphql_docs/update_internal_developer/change_log.rb#L35-L103 const CHANGES_TO_REPORT = [ ChangeType.FieldArgumentDefaultChanged, ChangeType.FieldArgumentTypeChanged, From aeedfac37e41201dee81fade3e73fad38d79285f Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 25 Nov 2020 11:12:13 -0500 Subject: [PATCH 13/16] Add graphql tests to CI, move snapshots to fixures, use mockdate --- .github/workflows/test.yml | 2 +- package-lock.json | 5 ++ package.json | 1 + tests/fixtures/changelog-entry.json | 31 ++++++++++++ tests/fixtures/updated-changelog-file.json | 12 +++++ .../build-changelog-test.js.snap | 50 ------------------- tests/graphql/build-changelog-test.js | 20 ++++++-- 7 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 tests/fixtures/changelog-entry.json create mode 100644 tests/fixtures/updated-changelog-file.json delete mode 100644 tests/graphql/__snapshots__/build-changelog-test.js.snap diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 502eeafab6..9239972028 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - test-group: [content, meta, rendering, routing, unit, links-and-images] + test-group: [content, meta, rendering, routing, unit, links-and-images, graphql] steps: # Each of these ifs needs to be repeated at each step to make sure the required check still runs # Even if if doesn't do anything diff --git a/package-lock.json b/package-lock.json index fe4a5a67b7..9cea144337 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15892,6 +15892,11 @@ "integrity": "sha1-mDaL6wnfdT9k9m2U5VNql7NqJDA=", "dev": true }, + "mockdate": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.2.tgz", + "integrity": "sha512-ldfYSUW1ocqSHGTK6rrODUiqAFPGAg0xaHqYJ5tvj1hQyFsjuHpuWgWFTZWwDVlzougN/s2/mhDr8r5nY5xDpA==" + }, "morgan": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", diff --git a/package.json b/package.json index 067dc8fcd4..e1327dd1ed 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "lodash": "^4.17.19", "mini-css-extract-plugin": "^0.9.0", "mkdirp": "^1.0.3", + "mockdate": "^3.0.2", "morgan": "^1.9.1", "node-fetch": "^2.6.1", "platform-utils": "^1.2.0", diff --git a/tests/fixtures/changelog-entry.json b/tests/fixtures/changelog-entry.json new file mode 100644 index 0000000000..900dbe3a3b --- /dev/null +++ b/tests/fixtures/changelog-entry.json @@ -0,0 +1,31 @@ +{ + "previewChanges": [ + { + "changes": [ + "Field `Query.previewField` changed type from `PreviewType` to `PreviewType!`", + "Type for argument `changeTypeArgument` on field 'PreviewType.field1` changed from `Int` to `Float'" + ], + "title": "The [Test preview](/graphql/overview/schema-previews#test-preview) includes these changes:" + } + ], + "schemaChanges": [ + { + "changes": [ + "Field `removedField` was removed from object type `Query`", + "Type for argument `argumentMadeRequired` on field `Query.argumentsField` changed from `Int` to `Int!`", + "Type for argument `argumentMadeOptional` on field `Query.argumentsField` changed from `Int!` to `Int`", + "Argument `removedRequiredArgument: Int!` was removed from field `Query.argumentsField`", + "Argument `removedOptionalArgument: Int!` was removed from field `Query.argumentsField`" + ], + "title": "The GraphQL schema includes these changes:" + } + ], + "upcomingChanges": [ + { + "changes": [ + "On member `Query.stableField`:`stableField` will be removed. **Effective 2021-06-01**." + ], + "title": "The following changes will be made to the schema:" + } + ] +} diff --git a/tests/fixtures/updated-changelog-file.json b/tests/fixtures/updated-changelog-file.json new file mode 100644 index 0000000000..3e8ee60410 --- /dev/null +++ b/tests/fixtures/updated-changelog-file.json @@ -0,0 +1,12 @@ +[ + { + "someStuff": true, + "date": "2020-11-20" + }, + { + "previous_entry": "..." + }, + { + "another_previous_entry": "..." + } +] diff --git a/tests/graphql/__snapshots__/build-changelog-test.js.snap b/tests/graphql/__snapshots__/build-changelog-test.js.snap deleted file mode 100644 index bcf7b6d289..0000000000 --- a/tests/graphql/__snapshots__/build-changelog-test.js.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`creating a changelog from old schema and new schema finds a diff of schema changes, upcoming changes, and preview changes 1`] = ` -Object { - "previewChanges": Array [ - Object { - "changes": Array [ - "Field \`Query.previewField\` changed type from \`PreviewType\` to \`PreviewType!\`", - "Type for argument \`changeTypeArgument\` on field 'PreviewType.field1\` changed from \`Int\` to \`Float'", - ], - "title": "The [Test preview](/graphql/overview/schema-previews#test-preview) includes these changes:", - }, - ], - "schemaChanges": Array [ - Object { - "changes": Array [ - "Field \`removedField\` was removed from object type \`Query\`", - "Type for argument \`argumentMadeRequired\` on field \`Query.argumentsField\` changed from \`Int\` to \`Int!\`", - "Type for argument \`argumentMadeOptional\` on field \`Query.argumentsField\` changed from \`Int!\` to \`Int\`", - "Argument \`removedRequiredArgument: Int!\` was removed from field \`Query.argumentsField\`", - "Argument \`removedOptionalArgument: Int!\` was removed from field \`Query.argumentsField\`", - ], - "title": "The GraphQL schema includes these changes:", - }, - ], - "upcomingChanges": Array [ - Object { - "changes": Array [ - "On member \`Query.stableField\`:\`stableField\` will be removed. **Effective 2021-06-01**.", - ], - "title": "The following changes will be made to the schema:", - }, - ], -} -`; - -exports[`updating the changelog file modifies the entry object and the file on disk 1`] = ` -"[ - { - \\"someStuff\\": true, - \\"date\\": \\"2020-11-23\\" - }, - { - \\"previous_entry\\": \\"...\\" - }, - { - \\"another_previous_entry\\": \\"...\\" - } -]" -`; diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index 35342eb6b4..ab2f9cf524 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -1,8 +1,15 @@ const yaml = require('js-yaml') const { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } = require('../../script/graphql/build-changelog') const fs = require('fs') +const MockDate = require("mockdate") +const expectedChangelogEntry = require('../fixtures/changelog-entry') +const expectedUpdatedChangelogFile = require('../fixtures/updated-changelog-file') describe('creating a changelog from old schema and new schema', () => { + afterEach(() => { + MockDate.reset() + }) + it('finds a diff of schema changes, upcoming changes, and preview changes', async () => { const oldSchemaString = ` type PreviewType { @@ -68,7 +75,7 @@ upcoming_changes: `).upcoming_changes const entry = await createChangelogEntry(oldSchemaString, newSchemaString, previews, oldUpcomingChanges, newUpcomingChanges) - expect(entry).toMatchSnapshot() + expect(entry).toEqual(expectedChangelogEntry) }) it('returns null when there isnt any difference', async () => { @@ -100,18 +107,25 @@ describe('Preparing preview links', () => { }) describe('updating the changelog file', () => { + afterEach(() => { + MockDate.reset() + }) + it('modifies the entry object and the file on disk', () => { const testTargetPath = 'tests/graphql/example_changelog.json' const previousContents = fs.readFileSync(testTargetPath) const exampleEntry = { someStuff: true } + const expectedDate = "2020-11-20" + MockDate.set(expectedDate) + prependDatedEntry(exampleEntry, testTargetPath) const newContents = fs.readFileSync(testTargetPath, 'utf8') // reset the file: fs.writeFileSync(testTargetPath, previousContents) - const expectedDate = (new Date()).toISOString().split('T')[0] + expect(exampleEntry).toEqual({ someStuff: true, date: expectedDate }) - expect(newContents).toMatchSnapshot() + expect(JSON.parse(newContents)).toEqual(expectedUpdatedChangelogFile) }) }) From fc54b4d43c6404a1249289a87ea0c225d95b8975 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 25 Nov 2020 16:30:37 -0500 Subject: [PATCH 14/16] Fix lint errors --- .github/workflows/test.yml | 3 ++- tests/graphql/build-changelog-test.js | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9239972028..fa780ffcb6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,8 @@ jobs: strategy: fail-fast: false matrix: - test-group: [content, meta, rendering, routing, unit, links-and-images, graphql] + test-group: + [content, meta, rendering, routing, unit, links-and-images, graphql] steps: # Each of these ifs needs to be repeated at each step to make sure the required check still runs # Even if if doesn't do anything diff --git a/tests/graphql/build-changelog-test.js b/tests/graphql/build-changelog-test.js index ab2f9cf524..1a55d59bab 100644 --- a/tests/graphql/build-changelog-test.js +++ b/tests/graphql/build-changelog-test.js @@ -1,7 +1,7 @@ const yaml = require('js-yaml') const { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntry } = require('../../script/graphql/build-changelog') const fs = require('fs') -const MockDate = require("mockdate") +const MockDate = require('mockdate') const expectedChangelogEntry = require('../fixtures/changelog-entry') const expectedUpdatedChangelogFile = require('../fixtures/updated-changelog-file') @@ -116,7 +116,7 @@ describe('updating the changelog file', () => { const previousContents = fs.readFileSync(testTargetPath) const exampleEntry = { someStuff: true } - const expectedDate = "2020-11-20" + const expectedDate = '2020-11-20' MockDate.set(expectedDate) prependDatedEntry(exampleEntry, testTargetPath) @@ -124,7 +124,6 @@ describe('updating the changelog file', () => { // reset the file: fs.writeFileSync(testTargetPath, previousContents) - expect(exampleEntry).toEqual({ someStuff: true, date: expectedDate }) expect(JSON.parse(newContents)).toEqual(expectedUpdatedChangelogFile) }) From caf4add9a567116c8e871a85a938b2108fe3ba7e Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 25 Nov 2020 16:44:48 -0500 Subject: [PATCH 15/16] Move mockdate to devdependencies --- package-lock.json | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c5d7cc9bb..b646a267b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15892,7 +15892,8 @@ "mockdate": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.2.tgz", - "integrity": "sha512-ldfYSUW1ocqSHGTK6rrODUiqAFPGAg0xaHqYJ5tvj1hQyFsjuHpuWgWFTZWwDVlzougN/s2/mhDr8r5nY5xDpA==" + "integrity": "sha512-ldfYSUW1ocqSHGTK6rrODUiqAFPGAg0xaHqYJ5tvj1hQyFsjuHpuWgWFTZWwDVlzougN/s2/mhDr8r5nY5xDpA==", + "dev": true }, "morgan": { "version": "1.9.1", diff --git a/package.json b/package.json index 0e0b881275..f4223a3e5b 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "lodash": "^4.17.19", "mini-css-extract-plugin": "^0.9.0", "mkdirp": "^1.0.3", - "mockdate": "^3.0.2", "morgan": "^1.9.1", "node-fetch": "^2.6.1", "parse5": "^6.0.1", @@ -123,6 +122,7 @@ "make-promises-safe": "^5.1.0", "mime": "^2.4.4", "mock-express-response": "^0.2.2", + "mockdate": "^3.0.2", "nock": "^13.0.4", "nodemon": "^2.0.4", "npm-merge-driver-install": "^2.0.0", From 69bd6f2dbd64a0d0a5ac8485b6cd66f7c1c9e36c Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Tue, 1 Dec 2020 15:15:28 -0500 Subject: [PATCH 16/16] Remove build-changelog-from-markdown.js --- .github/workflows/update-graphql-files.yml | 7 +- lib/graphql/README.md | 3 - script/README.md | 8 -- script/graphql/README.md | 3 +- .../graphql/build-changelog-from-markdown.js | 130 ------------------ script/graphql/build-changelog.js | 1 - 6 files changed, 2 insertions(+), 150 deletions(-) delete mode 100755 script/graphql/build-changelog-from-markdown.js diff --git a/.github/workflows/update-graphql-files.yml b/.github/workflows/update-graphql-files.yml index febfcf618c..0ba265a0f7 100644 --- a/.github/workflows/update-graphql-files.yml +++ b/.github/workflows/update-graphql-files.yml @@ -37,20 +37,15 @@ jobs: env: # need to use a token from a user with access to github/github for this step GITHUB_TOKEN: ${{ secrets.ZEKE_PAT_WITH_REPO_AND_WORKFLOW_SCOPE_FOR_REPO_SYNC }} - # technically the changelog should only be updated once per day, but we can safely - # run build-changelog-from-markdown.js in its current form once per hour; when we - # rewrite the changelog script, we may need to run it in a separate workflow on a - # once-per-day schedule; see details in https://github.com/github/docs-internal/issues/12722. run: | script/graphql/update-files.js - script/graphql/build-changelog-from-markdown.js - name: Create pull request id: create-pull-request uses: peter-evans/create-pull-request@938e6aea6f8dbdaced2064e948cb806c77fe87b8 with: # need to use a token with repo and workflow scopes for this step token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }} - commit-message: 'Action ran graphql scripts "update-files" and "build-changelog-from-markdown"' + commit-message: 'Action ran graphql script"update-files"' title: GraphQL schema update body: "Hello! Some GraphQL data in github/github was updated recently. This PR diff --git a/lib/graphql/README.md b/lib/graphql/README.md index bd34672912..00d5b0e110 100644 --- a/lib/graphql/README.md +++ b/lib/graphql/README.md @@ -24,9 +24,6 @@ Generated by `script/graphql/update-files.js`: * `lib/graphql/static/schema-VERSION.json` (separate files per version) * `lib/graphql/static/previews.json` * `lib/graphql/static/upcoming-changes.json` - -Generated by `script/graphql/build-changelog-from-markdown.js`: - * `lib/graphql/static/changelog.json` ## Rendering docs diff --git a/script/README.md b/script/README.md index ec7beb9881..178aff0367 100644 --- a/script/README.md +++ b/script/README.md @@ -179,12 +179,6 @@ Given: /github/getting-started-with-github/using-github Returns: /free-pro-team@ Given: /enterprise/admin/installation/upgrading-github-enterprise Returns: /enterprise-server@2.22/admin/installation/upgrading-github-enterprise ---- - - -### [`graphql/build-changelog-from-markdown.js`](graphql/build-changelog-from-markdown.js) - - --- @@ -446,5 +440,3 @@ This script is used by other scripts to update temporary AWS credentials and aut Use this script to upload individual or batched asset files to a versioned S3 bucket. Run `upload-images-to-s3.js --help` for usage details. --- - - diff --git a/script/graphql/README.md b/script/graphql/README.md index da3904a448..4588357efd 100644 --- a/script/graphql/README.md +++ b/script/graphql/README.md @@ -1,10 +1,9 @@ # GraphQL scripts A [scheduled workflow](../.github/workflows/update-graphql-files.yml) runs the following -scripts on an hourly basis: +scripts on a daily basis: ``` script/graphql/update-files.js -script/graphql/build-changelog-from-markdown.js ``` These scripts update the [static JSON files](../../lib/graphql/static) used to render GraphQL docs. See the [`lib/graphql/README`](../../lib/graphql/README.md) diff --git a/script/graphql/build-changelog-from-markdown.js b/script/graphql/build-changelog-from-markdown.js deleted file mode 100755 index 15d5fb3e52..0000000000 --- a/script/graphql/build-changelog-from-markdown.js +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env node - -const fs = require('fs') -const path = require('path') -const { sortBy, reverse } = require('lodash') -const frontmatter = require('../../lib/frontmatter') -const git = require('../../lib/git-utils') -const staticChangelog = path.join(process.cwd(), 'lib/graphql/static/changelog.json') - -// values for api -const owner = 'github' -const repo = 'internal-developer.github.com' -const ref = 'heads/master' - -const previewsBaseLink = '/graphql/overview/schema-previews' - -const changesList = /(\n*[\s\S]*?\n)$/m - -// until 2018-02-14, all changelogs used the phrase 'The following changes were made to the GraphQL schema' -const schemaRegexGlobal = new RegExp('(The GraphQL schema includes these changes:|The following changes were made to the GraphQL schema:)' + changesList.source, 'mg') -const previewRegexGlobal = new RegExp('(The .*?preview.*? includes these changes:)' + changesList.source, 'mg') -const upcomingRegexGlobal = new RegExp('(The following changes will be made to the schema:)' + changesList.source, 'mg') - -const schemaRegexSingle = new RegExp(schemaRegexGlobal.source, 'm') -const previewRegexSingle = new RegExp(previewRegexGlobal.source, 'm') -const upcomingRegexSingle = new RegExp(upcomingRegexGlobal.source, 'm') - -main() - -async function main () { - const tree = await git.getTree(owner, repo, ref) - const changelogFiles = tree.filter(entry => entry.path.includes('v4/changelog') && entry.type === 'blob') - - const changelog = [] - - await Promise.all(changelogFiles.map(async (blob) => { - // get the contents of `content/v4/changelog/*` files from internal-developer.github.com - const contents = await git.getContentsForBlob(owner, repo, blob) - const file = blob.path - - if (file.endsWith('index.html')) return - process.stdout.write('.') - - const date = path.basename(file).replace('-schema-changes.md', '') - const { content } = frontmatter(contents) - - // match each section title and list of changes - const schemaChangesMatches = content.match(schemaRegexGlobal) - const previewChangesMatches = content.match(previewRegexGlobal) - const upcomingChangesMatches = content.match(upcomingRegexGlobal) - - const entry = {} - - // do a little formatting cleanup - entry.date = date - entry.schemaChanges = getEntry(schemaChangesMatches, schemaRegexSingle) - entry.previewChanges = getEntry(previewChangesMatches, previewRegexSingle) - entry.upcomingChanges = getEntry(upcomingChangesMatches, upcomingRegexSingle) - - // very first changelog has custom content - if (date === '2017-05-22') { - entry.schemaChanges[0].changes.push('Nothing! The schema was made public!') - } - - changelog.push(entry) - })) - - // sort by newest entries first - const sortedChangelog = reverse(sortBy(changelog, ['date'])) - - // write json file - fs.writeFileSync(staticChangelog, JSON.stringify(sortedChangelog, null, 2)) - console.log(`\n\nupdated ${staticChangelog}`) -} - -function getEntry (matches, regex) { - return matches - ? matches.map(match => { - const entry = {} - entry.title = cleanPreviewLinks(match.match(regex)[1]) - entry.changes = getChangedItems(match.match(regex)[2]) - return entry - }) - : [] -} - -function getChangedItems (string) { - return string - .split('\n*') - .slice(1) - .map(i => i.trim()) -} - -// do some cleanup of preview links -function cleanPreviewLinks (title) { - const previewMarkup = title.match(/\[(.*?)\]\((.*?)\)/) - if (!previewMarkup) return title - - const rawName = previewMarkup[1] - const rawLink = previewMarkup[2] - - let cleanName = rawName - let cleanLink = rawLink - - // fix two malformed links - if (cleanName.includes('MergeInfoPreview')) { - cleanName = 'Merge info preview' - cleanLink = `${previewsBaseLink}#merge-info-preview` - } - - if (cleanName.includes('UpdateRefsPreview')) { - cleanName = 'Update refs preview' - cleanLink = `${previewsBaseLink}#update-refs-preview` - } - - cleanName = !cleanName.endsWith('preview') - ? `${cleanName} preview` - : cleanName - - cleanLink = !cleanLink.endsWith('-preview') - ? `${cleanLink}-preview` - : cleanLink - - cleanLink = cleanLink - .replace('/v4/previews/', previewsBaseLink) - - return title - .replace(rawName, cleanName) - .replace(rawLink, cleanLink) -} diff --git a/script/graphql/build-changelog.js b/script/graphql/build-changelog.js index 0fb281fa9a..fc67d5f558 100644 --- a/script/graphql/build-changelog.js +++ b/script/graphql/build-changelog.js @@ -111,7 +111,6 @@ async function createChangelogEntry (oldSchemaString, newSchemaString, previews, /** * Prepare the preview title from github/github source for the docs. - * (ported from build-changelog-from-markdown) * @param {string} title * @return {string} */