Add GraphQL Post-Merge Schema Check

why:
- Schema checks ensure that any change to the Canvas GraphQL Schema
  don't impact existing queries as well as ensuring we don't break
  supergraph composition.
- We're starting with a post-merge build to see how common of an issue
  this is for now. We'll move it into the deploy and pre-merge steps
  once we're sure we like it.

flag=none

[canvas-builds-refspec=0e2b75ca09d79fe85fdb749b9288dabbbfc86012]
[change-merged]
[build-registry-path=jenkins/canvas-lms/interop-7174]

closes INTEROP-7174

test-plan:
- the simulated post-merge build reports to the appropriate Slack
  channel and we *don't* get a message about a schema check failure.
- we'll get eyes from devx and our SET to make sure everything looks
  A-OK.

Change-Id: Ibdb55c1f50d0ab71d809bb06a5f0d01a5b7fbc02
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296771
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Aaron Ogata <aogata@instructure.com>
Build-Review: Aaron Ogata <aogata@instructure.com>
QA-Review: Ryan Hawkins <ryan.hawkins@instructure.com>
Product-Review: Ryan Hawkins <ryan.hawkins@instructure.com>
This commit is contained in:
Ryan Hawkins 2022-07-21 11:55:27 -06:00
parent f412d1f65e
commit 5fdaac076d
6 changed files with 125 additions and 6 deletions

5
Jenkinsfile vendored
View File

@ -578,6 +578,11 @@ pipeline {
.required(configuration.isChangeMerged()) .required(configuration.isChangeMerged())
.execute(dependencyCheckStage.queueTestStage()) .execute(dependencyCheckStage.queueTestStage())
extendedStage('GraphQL Post-Merge Schema Check')
.nodeRequirements(label: configuration.nodeLabel(), podTemplate: graphqlSchemaCheckStage.nodeRequirementsTemplate(), container: 'graphql-schema-check')
.required(configuration.isChangeMerged() && filesChangedStage.hasGraphqlFiles(buildConfig))
.execute(graphqlSchemaCheckStage.queueTestStage())
extendedStage('Linters') extendedStage('Linters')
.hooks([onNodeReleasing: lintersStage.tearDownNode()]) .hooks([onNodeReleasing: lintersStage.tearDownNode()])
.nodeRequirements(label: configuration.nodeLabel(), podTemplate: lintersStage.nodeRequirementsTemplate()) .nodeRequirements(label: configuration.nodeLabel(), podTemplate: lintersStage.nodeRequirementsTemplate())

View File

@ -29,6 +29,9 @@ module Types
field :name, String, null: true field :name, String, null: true
# A simple test field to force a schema check. TODO: Remove once test of post-merge schema check works properly.
field :test_field, String, null: true
field :outcome_proficiency, OutcomeProficiencyType, null: true field :outcome_proficiency, OutcomeProficiencyType, null: true
def outcome_proficiency def outcome_proficiency
# This does a recursive lookup of parent accounts, not sure how we could # This does a recursive lookup of parent accounts, not sure how we could

View File

@ -40,6 +40,10 @@ def hasYarnFiles(buildConfig) {
return buildConfig[STAGE_NAME].value('yarnFiles') return buildConfig[STAGE_NAME].value('yarnFiles')
} }
def hasGraphqlFiles(buildConfig) {
return buildConfig[STAGE_NAME].value('graphqlFiles')
}
def hasNewDeletedSpecFiles(buildConfig) { def hasNewDeletedSpecFiles(buildConfig) {
return buildConfig[STAGE_NAME].value('addedOrDeletedSpecFiles') return buildConfig[STAGE_NAME].value('addedOrDeletedSpecFiles')
} }
@ -59,6 +63,7 @@ def call(stageConfig) {
stageConfig.value('featureFlagFiles', git.changedFiles(['config/feature_flags'], 'HEAD^')) stageConfig.value('featureFlagFiles', git.changedFiles(['config/feature_flags'], 'HEAD^'))
stageConfig.value('groovyFiles', git.changedFiles(['.*.groovy', 'Jenkinsfile.*'], 'HEAD^')) stageConfig.value('groovyFiles', git.changedFiles(['.*.groovy', 'Jenkinsfile.*'], 'HEAD^'))
stageConfig.value('yarnFiles', git.changedFiles(['package.json', 'yarn.lock'], 'HEAD^')) stageConfig.value('yarnFiles', git.changedFiles(['package.json', 'yarn.lock'], 'HEAD^'))
stageConfig.value('graphqlFiles', git.changedFiles(['app/graphql'], 'HEAD^'))
stageConfig.value('migrationFiles', sh(script: 'build/new-jenkins/check-for-migrations.sh', returnStatus: true) == 0) stageConfig.value('migrationFiles', sh(script: 'build/new-jenkins/check-for-migrations.sh', returnStatus: true) == 0)
stageConfig.value('addedOrDeletedSpecFiles', sh(script: 'git diff --name-only --diff-filter=AD HEAD^..HEAD | grep "_spec.rb"', returnStatus: true) == 0) stageConfig.value('addedOrDeletedSpecFiles', sh(script: 'git diff --name-only --diff-filter=AD HEAD^..HEAD | grep "_spec.rb"', returnStatus: true) == 0)

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
def nodeRequirementsTemplate() {
def baseTestContainer = [
image: env.LINTERS_RUNNER_IMAGE,
command: 'cat'
]
return [
containers: [baseTestContainer + [name: 'graphql-schema-check']]
]
}
def queueTestStage() {
{ ->
withCredentials([string(credentialsId: 'apollo-key', variable: 'APOLLO_KEY')]) {
try {
// Because this gets run inside a Docker container, we can't return the status, as it gets interpreted
// by our custom Docker execution library as being part of the shell command.
sh """
RAILS_ENV=test bundle exec rake graphql:schema
yarn rover subgraph check ${configuration.apolloGraphRef()} --name ${configuration.apolloSubgraphName()} --schema ${configuration.apolloSchemaPath()}
"""
} catch (Exception e) {
// For now, if the schema check fails, simply alert the interop team, rather than fail the build.
// We're only collecting information for now.
def extra = 'The preceding patchset failed the GraphQL Post-Merge Schema Check. Please review the schema check to determine if this was a false positive or if the author needs to amend their changes. Note that a link to the schema check within Apollo Studio is output by Rover.'
slackHelpers.sendSlackFailureWithMsg('#interop-alerts', extra, false)
}
}
}
}

View File

@ -192,6 +192,7 @@
"@apollo/react-hooks": "~3.0.1", "@apollo/react-hooks": "~3.0.1",
"@apollo/react-ssr": "~3.0.1", "@apollo/react-ssr": "~3.0.1",
"@apollo/react-testing": "~3.0.1", "@apollo/react-testing": "~3.0.1",
"@apollo/rover": "^0.7.0",
"@babel/cli": "^7.0.0", "@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0", "@babel/core": "^7.0.0",
"@babel/parser": "^7", "@babel/parser": "^7",

View File

@ -86,6 +86,16 @@
fast-json-stable-stringify "^2.0.0" fast-json-stable-stringify "^2.0.0"
tslib "^1.10.0" tslib "^1.10.0"
"@apollo/rover@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@apollo/rover/-/rover-0.7.0.tgz#469859ff8efaca36b7d57fca7cf0544c90e14678"
integrity sha512-OTTZ5/HDoT490UpkPXcEzSYLkC/XiJGjSJysAoiXy8/EVvPPe7qlQ8arE3/qeRwWe83yz4YT22kHjHMpo6Pi2g==
dependencies:
axios-proxy-builder "^0.1.1"
binary-install "^1.0.1"
console.table "^0.10.0"
detect-libc "^2.0.0"
"@babel/cli@^7", "@babel/cli@^7.0.0": "@babel/cli@^7", "@babel/cli@^7.0.0":
version "7.14.5" version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.14.5.tgz#9551b194f02360729de6060785bbdcce52c69f0a" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.14.5.tgz#9551b194f02360729de6060785bbdcce52c69f0a"
@ -7867,6 +7877,13 @@ axios-cache-adapter@^2.7.0:
cache-control-esm "1.0.0" cache-control-esm "1.0.0"
md5 "^2.2.1" md5 "^2.2.1"
axios-proxy-builder@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/axios-proxy-builder/-/axios-proxy-builder-0.1.2.tgz#1149ffd916d0817c665c0bff2d50eeb10afce5bf"
integrity sha512-6uBVsBZzkB3tCC8iyx59mCjQckhB8+GQrI9Cop8eC7ybIsvs/KtnNgEBfRMSEa7GqK2VBGUzgjNYMdPIfotyPA==
dependencies:
tunnel "^0.0.6"
axios@^0.21.1: axios@^0.21.1:
version "0.21.1" version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
@ -7874,6 +7891,13 @@ axios@^0.21.1:
dependencies: dependencies:
follow-redirects "^1.10.0" follow-redirects "^1.10.0"
axios@^0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
dependencies:
follow-redirects "^1.14.8"
axobject-query@^2.2.0: axobject-query@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@ -8359,6 +8383,15 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
binary-install@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/binary-install/-/binary-install-1.0.1.tgz#8f2c0ab5e515a45933114b4ca9100ef45adb6a56"
integrity sha512-5/rP8iHlYWwV7OKX1PaYasm2vi5iq4SLM+fT9UVjbbfiwR4cw+WANFTapOcVMznOMa3s6tYFiq84tbijopravg==
dependencies:
axios "^0.26.1"
rimraf "^3.0.2"
tar "^6.1.11"
bindings@^1.5.0: bindings@^1.5.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
@ -9754,6 +9787,13 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
console.table@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/console.table/-/console.table-0.10.0.tgz#0917025588875befd70cf2eff4bef2c6e2d75d04"
integrity sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==
dependencies:
easy-table "1.1.0"
constant-case@^2.0.0: constant-case@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46"
@ -10788,6 +10828,11 @@ detect-indent@^5.0.0:
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
detect-libc@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
detect-newline@2.X: detect-newline@2.X:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
@ -11092,6 +11137,13 @@ each-props@^1.3.2:
is-plain-object "^2.0.1" is-plain-object "^2.0.1"
object.defaults "^1.1.0" object.defaults "^1.1.0"
easy-table@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/easy-table/-/easy-table-1.1.0.tgz#86f9ab4c102f0371b7297b92a651d5824bc8cb73"
integrity sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==
optionalDependencies:
wcwidth ">=1.0.1"
ebml-block@^1.1.0: ebml-block@^1.1.0:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/ebml-block/-/ebml-block-1.1.2.tgz#fd49951b0faf5a3049bdd61c851a76b5e679c290" resolved "https://registry.yarnpkg.com/ebml-block/-/ebml-block-1.1.2.tgz#fd49951b0faf5a3049bdd61c851a76b5e679c290"
@ -12849,10 +12901,10 @@ follow-redirects@0.0.3:
dependencies: dependencies:
underscore "" underscore ""
follow-redirects@^1.0.0, follow-redirects@^1.10.0: follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.14.8:
version "1.14.1" version "1.15.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
for-in@^1.0.1, for-in@^1.0.2: for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2" version "1.0.2"
@ -23693,7 +23745,7 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
tar@^6.0.2: tar@^6.0.2, tar@^6.1.11:
version "6.1.11" version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
@ -24533,6 +24585,11 @@ tunnel-agent@0.6.0, tunnel-agent@^0.6.0:
dependencies: dependencies:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
tunnel@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
tweetnacl@^0.14.3, tweetnacl@~0.14.0: tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5" version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
@ -25401,7 +25458,7 @@ wcag-element-contrast@^1.0.1:
resolved "https://registry.yarnpkg.com/wcag-element-contrast/-/wcag-element-contrast-1.0.2.tgz#5a90cb7cdc252979cf3e2bd27161e1bf9ad4c2f6" resolved "https://registry.yarnpkg.com/wcag-element-contrast/-/wcag-element-contrast-1.0.2.tgz#5a90cb7cdc252979cf3e2bd27161e1bf9ad4c2f6"
integrity sha1-WpDLfNwlKXnPPivScWHhv5rUwvY= integrity sha1-WpDLfNwlKXnPPivScWHhv5rUwvY=
wcwidth@^1.0.1: wcwidth@>=1.0.1, wcwidth@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==