@graphql-inspector/action
Version:
GraphQL Inspector functionality for GitHub Actions
187 lines (186 loc) • 7.29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = run;
const tslib_1 = require("tslib");
const path_1 = require("path");
const graphql_1 = require("graphql");
const core = tslib_1.__importStar(require("@actions/core"));
const github = tslib_1.__importStar(require("@actions/github"));
const diff_js_1 = require("../helpers/diff.js");
const loaders_js_1 = require("../helpers/loaders.js");
const schema_js_1 = require("../helpers/schema.js");
const types_js_1 = require("../helpers/types.js");
const utils_js_1 = require("../helpers/utils.js");
const checks_js_1 = require("./checks.js");
const files_js_1 = require("./files.js");
const git_js_1 = require("./git.js");
const utils_js_2 = require("./utils.js");
const CHECK_NAME = 'GraphQL Inspector';
async function run() {
core.info(`GraphQL Inspector started`);
// env
let ref = process.env.GITHUB_SHA;
const commitSha = (0, git_js_1.getCurrentCommitSha)();
core.info(`Ref: ${ref}`);
core.info(`Commit SHA: ${commitSha}`);
const token = core.getInput('github-token', { required: true });
const checkName = core.getInput('name') || CHECK_NAME;
let workspace = process.env.GITHUB_WORKSPACE;
if (!workspace) {
return core.setFailed('Failed to resolve workspace directory. GITHUB_WORKSPACE is missing');
}
const useMerge = (0, utils_js_2.castToBoolean)(core.getInput('experimental_merge'), true);
const useAnnotations = (0, utils_js_2.castToBoolean)(core.getInput('annotations'));
const failOnBreaking = (0, utils_js_2.castToBoolean)(core.getInput('fail-on-breaking'));
const endpoint = core.getInput('endpoint');
const approveLabel = core.getInput('approve-label') || 'approved-breaking-change';
const rulesList = (0, utils_js_2.getInputAsArray)('rules') || [];
const onUsage = core.getInput('onUsage');
const octokit = github.getOctokit(token);
// repo
const { owner, repo } = github.context.repo;
// pull request
const pullRequest = await (0, git_js_1.getAssociatedPullRequest)(octokit, commitSha);
core.info(`Creating a check named "${checkName}"`);
const check = await octokit.rest.checks.create({
owner,
repo,
name: checkName,
head_sha: commitSha,
status: 'in_progress',
});
const checkId = check.data.id;
core.info(`Check ID: ${checkId}`);
const schemaPointer = core.getInput('schema', { required: true });
const loadFile = (0, files_js_1.fileLoader)({
octokit,
owner,
repo,
});
if (!schemaPointer) {
core.error('No `schema` variable');
return core.setFailed('Failed to find `schema` variable');
}
const rules = rulesList
.map(r => {
const rule = (0, utils_js_2.resolveRule)(r);
if (!rule) {
core.error(`Rule ${r} is invalid. Did you specify the correct path?`);
}
return rule;
})
.filter(Boolean);
// Different lengths mean some rules were resolved to undefined
if (rules.length !== rulesList.length) {
return core.setFailed("Some rules weren't recognised");
}
let config;
if (onUsage) {
const checkUsage = require(onUsage);
if (checkUsage) {
config = {
checkUsage,
};
}
}
let [schemaRef, schemaPath] = schemaPointer.split(':');
if (useMerge && pullRequest?.state === 'open') {
ref = `refs/pull/${pullRequest.number}/merge`;
workspace = undefined;
core.info(`EXPERIMENTAL - Using Pull Request ${ref}`);
const baseRef = pullRequest.base?.ref;
if (baseRef) {
schemaRef = baseRef;
core.info(`EXPERIMENTAL - Using ${baseRef} as base schema ref`);
}
}
if (endpoint) {
schemaPath = schemaPointer;
}
const isNewSchemaUrl = endpoint && schemaPath.startsWith('http');
const [oldFile, newFile] = await Promise.all([
endpoint
? (0, loaders_js_1.printSchemaFromEndpoint)(endpoint)
: loadFile({
ref: schemaRef,
path: schemaPath,
}),
isNewSchemaUrl
? (0, loaders_js_1.printSchemaFromEndpoint)(schemaPath)
: loadFile({
path: schemaPath,
ref,
workspace,
}),
]);
core.info('Got both sources');
let oldSchema;
let newSchema;
let sources;
if ((0, path_1.extname)(schemaPath.toLowerCase()) === '.json') {
oldSchema = endpoint ? (0, graphql_1.buildSchema)(oldFile) : (0, graphql_1.buildClientSchema)(JSON.parse(oldFile));
newSchema = (0, graphql_1.buildClientSchema)(JSON.parse(newFile));
sources = {
old: new graphql_1.Source((0, graphql_1.printSchema)(oldSchema), endpoint || `${schemaRef}:${schemaPath}`),
new: new graphql_1.Source((0, graphql_1.printSchema)(newSchema), schemaPath),
};
}
else {
sources = {
old: new graphql_1.Source(oldFile, endpoint || `${schemaRef}:${schemaPath}`),
new: new graphql_1.Source(newFile, schemaPath),
};
oldSchema = (0, schema_js_1.produceSchema)(sources.old);
newSchema = (0, schema_js_1.produceSchema)(sources.new);
}
const schemas = {
old: oldSchema,
new: newSchema,
};
core.info(`Built both schemas`);
core.info(`Start comparing schemas`);
const action = await (0, diff_js_1.diff)({
path: schemaPath,
schemas,
sources,
rules,
config,
});
let conclusion = action.conclusion;
let annotations = action.annotations || [];
const changes = action.changes || [];
core.setOutput('changes', String(changes.length || 0));
core.info(`Changes: ${changes.length || 0}`);
const hasApprovedBreakingChangeLabel = pullRequest?.labels?.some((label) => label.name === approveLabel);
// Force Success when failOnBreaking is disabled
if ((failOnBreaking === false || hasApprovedBreakingChangeLabel) &&
conclusion === types_js_1.CheckConclusion.Failure) {
core.info('FailOnBreaking disabled. Forcing SUCCESS');
conclusion = types_js_1.CheckConclusion.Success;
}
if (useAnnotations === false || isNewSchemaUrl) {
core.info(`Anotations are disabled. Skipping annotations...`);
annotations = [];
}
const summary = (0, utils_js_1.createSummary)(changes, 100, false);
const title = conclusion === types_js_1.CheckConclusion.Failure
? 'Something is wrong with your schema'
: 'Everything looks good';
core.info(`Conclusion: ${conclusion}`);
try {
return await (0, checks_js_1.updateCheckRun)(octokit, checkId, {
conclusion,
output: { title, summary, annotations },
});
}
catch (e) {
// Error
core.error(e.message || e);
const title = 'Invalid config. Failed to add annotation';
await (0, checks_js_1.updateCheckRun)(octokit, checkId, {
conclusion: types_js_1.CheckConclusion.Failure,
output: { title, summary: title, annotations: [] },
});
return core.setFailed(title);
}
}