// @ts-ignore import inquirerAutocomplete from 'inquirer-autocomplete-prompt'; import { isEmpty, merge } from 'lodash'; import { green, yellow, yellowBright } from 'chalk'; import yosay from 'yosay'; import Generator from 'yeoman-generator'; import { version } from '../../package.json'; import { ServiceCatalog } from './svc/serviceInstance'; import { Namespace } from './k8s/ns'; import validateAppName from './app/app'; const types = require('@sap-devx/yeoman-ui-types'); export default class KymaGenerator extends Generator { prompts: any; private svc: any; private ns: any; private appWizard: any; private errorFound = false; private props: Generator.Answers | undefined; private namespace: Namespace = new Namespace(); constructor(args: string | string[], opts: {}) { super(args, opts); // used as inquirer UI doesnt support autocomplete plugins if (this.env.adapter.promptModule) { this.env.adapter.promptModule.registerPrompt( 'autocomplete', inquirerAutocomplete, ); } // used for the project wizard steps & finish button this.appWizard = types.AppWizard.create(opts); const prompts = [ { name: 'Project Details', description: 'Kyma micro-service template project details', }, ]; this.prompts = new types.Prompts(prompts); } async initializing() { this.log( yosay( `Welcome to the ${yellowBright('generator-kyma')} \n project generator version: ${version} (experimental) `, ), ); this.desc('Generate a KYMA app.'); // POC defaults this.props = { ProjectDetails: 'kyma-app', port: 5000, hostName: 'kyma-app-host', namespace: 'default', tech: 'Nodejs', serviceInstanceName: undefined, }; try { this.ns = await this.namespace.getNamespaces(); } catch (e) { console.log(e); } if (!this.ns?.length) { console.log( 'There is no active connection to KYMA cluster, please check the kubeconfig and try again', ); this.appWizard.showError( 'There is no active connection to KYMA cluster, please check the kubeconfig and try again', types.MessageType.prompt, ); this.errorFound = true; process.exit(1); } } async prompting() { const that = this; const prompts = [ { name: 'ProjectDetails', message: 'Enter a project name: ', type: 'input', default: this.props!.ProjectDetails, validate(input: string) { if (that.errorFound) { return false; } const appName = validateAppName(input); return !appName[1] ? appName[0] : true; }, }, { name: 'namespace', type: 'rawlist', message: 'Select a namespace: ', choices() { return that.ns; }, validate(val: boolean) { return val ? true : 'use the namespace where the service instance is provisioned'; }, when() { return !!that.ns?.length; }, }, { name: 'serviceInstanceName', type: 'list', message: 'Select the service instance to which you want to bind the application: ', choices() { return that.svc; }, default: 'None', async when(value: any) { if (value.namespace) { try { const svcat = new ServiceCatalog(); that.svc = await svcat.getServiceInstances(value.namespace); } catch (e) { console.log(e); } if (that.svc?.length) { that.svc = ['None'].concat(that.svc); return !!that.svc?.length; } return false; } return false; }, }, ]; return this.prompt(prompts).then( (props: { values: any }) => { that.props = merge({}, that.props, props); console.log(props); }, ); } writing() { switch (this.props!.tech) { case 'Python': this.fs.copyTpl( this.templatePath('python'), this.destinationPath(this.props!.ProjectDetails), this.props, ); break; case 'Nodejs': this.fs.copyTpl( this.templatePath('nodejs'), this.destinationPath(this.props!.ProjectDetails), this.props, ); break; case 'Go': this.fs.copyTpl( this.templatePath('go'), this.destinationPath(this.props!.ProjectDetails), this.props, ); break; default: } // general artifacts this.fs.copyTpl( this.templatePath('k8s'), this.destinationPath(this.props!.ProjectDetails, '/k8s'), this.props, ); if ( this.props!.serviceInstanceName != 'None' && this.props?.serviceInstanceName ) { this.fs.copyTpl( this.templatePath('svc'), this.destinationPath(this.props!.ProjectDetails, '/k8s'), this.props, ); } this.fs.copyTpl( this.templatePath('k8s'), this.destinationPath(this.props!.ProjectDetails, '/k8s'), this.props, ); this.fs.copyTpl( this.templatePath('general/**'), this.destinationPath(this.props!.ProjectDetails), this.props, null!, { globOptions: { dot: true } }, ); } end() { if (isEmpty(this.namespace?.namespaceInstances)) { this.log( yosay( `${yellow( "The project has been generated successfully. However, we weren't able to connect to K8S to create the service binding. see the README file for further information.", )} `, ), ); } else { this.log( yosay( `${green( 'The project has been generated successfully. see the README file for further information.', )} `, ), ); } } }