@graphql-hive/cli
Version:
A CLI util to manage and control your GraphQL Hive
234 lines • 9.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs_1 = require("fs");
const graphql_1 = require("graphql");
const utils_1 = require("@graphql-tools/utils");
const core_1 = require("@oclif/core");
const base_command_1 = tslib_1.__importDefault(require("../../base-command"));
const config_1 = require("../../helpers/config");
const git_1 = require("../../helpers/git");
const schema_1 = require("../../helpers/schema");
const validation_1 = require("../../helpers/validation");
class SchemaPublish extends base_command_1.default {
resolveMetadata(metadata) {
if (!metadata) {
return;
}
try {
JSON.parse(metadata);
// If we are able to parse it, it means it's a valid JSON, let's use it as-is
return metadata;
}
catch (e) {
// If we can't parse it, we can try to load it from FS
const exists = (0, fs_1.existsSync)(metadata);
if (!exists) {
throw new Error(`Failed to load metadata from "${metadata}": Please specify a path to an existing file, or a string with valid JSON.`);
}
try {
const fileContent = (0, fs_1.readFileSync)(metadata, 'utf-8');
JSON.parse(fileContent);
return fileContent;
}
catch (e) {
throw new Error(`Failed to load metadata from file "${metadata}": Please make sure the file is readable and contains a valid JSON`);
}
}
}
async run() {
var _a;
try {
const { flags, args } = await this.parse(SchemaPublish);
await this.require(flags);
const registry = this.ensure({
key: 'registry',
args: flags,
defaultValue: config_1.graphqlEndpoint,
env: 'HIVE_REGISTRY',
});
const service = this.maybe('service', flags);
const url = this.maybe('url', flags);
const file = args.file;
const token = this.ensure({
key: 'token',
args: flags,
env: 'HIVE_TOKEN',
});
const force = this.maybe('force', flags);
const experimental_acceptBreakingChanges = this.maybe('experimental_acceptBreakingChanges', flags);
const metadata = this.resolveMetadata(this.maybe('metadata', flags));
const usesGitHubApp = this.maybe('github', flags) === true;
let commit = flags.commit;
let author = flags.author;
if (!commit || !author) {
const git = await (0, git_1.gitInfo)(() => {
this.warn(`No git information found. Couldn't resolve author and commit.`);
});
if (!commit) {
commit = git.commit;
}
if (!author) {
author = git.author;
}
}
if (!author) {
throw new core_1.Errors.CLIError(`Missing "author"`);
}
if (!commit) {
throw new core_1.Errors.CLIError(`Missing "commit"`);
}
let sdl;
try {
const rawSdl = await (0, schema_1.loadSchema)(file);
(0, validation_1.invariant)(typeof rawSdl === 'string' && rawSdl.length > 0, 'Schema seems empty');
const transformedSDL = (0, graphql_1.print)((0, utils_1.transformCommentsToDescriptions)(rawSdl));
sdl = (0, schema_1.minifySchema)(transformedSDL);
}
catch (err) {
if (err instanceof graphql_1.GraphQLError) {
const location = (_a = err.locations) === null || _a === void 0 ? void 0 : _a[0];
const locationString = location
? ` at line ${location.line}, column ${location.column}`
: '';
throw new Error(`The SDL is not valid${locationString}:\n ${err.message}`);
}
throw err;
}
const result = await this.registryApi(registry, token).schemaPublish({
input: {
service,
url,
author,
commit,
sdl,
force,
experimental_acceptBreakingChanges: experimental_acceptBreakingChanges === true,
metadata,
github: usesGitHubApp,
},
usesGitHubApp,
});
if (result.schemaPublish.__typename === 'SchemaPublishSuccess') {
const changes = result.schemaPublish.changes;
if (result.schemaPublish.initial) {
this.success('Published initial schema.');
}
else if (result.schemaPublish.successMessage) {
this.success(result.schemaPublish.successMessage);
}
else if (changes && changes.total === 0) {
this.success('No changes. Skipping.');
}
else {
if (changes) {
schema_1.renderChanges.call(this, changes);
}
this.success('Schema published');
}
if (result.schemaPublish.linkToWebsite) {
this.info(`Available at ${result.schemaPublish.linkToWebsite}`);
}
}
else if (result.schemaPublish.__typename === 'SchemaPublishMissingServiceError') {
this.fail(`${result.schemaPublish.missingServiceError} Please use the '--service <name>' parameter.`);
this.exit(1);
}
else if (result.schemaPublish.__typename === 'SchemaPublishMissingUrlError') {
this.fail(`${result.schemaPublish.missingUrlError} Please use the '--url <url>' parameter.`);
this.exit(1);
}
else if (result.schemaPublish.__typename === 'SchemaPublishError') {
const changes = result.schemaPublish.changes;
const errors = result.schemaPublish.errors;
schema_1.renderErrors.call(this, errors);
if (changes && changes.total) {
this.log('');
schema_1.renderChanges.call(this, changes);
}
this.log('');
if (!force) {
this.fail('Failed to publish schema');
this.exit(1);
}
else {
this.success('Schema published (forced)');
}
if (result.schemaPublish.linkToWebsite) {
this.info(`Available at ${result.schemaPublish.linkToWebsite}`);
}
}
else if (result.schemaPublish.__typename === 'GitHubSchemaPublishSuccess') {
this.success(result.schemaPublish.message);
}
else {
this.error('message' in result.schemaPublish ? result.schemaPublish.message : 'Unknown error');
}
}
catch (error) {
if (error instanceof core_1.Errors.ExitError) {
throw error;
}
else {
this.fail('Failed to publish schema');
this.handleFetchError(error);
}
}
}
}
SchemaPublish.description = 'publishes schema';
SchemaPublish.flags = {
service: core_1.Flags.string({
description: 'service name (only for distributed schemas)',
}),
url: core_1.Flags.string({
description: 'service url (only for distributed schemas)',
}),
metadata: core_1.Flags.string({
description: 'additional metadata to attach to the GraphQL schema. This can be a string with a valid JSON, or a path to a file containing a valid JSON',
}),
registry: core_1.Flags.string({
description: 'registry address',
}),
token: core_1.Flags.string({
description: 'api token',
}),
author: core_1.Flags.string({
description: 'author of the change',
}),
commit: core_1.Flags.string({
description: 'associated commit sha',
}),
github: core_1.Flags.boolean({
description: 'Connect with GitHub Application',
default: false,
}),
force: core_1.Flags.boolean({
description: 'force publish even on breaking changes',
default: false,
deprecated: {
message: '--force is enabled by default for newly created projects',
},
}),
experimental_acceptBreakingChanges: core_1.Flags.boolean({
description: '(experimental) accept breaking changes and mark schema as valid (only if composable)',
deprecated: {
message: '--experimental_acceptBreakingChanges is enabled by default for newly created projects',
},
}),
require: core_1.Flags.string({
description: 'Loads specific require.extensions before running the codegen and reading the configuration',
default: [],
multiple: true,
}),
};
SchemaPublish.args = [
{
name: 'file',
required: true,
description: 'Path to the schema file(s)',
hidden: false,
},
];
exports.default = SchemaPublish;
//# sourceMappingURL=publish.js.map