diff --git a/atom-extensions/atom-bosh/.gitignore b/atom-extensions/atom-bosh/.gitignore index 51786ff67..0b79f4de1 100644 --- a/atom-extensions/atom-bosh/.gitignore +++ b/atom-extensions/atom-bosh/.gitignore @@ -1,6 +1,7 @@ /.idea /node_modules /server +/build *.tgz *.iml *.log \ No newline at end of file diff --git a/atom-extensions/atom-bosh/lib/main.js b/atom-extensions/atom-bosh/lib/bosh-yaml-client.ts similarity index 63% rename from atom-extensions/atom-bosh/lib/main.js rename to atom-extensions/atom-bosh/lib/bosh-yaml-client.ts index 9549d9dd2..de10801b7 100644 --- a/atom-extensions/atom-bosh/lib/main.js +++ b/atom-extensions/atom-bosh/lib/bosh-yaml-client.ts @@ -1,21 +1,22 @@ -const path = require('path'); -const { JavaProcessLanguageClient } = require('@pivotal-tools/atom-languageclient-commons'); -const PROPERTIES = require('../properties.json'); +import * as path from 'path'; +import {JavaProcessLanguageClient} from '@pivotal-tools/atom-languageclient-commons'; +import {ActiveServer} from 'atom-languageclient'; +import {JVM} from '@pivotal-tools/jvm-launch-utils'; -class BoshYamlClient extends JavaProcessLanguageClient { + +export class BoshYamlClient extends JavaProcessLanguageClient { constructor() { //noinspection JSAnnotator super( - PROPERTIES.jarUrl, path.join(__dirname, '..', 'server'), 'bosh-language-server.jar' - ); + ); } - postInitialization(server) { + postInitialization(server: ActiveServer) { this.sendConfig(server); - this._disposable.add(atom.config.observe('bosh-yaml', () => this.sendConfig(server))); + (this)._disposable.add(atom.config.observe('bosh-yaml', () => this.sendConfig(server))); } getGrammarScopes() { @@ -37,7 +38,7 @@ class BoshYamlClient extends JavaProcessLanguageClient { super.activate(); } - launchVmArgs(jvm) { + launchVmArgs(jvm: JVM): Promise { return Promise.resolve([ '-Dorg.slf4j.simpleLogger.logFile=bosh-yaml.log', '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug', @@ -45,10 +46,8 @@ class BoshYamlClient extends JavaProcessLanguageClient { } - sendConfig(server) { + sendConfig(server: ActiveServer) { server.connection.didChangeConfiguration({ settings: atom.config.get('bosh-yaml') }); } -} - -module.exports = new BoshYamlClient(); +} \ No newline at end of file diff --git a/atom-extensions/atom-bosh/lib/main.ts b/atom-extensions/atom-bosh/lib/main.ts new file mode 100644 index 000000000..6d7c31622 --- /dev/null +++ b/atom-extensions/atom-bosh/lib/main.ts @@ -0,0 +1,3 @@ +import {BoshYamlClient} from './bosh-yaml-client'; + +module.exports = new BoshYamlClient(); \ No newline at end of file diff --git a/atom-extensions/atom-bosh/package.json b/atom-extensions/atom-bosh/package.json index fbf34bace..cb0262a5f 100644 --- a/atom-extensions/atom-bosh/package.json +++ b/atom-extensions/atom-bosh/package.json @@ -1,26 +1,23 @@ { "name": "bosh-yaml", - "main": "./lib/main", - "version": "0.1.5", + "version": "0.1.6", "description": "Provides validation and content assist for various Bosh configuration files", "repository": "https://github.com/spring-projects/atom-bosh", "icon": "icon.png", "license": "MIT", "engines": { - "atom": ">=1.21.0" + "atom": ">=1.24.0" }, + "main": "./build/main", + "types": "./build/main.d.ts", "files": [ "grammars/", "settings/", "lib/", + "build/", "server/", "properties.json" ], - "dependencies": { - "atom-package-deps": "^4.6.0", - "download": "^6.2.5", - "@pivotal-tools/atom-languageclient-commons": "0.0.2" - }, "configSchema": { "bosh": { "type": "object", @@ -50,11 +47,22 @@ } } }, + "dependencies": { + "atom-package-deps": "^4.6.0", + "download": "^6.2.5", + "@pivotal-tools/atom-languageclient-commons": "0.0.4" + }, "devDependencies": { + "typescript": "^2.7.2", + "tslint": "^5.9.1", "coffeelint": "^1.10.1" }, "scripts": { - "clean": "rm -fr node_modules", + "clean": "rm -fr build", + "compile": "tsc", + "build": "npm run clean && npm run compile ", + "watch": "tsc -watch", + "lint": "tslint -c tslint.json 'lib/**/*.ts'", "postinstall": "node script.js" }, "package-deps": [ diff --git a/atom-extensions/atom-bosh/properties.json b/atom-extensions/atom-bosh/properties.json index d588ead1d..e705c39ea 100644 --- a/atom-extensions/atom-bosh/properties.json +++ b/atom-extensions/atom-bosh/properties.json @@ -1,3 +1,3 @@ { - "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/bosh-language-server-0.0.10-201711061741.jar" + "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/bosh-language-server-0.1.5-201803080105.jar" } diff --git a/atom-extensions/atom-bosh/tsconfig.json b/atom-extensions/atom-bosh/tsconfig.json new file mode 100644 index 000000000..a333b271b --- /dev/null +++ b/atom-extensions/atom-bosh/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "build", + "lib": ["es7", "dom"], + "declaration": true, + "inlineSources": true, + "inlineSourceMap": true, + "strictNullChecks": true, + "noImplicitAny": true, + "baseUrl": "./" + }, + "include": [ + "lib/**/*.ts" + ] +} \ No newline at end of file diff --git a/atom-extensions/atom-bosh/tslint.json b/atom-extensions/atom-bosh/tslint.json new file mode 100644 index 000000000..068b76067 --- /dev/null +++ b/atom-extensions/atom-bosh/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": false, + "object-literal-sort-keys": false, + "ordered-imports": false, + "member-ordering": false, + "one-line": false, + "interface-name": false, + "variable-name": false, + "max-classes-per-file": false, + "no-unused-expression": false, + "no-empty": false, + "one-variable-per-declaration": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-module" + ] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/atom-extensions/atom-cf-manifest-yaml/.gitignore b/atom-extensions/atom-cf-manifest-yaml/.gitignore index 51786ff67..0b79f4de1 100644 --- a/atom-extensions/atom-cf-manifest-yaml/.gitignore +++ b/atom-extensions/atom-cf-manifest-yaml/.gitignore @@ -1,6 +1,7 @@ /.idea /node_modules /server +/build *.tgz *.iml *.log \ No newline at end of file diff --git a/atom-extensions/atom-cf-manifest-yaml/lib/main.ts b/atom-extensions/atom-cf-manifest-yaml/lib/main.ts new file mode 100644 index 000000000..c8920a147 --- /dev/null +++ b/atom-extensions/atom-cf-manifest-yaml/lib/main.ts @@ -0,0 +1,3 @@ +import {ManifestYamlLanguageClient} from './manifest-yaml-language-client'; + +module.exports = new ManifestYamlLanguageClient(); \ No newline at end of file diff --git a/atom-extensions/atom-cf-manifest-yaml/lib/main.js b/atom-extensions/atom-cf-manifest-yaml/lib/manifest-yaml-language-client.ts similarity index 70% rename from atom-extensions/atom-cf-manifest-yaml/lib/main.js rename to atom-extensions/atom-cf-manifest-yaml/lib/manifest-yaml-language-client.ts index 929218105..b8c3c2821 100644 --- a/atom-extensions/atom-cf-manifest-yaml/lib/main.js +++ b/atom-extensions/atom-cf-manifest-yaml/lib/manifest-yaml-language-client.ts @@ -1,13 +1,12 @@ -const path = require('path'); -const { JavaProcessLanguageClient } = require('@pivotal-tools/atom-languageclient-commons'); -const PROPERTIES = require('../properties.json'); +import * as path from 'path'; +import { JavaProcessLanguageClient } from '@pivotal-tools/atom-languageclient-commons'; +import {JVM} from '@pivotal-tools/jvm-launch-utils'; -class ManifestYamlLanguageClient extends JavaProcessLanguageClient { +export class ManifestYamlLanguageClient extends JavaProcessLanguageClient { constructor() { //noinspection JSAnnotator super( - PROPERTIES.jarUrl, path.join(__dirname, '..', 'server'), 'cf-manifest-language-server.jar' ); @@ -33,7 +32,7 @@ class ManifestYamlLanguageClient extends JavaProcessLanguageClient { super.activate(); } - launchVmArgs(version) { + launchVmArgs(jvm: JVM) { return Promise.resolve([ '-Dorg.slf4j.simpleLogger.logFile=manifest-yaml.log', '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug', @@ -41,6 +40,4 @@ class ManifestYamlLanguageClient extends JavaProcessLanguageClient { } -} - -module.exports = new ManifestYamlLanguageClient(); +} \ No newline at end of file diff --git a/atom-extensions/atom-cf-manifest-yaml/package.json b/atom-extensions/atom-cf-manifest-yaml/package.json index 24b9e9506..7a37af272 100644 --- a/atom-extensions/atom-cf-manifest-yaml/package.json +++ b/atom-extensions/atom-cf-manifest-yaml/package.json @@ -1,31 +1,39 @@ { "name": "cf-manifest-yaml", - "main": "./lib/main", - "version": "0.1.5", + "version": "0.1.6", "description": "Cloud Foundry Deployment Manifest YAML support for Atom", "repository": "https://github.com/spring-projects/atom-cf-manifest-yaml", "icon": "icon.png", "license": "MIT", "engines": { - "atom": ">=1.21.0" + "atom": ">=1.24.0" }, + "main": "./build/main", + "types": "./build/main.d.ts", "files": [ "grammars/", "settings/", "lib/", + "build/", "server/", "properties.json" ], "dependencies": { "atom-package-deps": "^4.6.0", "download": "^6.2.5", - "@pivotal-tools/atom-languageclient-commons": "0.0.2" + "@pivotal-tools/atom-languageclient-commons": "0.0.4" }, "devDependencies": { + "typescript": "^2.7.2", + "tslint": "^5.9.1", "coffeelint": "^1.10.1" }, "scripts": { - "clean": "rm -fr node_modules", + "clean": "rm -fr build", + "compile": "tsc", + "build": "npm run clean && npm run compile ", + "watch": "tsc -watch", + "lint": "tslint -c tslint.json 'lib/**/*.ts'", "postinstall": "node script.js" }, "package-deps": [ diff --git a/atom-extensions/atom-cf-manifest-yaml/properties.json b/atom-extensions/atom-cf-manifest-yaml/properties.json index e1897ba1a..8b84198ce 100644 --- a/atom-extensions/atom-cf-manifest-yaml/properties.json +++ b/atom-extensions/atom-cf-manifest-yaml/properties.json @@ -1,3 +1,3 @@ { - "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/manifest-yaml-language-server-0.0.10-201711061741.jar" + "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/manifest-yaml-language-server-0.1.5-201803080105.jar" } diff --git a/atom-extensions/atom-cf-manifest-yaml/tsconfig.json b/atom-extensions/atom-cf-manifest-yaml/tsconfig.json new file mode 100644 index 000000000..a333b271b --- /dev/null +++ b/atom-extensions/atom-cf-manifest-yaml/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "build", + "lib": ["es7", "dom"], + "declaration": true, + "inlineSources": true, + "inlineSourceMap": true, + "strictNullChecks": true, + "noImplicitAny": true, + "baseUrl": "./" + }, + "include": [ + "lib/**/*.ts" + ] +} \ No newline at end of file diff --git a/atom-extensions/atom-cf-manifest-yaml/tslint.json b/atom-extensions/atom-cf-manifest-yaml/tslint.json new file mode 100644 index 000000000..068b76067 --- /dev/null +++ b/atom-extensions/atom-cf-manifest-yaml/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": false, + "object-literal-sort-keys": false, + "ordered-imports": false, + "member-ordering": false, + "one-line": false, + "interface-name": false, + "variable-name": false, + "max-classes-per-file": false, + "no-unused-expression": false, + "no-empty": false, + "one-variable-per-declaration": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-module" + ] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/atom-extensions/atom-commons/.babelrc b/atom-extensions/atom-commons/.babelrc deleted file mode 100644 index 3b514bd56..000000000 --- a/atom-extensions/atom-commons/.babelrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "sourceMap": "inline", - "plugins": [ - ["add-module-exports", {}], - ["transform-async-to-generator", {}], - ["transform-decorators-legacy", {}], - ["transform-class-properties", {}], - ["transform-es2015-modules-commonjs", {"strictMode": false}], - ["transform-export-extensions", {}], - ["transform-do-expressions", {}], - ["transform-function-bind", {}], - ["transform-object-rest-spread", {}], - ["transform-flow-strip-types", {}], - ] -} \ No newline at end of file diff --git a/atom-extensions/atom-commons/lib/index.js b/atom-extensions/atom-commons/lib/index.js deleted file mode 100644 index e2b2e7c79..000000000 --- a/atom-extensions/atom-commons/lib/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import { JavaProcessLanguageClient } from './java-process-language-client'; -import { StsAdapter } from './sts-adapter'; - -export { JavaProcessLanguageClient, StsAdapter }; \ No newline at end of file diff --git a/atom-extensions/atom-commons/lib/java-process-language-client.js b/atom-extensions/atom-commons/lib/java-process-language-client.js deleted file mode 100644 index 173e53433..000000000 --- a/atom-extensions/atom-commons/lib/java-process-language-client.js +++ /dev/null @@ -1,217 +0,0 @@ -const cp = require('child_process'); -const fs = require('fs'); -const path = require('path'); -const url = require('url'); -const remote = require('remote-file-size'); -const PortFinder = require('portfinder'); -const net = require('net'); -const rpc = require('vscode-jsonrpc'); -const {AutoLanguageClient, DownloadFile} = require('atom-languageclient'); -const { Disposable } = require('atom'); -import { StsAdapter } from './sts-adapter'; - -import {findJdk, findJvm} from '@pivotal-tools/jvm-launch-utils'; - -export class JavaProcessLanguageClient extends AutoLanguageClient { - - DEBUG = false; - - constructor(serverDownloadUrl, serverHome, serverLauncherJar) { - super(); - - this.serverHome = serverHome; - this.serverDownloadUrl = serverDownloadUrl; - this.serverLauncherJar = serverLauncherJar; - } - - getServerJar() { - return path.resolve(this.serverHome, this.serverLauncherJar); - } - - showErrorMessage(detail, desc) { - const notification = atom.notifications.addError('Cannot start Language Server', { - dismissable: true, - detail: detail, - description: desc, - buttons: [{ - text: 'OK', - onDidClick: () => { - notification.dismiss() - }, - }] - }); - return Promise.reject(new Error(detail)); - } - - getInitializeParams(projectPath, process) { - const initParams = super.getInitializeParams(projectPath, process); - initParams.capabilities = { - workspace: { - executeCommand: { - } - } - }; - return initParams; - } - - startServerProcess () { - // //TODO: Remove when debugging is over - atom.config.set('core.debugLSP', true); - - let childProcess; - - if (this.DEBUG) { - return this.connectToLS(); - } - - return new Promise((resolve, reject) => { - let basePort = Math.floor(Math.random() * 10000) + 40000; - PortFinder.getPort({port: basePort}, (err, port) => { - this.server = net.createServer(socket => { - this.socket = socket; - resolve(childProcess); - }); - - this.server.listen(port, 'localhost', () => { - this.launchProcess(port).then(p => childProcess = p); - }); - }); - }); - } - - connectToLS() { - return new Promise(resolve => { - this.socket = net.connect({ - port: 5007 - }); - resolve({ - pid: -1, - kill: function() { - console.log('fake shutdown'); - } - }) - }); - } - - // Start adapters that are not shared between servers - startExclusiveAdapters(server) { - super.startExclusiveAdapters(server); - - const stsAdapter = this.createStsAdapter() || new StsAdapter(); - server.connection._onRequest({method: 'sts/moveCursor'}, params => stsAdapter.onMoveCursor(params)); - server.connection._onNotification({method: 'sts/progress'}, params => stsAdapter.onProgress(params)); - server.connection._onNotification({method: 'sts/highlight'}, params => stsAdapter.onHighlight(params)); - } - - preferJdk() { - return false; - } - - findJvm() { - return this.preferJdk() ? findJdk() : findJvm(); - } - - launchProcess(port) { - return this.findJvm() - .catch(error => { - return this.showErrorMessage("Error trying to find JVM", ""+error); - }) - .then(jvm => { - if (!jvm) { - return this.showErrorMessage("Couldn't locate java in $JAVA_HOME or $PATH"); - } - let version = jvm.getMajorVersion(); - if (version<8) { - return this.showErrorMessage( - 'No compatible Java Runtime Environment found', - 'The Java Runtime Environment is either below version "1.8" or is missing from the system' - ); - } - return this.launchVmArgs(jvm).then(args => { - args.push(`-Dserver.port=${port}`); - return this.doLaunchProcess( - jvm, - this.getServerJar(), - port, - args - ); - }); - }); - } - - launchVmArgs(jvm) { - return Promise.resolve([]); - } - - doLaunchProcess(jvm, launcher, port, args=[]) { - let vmArgs = args.concat([ - // Atom doesn't have lazy completion proposals support - completionItem/resolve message. Disable lazy completions - '-Dlsp.lazy.completions.disable=true', - '-Dlsp.completions.indentation.enable=true', - '-Dlsp.yaml.completions.errors.disable=true', - ]); - - this.logger.debug(`starting "${jvm.getJavaExecutable()} ${vmArgs.join('\n')}\n-jar ${launcher}"`); - return jvm.jarLaunch(launcher, vmArgs, { cwd: this.serverHome }); - } - - installServer () { - const localFileName = this.getServerJar(); - this.logger.log(`Downloading ${this.serverDownloadUrl} to ${localFileName}`); - return this.fileExists(this.serverHome) - .then(doesExist => { if (!doesExist) fs.mkdir(this.serverHome) }) - .then(() => this.remoteFileSize(this.serverDownloadUrl)) - .then((size) => DownloadFile(this.serverDownloadUrl, localFileName, (bytesDone, percent) => this.handleDownlaodPercentChange(bytesDone, size, percent), size)) - .then(() => this.fileExists(this.getServerJar())) - .then(doesExist => { if (!doesExist) throw Error(`Failed to install the ${this.getServerName()} language server`) }) - .then(() => this.handleServerInstalled()) - .then(() => Promise.resolve(true)); - } - - handleDownlaodPercentChange(bytesDone, size, percent) { - - } - - handleServerInstalled() { - - } - - preInitialization(connection) { - connection.onCustom('language/status', (e) => this.updateStatusBar(`${e.type.replace(/^Started$/, '')} ${e.message}`)); - } - - remoteFileSize(url) { - return new Promise((resolve, reject) => { - remote(url, (e,s) => { - if (e) { - reject(e); - } else { - resolve(s); - } - }); - }); - } - - fileExists (path) { - return new Promise((resolve, reject) => { - fs.access(path, fs.R_OK, error => { - resolve(!error || error.code !== 'ENOENT'); - }) - }) - } - - // Late wire-up of listeners after initialize method has been sent - postInitialization(server) { - server.disposable.add(new Disposable(() => { - if (this.server) { - this.server.close() - } - })); - } - - createStsAdapter() { - - } - -} - diff --git a/atom-extensions/atom-commons/lib/java-process-language-client.ts b/atom-extensions/atom-commons/lib/java-process-language-client.ts new file mode 100644 index 000000000..1006a7e43 --- /dev/null +++ b/atom-extensions/atom-commons/lib/java-process-language-client.ts @@ -0,0 +1,163 @@ +import * as path from 'path'; +import {getPort} from 'portfinder'; +import {Server, createServer, connect} from 'net'; +import {AtomEnvironment, Disposable} from 'atom'; +import {HighlightParams, ProgressParams, CursorMovementParams, StsAdapter} from './sts-adapter'; +import {ActiveServer, LanguageServerProcess} from 'atom-languageclient'; +import {AutoLanguageClient} from 'atom-languageclient'; +import {findJdk, findJvm, JVM} from '@pivotal-tools/jvm-launch-utils'; +import {InitializeParams} from 'vscode-languageserver-protocol'; + +export class JavaProcessLanguageClient extends AutoLanguageClient { + + DEBUG = false; + + private server: Server; + + constructor(protected serverHome: string, protected serverLauncherJar: string) { + super(); + } + + getServerJar(): string { + return path.resolve(this.serverHome, this.serverLauncherJar); + } + + showErrorMessage(detail: string, desc?: string): Promise { + const atomEnv: AtomEnvironment = atom; + const notification = atomEnv.notifications.addError('Cannot start Language Server', { + dismissable: true, + detail: detail, + description: desc, + buttons: [{ + text: 'OK', + onDidClick: () => { + notification.dismiss() + }, + }] + }); + return Promise.reject(new Error(detail)); + } + + protected getInitializeParams(projectPath: string, process: LanguageServerProcess): InitializeParams { + const initParams = super.getInitializeParams(projectPath, process); + initParams.capabilities = { + workspace: { + executeCommand: { + } + } + }; + return super.getInitializeParams(projectPath, process); + } + + protected startServerProcess(projectPath: string): LanguageServerProcess | Promise { + // TODO: Remove when debugging is over + const atomEnv: AtomEnvironment = atom; + atomEnv.config.set('core.debugLSP', true); + + let childProcess: LanguageServerProcess; + + if (this.DEBUG) { + return this.connectToLS(); + } + + return new Promise((resolve, reject) => { + let basePort = Math.floor(Math.random() * 10000) + 40000; + getPort({port: basePort}, (err, port) => { + this.server = createServer(socket => { + this.socket = socket; + resolve(childProcess); + }); + + this.server.listen(port, 'localhost', () => { + this.launchProcess(port).then(p => childProcess = p); + }); + }); + }); + } + + private connectToLS(): LanguageServerProcess | Promise { + return new Promise(resolve => { + this.socket = connect({ + port: 5007 + }); + resolve( { + pid: -1, + kill: () => { + console.log('fake shutdown'); + } + }) + }); + } + + // Start adapters that are not shared between servers + protected postInitialization(server: ActiveServer): void { + const stsAdapter = this.createStsAdapter() || new StsAdapter(); + (server.connection)._onRequest({method: 'sts/moveCursor'}, (params: CursorMovementParams) => stsAdapter.onMoveCursor(params)); + server.connection.onCustom('sts/progress', (params: ProgressParams) => stsAdapter.onProgress(params)); + server.connection.onCustom('sts/highlight', (params: HighlightParams) => stsAdapter.onHighlight(params)); + + server.disposable.add(new Disposable(() => { + if (this.server) { + this.server.close() + } + })); + + } + + preferJdk(): boolean { + return false; + } + + findJvm(): Promise { + return this.preferJdk() ? findJdk() : findJvm(); + } + + private launchProcess(port: number): Promise { + return this.findJvm() + .catch(error => { + return this.showErrorMessage("Error trying to find JVM", ""+error); + }) + .then(jvm => { + if (!jvm) { + return this.showErrorMessage("Couldn't locate java in $JAVA_HOME or $PATH"); + } + let version = jvm.getMajorVersion(); + if (version<8) { + return this.showErrorMessage( + 'No compatible Java Runtime Environment found', + 'The Java Runtime Environment is either below version "1.8" or is missing from the system' + ); + } + return this.launchVmArgs(jvm).then(args => { + args.push(`-Dserver.port=${port}`); + return this.doLaunchProcess( + jvm, + this.getServerJar(), + args + ); + }); + }); + } + + protected launchVmArgs(jvm: JVM): Promise { + return Promise.resolve([]); + } + + private doLaunchProcess(jvm: JVM, launcher: string, args: string[] =[]): LanguageServerProcess { + let vmArgs = args.concat([ + // Atom doesn't have lazy completion proposals support - completionItem/resolve message. Disable lazy completions + '-Dsts.lsp.client=atom', + '-Dlsp.completions.indentation.enable=true', + '-Dlsp.yaml.completions.errors.disable=true', + ]); + + this.logger.debug(`starting "${jvm.getJavaExecutable()} ${vmArgs.join('\n')}\n-jar ${launcher}"`); + return jvm.jarLaunch(launcher, vmArgs, { cwd: this.serverHome }); + } + + createStsAdapter(): StsAdapter | null { + return null; + } + +} + diff --git a/atom-extensions/atom-commons/lib/main.ts b/atom-extensions/atom-commons/lib/main.ts new file mode 100644 index 000000000..a196c7880 --- /dev/null +++ b/atom-extensions/atom-commons/lib/main.ts @@ -0,0 +1,10 @@ +import {JavaProcessLanguageClient} from './java-process-language-client'; +import {StsAdapter, CursorMovementParams, HighlightParams, ProgressParams} from './sts-adapter'; + +export { + JavaProcessLanguageClient, + StsAdapter, + CursorMovementParams, + HighlightParams, + ProgressParams +} \ No newline at end of file diff --git a/atom-extensions/atom-commons/lib/sts-adapter.js b/atom-extensions/atom-commons/lib/sts-adapter.js deleted file mode 100644 index 45c7e12ea..000000000 --- a/atom-extensions/atom-commons/lib/sts-adapter.js +++ /dev/null @@ -1,20 +0,0 @@ -import {Convert} from 'atom-languageclient'; - -export class StsAdapter { - - constructor() {} - - findEditors(uri) { - return atom.workspace.getTextEditors() - .filter(e => e && e.getPath() && Convert.pathToUri(e.getPath()) === uri); - } - - onMoveCursor(params) { - findEditors(params.uri).forEach(e => e.setCursorScreenPosition(Convert.positionToPoint(params.position))); - return { applied: true}; - } - - onProgress(params) {} - - onHighlight(params) {} -} diff --git a/atom-extensions/atom-commons/lib/sts-adapter.ts b/atom-extensions/atom-commons/lib/sts-adapter.ts new file mode 100644 index 000000000..649632c56 --- /dev/null +++ b/atom-extensions/atom-commons/lib/sts-adapter.ts @@ -0,0 +1,38 @@ +import {Convert} from 'atom-languageclient'; +import {AtomEnvironment, TextEditor} from 'atom'; +import {Position, Range, TextDocumentIdentifier} from 'vscode-languageserver-protocol'; + +export class StsAdapter { + + constructor() {} + + findEditors(uri: string): TextEditor[] { + const atomEnv: AtomEnvironment = atom; + return atomEnv.workspace.getTextEditors() + .filter(e => e && e.getPath() && Convert.pathToUri(e.getPath() || '') === uri); + } + + onMoveCursor(params: CursorMovementParams): any { + this.findEditors(params.uri).forEach(e => e.setCursorScreenPosition(Convert.positionToPoint(params.position))); + return {applied: true}; + } + + onProgress(params: ProgressParams): void {} + + onHighlight(params: HighlightParams): void {} +} + +export interface CursorMovementParams { + readonly uri: string; + readonly position: Position; +} + +export interface ProgressParams { + readonly id: string; + readonly statusMsg: string; +} + +export interface HighlightParams { + readonly doc: TextDocumentIdentifier; + readonly ranges: Range[]; +} diff --git a/atom-extensions/atom-commons/package.json b/atom-extensions/atom-commons/package.json index 6652e0363..9ddbb592b 100644 --- a/atom-extensions/atom-commons/package.json +++ b/atom-extensions/atom-commons/package.json @@ -1,56 +1,35 @@ { "name": "@pivotal-tools/atom-languageclient-commons", - "version": "0.0.2", + "version": "0.0.4", "description": "Atom language client commons for STS4 language servers", "repository": "https://github.com/spring-projects/sts4", "license": "MIT", "engines": { - "atom": ">=1.17.0" + "atom": ">=1.24.0" }, - "dependencies": { - "@pivotal-tools/jvm-launch-utils": "0.0.11", - "atom-languageclient": "0.8.0", - "decompress": "^4.2.0", - "portfinder": "^1.0.13", - "postinstall-build": "5.0.1", - "remote-file-size": "^3.0.3" - }, - "main": "./build/lib/index", + "main": "./build/main", + "types": "./build/main.d.ts", "files": [ - "build/" + "build/", + "lib/" ], "scripts": { "clean": "rm -rf build", - "compile": "babel lib --out-dir build/lib", - "postinstall": "postinstall-build --only-as-dependency build \"npm run compile\"", - "prepublish": "npm run clean && npm run compile", - "watch": "babel lib --out-dir build/lib -w" + "compile": "tsc", + "watch": "tsc -watch", + "lint": "tslint -c tslint.json 'lib/**/*.ts'", + "prepublish": "npm run clean && npm run compile" + }, + "dependencies": { + "@pivotal-tools/jvm-launch-utils": "0.0.11", + "atom-languageclient": "0.9.2", + "portfinder": "^1.0.13", + "@types/atom": "^1.24.1", + "@types/node": "^8.0.41", + "vscode-languageserver-protocol": "3.6.0-next.5" }, - "atomTranspilers": [ - { - "glob": "{lib}/**/*.js", - "transpiler": "atom-babel6-transpiler", - "options": { - "cacheKeyFiles": [ - "package.json", - ".babelrc" - ] - } - } - ], "devDependencies": { - "atom-babel6-transpiler": "0.0.3", - "babel-cli": "^6.24.0", - "babel-core": "6.22.1", - "babel-plugin-add-module-exports": "0.2.1", - "babel-plugin-transform-async-to-generator": "6.22.0", - "babel-plugin-transform-class-properties": "6.23.0", - "babel-plugin-transform-decorators-legacy": "1.3.4", - "babel-plugin-transform-do-expressions": "6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "6.23.0", - "babel-plugin-transform-export-extensions": "6.22.0", - "babel-plugin-transform-flow-strip-types": "6.22.0", - "babel-plugin-transform-function-bind": "6.22.0", - "babel-plugin-transform-object-rest-spread": "6.23.0" + "tslint": "^5.9.1", + "typescript": "^2.7.2" } } diff --git a/atom-extensions/atom-commons/tsconfig.json b/atom-extensions/atom-commons/tsconfig.json new file mode 100644 index 000000000..b22a85ff1 --- /dev/null +++ b/atom-extensions/atom-commons/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "build", + "lib": ["es7", "dom"], + "declaration": true, + "inlineSources": true, + "inlineSourceMap": true, + "strictNullChecks": true, + "noImplicitAny": true, + "baseUrl": "./" + }, + "include": [ + "lib/**/*.ts", + ] +} \ No newline at end of file diff --git a/atom-extensions/atom-commons/tslint.json b/atom-extensions/atom-commons/tslint.json new file mode 100644 index 000000000..068b76067 --- /dev/null +++ b/atom-extensions/atom-commons/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": false, + "object-literal-sort-keys": false, + "ordered-imports": false, + "member-ordering": false, + "one-line": false, + "interface-name": false, + "variable-name": false, + "max-classes-per-file": false, + "no-unused-expression": false, + "no-empty": false, + "one-variable-per-declaration": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-module" + ] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/atom-extensions/atom-concourse/.gitignore b/atom-extensions/atom-concourse/.gitignore index 0dd84018c..9ad2c10c9 100644 --- a/atom-extensions/atom-concourse/.gitignore +++ b/atom-extensions/atom-concourse/.gitignore @@ -1,6 +1,7 @@ /.idea /node_modules /server +/build *.tgz *iml *.log \ No newline at end of file diff --git a/atom-extensions/atom-concourse/README.md b/atom-extensions/atom-concourse/README.md index 11e12d3f7..34cd347c8 100644 --- a/atom-extensions/atom-concourse/README.md +++ b/atom-extensions/atom-concourse/README.md @@ -2,7 +2,7 @@ [![macOS Build Status](https://travis-ci.org/spring-projects/atom-concourse.svg?branch=master)](https://travis-ci.org/spring-projects/atom-concourse) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1jvknxt9jhykgrxo?svg=true)](https://ci.appveyor.com/project/spring-projects/atom-concourse/branch/master) [![Dependency Status](https://david-dm.org/spring-projects/atom-concourse.svg)](https://david-dm.org/spring-projects/atom-concourse) This extension provides basic validation, content assist and hover infos -for editing Concourse [Pipeline](https://concourse.ci/pipelines.html) and [Task Configuration](https://concourse.ci/running-tasks.html) Files. +for editing Concourse [Pipeline](https://concourse-ci.org/pipelines.html) and [Task Configuration](https://concourse-ci.org/running-tasks.html) Files. It is recommended to use this extension package when `atom-ide-ui` atom extension package is installed. Thus, reconciling (error/warning markers) and hover support is fully functional. diff --git a/atom-extensions/atom-concourse/lib/main.js b/atom-extensions/atom-concourse/lib/concourse-ci-yaml-client.ts similarity index 73% rename from atom-extensions/atom-concourse/lib/main.js rename to atom-extensions/atom-concourse/lib/concourse-ci-yaml-client.ts index d8f0ff835..b075a8779 100644 --- a/atom-extensions/atom-concourse/lib/main.js +++ b/atom-extensions/atom-concourse/lib/concourse-ci-yaml-client.ts @@ -1,13 +1,12 @@ -const path = require('path'); -const { JavaProcessLanguageClient } = require('@pivotal-tools/atom-languageclient-commons'); -const PROPERTIES = require('../properties.json'); +import * as path from 'path'; +import { JavaProcessLanguageClient } from '@pivotal-tools/atom-languageclient-commons'; +import {JVM} from '@pivotal-tools/jvm-launch-utils'; -class ConcourseCiYamlClient extends JavaProcessLanguageClient { +export class ConcourseCiYamlClient extends JavaProcessLanguageClient { constructor() { //noinspection JSAnnotator super( - PROPERTIES.jarUrl, path.join(__dirname, '..', 'server'), 'concourse-language-server.jar' ); @@ -33,7 +32,7 @@ class ConcourseCiYamlClient extends JavaProcessLanguageClient { super.activate(); } - launchVmArgs(jvm) { + launchVmArgs(jvm: JVM) { return Promise.resolve([ '-Dorg.slf4j.simpleLogger.logFile=concourse-ci-yaml.log', '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug', @@ -41,6 +40,4 @@ class ConcourseCiYamlClient extends JavaProcessLanguageClient { } -} - -module.exports = new ConcourseCiYamlClient(); +} \ No newline at end of file diff --git a/atom-extensions/atom-concourse/lib/main.ts b/atom-extensions/atom-concourse/lib/main.ts new file mode 100644 index 000000000..d441a0d1d --- /dev/null +++ b/atom-extensions/atom-concourse/lib/main.ts @@ -0,0 +1,3 @@ +import {ConcourseCiYamlClient} from './concourse-ci-yaml-client'; + +module.exports = new ConcourseCiYamlClient(); \ No newline at end of file diff --git a/atom-extensions/atom-concourse/package.json b/atom-extensions/atom-concourse/package.json index 80dcea653..6403267dc 100644 --- a/atom-extensions/atom-concourse/package.json +++ b/atom-extensions/atom-concourse/package.json @@ -1,17 +1,19 @@ { "name": "concourse-pipeline-yaml", - "main": "./lib/main", - "version": "0.1.5", + "version": "0.1.6", "description": "Provides validation and content assist for Concourse CI pipeline and task configuration yml files", "repository": "https://github.com/spring-projects/atom-concourse", "icon": "icon.png", "license": "MIT", "engines": { - "atom": ">=1.21.0" + "atom": ">=1.24.0" }, + "main": "./build/main", + "types": "./build/main.d.ts", "files": [ "grammars/", "settings/", + "build/", "lib/", "server/", "properties.json" @@ -19,13 +21,19 @@ "dependencies": { "atom-package-deps": "^4.6.0", "download": "^6.2.5", - "@pivotal-tools/atom-languageclient-commons": "0.0.2" + "@pivotal-tools/atom-languageclient-commons": "0.0.4" }, "devDependencies": { + "typescript": "^2.7.2", + "tslint": "^5.9.1", "coffeelint": "^1.10.1" }, "scripts": { - "clean": "rm -fr node_modules", + "clean": "rm -fr build", + "compile": "tsc", + "build": "npm run clean && npm run compile ", + "watch": "tsc -watch", + "lint": "tslint -c tslint.json 'lib/**/*.ts'", "postinstall": "node script.js" }, "package-deps": [ diff --git a/atom-extensions/atom-concourse/tsconfig.json b/atom-extensions/atom-concourse/tsconfig.json new file mode 100644 index 000000000..a333b271b --- /dev/null +++ b/atom-extensions/atom-concourse/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "build", + "lib": ["es7", "dom"], + "declaration": true, + "inlineSources": true, + "inlineSourceMap": true, + "strictNullChecks": true, + "noImplicitAny": true, + "baseUrl": "./" + }, + "include": [ + "lib/**/*.ts" + ] +} \ No newline at end of file diff --git a/atom-extensions/atom-concourse/tslint.json b/atom-extensions/atom-concourse/tslint.json new file mode 100644 index 000000000..068b76067 --- /dev/null +++ b/atom-extensions/atom-concourse/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": false, + "object-literal-sort-keys": false, + "ordered-imports": false, + "member-ordering": false, + "one-line": false, + "interface-name": false, + "variable-name": false, + "max-classes-per-file": false, + "no-unused-expression": false, + "no-empty": false, + "one-variable-per-declaration": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-module" + ] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/atom-extensions/atom-spring-boot/.gitignore b/atom-extensions/atom-spring-boot/.gitignore index 38d57c0ad..2e6ca2885 100644 --- a/atom-extensions/atom-spring-boot/.gitignore +++ b/atom-extensions/atom-spring-boot/.gitignore @@ -1,3 +1,4 @@ .idea/ server/ node_modules/ +build/ diff --git a/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts b/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts new file mode 100644 index 000000000..d028a686f --- /dev/null +++ b/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts @@ -0,0 +1,56 @@ +import {StsAdapter, HighlightParams} from '@pivotal-tools/atom-languageclient-commons'; +import {Convert} from 'atom-languageclient'; +import { Range } from 'vscode-languageserver-protocol'; +import {TextEditor} from 'atom'; + +const BOOT_DATA_MARKER_TYPE: any = 'BootApp-Hint'; +const BOOT_HINT_GUTTER_NAME = 'boot-hint-gutter'; + +export class BootStsAdapter extends StsAdapter { + + constructor() { + super(); + } + + onHighlight(params: HighlightParams) { + this.findEditors(params.doc.uri).forEach(editor => this.markHintsForEditor(editor, params.ranges)); + } + + private markHintsForEditor(editor: TextEditor, ranges: Range[]) { + editor.findMarkers(BOOT_DATA_MARKER_TYPE).forEach(m => m.destroy()); + if (Array.isArray(ranges)) { + ranges.forEach(range => this.createHintMarker(editor, range)); + } + const gutter = editor.gutterWithName(BOOT_HINT_GUTTER_NAME); + if (gutter) { + if (!ranges || !ranges.length) { + gutter.hide(); + } else if (!gutter.isVisible()) { + gutter.show(); + } + } + } + + private createHintMarker(editor: TextEditor, range: Range) { + // Create marker model + const marker = editor.markBufferRange(Convert.lsRangeToAtomRange(range), BOOT_DATA_MARKER_TYPE); + + // Marker around the text in the editor + editor.decorateMarker(marker, { + type: 'highlight', + class: 'boot-hint' + }); + + // Marker in the diagnostic gutter + let gutter = editor.gutterWithName(BOOT_HINT_GUTTER_NAME); + if (!gutter) { + gutter = editor.addGutter({ + name: BOOT_HINT_GUTTER_NAME, + visible: false, + }); + } + const iconElement = document.createElement('span'); + iconElement.setAttribute('class', 'gutter-boot-hint'); + gutter.decorateMarker(marker, {item: iconElement}); + } +} \ No newline at end of file diff --git a/atom-extensions/atom-spring-boot/lib/main.js b/atom-extensions/atom-spring-boot/lib/main.js deleted file mode 100644 index 9e78051d2..000000000 --- a/atom-extensions/atom-spring-boot/lib/main.js +++ /dev/null @@ -1,128 +0,0 @@ -const path = require('path'); -const { JavaProcessLanguageClient, StsAdapter } = require('@pivotal-tools/atom-languageclient-commons'); -const { Convert } = require('atom-languageclient'); -const PROPERTIES = require('../properties.json'); - -const BOOT_DATA_MARKER_TYPE = 'BootApp-Hint'; -const BOOT_HINT_GUTTER_NAME = 'boot-hint-gutter'; - -class SpringBootLanguageClient extends JavaProcessLanguageClient { - - constructor() { - //noinspection JSAnnotator - super( - PROPERTIES.jarUrl, - path.join(__dirname, '..', 'server'), - 'spring-boot-language-server.jar' - ); - // this.DEBUG = true; - } - - postInitialization(server) { - this.sendConfig(server); - this._disposable.add(atom.config.observe('boot-java', () => this.sendConfig(server))); - } - - sendConfig(server) { - server.connection.didChangeConfiguration({ settings: {'boot-java': atom.config.get('boot-java') }}); - } - - getGrammarScopes() { - return ['source.java', 'source.boot-properties', 'source.boot-properties-yaml']; - } - - getLanguageName() { - return 'spring-boot'; - } - - getServerName() { - return 'Spring Boot'; - } - - activate() { - require('atom-package-deps') - .install('spring-boot') - .then(() => console.debug('All dependencies installed, good to go')); - super.activate(); - } - - preferJdk() { - return true; - } - - launchVmArgs(jvm) { - let vmargs = [ - // '-Xdebug', - // '-agentlib:jdwp=transport=dt_socket,server=y,address=7999,suspend=n', - '-Dorg.slf4j.simpleLogger.logFile=boot-java.log', - '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug', - ]; - if (!jvm.isJdk()) { - this.showErrorMessage( - '"Boot-Java" Package Functionality Limited', - 'JAVA_HOME or PATH environment variable seems to point to a JRE. A JDK is required, hence Boot Hints are unavailable.' - ); - } - return Promise.resolve(vmargs); - } - - createStsAdapter() { - return new BootStsAdapter(); - } - - filterChangeWatchedFiles(filePath) { - return filePath.endsWith('.gradle') || filePath.endsWith(path.join('', 'pom.xml')); - } - -} - -class BootStsAdapter extends StsAdapter { - - constructor() { - super(); - } - - onHighlight(params) { - this.findEditors(params.doc.uri).forEach(editor => this.markHintsForEditor(editor, params.ranges)); - } - - markHintsForEditor(editor, ranges) { - editor.findMarkers(BOOT_DATA_MARKER_TYPE).forEach(m => m.destroy()); - if (Array.isArray(ranges)) { - ranges.forEach(range => this.createHintMarker(editor, range)); - } - const gutter = editor.gutterWithName(BOOT_HINT_GUTTER_NAME); - if (gutter) { - if (!ranges || !ranges.length) { - gutter.hide(); - } else if (!gutter.isVisible()) { - gutter.show(); - } - } - } - - createHintMarker(editor, range) { - // Create marker model - const marker = editor.markBufferRange(Convert.lsRangeToAtomRange(range), BOOT_DATA_MARKER_TYPE); - - // Marker around the text in the editor - editor.decorateMarker(marker, { - type: 'highlight', - class: 'boot-hint' - }); - - // Marker in the diagnostic gutter - let gutter = editor.gutterWithName(BOOT_HINT_GUTTER_NAME); - if (!gutter) { - gutter = editor.addGutter({ - name: BOOT_HINT_GUTTER_NAME, - visible: false, - }); - } - const iconElement = document.createElement('span'); - iconElement.setAttribute('class', 'gutter-boot-hint'); - gutter.decorateMarker(marker, {item: iconElement}); - } -} - -module.exports = new SpringBootLanguageClient(); diff --git a/atom-extensions/atom-spring-boot/lib/main.ts b/atom-extensions/atom-spring-boot/lib/main.ts new file mode 100644 index 000000000..d99dbed3a --- /dev/null +++ b/atom-extensions/atom-spring-boot/lib/main.ts @@ -0,0 +1,3 @@ +import {SpringBootLanguageClient} from './spring-boot-language-client'; + +module.exports = new SpringBootLanguageClient(); \ No newline at end of file diff --git a/atom-extensions/atom-spring-boot/lib/spring-boot-language-client.ts b/atom-extensions/atom-spring-boot/lib/spring-boot-language-client.ts new file mode 100644 index 000000000..1979d840e --- /dev/null +++ b/atom-extensions/atom-spring-boot/lib/spring-boot-language-client.ts @@ -0,0 +1,75 @@ +import * as path from 'path'; +import {JavaProcessLanguageClient} from '@pivotal-tools/atom-languageclient-commons'; +import {BootStsAdapter} from './boot-sts-adapter'; +import {ActiveServer} from 'atom-languageclient'; +import {JVM} from '@pivotal-tools/jvm-launch-utils'; + +export class SpringBootLanguageClient extends JavaProcessLanguageClient { + + constructor() { + //noinspection JSAnnotator + super( + path.join(__dirname, '..', 'server'), + 'spring-boot-language-server.jar' + ); + // this.DEBUG = true; + } + + protected postInitialization(server: ActiveServer) { + super.postInitialization(server); + this.sendConfig(server); + (this)._disposable.add(atom.config.observe('boot-java', () => this.sendConfig(server))); + } + + private sendConfig(server: ActiveServer) { + server.connection.didChangeConfiguration({ settings: {'boot-java': atom.config.get('boot-java') }}); + } + + getGrammarScopes() { + return ['source.java', 'source.boot-properties', 'source.boot-properties-yaml']; + } + + getLanguageName() { + return 'spring-boot'; + } + + getServerName() { + return 'Spring Boot'; + } + + activate() { + require('atom-package-deps') + .install('spring-boot') + .then(() => console.debug('All dependencies installed, good to go')); + super.activate(); + } + + preferJdk() { + return true; + } + + launchVmArgs(jvm: JVM) { + let vmargs = [ + // '-Xdebug', + // '-agentlib:jdwp=transport=dt_socket,server=y,address=7999,suspend=n', + '-Dorg.slf4j.simpleLogger.logFile=boot-java.log', + '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug', + ]; + if (!jvm.isJdk()) { + this.showErrorMessage( + '"Boot-Java" Package Functionality Limited', + 'JAVA_HOME or PATH environment variable seems to point to a JRE. A JDK is required, hence Boot Hints are unavailable.' + ); + } + return Promise.resolve(vmargs); + } + + createStsAdapter() { + return new BootStsAdapter(); + } + + filterChangeWatchedFiles(filePath: string) { + return filePath.endsWith('.gradle') || filePath.endsWith(path.join('', 'pom.xml')); + } + +} diff --git a/atom-extensions/atom-spring-boot/package.json b/atom-extensions/atom-spring-boot/package.json index 1d034d6a9..55c0ae214 100644 --- a/atom-extensions/atom-spring-boot/package.json +++ b/atom-extensions/atom-spring-boot/package.json @@ -1,17 +1,19 @@ { "name": "spring-boot", - "main": "./lib/main", - "version": "0.1.5", + "version": "0.1.6", "description": "Spring Boot support for Atom", "repository": "https://github.com/spring-projects/atom-spring-boot", "icon": "icon.png", "license": "MIT", "engines": { - "atom": ">=1.21.0" + "atom": ">=1.24.0" }, + "main": "./build/main", + "types": "./build/main.d.ts", "files": [ "grammars/", "settings/", + "build/", "lib/", "server/", "styles/", @@ -25,16 +27,21 @@ } }, "dependencies": { - "@pivotal-tools/atom-languageclient-commons": "0.0.2", - "atom-languageclient": "0.8.0", + "@pivotal-tools/atom-languageclient-commons": "0.0.4", "atom-package-deps": "^4.6.0", "download": "^6.2.5" }, "devDependencies": { + "typescript": "^2.7.2", + "tslint": "^5.9.1", "coffeelint": "^1.10.1" }, "scripts": { - "clean": "rm -fr node_modules", + "clean": "rm -rf build", + "compile": "tsc", + "build": "npm run clean && npm run compile ", + "watch": "tsc -watch", + "lint": "tslint -c tslint.json 'lib/**/*.ts'", "postinstall": "node script.js" }, "package-deps": [ diff --git a/atom-extensions/atom-spring-boot/properties.json b/atom-extensions/atom-spring-boot/properties.json index fc5866d86..5f72a3b34 100644 --- a/atom-extensions/atom-spring-boot/properties.json +++ b/atom-extensions/atom-spring-boot/properties.json @@ -1,3 +1,3 @@ { - "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/spring-boot-language-server-0.1.5-201803022113.jar" + "jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/spring-boot-language-server-0.1.5-201803051440.jar" } diff --git a/atom-extensions/atom-spring-boot/tsconfig.json b/atom-extensions/atom-spring-boot/tsconfig.json new file mode 100644 index 000000000..a333b271b --- /dev/null +++ b/atom-extensions/atom-spring-boot/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "build", + "lib": ["es7", "dom"], + "declaration": true, + "inlineSources": true, + "inlineSourceMap": true, + "strictNullChecks": true, + "noImplicitAny": true, + "baseUrl": "./" + }, + "include": [ + "lib/**/*.ts" + ] +} \ No newline at end of file diff --git a/atom-extensions/atom-spring-boot/tslint.json b/atom-extensions/atom-spring-boot/tslint.json new file mode 100644 index 000000000..068b76067 --- /dev/null +++ b/atom-extensions/atom-spring-boot/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": false, + "object-literal-sort-keys": false, + "ordered-imports": false, + "member-ordering": false, + "one-line": false, + "interface-name": false, + "variable-name": false, + "max-classes-per-file": false, + "no-unused-expression": false, + "no-empty": false, + "one-variable-per-declaration": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-module" + ] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/concourse/pipeline.yml b/concourse/pipeline.yml index 4ffcc7ddc..6172b66a8 100644 --- a/concourse/pipeline.yml +++ b/concourse/pipeline.yml @@ -494,6 +494,67 @@ jobs: params: repository: out/repo rebase: true +- name: tag-atom-release + plan: + - aggregate: + - get: sts4 + - get: atom-bosh + passed: + - prepare-bosh-atom-rc + - get: atom-concourse + passed: + - prepare-concourse-atom-rc + - get: atom-spring-boot + passed: + - prepare-spring-boot-atom-rc + - get: atom-cf-manifest-yaml + passed: + - prepare-manifest-yaml-atom-rc + - task: tag-atom-releases + file: sts4/concourse/tasks/tag-atom-releases.yml + - aggregate: + - put: atom-bosh + params: + repository: out/atom-bosh + only_tag: true + - put: atom-concourse + params: + repository: out/atom-concourse + only_tag: true + - put: atom-spring-boot + params: + repository: out/atom-spring-boot + only_tag: true + - put: atom-cf-manifest-yaml + params: + repository: out/atom-cf-manifest-yaml + only_tag: true +- name: publish-atom-releases + serial: true + plan: + - aggregate: + - get: sts4 + - get: atom-concourse + trigger: true + passed: + - tag-atom-release + - task: publish-atom-releases + file: sts4/concourse/tasks/publish-atom-releases.yml + params: + atom_token: ((atom_token)) + on_failure: + put: slack-notification + params: + text: | + Concourse ${BUILD_PIPELINE_NAME}/${BUILD_JOB_NAME}/${BUILD_NAME} has failed! + on_success: + put: slack-notification + params: + channel: "#tools-team-internal" + text: | + STS 4 Atom Extensions released + Releases now available on Atom Marketplace: + • - name: build-concourse-rc plan: - aggregate: @@ -699,6 +760,52 @@ jobs: - put: version params: file: version/version +- name: publish-concourse-vsix-release + serial: true + plan: + - aggregate: + - get: tasks + - get: sts4 + passed: + - build-concourse-rc + - get: version + passed: + - build-concourse-rc + params: + bump: final + - get: s3-concourse-vsix-snapshot + passed: + - build-concourse-rc + - task: publish-release + file: tasks/concourse/tasks/publish-concourse-vsix-release.yml + input_mapping: + sts4: tasks + params: + vsce_token: ((vsce_token)) + on_failure: + put: slack-notification + params: + text: | + Concourse ${BUILD_PIPELINE_NAME}/${BUILD_JOB_NAME}/${BUILD_NAME} has failed! + on_success: + put: slack-notification + params: + channel: "#tools-team-internal" + text_file: version/version + text: | + STS 4 VScode Extensions $TEXT_FILE_CONTENT released + Releases now available on Vscode Marketplace: + • + - aggregate: + - put: sts4-out + params: + repository: sts4 + only_tag: true + tag: version/version + tag_prefix: V_ + - put: version + params: + file: version/version - name: bump-version-patch serial: true plan: @@ -981,6 +1088,7 @@ groups: - build-consourse-vsix-snapshot - build-bosh-vsix-snapshot - build-spring-boot-vsix-snapshot + - publish-concourse-vsix-release - name: bump-versions jobs: - bump-version-patch @@ -993,13 +1101,20 @@ groups: - build-bosh-atom-package - build-manifest-yaml-atom-package - build-spring-boot-atom-package -- name: atom-rc +- name: atom-release jobs: + - atom-language-servers-test + - build-concourse-atom-package + - build-bosh-atom-package + - build-manifest-yaml-atom-package + - build-spring-boot-atom-package - prepare-bosh-atom-rc - prepare-concourse-atom-rc - prepare-manifest-yaml-atom-rc - prepare-spring-boot-atom-rc - promote-fatjars-to-rc + - tag-atom-release + - publish-atom-releases - name: setup jobs: - build-mvn-cache diff --git a/concourse/tasks/build-atom-package.sh b/concourse/tasks/build-atom-package.sh index bee5a4075..ebb7b06b3 100755 --- a/concourse/tasks/build-atom-package.sh +++ b/concourse/tasks/build-atom-package.sh @@ -11,6 +11,7 @@ fatjar_version=`cat fatjar/version` #cd $atom_commons #npm install +#npm run build cd $atom_package @@ -24,6 +25,8 @@ EOF npm install +npm run build + # push code to release repository cd $workdir diff --git a/concourse/tasks/publish-atom-releases.sh b/concourse/tasks/publish-atom-releases.sh new file mode 100755 index 000000000..1fc068c9a --- /dev/null +++ b/concourse/tasks/publish-atom-releases.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e +workdir=`pwd` + +atom_packages=`ls -d atom-*` + +for atom_package in $atom_packages +do + echo "****************************************************************" + echo "*** Publishing : ${atom_package}" + echo "****************************************************************" + cd $workdir/$atom_package + tag=v$(cat package.json | jq -r ".version") + export ATOM_ACCESS_TOKEN=$atom_token + # apm login --token $atom_token + apm publish --tag $tag +done diff --git a/concourse/tasks/publish-atom-releases.yml b/concourse/tasks/publish-atom-releases.yml new file mode 100644 index 000000000..7d733cc68 --- /dev/null +++ b/concourse/tasks/publish-atom-releases.yml @@ -0,0 +1,13 @@ +inputs: +- name: sts4 +- name: atom-concourse +params: + atom_token: atom_token_must_be_provided!!! +platform: linux +run: + path: sts4/concourse/tasks/publish-atom-releases.sh +image_resource: + type: docker-image + source: + repository: kdvolder/atom-apm + \ No newline at end of file diff --git a/concourse/tasks/publish-concourse-vsix-release.yml b/concourse/tasks/publish-concourse-vsix-release.yml new file mode 100644 index 000000000..043079137 --- /dev/null +++ b/concourse/tasks/publish-concourse-vsix-release.yml @@ -0,0 +1,11 @@ +inputs: +- name: sts4 +- name: s3-concourse-vsix-snapshot +platform: linux +run: + path: sts4/concourse/tasks/publish-vsix-releases.sh +image_resource: + type: docker-image + source: + repository: kdvolder/sts4-build-env + \ No newline at end of file diff --git a/concourse/tasks/tag-atom-releases.sh b/concourse/tasks/tag-atom-releases.sh new file mode 100755 index 000000000..cc6ffed87 --- /dev/null +++ b/concourse/tasks/tag-atom-releases.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e +# set -x +workdir=$(pwd) +out=${workdir}/out + +git config --global user.email "kdevolder@pivotal.io" +git config --global user.name "Kris De Volder" + +for package in atom-* ; do + echo "Processing ${package}..." + + mkdir "${out}/${package}" + cd "${out}" + git clone "${workdir}/${package}/.git" + + cd ${package} + tag=v$(cat package.json | jq -r ".version") + echo "Tag: ${tag}" + git tag $tag +done \ No newline at end of file diff --git a/concourse/tasks/tag-atom-releases.yml b/concourse/tasks/tag-atom-releases.yml new file mode 100644 index 000000000..022ab6e2f --- /dev/null +++ b/concourse/tasks/tag-atom-releases.yml @@ -0,0 +1,15 @@ +platform: linux +image_resource: + type: docker-image + source: + repository: kdvolder/sts4-build-env +inputs: +- name: sts4 +- name: atom-bosh +- name: atom-concourse +- name: atom-spring-boot +- name: atom-cf-manifest-yaml +outputs: +- name: out +run: + path: sts4/concourse/tasks/tag-atom-releases.sh diff --git a/eclipse-distribution/common/html/nightly-distributions.html b/eclipse-distribution/common/html/nightly-distributions.html index ae8f3ed17..cbb3d88b5 100644 --- a/eclipse-distribution/common/html/nightly-distributions.html +++ b/eclipse-distribution/common/html/nightly-distributions.html @@ -21,13 +21,31 @@ Instead add them to the available update sites in your Eclipse/STS preferences or paste them into the "Install New Software" dialog.

-

+

STS4 Distribution:

+

STS4 language server extensions (this repository is meant to be used to ship updates of the language server extensions to existing STS4 installations. In production, the release version of this repository is used.) +

+ +

+

+

+ +

STS3 language server extensions (this repository is used by existing STS3 installations and can be used to update the embedded CF manifest language server that is already used by STS3 independent of general STS3 releases. In production, the release version of this repository is used.) +

+ +

+

+

+

Eclipse-based Distribution Builds

Spring Tool Suite 4 - based on Eclipse Photon Milestone Builds (4.8.0 Mx)

diff --git a/eclipse-distribution/org.springframework.boot.ide.branding/plugin_customization.ini b/eclipse-distribution/org.springframework.boot.ide.branding/plugin_customization.ini index 87bfff6f5..b440c52fb 100644 --- a/eclipse-distribution/org.springframework.boot.ide.branding/plugin_customization.ini +++ b/eclipse-distribution/org.springframework.boot.ide.branding/plugin_customization.ini @@ -30,28 +30,21 @@ org.eclipse.core.resources/refresh.lightweight.enabled=true # Order help books in table of contents org.eclipse.help/HELP_DATA = helpData.xml +# enable line number ruler in all textual editors by default +org.eclipse.ui.editors/lineNumberRuler=true + # Disable M2Eclipse repository index download org.eclipse.m2e.core/eclipse.m2.updateIndexes=false - -# Disable Atlassian connector data usage tracking -com.atlassian.connector.eclipse.monitor.usage/com.atlassian.connector.eclipse.monitor.usage.enabled=false -com.atlassian.connector.eclipse.monitor.ui/com.atlassian.connector.eclipse.monitor.usage.enabled=false -com.atlassian.connector.eclipse.monitor.ui/com.atlassian.connector.eclipse.monitor.usage.first.time=false +org.eclipse.m2e.core/eclipse.m2.downloadSources=true # Disable Mylyn service message org.eclipse.mylyn.tasks.ui/org.eclipse.mylyn.tasks.ui.servicemessage.id=0 -# check for updates every Tuesday at 10am +# check for updates # automatic update options are defined in org.eclipse.equinox.p2.sdk.scheduler.PreferenceConstants org.eclipse.equinox.p2.ui.sdk.scheduler/enabled=true -org.eclipse.equinox.p2.ui.sdk.scheduler/schedule=on-schedule -org.eclipse.equinox.p2.ui.sdk.scheduler/day=Every Tuesday -org.eclipse.equinox.p2.ui.sdk.scheduler/hour=10\:00 AM - -# remind the user every 24 hours -org.eclipse.equinox.p2.ui.sdk.scheduler/remindOnSchedule=true -# see AutomaticUpdatesPopup, values can be "30 minutes", "Hour", "4 Hours" -org.eclipse.equinox.p2.ui.sdk.scheduler/remindElapsedTime=24 Hours +org.eclipse.equinox.p2.ui.sdk.scheduler/schedule=on-fuzzy-schedule +org.eclipse.equinox.p2.ui.sdk.scheduler/fuzzy_recurrence=Once a week # download updates before notifying the user org.eclipse.equinox.p2.ui.sdk.scheduler/download=false diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF index 732cc2700..47ab66e58 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Spring Boot Language Server Bundle-Vendor: Pivotal, Inc. Bundle-SymbolicName: org.springframework.tooling.boot.ls;singleton:=true -Bundle-Version: 0.1.5.qualifier +Bundle-Version: 0.1.6.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.eclipse.core.runtime;bundle-version="3.12.0", diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml index cb88400dc..d4c919431 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml @@ -12,14 +12,14 @@ org.springframework.tooling.boot.ls - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT eclipse-plugin org.springframework.ide.vscode spring-boot-language-server - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java index dd3df89d8..8e2f74812 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java @@ -16,7 +16,7 @@ package org.springframework.tooling.boot.ls; public class Constants { public static final String PLUGIN_ID = "org.springframework.tooling.boot.ls"; - public static final String LANGUAGE_SERVER_VERSION = "0.1.5-SNAPSHOT.jar"; + public static final String LANGUAGE_SERVER_VERSION = "0.1.6-SNAPSHOT.jar"; public static final String PREF_BOOT_HINTS = "boot-java.boot-hints.on"; diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF index 16c49a5f7..6d96420d5 100644 --- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: BOSH Manifest Language Server Bundle-Vendor: Pivotal, Inc. Bundle-SymbolicName: org.springframework.tooling.bosh.ls;singleton:=true -Bundle-Version: 0.1.5.qualifier +Bundle-Version: 0.1.6.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.eclipse.core.runtime;bundle-version="3.12.0", diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml index 218addf31..8de901cde 100644 --- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml @@ -12,14 +12,14 @@ org.springframework.tooling.bosh.ls - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT eclipse-plugin org.springframework.ide.vscode bosh-language-server - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT org.springframework.ide.eclipse diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java index c8bceeb22..d4cbb5f66 100644 --- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java +++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java @@ -16,6 +16,6 @@ package org.springframework.tooling.bosh.ls; public class Constants { public static final String PLUGIN_ID = "org.springframework.tooling.bosh.ls"; - public static final String LANGUAGE_SERVER_VERSION = "0.1.5-SNAPSHOT"; + public static final String LANGUAGE_SERVER_VERSION = "0.1.6-SNAPSHOT"; } diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF index 40a21a737..e8a9f412a 100644 --- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Cloud Foundry Manifest Language Server Bundle-Vendor: Pivotal, Inc. Bundle-SymbolicName: org.springframework.tooling.cloudfoundry.manifest.ls;singleton:=true -Bundle-Version: 0.1.5.qualifier +Bundle-Version: 0.1.6.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.8.0", org.eclipse.core.runtime;bundle-version="3.12.0", diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml index 6e1a807da..40e137805 100644 --- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml @@ -12,14 +12,14 @@ org.springframework.tooling.cloudfoundry.manifest.ls - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT eclipse-plugin org.springframework.ide.vscode manifest-yaml-language-server - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java index 34a9c9e34..6d748db39 100644 --- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java +++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java @@ -16,6 +16,6 @@ package org.springframework.tooling.cloudfoundry.manifest.ls; public class Constants { public static final String PLUGIN_ID = "org.springframework.tooling.cloudfoundry.manifest.ls"; - public static final String LANGUAGE_SERVER_VERSION = "0.1.5-SNAPSHOT.jar"; + public static final String LANGUAGE_SERVER_VERSION = "0.1.6-SNAPSHOT.jar"; } diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF index 125520bb8..1f76e9263 100644 --- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Concourse Pipeline Language Server Bundle-Vendor: Pivotal, Inc. Bundle-SymbolicName: org.springframework.tooling.concourse.ls;singleton:=true -Bundle-Version: 0.1.5.qualifier +Bundle-Version: 0.1.6.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.eclipse.core.runtime;bundle-version="3.12.0", diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml index f77aa4a62..56b775c0c 100644 --- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml @@ -12,14 +12,14 @@ org.springframework.tooling.concourse.ls - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT eclipse-plugin org.springframework.ide.vscode concourse-language-server - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT org.springframework.ide.eclipse diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java index 8b09972fc..8cc4bd2db 100644 --- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java +++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java @@ -16,6 +16,6 @@ package org.springframework.tooling.concourse.ls; public class Constants { public static final String PLUGIN_ID = "org.springframework.tooling.concourse.ls"; - public static final String LANGUAGE_SERVER_VERSION = "0.1.5-SNAPSHOT"; + public static final String LANGUAGE_SERVER_VERSION = "0.1.6-SNAPSHOT"; } diff --git a/headless-services/bosh-language-server/pom.xml b/headless-services/bosh-language-server/pom.xml index 8ff50bf3c..697cc4320 100644 --- a/headless-services/bosh-language-server/pom.xml +++ b/headless-services/bosh-language-server/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../commons/pom.xml diff --git a/headless-services/commons/commons-boot-app-cli/pom.xml b/headless-services/commons/commons-boot-app-cli/pom.xml index 430dd3947..c78d26c67 100644 --- a/headless-services/commons/commons-boot-app-cli/pom.xml +++ b/headless-services/commons/commons-boot-app-cli/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-cf/pom.xml b/headless-services/commons/commons-cf/pom.xml index 7e608e38b..6a194b823 100644 --- a/headless-services/commons/commons-cf/pom.xml +++ b/headless-services/commons/commons-cf/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-gradle/pom.xml b/headless-services/commons/commons-gradle/pom.xml index d747295e5..30be7b8ea 100644 --- a/headless-services/commons/commons-gradle/pom.xml +++ b/headless-services/commons/commons-gradle/pom.xml @@ -9,7 +9,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java index cef457221..f9af09e06 100644 --- a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java +++ b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java @@ -76,8 +76,8 @@ public class GradleCore { */ ((DefaultGradleConnector) gradleConnector).daemonMaxIdleTime(1, TimeUnit.SECONDS); configuration.configure(gradleConnector); - // Use patched Gradle 4.3 distribution as a workaround for https://github.com/gradle/gradle/issues/2483 - gradleConnector.useDistribution(URI.create("http://s3-test.spring.io/sts4/custom-gradle-builds/gradle-4.3-build.zip")); + // Use patched Gradle 4.4 distribution or higher as a workaround for https://github.com/gradle/gradle/issues/2483 + gradleConnector.useGradleVersion("4.6"); connection = gradleConnector.connect(); return connection.getModel(modelType); } catch (GradleConnectionException e) { diff --git a/headless-services/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java b/headless-services/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java index 8e58dc89e..7def43ca1 100644 --- a/headless-services/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java +++ b/headless-services/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java @@ -83,7 +83,7 @@ public class GradleProjectTest { @Test public void outputFolder() throws Exception { GradleJavaProject project = getGradleProject("test-app-1"); - assertTrue(project.getClasspath().getOutputFolder().endsWith("bin")); + assertTrue(project.getClasspath().getOutputFolder().toString().contains("/bin")); } @Test diff --git a/headless-services/commons/commons-java/pom.xml b/headless-services/commons/commons-java/pom.xml index 642f11823..ec2677d4f 100644 --- a/headless-services/commons/commons-java/pom.xml +++ b/headless-services/commons/commons-java/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-language-server/pom.xml b/headless-services/commons/commons-language-server/pom.xml index b2529ba7b..0313e223b 100644 --- a/headless-services/commons/commons-language-server/pom.xml +++ b/headless-services/commons/commons-language-server/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index 94c03f255..e6f3c48d7 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2018 Pivotal, Inc. + * Copyright (c) 2016, 2018 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -31,12 +31,14 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; import org.springframework.ide.vscode.commons.languageserver.util.SortKeys; import org.springframework.ide.vscode.commons.util.BadLocationException; -import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.util.text.TextDocument; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; +import com.google.gson.JsonPrimitive; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -46,6 +48,8 @@ import reactor.core.scheduler.Schedulers; */ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { + private static final Supplier LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class)); + public static class LazyCompletionResolver { private int nextId = 0; //Used to assign unique id to completion items. @@ -64,7 +68,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { try { resolveItem(doc, completion, unresolved); } catch (Exception e) { - Log.log(e); + LOG.get().error("{}", e); } }); return id; @@ -73,12 +77,12 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { public synchronized void resolveNow(CompletionItem unresolved) { Object id = unresolved.getData(); if (id!=null) { - Consumer resolver = resolvers.get(id); + Consumer resolver = resolvers.get(id instanceof JsonPrimitive ? ((JsonPrimitive)id).getAsString() : id); if (resolver!=null) { resolver.accept(unresolved); unresolved.setData(null); //No longer needed after item is resolved. } else { - Log.warn("Couldn't resolve completion item. Did it already get flushed from the resolver's cache? "+unresolved.getLabel()); + LOG.get().warn("Couldn't resolve completion item. Did it already get flushed from the resolver's cache? "+unresolved.getLabel()); } } } @@ -225,7 +229,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { return Optional.of(vscodeEdit); } } catch (Exception e) { - Log.log(e); + LOG.get().error("{}", e); return Optional.empty(); } } @@ -241,7 +245,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { return StringUtil.stripIndentation(refIndent, newText); } } catch (BadLocationException e) { - Log.log(e); + LOG.get().error("{}", e); } return newText; } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index 5a0f53609..71a4ec0c7 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -238,7 +238,6 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA if (ih!=null){ ih.accept(params); } - Log.info("IntializeResult = {}"); return CompletableFuture.completedFuture(result); } diff --git a/headless-services/commons/commons-maven/pom.xml b/headless-services/commons/commons-maven/pom.xml index 6ee5b1fcc..6bee0cd22 100644 --- a/headless-services/commons/commons-maven/pom.xml +++ b/headless-services/commons/commons-maven/pom.xml @@ -10,7 +10,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-util/pom.xml b/headless-services/commons/commons-util/pom.xml index 7ed256b38..517295f82 100644 --- a/headless-services/commons/commons-util/pom.xml +++ b/headless-services/commons/commons-util/pom.xml @@ -7,7 +7,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/commons-yaml/pom.xml b/headless-services/commons/commons-yaml/pom.xml index d9831a553..70398f55a 100644 --- a/headless-services/commons/commons-yaml/pom.xml +++ b/headless-services/commons/commons-yaml/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/java-properties/pom.xml b/headless-services/commons/java-properties/pom.xml index 1f44a463c..49baea0dd 100644 --- a/headless-services/commons/java-properties/pom.xml +++ b/headless-services/commons/java-properties/pom.xml @@ -7,7 +7,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/language-server-test-harness/pom.xml b/headless-services/commons/language-server-test-harness/pom.xml index a6a93027e..79a02669c 100644 --- a/headless-services/commons/language-server-test-harness/pom.xml +++ b/headless-services/commons/language-server-test-harness/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../pom.xml diff --git a/headless-services/commons/pom.xml b/headless-services/commons/pom.xml index 9359b9607..b0c6d8a8d 100644 --- a/headless-services/commons/pom.xml +++ b/headless-services/commons/pom.xml @@ -6,7 +6,7 @@ org.springframework.ide.vscode commons-parent pom - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT commons-parent diff --git a/headless-services/concourse-language-server/pom.xml b/headless-services/concourse-language-server/pom.xml index 693d01de1..79b8e5f86 100644 --- a/headless-services/concourse-language-server/pom.xml +++ b/headless-services/concourse-language-server/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../commons/pom.xml diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java index 29aa9e026..3fda51e44 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java @@ -401,8 +401,11 @@ public class PipelineYmlSchema implements YamlSchema { addProp(resourceType, "source", resourceSource); addProp(resourceType, "privileged", t_boolean); + YType t_group_name_def= f.yatomic("Group Name") + .parseWith(ValueParsers.NE_STRING); + AbstractType group = f.ybean("Group"); - addProp(group, "name", t_ne_string).isPrimary(true); + addProp(group, "name", t_group_name_def).isPrimary(true); addProp(group, "resources", f.yseq(t_resource_name)); addProp(group, "jobs", f.yseq(t_job_name)); @@ -414,7 +417,8 @@ public class PipelineYmlSchema implements YamlSchema { definitionTypes = ImmutableList.of( jobNameDef, resourceTypeNameDef, - t_resource_name_def + t_resource_name_def, + t_group_name_def ); initializeDefaultResourceTypes(); diff --git a/headless-services/concourse-language-server/src/main/resources/desc/GetStep/get.md b/headless-services/concourse-language-server/src/main/resources/desc/GetStep/get.md index e8edb17eb..c55bf8c5a 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/GetStep/get.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/GetStep/get.md @@ -17,5 +17,5 @@ plan: get: string ``` -*Required.* The logical name of the resource being fetched. This name satisfies logical inputs to a [Task](https://concourse.ci/concepts.html#tasks), and may be referenced within the plan itself (e.g. in the `file` attribute of a `task` step). +*Required.* The logical name of the resource being fetched. This name satisfies logical inputs to a [Task](https://concourse-ci.org/concepts.html#tasks), and may be referenced within the plan itself (e.g. in the `file` attribute of a `task` step). diff --git a/headless-services/concourse-language-server/src/main/resources/desc/GetStep/version.md b/headless-services/concourse-language-server/src/main/resources/desc/GetStep/version.md index 784a162a0..0743906f1 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/GetStep/version.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/GetStep/version.md @@ -4,4 +4,4 @@ If set to `latest`, scheduling will just find the latest available version of a If set to `every`, builds will walk through all available versions of the resource. Note that if `passed` is also configured, it will only step through the versions satisfying the constraints. -If set to a specific version (e.g. `{ref: abcdef123}`), only that version will be used. Note that the version must be available and detected by the resource, otherwise the input will never be satisfied. You may want to use [check-resource](https://concourse.ci/fly-check-resource.html) to force detection of resource versions, if you need to use an older one that was never detected (as all newly configured resources start from the latest version). \ No newline at end of file +If set to a specific version (e.g. `{ref: abcdef123}`), only that version will be used. Note that the version must be available and detected by the resource, otherwise the input will never be satisfied. You may want to use [check-resource](https://concourse-ci.org/fly-check-resource.html) to force detection of resource versions, if you need to use an older one that was never detected (as all newly configured resources start from the latest version). \ No newline at end of file diff --git a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/ignore_paths.md b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/ignore_paths.md index 7b829339a..1b9c4ba78 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/ignore_paths.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/ignore_paths.md @@ -3,8 +3,8 @@ to the specified files are ignored. Note that if you want to push commits that change these files via a `put`, the commit will still be "detected", as [`check` and `put` both introduce -versions](https://concourse.ci/pipeline-mechanics.html#collecting-versions). +versions](https://concourse-ci.org/pipeline-mechanics.html#collecting-versions). To avoid this you should define a second resource that you use for commits that change files that you don't want to feed back into your pipeline - think of one as read-only (with `ignore_paths`) and one as write-only (which -shouldn't need it). \ No newline at end of file +shouldn't need it). diff --git a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/password.md b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/password.md index 5bdec2ca5..3c1ec79b6 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/password.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/password.md @@ -1,3 +1,3 @@ *Optional.* Password for HTTP(S) auth when pulling/pushing. -Note: You can also use pipeline templating to hide this password in source control. (For more information: https://concourse.ci/fly-set-pipeline.html) +Note: You can also use pipeline templating to hide this password in source control. (For more information: https://concourse-ci.org/fly-set-pipeline.html) diff --git a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/private_key.md b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/private_key.md index 509214543..10999a77a 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/GitSource/private_key.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/GitSource/private_key.md @@ -9,4 +9,4 @@ Example: DWiJL+OFeg9kawcUL6hQ8JeXPhlImG6RTUffma9+iGQyyBMCGd1l -----END RSA PRIVATE KEY----- -Note: You can also use pipeline templating to hide this private key in source control. (For more information: https://concourse.ci/fly-set-pipeline.html) \ No newline at end of file +Note: You can also use pipeline templating to hide this private key in source control. (For more information: https://concourse-ci.org/fly-set-pipeline.html) diff --git a/headless-services/concourse-language-server/src/main/resources/desc/Pipeline/groups.md b/headless-services/concourse-language-server/src/main/resources/desc/Pipeline/groups.md index ca5c424f2..5152f9cb5 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/Pipeline/groups.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/Pipeline/groups.md @@ -17,5 +17,5 @@ A simple grouping for the pipeline above may look like: This would display two tabs at the top of the home page: "tests" and "deploy". Once you have added groups to your pipeline then all jobs must be in a group otherwise they will not be visible. -For a real world example of how groups can be used to simplify navigation and provide logical grouping, see the groups used at the top of the page in the [Concourse pipeline](https://ci.concourse.ci/). +For a real world example of how groups can be used to simplify navigation and provide logical grouping, see the groups used at the top of the page in the [Concourse pipeline](https://ci.concourse-ci.org/). diff --git a/headless-services/concourse-language-server/src/main/resources/desc/PutStep/put.md b/headless-services/concourse-language-server/src/main/resources/desc/PutStep/put.md index 4811bc0a5..38d66e462 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/PutStep/put.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/PutStep/put.md @@ -1,7 +1,7 @@ -Pushes to the given [Resource](https://concourse.ci/concepts.html#resources). +Pushes to the given [Resource](https://concourse-ci.org/concepts.html#resources). All artifacts collected during the plan's execution will be available in the working directory. -For example, the following plan fetches a repo using [get](https://concourse.ci/get-step.html) and pushes it to another repo (assuming `repo-develop` and `repo-master` are defined as `git` resources): +For example, the following plan fetches a repo using [get](https://concourse-ci.org/get-step.html) and pushes it to another repo (assuming `repo-develop` and `repo-master` are defined as `git` resources): ``` plan: @@ -34,4 +34,4 @@ plan: put: string ``` -Required. The logical name of the resource being pushed. The pushed resource will be available under this name after the push succeeds. \ No newline at end of file +Required. The logical name of the resource being pushed. The pushed resource will be available under this name after the push succeeds. diff --git a/headless-services/concourse-language-server/src/main/resources/desc/PutStep/resource.md b/headless-services/concourse-language-server/src/main/resources/desc/PutStep/resource.md index 2d615d13d..51307373f 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/PutStep/resource.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/PutStep/resource.md @@ -1,3 +1,3 @@ *Optional.* Defaults to `name`. -The resource to update, as configured in [resources](https://concourse.ci/configuring-resources.html). +The resource to update, as configured in [resources](https://concourse-ci.org/configuring-resources.html). diff --git a/headless-services/concourse-language-server/src/main/resources/desc/Resource/name.md b/headless-services/concourse-language-server/src/main/resources/desc/Resource/name.md index 7c5ceaa24..4e11c8bda 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/Resource/name.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/Resource/name.md @@ -1 +1 @@ -*Required.* The name of the resource. This should be short and simple. This name will be referenced by [build plans](https://concourse.ci/build-plans.html) of jobs in the pipeline. \ No newline at end of file +*Required.* The name of the resource. This should be short and simple. This name will be referenced by [build plans](https://concourse-ci.org/build-plans.html) of jobs in the pipeline. diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image_resource.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image_resource.md index e4704e722..854cc9819 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image_resource.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image_resource.md @@ -19,4 +19,4 @@ The following example configures the task to use the `golang:1.6` Docker image: You can use any resource that returns a filesystem in the correct format (a `/rootfs` directory and a `metadata.json` file in the top level) but normally this will be the [Docker Image resource](https://github.com/concourse/docker-image-resource). If you'd like to make a resource of your own that supports this please use that as a reference implementation for now. -If you want to use an artifact source within the plan containing an image, you must set the [image](https://concourse.ci/task-step.html#task-image) in the plan step instead. \ No newline at end of file +If you want to use an artifact source within the plan containing an image, you must set the [image](https://concourse-ci.org/task-step.html#task-image) in the plan step instead. diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/inputs.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/inputs.md index 94b55bbae..edc7f9fa8 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/inputs.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/inputs.md @@ -1,3 +1,3 @@ *Required.* The expected set of inputs for the task. -This determines which artifacts will propagate into the task, as the [build plan](https://concourse.ci/build-plans.html) executes. If any specified inputs are not present, the task will end with an error, without running. +This determines which artifacts will propagate into the task, as the [build plan](https://concourse-ci.org/build-plans.html) executes. If any specified inputs are not present, the task will end with an error, without running. diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/outputs.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/outputs.md index 0d7bee54e..34addcce4 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/outputs.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/outputs.md @@ -1,6 +1,6 @@ *Optional.* The artifacts produced by the task. -Each output configures a directory to make available to later steps in the [build plan](https://concourse.ci/build-plans.html). The directory will be automatically created before the task runs, and the task should place any artifacts it wants to export in the directory. +Each output configures a directory to make available to later steps in the [build plan](https://concourse-ci.org/build-plans.html). The directory will be automatically created before the task runs, and the task should place any artifacts it wants to export in the directory. For example, the following task and script would be used to propagate a built binary to later steps: diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskStep/task.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskStep/task.md index 2f4b0a502..a0e279f89 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/TaskStep/task.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskStep/task.md @@ -1,4 +1,4 @@ -Executes a [Task](https://concourse.ci/concepts.html#tasks), either from a file fetched via the preceding steps, or with inlined configuration. +Executes a [Task](https://concourse-ci.org/concepts.html#tasks), either from a file fetched via the preceding steps, or with inlined configuration. task: string diff --git a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index 0e30f3b89..b27444084 100644 --- a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -3458,15 +3458,20 @@ public class ConcourseEditorTest { "- name: bar-resource\n" + "jobs:\n" + "- name: do-some-stuff\n" + - "- name: do-more-stuff\n" + "- name: do-more-stuff\n" + + "groups:\n" + + "- name: group-one\n" + + "- name: group-two\n" ); - editor.assertDocumentSymbols( + editor.assertDocumentSymbols( "some-resource-type|ResourceType", "foo-resource|Resource", "bar-resource|Resource", "do-some-stuff|Job", - "do-more-stuff|Job" + "do-more-stuff|Job", + "group-one|Group", + "group-two|Group" ); } diff --git a/headless-services/manifest-yaml-language-server/pom.xml b/headless-services/manifest-yaml-language-server/pom.xml index cf666382d..b2f11c6cf 100644 --- a/headless-services/manifest-yaml-language-server/pom.xml +++ b/headless-services/manifest-yaml-language-server/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../commons/pom.xml diff --git a/headless-services/spring-boot-language-server/pom.xml b/headless-services/spring-boot-language-server/pom.xml index 7c197b297..a9cc190b7 100644 --- a/headless-services/spring-boot-language-server/pom.xml +++ b/headless-services/spring-boot-language-server/pom.xml @@ -8,7 +8,7 @@ org.springframework.ide.vscode commons-parent - 0.1.5-SNAPSHOT + 0.1.6-SNAPSHOT ../commons/pom.xml diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/MediaTypeMapping.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/MediaTypeMapping.java new file mode 100644 index 000000000..a3ecae47c --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/MediaTypeMapping.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2018 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.requestmapping; + +/** + * @author Martin Lippert + */ +public enum MediaTypeMapping { + + ALL("*/*"), + APPLICATION_ATOM_XML("application/atom+xml"), + APPLICATION_FORM_URLENCODED("application/x-www-form-urlencoded"), + APPLICATION_JSON("application/json"), + APPLICATION_JSON_UTF8("application/json;charset=UTF-8"), + APPLICATION_OCTET_STREAM("application/octet-stream"), + APPLICATION_PDF("application/pdf"), + APPLICATION_PROBLEM_JSON("application/problem+json"), + APPLICATION_PROBLEM_JSON_UTF8("application/problem+json;charset=UTF-8"), + APPLICATION_PROBLEM_XML("application/problem+xml"), + APPLICATION_RSS_XML("application/rss+xml"), + APPLICATION_STREAM_JSON("application/stream+json"), + APPLICATION_XHTML_XML("application/xhtml+xml"), + APPLICATION_XML("application/xml"), + IMAGE_GIF("image/gif"), + IMAGE_JPEG("image/jpeg"), + IMAGE_PNG("image/png"), + MULTIPART_FORM_DATA("multipart/form-data"), + TEXT_EVENT_STREAM("text/event-stream"), + TEXT_HTML("text/html"), + TEXT_MARKDOWN("text/markdown"), + TEXT_PLAIN("text/plain"), + TEXT_XML("text/xml"); + + private String mediaType; + + private MediaTypeMapping(String mediaType) { + this.mediaType = mediaType; + } + + public String getMediaType() { + return mediaType; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java index a2c34fb5a..bd611e553 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java @@ -28,8 +28,6 @@ import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.lsp4j.Location; -import org.eclipse.lsp4j.SymbolInformation; -import org.eclipse.lsp4j.SymbolKind; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; @@ -48,9 +46,9 @@ public class RequestMappingSymbolProvider implements SymbolProvider { Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())); String[] path = getPath(node); String[] parentPath = getParentPath(node); - String[] method = getMethod(node); - - String methodStr = method == null || method.length == 0 ? "" : String.join(",", method); + String[] methods = getMethod(node); + String[] contentTypes = getContentTypes(node); + String[] acceptTypes = getAcceptTypes(node); return (parentPath == null ? Stream.of("") : Arrays.stream(parentPath)).filter(Objects::nonNull) .flatMap(parent -> (path == null ? Stream.empty() : Arrays.stream(path)) @@ -62,8 +60,7 @@ public class RequestMappingSymbolProvider implements SymbolProvider { } return resultPath.startsWith("/") ? resultPath : "/" + resultPath; })) - .map(p -> "@" + p + (methodStr.isEmpty() ? "" : " -- " + methodStr)) - .map(symbolLabel -> new EnhancedSymbolInformation(new SymbolInformation(symbolLabel, SymbolKind.Interface, location), null)) + .map(p -> RouteUtils.createRouteSymbol(location, p, methods, contentTypes, acceptTypes, null)) .collect(Collectors.toList()); } catch (Exception e) { e.printStackTrace(); @@ -176,6 +173,44 @@ public class RequestMappingSymbolProvider implements SymbolProvider { } return null; } + + private String[] getAcceptTypes(Annotation node) { + if (node.isNormalAnnotation()) { + NormalAnnotation normNode = (NormalAnnotation) node; + List values = normNode.values(); + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + Object object = iterator.next(); + if (object instanceof MemberValuePair) { + MemberValuePair pair = (MemberValuePair) object; + String valueName = pair.getName().getIdentifier(); + if (valueName != null && valueName.equals("consumes")) { + Expression expression = pair.getValue(); + return ASTUtils.getExpressionValueAsArray(expression); + } + } + } + } + return new String[0]; + } + + private String[] getContentTypes(Annotation node) { + if (node.isNormalAnnotation()) { + NormalAnnotation normNode = (NormalAnnotation) node; + List values = normNode.values(); + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + Object object = iterator.next(); + if (object instanceof MemberValuePair) { + MemberValuePair pair = (MemberValuePair) object; + String valueName = pair.getName().getIdentifier(); + if (valueName != null && valueName.equals("produces")) { + Expression expression = pair.getValue(); + return ASTUtils.getExpressionValueAsArray(expression); + } + } + } + } + return new String[0]; + } @Override public Collection getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RouteUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RouteUtils.java new file mode 100644 index 000000000..0cc7a4436 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RouteUtils.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2018 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.requestmapping; + +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; + +/** + * @author Martin Lippert + */ +public class RouteUtils { + + public static EnhancedSymbolInformation createRouteSymbol(Location location, String path, + String[] httpMethods, String[] contentTypes, String[] acceptTypes, Object enhancedInformation) { + + if (path != null && path.length() > 0) { + String label = "@" + (path.startsWith("/") ? path : ("/" + path)); + label += (httpMethods == null || httpMethods.length == 0 ? "" : " -- " + WebfluxUtils.getStringRep(httpMethods, string -> string)); + + String acceptType = WebfluxUtils.getStringRep(acceptTypes, WebfluxUtils::getMediaType); + label += acceptType != null ? " - Accept: " + acceptType : ""; + + String contentType = WebfluxUtils.getStringRep(contentTypes, WebfluxUtils::getMediaType); + label += contentType != null ? " - Content-Type: " + contentType : ""; + + return new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), enhancedInformation); + } + else { + return null; + } + + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxAcceptTypeFinder.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxAcceptTypeFinder.java new file mode 100644 index 000000000..c9b5dfa98 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxAcceptTypeFinder.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2018 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.requestmapping; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.MethodInvocation; + +/** + * @author Martin Lippert + */ +public class WebfluxAcceptTypeFinder extends ASTVisitor { + + private Set acceptTypes; + + public WebfluxAcceptTypeFinder() { + this.acceptTypes = new LinkedHashSet<>(); + } + + public Set getAcceptTypes() { + return acceptTypes; + } + + @Override + public boolean visit(MethodInvocation node) { + IMethodBinding methodBinding = node.resolveMethodBinding(); + + if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { + String name = methodBinding.getName(); + if (name != null && WebfluxUtils.REQUEST_PREDICATE_ACCEPT_TYPE_METHOD.equals(name)) { + String acceptType = WebfluxUtils.extractSimpleNameArgument(node); + if (acceptType != null) { + acceptTypes.add(acceptType); + } + } + } + + return !WebfluxUtils.isRouteMethodInvocation(methodBinding); + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxContentTypeFinder.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxContentTypeFinder.java new file mode 100644 index 000000000..2e8cf56db --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxContentTypeFinder.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2018 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.requestmapping; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.MethodInvocation; + +/** + * @author Martin Lippert + */ +public class WebfluxContentTypeFinder extends ASTVisitor { + + private Set contentTypes; + private ASTNode root; + + public WebfluxContentTypeFinder(ASTNode root) { + this.root = root; + this.contentTypes = new LinkedHashSet<>(); + } + + public Set getContentTypes() { + return contentTypes; + } + + @Override + public boolean visit(MethodInvocation node) { + boolean visitChildren = true; + + if (node != this.root) { + IMethodBinding methodBinding = node.resolveMethodBinding(); + + if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { + String name = methodBinding.getName(); + if (name != null && WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(name)) { + String contentType = WebfluxUtils.extractSimpleNameArgument(node); + if (contentType != null) { + contentTypes.add(contentType); + } + } + } + + if (WebfluxUtils.isRouteMethodInvocation(methodBinding)) { + visitChildren = false; + } + } + return visitChildren; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerCodeLensProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerCodeLensProvider.java index 556394572..fc14555d9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerCodeLensProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerCodeLensProvider.java @@ -71,7 +71,19 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider { CodeLens codeLens = new CodeLens(); codeLens.setRange(document.toRange(node.getName().getStartPosition(), node.getName().getLength())); - codeLens.setCommand(new Command(handlerInfo.getSymbol(), null)); + + String httpMethod = WebfluxUtils.getStringRep(handlerInfo.getHttpMethods(), string -> string); + String codeLensCommand = httpMethod != null ? httpMethod + " " : ""; + + codeLensCommand += handlerInfo.getPath(); + + String acceptType = WebfluxUtils.getStringRep(handlerInfo.getAcceptTypes(), WebfluxUtils::getMediaType); + codeLensCommand += acceptType != null ? " - Accept: " + acceptType : ""; + + String contentType = WebfluxUtils.getStringRep(handlerInfo.getContentTypes(), WebfluxUtils::getMediaType); + codeLensCommand += contentType != null ? " - Content-Type: " + contentType : ""; + + codeLens.setCommand(new Command(codeLensCommand, null)); resultAccumulator.add(codeLens); } catch (BadLocationException e) { @@ -81,5 +93,5 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider { } } } - + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerInformation.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerInformation.java index 4bf3c4ae9..6e8c993df 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerInformation.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxHandlerInformation.java @@ -15,18 +15,22 @@ package org.springframework.ide.vscode.boot.java.requestmapping; */ public class WebfluxHandlerInformation { - private final String symbol; - private String handlerClass; - private String handlerMethod; + private final String handlerClass; + private final String handlerMethod; - public WebfluxHandlerInformation(String symbol, String handlerClass, String handlerMethod) { - this.symbol = symbol; + private final String path; + private final String[] httpMethods; + private final String[] contentTypes; + private final String[] acceptTypes; + + public WebfluxHandlerInformation(String handlerClass, String handlerMethod, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) { this.handlerClass = handlerClass; this.handlerMethod = handlerMethod; - } - - public String getSymbol() { - return symbol; + + this.path = path; + this.httpMethods = httpMethods; + this.contentTypes = contentTypes; + this.acceptTypes = acceptTypes; } public String getHandlerClass() { @@ -36,5 +40,21 @@ public class WebfluxHandlerInformation { public String getHandlerMethod() { return handlerMethod; } + + public String getPath() { + return path; + } + + public String[] getHttpMethods() { + return httpMethods; + } + + public String[] getContentTypes() { + return contentTypes; + } + + public String[] getAcceptTypes() { + return acceptTypes; + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxMethodFinder.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxMethodFinder.java index a8a48ef55..57cbd1a54 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxMethodFinder.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxMethodFinder.java @@ -10,28 +10,29 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.requestmapping; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.MethodInvocation; -import org.eclipse.jdt.core.dom.QualifiedName; /** * @author Martin Lippert */ public class WebfluxMethodFinder extends ASTVisitor { - private String method; + private Set methods; private ASTNode root; public WebfluxMethodFinder(ASTNode root) { this.root = root; + this.methods = new LinkedHashSet<>(); } - public String getMethod() { - return method; + public Set getMethods() { + return methods; } @Override @@ -44,10 +45,10 @@ public class WebfluxMethodFinder extends ASTVisitor { if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { String name = methodBinding.getName(); if (name != null && WebfluxUtils.REQUEST_PREDICATE_HTTPMETHOD_METHODS.contains(name)) { - method = name; + methods.add(name); } else if (name != null && WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(name)) { - method = extractMethodValue(node); + methods.add(WebfluxUtils.extractQualifiedNameArgument(node)); } } @@ -58,18 +59,4 @@ public class WebfluxMethodFinder extends ASTVisitor { return visitChildren; } - private String extractMethodValue(MethodInvocation node) { - List arguments = node.arguments(); - if (arguments != null && arguments.size() > 0) { - Object object = arguments.get(0); - if (object instanceof QualifiedName) { - QualifiedName qualifiedName = (QualifiedName) object; - if (qualifiedName.getName() != null) { - return qualifiedName.getName().toString(); - } - } - } - return null; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxPathFinder.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxPathFinder.java index 20260238f..60a323295 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxPathFinder.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxPathFinder.java @@ -41,7 +41,7 @@ public class WebfluxPathFinder extends ASTVisitor { if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { String name = methodBinding.getName(); if (name != null && WebfluxUtils.REQUEST_PREDICATE_ALL_PATH_METHODS.contains(name)) { - path = WebfluxUtils.extractPath(node); + path = WebfluxUtils.extractStringLiteralArgument(node); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java index 30fdeda6c..9f0ea3d65 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java @@ -13,6 +13,8 @@ package org.springframework.ide.vscode.boot.java.requestmapping; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; +import java.util.function.Function; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; @@ -26,8 +28,6 @@ import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.lsp4j.Location; -import org.eclipse.lsp4j.SymbolInformation; -import org.eclipse.lsp4j.SymbolKind; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; import org.springframework.ide.vscode.commons.util.BadLocationException; @@ -87,40 +87,134 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider { } protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, List result) { - String foundPath = extractPathFromRouterFunction(node); - String path = extractPath(node, foundPath); - String httpMethod = extractMethod(node); + String path = extractPath(node); + + String[] httpMethods = extractMethods(node); + String[] contentTypes = extractContentTypes(node); + String[] acceptTypes = extractAcceptTypes(node); int methodNameStart = node.getName().getStartPosition(); int invocationStart = node.getStartPosition(); if (path != null && path.length() > 0) { try { - Location location = new Location(doc.getUri(), doc.toRange(methodNameStart, node.getLength() - (methodNameStart - invocationStart))); - String label = "@" + (path.startsWith("/") ? path : ("/" + path)) + (httpMethod == null || httpMethod.isEmpty() ? "" : " -- " + httpMethod); - WebfluxHandlerInformation handler = extractHandlerInformation(node, label); - - result.add(new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), handler)); + Location location = new Location(doc.getUri(), doc.toRange(methodNameStart, node.getLength() - (methodNameStart - invocationStart))); + WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethods, contentTypes, acceptTypes); + + result.add(RouteUtils.createRouteSymbol(location, path, httpMethods, contentTypes, acceptTypes, handler)); + } catch (BadLocationException e) { e.printStackTrace(); } } } - private String extractPathFromRouterFunction(MethodInvocation routerInvocation) { + private String extractPath(MethodInvocation routerInvocation) { WebfluxPathFinder pathFinder = new WebfluxPathFinder(routerInvocation); routerInvocation.accept(pathFinder); - String path = pathFinder.getPath(); - if (path == null) path = ""; + List path = new ArrayList<>(); + String firstPath = pathFinder.getPath(); + if (firstPath != null) { + path.add(firstPath); + } + + extractNestedValue(routerInvocation, path, (methodInvocation) -> { + IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); + String methodName = methodBinding.getName(); + + if (WebfluxUtils.REQUEST_PREDICATE_PATH_METHOD.equals(methodName)) { + String additionalPath = WebfluxUtils.extractStringLiteralArgument(methodInvocation); + if (additionalPath != null && additionalPath.length() > 0) { + return additionalPath; + } + } + return null; + }); + + StringBuilder result = new StringBuilder(); + path.stream().forEach(part -> result.insert(0, part)); + + return result.toString(); - return path; } - private String extractPath(ASTNode node, String path) { + private String[] extractMethods(MethodInvocation routerInvocation) { + WebfluxMethodFinder methodFinder = new WebfluxMethodFinder(routerInvocation); + List arguments = routerInvocation.arguments(); + for (Object argument : arguments) { + if (argument != null && argument instanceof ASTNode) { + ((ASTNode)argument).accept(methodFinder); + } + } + + final Set methods = methodFinder.getMethods(); + + extractNestedValue(routerInvocation, methods, (methodInvocation) -> { + IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); + String methodName = methodBinding.getName(); + + if (WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(methodName)) { + return WebfluxUtils.extractQualifiedNameArgument(methodInvocation); + } + return null; + }); + + return (String[]) methods.toArray(new String[methods.size()]); + } + + private String[] extractAcceptTypes(MethodInvocation routerInvocation) { + WebfluxAcceptTypeFinder typeFinder = new WebfluxAcceptTypeFinder(); + List arguments = routerInvocation.arguments(); + for (Object argument : arguments) { + if (argument != null && argument instanceof ASTNode) { + ((ASTNode)argument).accept(typeFinder); + } + } + + Set acceptTypes = typeFinder.getAcceptTypes(); + + extractNestedValue(routerInvocation, acceptTypes, (methodInvocation) -> { + IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); + String methodName = methodBinding.getName(); + + if (WebfluxUtils.REQUEST_PREDICATE_ACCEPT_TYPE_METHOD.equals(methodName)) { + return WebfluxUtils.extractSimpleNameArgument(methodInvocation); + } + return null; + }); + + return (String[]) acceptTypes.toArray(new String[acceptTypes.size()]); + } + + private String[] extractContentTypes(MethodInvocation routerInvocation) { + WebfluxContentTypeFinder contentTypeFinder = new WebfluxContentTypeFinder(routerInvocation); + List arguments = routerInvocation.arguments(); + for (Object argument : arguments) { + if (argument != null && argument instanceof ASTNode) { + ((ASTNode)argument).accept(contentTypeFinder); + } + } + + Set contentTypes = contentTypeFinder.getContentTypes(); + + extractNestedValue(routerInvocation, contentTypes, (methodInvocation) -> { + IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); + String methodName = methodBinding.getName(); + + if (WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(methodName)) { + return WebfluxUtils.extractSimpleNameArgument(methodInvocation); + } + return null; + }); + + return (String[]) contentTypes.toArray(new String[contentTypes.size()]); + } + + private void extractNestedValue(ASTNode node, Collection values, Function extractor) { if (node == null || node instanceof TypeDeclaration) { - return path; + return; } if (node instanceof MethodInvocation) { @@ -129,39 +223,25 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider { if (WebfluxUtils.ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { String name = methodBinding.getName(); - if ("nest".equals(name)) { + if (WebfluxUtils.REQUEST_PREDICATE_NEST_METHOD.equals(name)) { List arguments = methodInvocation.arguments(); for (Object argument : arguments) { if (argument instanceof MethodInvocation) { MethodInvocation nestedMethod = (MethodInvocation) argument; - IMethodBinding nestedMethodBinding = nestedMethod.resolveMethodBinding(); - - String nestedMethodName = nestedMethodBinding.getName(); - if ("path".equals(nestedMethodName)) { - String additionalPath = WebfluxUtils.extractPath(nestedMethod); - if (additionalPath != null && additionalPath.length() > 0) { - path = additionalPath + path; - } + String value = extractor.apply(nestedMethod); + if (value != null) { + values.add(value); } } - } } } } - return extractPath(node.getParent(), path); + extractNestedValue(node.getParent(), values, extractor); } - private String extractMethod(MethodInvocation routerInvocation) { - WebfluxMethodFinder methodFinder = new WebfluxMethodFinder(routerInvocation); - routerInvocation.accept(methodFinder); - - String method = methodFinder.getMethod(); - return method; - } - - private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String symbol) { + private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) { List arguments = node.arguments(); if (arguments != null) { @@ -177,7 +257,7 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider { String handlerMethod = methodBinding.getMethodDeclaration().toString(); if (handlerMethod != null) handlerMethod = handlerMethod.trim(); - return new WebfluxHandlerInformation(symbol, handlerClass, handlerMethod); + return new WebfluxHandlerInformation(handlerClass, handlerMethod, path, httpMethods, contentTypes, acceptTypes); } } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxUtils.java index 6de785cda..b42bd79b4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxUtils.java @@ -14,9 +14,12 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Function; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.StringLiteral; /** @@ -30,12 +33,15 @@ public class WebfluxUtils { public static final String REQUEST_PREDICATE_PATH_METHOD = "path"; public static final String REQUEST_PREDICATE_METHOD_METHOD = "method"; + public static final String REQUEST_PREDICATE_ACCEPT_TYPE_METHOD = "accept"; + public static final String REQUEST_PREDICATE_CONTENT_TYPE_METHOD = "contentType"; + public static final String REQUEST_PREDICATE_NEST_METHOD = "nest"; public static final Set REQUEST_PREDICATE_HTTPMETHOD_METHODS = new HashSet<>(Arrays.asList("GET", "POST", "DELETE", "PUT", "PATCH", "HEAD", "OPTIONS")); public static final Set REQUEST_PREDICATE_ALL_PATH_METHODS = new HashSet<>(Arrays.asList(REQUEST_PREDICATE_PATH_METHOD, "GET", "POST", "DELETE", "PUT", "PATCH", "HEAD", "OPTIONS")); - public static String extractPath(MethodInvocation node) { + public static String extractStringLiteralArgument(MethodInvocation node) { List arguments = node.arguments(); if (arguments != null && arguments.size() > 0) { Object object = arguments.get(0); @@ -47,6 +53,34 @@ public class WebfluxUtils { return null; } + public static String extractQualifiedNameArgument(MethodInvocation node) { + List arguments = node.arguments(); + if (arguments != null && arguments.size() > 0) { + Object object = arguments.get(0); + if (object instanceof QualifiedName) { + QualifiedName qualifiedName = (QualifiedName) object; + if (qualifiedName.getName() != null) { + return qualifiedName.getName().toString(); + } + } + } + return null; + } + + public static String extractSimpleNameArgument(MethodInvocation node) { + List arguments = node.arguments(); + if (arguments != null && arguments.size() > 0) { + Object object = arguments.get(0); + if (object instanceof SimpleName) { + SimpleName name = (SimpleName) object; + if (name.getFullyQualifiedName() != null) { + return name.getFullyQualifiedName().toString(); + } + } + } + return null; + } + public static boolean isRouteMethodInvocation(IMethodBinding methodBinding) { if (ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) { String name = methodBinding.getName(); @@ -62,8 +96,39 @@ public class WebfluxUtils { } return false; - } + public static String getMediaType(String constantRep) { + if (constantRep == null) { + return null; + } + + try { + if (constantRep.endsWith("_VALUE")) { + constantRep = constantRep.substring(0, constantRep.lastIndexOf("_VALUE")); + } + + MediaTypeMapping mediaType = MediaTypeMapping.valueOf(constantRep); + return mediaType.getMediaType(); + } + catch (IllegalArgumentException e) { + return constantRep; + } + } + + public static String getStringRep(String[] multipleTypes, Function valueConverter) { + if (multipleTypes == null || multipleTypes.length == 0) return null; + + StringBuilder result = new StringBuilder(valueConverter.apply(multipleTypes[0])); + for (int i = 1; i < multipleTypes.length; i++) { + result.append(","); + result.append(valueConverter.apply(multipleTypes[i])); + } + + return result.toString(); + } + + + } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java index a4d0538c3..4b1b191af 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java @@ -38,7 +38,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testSimpleRequestMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/SimpleMappingClass.java").toUri().toString(); @@ -50,7 +49,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testParentRequestMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/ParentMappingClass.java").toUri().toString(); @@ -62,7 +60,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testEmptyPathWithParentRequestMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/ParentMappingClass2.java").toUri().toString(); @@ -74,7 +71,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testMultiRequestMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/MultiRequestMappingClass.java").toUri().toString(); @@ -87,7 +83,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testGetMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -98,7 +93,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testDeleteMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -109,7 +103,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testPostMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -120,7 +113,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testPutMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -131,7 +123,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testPatchMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -142,7 +133,6 @@ public class RequestMappingSymbolProviderTest { @Test public void testGetRequestMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); @@ -153,13 +143,31 @@ public class RequestMappingSymbolProviderTest { @Test public void testMultiRequestMethodMappingSymbol() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); - File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString(); List symbols = getSymbols(docUri); assertTrue(containsSymbol(symbols, "@/postAndPutHello -- POST,PUT", docUri, 36, 1, 36, 76)); } + + @Test + public void testMediaTypes() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMappingMediaTypes.java").toUri().toString(); + List symbols = getSymbols(docUri); + assertEquals(7, symbols.size()); + assertTrue(containsSymbol(symbols, "@/consume1 -- HEAD - Accept: testconsume", docUri, 8, 1, 8, 90)); + assertTrue(containsSymbol(symbols, "@/consume2 - Accept: text/plain", docUri, 13, 1, 13, 73)); + assertTrue(containsSymbol(symbols, "@/consume3 - Accept: text/plain,testconsumetype", docUri, 18, 1, 18, 94)); + assertTrue(containsSymbol(symbols, "@/produce1 - Content-Type: testproduce", docUri, 23, 1, 23, 60)); + assertTrue(containsSymbol(symbols, "@/produce2 - Content-Type: text/plain", docUri, 28, 1, 28, 73)); + assertTrue(containsSymbol(symbols, "@/produce3 - Content-Type: text/plain,testproducetype", docUri, 33, 1, 33, 94)); + assertTrue(containsSymbol(symbols, "@/everything - Accept: application/json,text/plain,testconsume - Content-Type: application/json", docUri, 38, 1, 38, 170)); + } + + private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) { for (Iterator iterator = symbols.iterator(); iterator.hasNext();) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxCodeLensProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxCodeLensProviderTest.java index d374973b4..daf21949a 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxCodeLensProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxCodeLensProviderTest.java @@ -41,7 +41,7 @@ public class WebFluxCodeLensProviderTest { } @Test - public void testRoutesCodeLenses() throws Exception { + public void testRoutesCodeLensesSimpleCase() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); @@ -53,10 +53,65 @@ public class WebFluxCodeLensProviderTest { assertEquals(4, codeLenses.size()); - assertTrue(containsCodeLens(codeLenses, "@/hello -- GET", 25, 29, 25, 34)); - assertTrue(containsCodeLens(codeLenses, "@/echo -- POST", 30, 29, 30, 33)); - assertTrue(containsCodeLens(codeLenses, "@/quotes -- GET", 35, 29, 35, 41)); - assertTrue(containsCodeLens(codeLenses, "@/quotes -- GET", 41, 29, 41, 40)); + assertTrue(containsCodeLens(codeLenses, "GET /hello - Accept: text/plain", 25, 29, 25, 34)); + assertTrue(containsCodeLens(codeLenses, "POST /echo - Accept: text/plain - Content-Type: text/plain", 30, 29, 30, 33)); + assertTrue(containsCodeLens(codeLenses, "GET /quotes - Accept: application/stream+json", 35, 29, 35, 41)); + assertTrue(containsCodeLens(codeLenses, "GET /quotes - Accept: application/json", 41, 29, 41, 40)); + } + + @Test + public void testRoutesCodeLensesNestedRoutes1() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/PersonHandler1.java").toUri().toString(); + TextDocumentInfo doc = harness.getOrReadFile(new File(new URI(docUri)), LanguageId.JAVA.toString()); + TextDocumentInfo openedDoc = harness.openDocument(doc); + + List codeLenses = harness.getCodeLenses(openedDoc); + + assertEquals(3, codeLenses.size()); + + assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38)); + assertTrue(containsCodeLens(codeLenses, "POST /person/ - Content-Type: application/json", 13, 29, 13, 41)); + assertTrue(containsCodeLens(codeLenses, "GET /person - Accept: application/json", 17, 29, 17, 39)); + } + + @Test + public void testRoutesCodeLensesNestedRoutes2() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/PersonHandler2.java").toUri().toString(); + TextDocumentInfo doc = harness.getOrReadFile(new File(new URI(docUri)), LanguageId.JAVA.toString()); + TextDocumentInfo openedDoc = harness.openDocument(doc); + + List codeLenses = harness.getCodeLenses(openedDoc); + + assertEquals(3, codeLenses.size()); + + assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38)); + assertTrue(containsCodeLens(codeLenses, "POST / - Accept: application/json - Content-Type: application/json,application/pdf", 13, 29, 13, 41)); + assertTrue(containsCodeLens(codeLenses, "GET,HEAD /person - Accept: text/plain,application/json", 17, 29, 17, 39)); + } + + @Test + public void testRoutesCodeLensesNestedRoutes3() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/PersonHandler3.java").toUri().toString(); + TextDocumentInfo doc = harness.getOrReadFile(new File(new URI(docUri)), LanguageId.JAVA.toString()); + TextDocumentInfo openedDoc = harness.openDocument(doc); + + List codeLenses = harness.getCodeLenses(openedDoc); + + assertEquals(6, codeLenses.size()); +/* + assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38)); + assertTrue(containsCodeLens(codeLenses, "POST / - Accept: application/json - Content-Type: application/json, application/pdf", 13, 29, 13, 41)); + assertTrue(containsCodeLens(codeLenses, "GET, HEAD /person - Accept: text/plain, application/json", 17, 29, 17, 39)); +*/ } private boolean containsCodeLens(List codeLenses, String commandTitle, int startLine, int startPosition, int endLine, int endPosition) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxMappingSymbolProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxMappingSymbolProviderTest.java index 7e41d4173..0d8586774 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxMappingSymbolProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/WebFluxMappingSymbolProviderTest.java @@ -15,6 +15,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; @@ -46,8 +47,8 @@ public class WebFluxMappingSymbolProviderTest { String docUri = directory.toPath().resolve("src/main/java/org/test/UserController.java").toUri().toString(); List symbols = getSymbols(docUri); assertEquals(4, symbols.size()); - assertTrue(containsSymbol(symbols, "@/users", docUri, 19, 1, 19, 74)); - assertTrue(containsSymbol(symbols, "@/users/{username}", docUri, 24, 1, 24, 85)); + assertTrue(containsSymbol(symbols, "@/users - Content-Type: application/json", docUri, 13, 1, 13, 74)); + assertTrue(containsSymbol(symbols, "@/users/{username} - Content-Type: application/json", docUri, 18, 1, 18, 85)); List addons = getAdditionalInformation(docUri); assertNull(addons); @@ -61,66 +62,195 @@ public class WebFluxMappingSymbolProviderTest { String docUri = directory.toPath().resolve("src/main/java/org/test/QuoteRouter.java").toUri().toString(); List symbols = getSymbols(docUri); assertEquals(6, symbols.size()); - assertTrue(containsSymbol(symbols, "@/hello -- GET", docUri, 22, 5, 22, 70)); - assertTrue(containsSymbol(symbols, "@/echo -- POST", docUri, 23, 5, 23, 101)); - assertTrue(containsSymbol(symbols, "@/quotes -- GET", docUri, 24, 5, 24, 86)); - assertTrue(containsSymbol(symbols, "@/quotes -- GET", docUri, 25, 5, 25, 94)); + assertTrue(containsSymbol(symbols, "@/hello -- GET - Accept: text/plain", docUri, 22, 5, 22, 70)); + assertTrue(containsSymbol(symbols, "@/echo -- POST - Accept: text/plain - Content-Type: text/plain", docUri, 23, 5, 23, 101)); + assertTrue(containsSymbol(symbols, "@/quotes -- GET - Accept: application/json", docUri, 24, 5, 24, 86)); + assertTrue(containsSymbol(symbols, "@/quotes -- GET - Accept: application/stream+json", docUri, 25, 5, 25, 94)); List addons = getAdditionalInformation(docUri); assertEquals(4, addons.size()); - WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "@/hello -- GET").get(0); - assertEquals("@/hello -- GET", handlerInfo1.getSymbol()); + WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/hello", "GET").get(0); + assertEquals("/hello", handlerInfo1.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods())); + assertEquals(0, handlerInfo1.getContentTypes().length); + assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo1.getAcceptTypes())); assertEquals("org.test.QuoteHandler", handlerInfo1.getHandlerClass()); assertEquals("public Mono hello(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod()); - WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "@/echo -- POST").get(0); - assertEquals("@/echo -- POST", handlerInfo2.getSymbol()); + WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/echo", "POST").get(0); + assertEquals("/echo", handlerInfo2.getPath()); + assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods())); + assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo2.getContentTypes())); + assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo2.getAcceptTypes())); assertEquals("org.test.QuoteHandler", handlerInfo2.getHandlerClass()); assertEquals("public Mono echo(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod()); - WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "@/quotes -- GET").get(0); - assertEquals("@/quotes -- GET", handlerInfo3.getSymbol()); + WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/quotes", "GET").get(0); + assertEquals("/quotes", handlerInfo3.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo3.getHttpMethods())); + assertEquals(0, handlerInfo3.getContentTypes().length); + assertEquals("[APPLICATION_STREAM_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes())); assertEquals("org.test.QuoteHandler", handlerInfo3.getHandlerClass()); assertEquals("public Mono streamQuotes(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod()); - WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "@/quotes -- GET").get(1); - assertEquals("@/quotes -- GET", handlerInfo4.getSymbol()); + WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "/quotes", "GET").get(1); + assertEquals("/quotes", handlerInfo4.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo4.getHttpMethods())); + assertEquals(0, handlerInfo4.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo4.getAcceptTypes())); assertEquals("org.test.QuoteHandler", handlerInfo4.getHandlerClass()); assertEquals("public Mono fetchQuotes(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo4.getHandlerMethod()); } @Test - public void testNestedRoutesMappingSymbols() throws Exception { + public void testNestedRoutesMappingSymbols1() throws Exception { harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); - String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter.java").toUri().toString(); + String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter1.java").toUri().toString(); List symbols = getSymbols(docUri); assertEquals(5, symbols.size()); - assertTrue(containsSymbol(symbols, "@/person/{id} -- GET", docUri, 27, 6, 27, 45)); - assertTrue(containsSymbol(symbols, "@/person/ -- POST", docUri, 29, 6, 29, 83)); - assertTrue(containsSymbol(symbols, "@/person -- GET", docUri, 28, 7, 28, 60)); + assertTrue(containsSymbol(symbols, "@/person/{id} -- GET - Accept: application/json", docUri, 27, 6, 27, 45)); + assertTrue(containsSymbol(symbols, "@/person/ -- POST - Content-Type: application/json", docUri, 29, 6, 29, 83)); + assertTrue(containsSymbol(symbols, "@/person -- GET - Accept: application/json", docUri, 28, 7, 28, 60)); List addons = getAdditionalInformation(docUri); assertEquals(3, addons.size()); - WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "@/person/{id} -- GET").get(0); - assertEquals("@/person/{id} -- GET", handlerInfo1.getSymbol()); - assertEquals("org.test.PersonHandler", handlerInfo1.getHandlerClass()); + WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/{id}", "GET").get(0); + assertEquals("/person/{id}", handlerInfo1.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods())); + assertEquals(0, handlerInfo1.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo1.getAcceptTypes())); + assertEquals("org.test.PersonHandler1", handlerInfo1.getHandlerClass()); assertEquals("public Mono getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod()); - WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "@/person/ -- POST").get(0); - assertEquals("@/person/ -- POST", handlerInfo2.getSymbol()); - assertEquals("org.test.PersonHandler", handlerInfo2.getHandlerClass()); + WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/person/", "POST").get(0); + assertEquals("/person/", handlerInfo2.getPath()); + assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods())); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo2.getContentTypes())); + assertEquals(0, handlerInfo2.getAcceptTypes().length); + assertEquals("org.test.PersonHandler1", handlerInfo2.getHandlerClass()); assertEquals("public Mono createPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod()); - WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "@/person -- GET").get(0); - assertEquals("@/person -- GET", handlerInfo3.getSymbol()); - assertEquals("org.test.PersonHandler", handlerInfo3.getHandlerClass()); + WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person", "GET").get(0); + assertEquals("/person", handlerInfo3.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo3.getHttpMethods())); + assertEquals(0, handlerInfo3.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes())); + assertEquals("org.test.PersonHandler1", handlerInfo3.getHandlerClass()); assertEquals("public Mono listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod()); } + @Test + public void testNestedRoutesMappingSymbols2() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter2.java").toUri().toString(); + List symbols = getSymbols(docUri); + assertEquals(5, symbols.size()); + assertTrue(containsSymbol(symbols, "@/person/{id} -- GET - Accept: application/json", docUri, 29, 6, 29, 45)); + assertTrue(containsSymbol(symbols, "@/ -- POST - Accept: application/json - Content-Type: application/json,application/pdf", docUri, 31, 6, 31, 117)); + assertTrue(containsSymbol(symbols, "@/person -- GET,HEAD - Accept: text/plain,application/json", docUri, 30, 7, 30, 113)); + + List addons = getAdditionalInformation(docUri); + assertEquals(3, addons.size()); + + WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/{id}", "GET").get(0); + assertEquals("/person/{id}", handlerInfo1.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods())); + assertEquals(0, handlerInfo1.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo1.getAcceptTypes())); + assertEquals("org.test.PersonHandler2", handlerInfo1.getHandlerClass()); + assertEquals("public Mono getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/", "POST").get(0); + assertEquals("/", handlerInfo2.getPath()); + assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods())); + assertEquals("[APPLICATION_JSON, APPLICATION_PDF]", Arrays.toString(handlerInfo2.getContentTypes())); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo2.getAcceptTypes())); + assertEquals("org.test.PersonHandler2", handlerInfo2.getHandlerClass()); + assertEquals("public Mono createPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person", "HEAD").get(0); + assertEquals("/person", handlerInfo3.getPath()); + assertEquals("[GET, HEAD]", Arrays.toString(handlerInfo3.getHttpMethods())); + assertEquals(0, handlerInfo3.getContentTypes().length); + assertEquals("[TEXT_PLAIN, APPLICATION_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes())); + assertEquals("org.test.PersonHandler2", handlerInfo3.getHandlerClass()); + assertEquals("public Mono listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod()); + } + + @Test + public void testNestedRoutesMappingSymbols3() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI())); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()); + + String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter3.java").toUri().toString(); + List symbols = getSymbols(docUri); + assertEquals(8, symbols.size()); + + assertTrue(containsSymbol(symbols, "@/person/sub1/sub2/{id} -- GET - Accept: application/json", docUri, 29, 7, 29, 46)); + assertTrue(containsSymbol(symbols, "@/person/sub1/sub2 -- GET - Accept: application/json", docUri, 30, 8, 30, 61)); + assertTrue(containsSymbol(symbols, "@/person/sub1/sub2/nestedGet -- GET", docUri, 31, 9, 31, 56)); + assertTrue(containsSymbol(symbols, "@/person/sub1/andNestPath/andNestPathGET -- GET", docUri, 33, 5, 33, 54)); + assertTrue(containsSymbol(symbols, "@/person/ -- POST - Content-Type: application/json", docUri, 34, 5, 34, 82)); + assertTrue(containsSymbol(symbols, "@/nestedDelete -- DELETE", docUri, 35, 42, 35, 93)); + + List addons = getAdditionalInformation(docUri); + assertEquals(6, addons.size()); + + WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/sub1/sub2/{id}", "GET").get(0); + assertEquals("/person/sub1/sub2/{id}", handlerInfo1.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods())); + assertEquals(0, handlerInfo1.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo1.getAcceptTypes())); + assertEquals("org.test.PersonHandler3", handlerInfo1.getHandlerClass()); + assertEquals("public Mono getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/person/sub1/sub2", "GET").get(0); + assertEquals("/person/sub1/sub2", handlerInfo2.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo2.getHttpMethods())); + assertEquals(0, handlerInfo2.getContentTypes().length); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo2.getAcceptTypes())); + assertEquals("org.test.PersonHandler3", handlerInfo1.getHandlerClass()); + assertEquals("public Mono listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person/sub1/sub2/nestedGet", "GET").get(0); + assertEquals("/person/sub1/sub2/nestedGet", handlerInfo3.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo3.getHttpMethods())); + assertEquals(0, handlerInfo3.getContentTypes().length); + assertEquals(0, handlerInfo3.getAcceptTypes().length); + assertEquals("org.test.PersonHandler3", handlerInfo1.getHandlerClass()); + assertEquals("public Mono getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "/person/sub1/andNestPath/andNestPathGET", "GET").get(0); + assertEquals("/person/sub1/andNestPath/andNestPathGET", handlerInfo4.getPath()); + assertEquals("[GET]", Arrays.toString(handlerInfo4.getHttpMethods())); + assertEquals(0, handlerInfo4.getContentTypes().length); + assertEquals(0, handlerInfo4.getAcceptTypes().length); + assertEquals("org.test.PersonHandler3", handlerInfo4.getHandlerClass()); + assertEquals("public Mono getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo4.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo5 = getWebfluxHandler(addons, "/person/", "POST").get(0); + assertEquals("/person/", handlerInfo5.getPath()); + assertEquals("[POST]", Arrays.toString(handlerInfo5.getHttpMethods())); + assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo5.getContentTypes())); + assertEquals(0, handlerInfo5.getAcceptTypes().length); + assertEquals("org.test.PersonHandler3", handlerInfo5.getHandlerClass()); + assertEquals("public Mono createPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo5.getHandlerMethod()); + + WebfluxHandlerInformation handlerInfo6 = getWebfluxHandler(addons, "/nestedDelete", "DELETE").get(0); + assertEquals("/nestedDelete", handlerInfo6.getPath()); + assertEquals("[DELETE]", Arrays.toString(handlerInfo6.getHttpMethods())); + assertEquals(0, handlerInfo6.getContentTypes().length); + assertEquals(0, handlerInfo6.getAcceptTypes().length); + assertEquals("org.test.PersonHandler3", handlerInfo6.getHandlerClass()); + assertEquals("public Mono deletePerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo6.getHandlerMethod()); + } + private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) { for (Iterator iterator = symbols.iterator(); iterator.hasNext();) { SymbolInformation symbol = iterator.next(); @@ -146,11 +276,11 @@ public class WebFluxMappingSymbolProviderTest { return harness.getServerWrapper().getComponents().getSpringIndexer().getAdditonalInformation(docUri); } - private List getWebfluxHandler(List addons, String symbol) { + private List getWebfluxHandler(List addons, String path, String httpMethod) { return addons.stream() .filter((obj) -> obj instanceof WebfluxHandlerInformation) .map((obj -> (WebfluxHandlerInformation) obj)) - .filter((addon) -> addon.getSymbol().equals(symbol)) + .filter((addon) -> addon.getPath().equals(path) && Arrays.asList(addon.getHttpMethods()).contains(httpMethod)) .collect(Collectors.toList()); } diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/RequestMappingMediaTypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/RequestMappingMediaTypes.java new file mode 100644 index 000000000..60a29bd36 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/RequestMappingMediaTypes.java @@ -0,0 +1,44 @@ +package org.test; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +public class RequestMappingMediaTypes { + + @RequestMapping(path="/consume1", consumes = "testconsume", method= {RequestMethod.HEAD}) + public String consume1() { + return "Hello"; + } + + @RequestMapping(path="/consume2", consumes = MediaType.TEXT_PLAIN_VALUE) + public String consume2() { + return "Hello"; + } + + @RequestMapping(path="/consume3", consumes = {MediaType.TEXT_PLAIN_VALUE, "testconsumetype"}) + public String consume3() { + return "Hello"; + } + + @RequestMapping(path="/produce1", produces = "testproduce") + public String produce1() { + return "Hello"; + } + + @RequestMapping(path="/produce2", produces = MediaType.TEXT_PLAIN_VALUE) + public String produce2() { + return "Hello"; + } + + @RequestMapping(path="/produce3", produces = {MediaType.TEXT_PLAIN_VALUE, "testproducetype"}) + public String produce3() { + return "Hello"; + } + + @RequestMapping(path="/everything", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE, "testconsume"}, produces=MediaType.APPLICATION_JSON_VALUE) + public String everything() { + return "Hello"; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/pom.xml b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/pom.xml index 930b1a47c..83db5d821 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/pom.xml +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.M1 + 2.0.0.RELEASE @@ -35,10 +35,6 @@ org.springframework.boot spring-boot-starter-webflux - - org.springframework.boot - spring-boot-starter-data-mongodb-reactive - @@ -50,42 +46,4 @@ - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter1.java similarity index 90% rename from headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter.java rename to headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter1.java index 89d063b17..e409ee4bb 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter1.java @@ -17,11 +17,11 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; @Configuration -public class NestedRouter { +public class NestedRouter1 { @Bean - public RouterFunction routingFunction() { - PersonHandler handler = new PersonHandler(); + public RouterFunction routingFunction1() { + PersonHandler1 handler = new PersonHandler1(); return nest(path("/person"), nest(accept(APPLICATION_JSON), diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter2.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter2.java new file mode 100644 index 000000000..83ccffcf9 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter2.java @@ -0,0 +1,35 @@ +package org.test; + +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.http.MediaType.APPLICATION_PDF; +import static org.springframework.http.MediaType.TEXT_PLAIN; +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RequestPredicates.POST; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; +import static org.springframework.web.reactive.function.server.RequestPredicates.method; +import static org.springframework.web.reactive.function.server.RequestPredicates.path; +import static org.springframework.web.reactive.function.server.RouterFunctions.nest; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Configuration +public class NestedRouter2 { + + @Bean + public RouterFunction routingFunction2() { + PersonHandler2 handler = new PersonHandler2(); + + return nest(accept(APPLICATION_JSON), + nest(path("/person"), + route(GET("/{id}"), handler::getPerson) + .andRoute(method(HttpMethod.GET).and(method(HttpMethod.HEAD)).and(accept(TEXT_PLAIN)), handler::listPeople) + ).andRoute(POST("/").and(contentType(APPLICATION_JSON)).and(contentType(APPLICATION_PDF)), handler::createPerson)); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter3.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter3.java new file mode 100644 index 000000000..fc6a567ee --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/NestedRouter3.java @@ -0,0 +1,39 @@ +package org.test; + +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RequestPredicates.POST; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; +import static org.springframework.web.reactive.function.server.RequestPredicates.method; +import static org.springframework.web.reactive.function.server.RequestPredicates.path; +import static org.springframework.web.reactive.function.server.RouterFunctions.nest; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Configuration +public class NestedRouter3 { + + @Bean + public RouterFunction routingFunction() { + PersonHandler3 handler = new PersonHandler3(); + + return nest(path("/person"), + nest(path("/sub1"), + nest(path("/sub2"), + nest(accept(APPLICATION_JSON), + route(GET("/{id}"), handler::getPerson) + .andRoute(method(HttpMethod.GET), handler::listPeople)) + .andRoute(GET("/nestedGet"), handler::getPerson)) + .and(nest(path("/andNestPath"), + route(GET("/andNestPathGET"), handler::getPerson)))) + .andRoute(POST("/").and(contentType(APPLICATION_JSON)), handler::createPerson)) + .and(nest(method(HttpMethod.DELETE), route(path("/nestedDelete"), handler::deletePerson))); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler1.java similarity index 94% rename from headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler.java rename to headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler1.java index a1bdb96b4..73ceec1e6 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler1.java @@ -5,7 +5,7 @@ import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -public class PersonHandler { +public class PersonHandler1 { public Mono getPerson(ServerRequest request) { return ServerResponse.notFound().build(); diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler2.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler2.java new file mode 100644 index 000000000..d4d60aecc --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler2.java @@ -0,0 +1,22 @@ +package org.test; + +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +import reactor.core.publisher.Mono; + +public class PersonHandler2 { + + public Mono getPerson(ServerRequest request) { + return ServerResponse.notFound().build(); + } + + public Mono createPerson(ServerRequest request) { + return ServerResponse.notFound().build(); + } + + public Mono listPeople(ServerRequest request) { + return ServerResponse.notFound().build(); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler3.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler3.java new file mode 100644 index 000000000..a1a48331e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/PersonHandler3.java @@ -0,0 +1,26 @@ +package org.test; + +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +import reactor.core.publisher.Mono; + +public class PersonHandler3 { + + public Mono getPerson(ServerRequest request) { + return ServerResponse.notFound().build(); + } + + public Mono createPerson(ServerRequest request) { + return ServerResponse.notFound().build(); + } + + public Mono listPeople(ServerRequest request) { + return ServerResponse.notFound().build(); + } + + public Mono deletePerson(ServerRequest request) { + return ServerResponse.notFound().build(); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUser.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUser.java deleted file mode 100644 index d25f38aa1..000000000 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUser.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.test; - -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; - -@Document -public class TradingUser { - - @Id - private String id; - - private String userName; - - private String fullName; - - public TradingUser() { - } - - public TradingUser(String id, String userName, String fullName) { - this.id = id; - this.userName = userName; - this.fullName = fullName; - } - - public TradingUser(String userName, String fullName) { - this.userName = userName; - this.fullName = fullName; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getFullName() { - return fullName; - } - - public void setFullName(String fullName) { - this.fullName = fullName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - TradingUser that = (TradingUser) o; - - if (!id.equals(that.id)) return false; - return userName.equals(that.userName); - } - - @Override - public int hashCode() { - int result = id.hashCode(); - result = 31 * result + userName.hashCode(); - return result; - } -} - diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUserRepository.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUserRepository.java deleted file mode 100644 index 2cf539025..000000000 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/TradingUserRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.test; - -import reactor.core.publisher.Mono; - -import org.springframework.data.mongodb.repository.ReactiveMongoRepository; - -public interface TradingUserRepository extends ReactiveMongoRepository { - - Mono findByUserName(String userName); - -} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/UserController.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/UserController.java index 64621ec86..9de96cbeb 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/UserController.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-webflux-project/src/main/java/org/test/UserController.java @@ -1,30 +1,24 @@ package org.test; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + @RestController public class UserController { - private final TradingUserRepository tradingUserRepository; - - public UserController(TradingUserRepository tradingUserRepository) { - this.tradingUserRepository = tradingUserRepository; - } - @GetMapping(path = "/users", produces = MediaType.APPLICATION_JSON_VALUE) - public Flux listUsers() { - return this.tradingUserRepository.findAll(); + public Flux listUsers() { + return null; } @GetMapping(path = "/users/{username}", produces = MediaType.APPLICATION_JSON_VALUE) - public Mono showUsers(@PathVariable String username) { - return this.tradingUserRepository.findByUserName(username); + public Mono showUsers(@PathVariable String username) { + return null; } } \ No newline at end of file diff --git a/vscode-extensions/vscode-bosh/package.json b/vscode-extensions/vscode-bosh/package.json index c0b814310..c6b11ed5e 100644 --- a/vscode-extensions/vscode-bosh/package.json +++ b/vscode-extensions/vscode-bosh/package.json @@ -3,7 +3,7 @@ "displayName": "Bosh Editor", "description": "Provides validation and content assist for various Bosh configuration files", "icon": "icon.png", - "version": "0.1.5", + "version": "0.1.6", "publisher": "Pivotal", "repository": { "type": "git", diff --git a/vscode-extensions/vscode-concourse/README.md b/vscode-extensions/vscode-concourse/README.md index ea07bf277..cf80c123e 100644 --- a/vscode-extensions/vscode-concourse/README.md +++ b/vscode-extensions/vscode-concourse/README.md @@ -1,7 +1,7 @@ # Concourse Pipeline and Task Editor for Visual Studio Code This extension provides validation, content assist and documentation hovers -for editing [Concourse](https://concourse.ci/) Pipeline and Task configuration files. +for editing [Concourse](https://concourse-ci.org/) Pipeline and Task configuration files. ## Usage @@ -63,7 +63,7 @@ to its corresponding definition. ## Limitations -This Vscode Extension is still a work in progress. At the moment only a select few of the [built-in resource-types](https://concourse.ci/resource-types.html) +This Vscode Extension is still a work in progress. At the moment only a select few of the [built-in resource-types](https://concourse-ci.org/resource-types.html) have been fully defined in the Editor's Schema. The resource-types that are already defined in the schema are: diff --git a/vscode-extensions/vscode-concourse/package.json b/vscode-extensions/vscode-concourse/package.json index 46dc50e2b..7079769de 100644 --- a/vscode-extensions/vscode-concourse/package.json +++ b/vscode-extensions/vscode-concourse/package.json @@ -3,7 +3,7 @@ "displayName": "Concourse CI Pipeline Editor", "description": "Provides validation and content assist for Concourse CI pipeline and task configuration yml files", "icon": "icon.png", - "version": "0.1.5", + "version": "0.1.6", "publisher": "Pivotal", "repository": { "type": "git", diff --git a/vscode-extensions/vscode-manifest-yaml/package.json b/vscode-extensions/vscode-manifest-yaml/package.json index c38b3c4e6..0159b1be9 100644 --- a/vscode-extensions/vscode-manifest-yaml/package.json +++ b/vscode-extensions/vscode-manifest-yaml/package.json @@ -3,7 +3,7 @@ "displayName": "Cloudfoundry Manifest YML Support", "description": "Adds linting, content assist and hoverinfo's for Cloudfoundry Deployment Manifests (a.k.a. `manifest.yml`) files.", "icon": "icon.png", - "version": "0.1.5", + "version": "0.1.6", "publisher": "Pivotal", "repository": { "type": "git", diff --git a/vscode-extensions/vscode-spring-boot/package.json b/vscode-extensions/vscode-spring-boot/package.json index 681781d17..9f086fb02 100644 --- a/vscode-extensions/vscode-spring-boot/package.json +++ b/vscode-extensions/vscode-spring-boot/package.json @@ -3,7 +3,7 @@ "displayName": "Spring Boot Tools", "description": "Provides validation and content assist for Spring Boot `application.properties`, `application.yml` properties files. As well as Boot-specific support for `.java` files.", "icon": "spring-boot-logo.png", - "version": "0.1.5", + "version": "0.1.6", "publisher": "Pivotal", "repository": { "type": "git",