From 9d00cd82a8fc5e9cbe2d68a8410ce82cd63eef14 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Tue, 16 Apr 2024 16:45:16 +0200 Subject: docs: contributing guide --- subprojects/docs/docusaurus.config.ts | 5 +- subprojects/docs/src/develop/contributing.md | 51 ------ .../docs/src/develop/contributing/commands.md | 172 +++++++++++++++++++++ .../docs/src/develop/contributing/ide-setup.md | 94 +++++++++++ subprojects/docs/src/develop/contributing/index.md | 59 +++++++ .../docs/src/plugins/remarkPosix2Windows.ts | 166 ++++++++++++++++++++ 6 files changed, 495 insertions(+), 52 deletions(-) delete mode 100644 subprojects/docs/src/develop/contributing.md create mode 100644 subprojects/docs/src/develop/contributing/commands.md create mode 100644 subprojects/docs/src/develop/contributing/ide-setup.md create mode 100644 subprojects/docs/src/develop/contributing/index.md create mode 100644 subprojects/docs/src/plugins/remarkPosix2Windows.ts diff --git a/subprojects/docs/docusaurus.config.ts b/subprojects/docs/docusaurus.config.ts index 67ee1db4..25182f60 100644 --- a/subprojects/docs/docusaurus.config.ts +++ b/subprojects/docs/docusaurus.config.ts @@ -15,8 +15,10 @@ import { Config as SwcConfig } from '@swc/core'; import { themes } from 'prism-react-renderer'; import smartypants from 'remark-smartypants'; +import remarkPosix2Windows from './src/plugins/remarkPosix2Windows'; + const markdownOptions = { - remarkPlugins: [[smartypants, { dashes: 'oldschool' }]], + remarkPlugins: [[smartypants, { dashes: 'oldschool' }], remarkPosix2Windows], }; const docsOptions = { @@ -75,6 +77,7 @@ export default { respectPrefersColorScheme: true, }, prism: { + additionalLanguages: ['bash', 'java'], theme: themes.oneLight, darkTheme: themes.oneDark, }, diff --git a/subprojects/docs/src/develop/contributing.md b/subprojects/docs/src/develop/contributing.md deleted file mode 100644 index 4a135b81..00000000 --- a/subprojects/docs/src/develop/contributing.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -SPDX-FileCopyrightText: 2021-2023 The Refinery Authors -SPDX-License-Identifier: EPL-2.0 -sidebar_position: 1 -sidebar_label: Contributing ---- - -# Contributing to Refinery - -## Setting up the development environment - -### With IntelliJ IDEA - -We prefer IntelliJ IDEA as a development environment. -No special preparations should be necessary for importing the project as a Gradle project into IDEA. - -However, you will need Eclipse to edit Xtext (`*.xtext`) and MWE2 (`*.mwe2`) files and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`). -If you do not plan on making changes to such files, feel free to skip the Eclipse installation steps below. - -### With Eclipse IDE - -1. Download and install a _Java 21_ compatible JDK. For Windows, prefer OpenJDK builds from [Adoptium](https://adoptium.net/). - -2. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package. - -3. Launch Eclipse and create a new workspace. - -4. Open _Help > Eclipse Marketplace_ and install the following software: - * _EclEmma Java Code Coverage_ - * _EcoreTools : Ecore Diagram Editor_ - * _Sirius_ (ignore the warning during installation about the solution _Sirius_ not being available) - * _SonarLint_ - -5. Open _Window > Preferences_ and set the following preferences: - * _General > Workspace > Text file encoding_ should be _UTF-8_. - * _General > Workspace > New text file line delimiter_ should be _Unix_. - * Add the JDK 21 to _Java > Installed JREs_. - * Make sure JDK 21 is selected for _JavaSE-21_ at _Java > Installed JREs > Execution Environments_. - * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 21. Here, Buildship will show a yellow warning sign, which can be safely ignored. - * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _21_. - -6. Clone the project Git repository but do not import it into Eclipse yet. - -7. Open a new terminal an run `./gradlew prepareEclipse` (`.\gradlew prepareEclipse` on Windows) in the cloned repository. - * This should complete without any compilation errors. - * If you get any errors about the JVM version, check whether the `JAVA_HOME` environment variable is set to the location of JDK. You can query the variable with `echo $JAVA_HOME` on Linux and `echo $Env:JAVA_HOME` in PowerShell on Windows. To set it, use `export JAVA_HOME=/java/path/here` or `$Env:JAVA_HOME="C:\java\path\here"`, respectively. - * If the build fails with a `Host name must not be empty` error, you [might need to remove the empty proxy configuration from your global `gradle.properties` file](https://stackoverflow.com/a/62128323). - -8. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. - * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. - * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8. diff --git a/subprojects/docs/src/develop/contributing/commands.md b/subprojects/docs/src/develop/contributing/commands.md new file mode 100644 index 00000000..abfea704 --- /dev/null +++ b/subprojects/docs/src/develop/contributing/commands.md @@ -0,0 +1,172 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 1 +title: Build commands +--- + +# Building from the command line + +## Gradle commands + +We use [Gradle](https://gradle.org/) to manage the compilation and tests of Refinery. + +Java code is built directly by Gradle. +We use the [frontend-gradle-plugin](https://siouan.github.io/frontend-gradle-plugin/) to manage a [Node.js](https://nodejs.org/en) and [Yarn](https://yarnpkg.com/) installation, which in turn is used to build TypeScript code (including this documentation website). +Typically, Yarn commands are issued by Gradle and you don't need to work with the TypeScript build system directly if you're only working on the Java parts of Refinery. + +### `build` + +```bash posix2windows +./gradlew build +``` + +Compile all code, run all tests, and produce all build artifacts. + +You should run this command before submitting a [Pull request](https://github.com/graphs4value/refinery/pulls) to make sure that all code builds and tests pass on your local machine. +This will also be run by GitHub Actions for each commit or pull requests. + +### `publishToMavenLocal` + + +```bash posix2windows +./gradlew publishToMavenLocal +``` + +Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository). + +Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modification -- in other Java projects. + +For example, in Gradle, you may set + +```kotlin title="build.gradle.kts" +repositories { + mavenLocal() +} + +dependencies { + implementation("tools.refinery:refinery-generator:0.0.0-SNAPSHOT") +} +``` + +to add a dependency on Refinery to your Java project. + +### `serve` + +```bash posix2windows +./gradlew serve +``` + +Starts the Refinery backend and web interface on port 1312. + +This task is ideal for running the Refinery backend if you don't intend to work on the frontend. +The Refinery frontend TypeScript projects is automatically built before the server starts. +The server will use the latest build output of the frontend as static assets. + +The behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). +However, the default value of `REFINERY_LISTEN_PORT` is `1312`. + +### `serveBackend` + +```bash posix2windows +./gradlew serveBackend +``` + +Starts the Refinery backend on port 1312. + +This task is ideal for running the Refinery backend if you're working on the frontend. +No static assets will be build. +You'll need to use [`yarnw frontend dev`](#frontend-dev) + +Like [`gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). +However, the default value of `REFINERY_LISTEN_PORT` is `1312`. + +## Yarn commands + +We provide a `yarnw` wrapper script to invoke the Yarn distribution installed by frontend-gradle-plugin directly. +The following commands can only be run once [`gradlew build`](#build) has installed the necessary Node.js and Yarn packages. + +### `docs dev` + +```bash posix2windows +./yarn docs dev +``` + +Builds and serves this documentation in development mode on port 3000. +Saved changes to most documentation sources are immediately reflected in the browse without reloading. + +You can set the port with the `-p` option, e.g. to use port 1313, use + +```bash posix2windows +./yarn docs dev -p 1313 +``` + +:::note + +Running this command for the first time may generate error messages like +``` +ERROR failed to read input source map: failed to parse inline source map url +``` +which can be safely ignored. + +::: + +### `frontend dev` + +```bash posix2windows +./yarn frontend dev +``` + +Builds and serves the refinery frontend on port 1313. +Saved changes to most source files are immediately reflected in the browser without reload. + +Before running this command, you need to start [`gradlew serveBackend`](#servebackend) to provide a backend for the frontend to connect to. +The development server of the frontend will proxy all WebSocket connections to the backend. + +The following environmental variables influence the behavior of this command: + +#### `REFINERY_LISTEN_HOST` + +Hostname to listen at for incoming HTTP connections. + +**Default value:** `localhost` + +#### `REFINERY_LISTEN_PORT` + +TCP port to listen at for incoming HTTP connections. + +**Default value:** `1313` + +#### `REFINERY_BACKEND_HOST` + +Hostname of the Refinery backend. + +This should match the `REFINERY_LISTEN_HOST` passed to [`gradlew serveBackend`](#servebackend). + +**Default value:** `127.0.0.1` (connect to `localhost` over IPv4 only) + +#### `REFINERY_LISTEN_PORT` + +TCP port of the Refinery backend. + +This should match the `REFINERY_LISTEN_PORT` passed to [`gradlew serveBackend`](#servebackend). + +**Default value:** `1312` + +#### `REFINERY_PUBLIC_HOST` + +Publicly visible hostname of the Refinery instance. + +If you use a reverse proxy in front of the development server, you must set this variable. +Otherwise, connections to the development server will fail due to cross-origin protection. + +**Default value:** equal to `REFINERY_LISTEN_HOST` + +#### `REFINERY_PUBLIC_PORT` + +Publicly visible port of the Refinery instance. + +If you use a reverse proxy in front of the development server, you must set this variable. +Otherwise, connections to the development server will fail due to cross-origin protection. + +**Default value:** equal to `REFINERY_LISTEN_PORT` diff --git a/subprojects/docs/src/develop/contributing/ide-setup.md b/subprojects/docs/src/develop/contributing/ide-setup.md new file mode 100644 index 00000000..742035e0 --- /dev/null +++ b/subprojects/docs/src/develop/contributing/ide-setup.md @@ -0,0 +1,94 @@ +--- +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 2 +title: IDE setup +--- + +# Setting up the development environment + +## IntelliJ IDEA + +We prefer [IntelliJ IDEA](https://www.jetbrains.com/idea/) as a Java development environment. +No special preparations should be necessary for importing the project as a Gradle project into IDEA: + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later). + +2. Clone the project git repository and open it in IntelliJ IDEA. Make sure to _open_ the project instead of creating a _new_ one in the same directory. + +3. IntelliJ IDEA should build and index the project. If there are errors, it is likely that the `JAVA_HOME` was incorrectly set: + * In _Project Structure > Project settings > Project > SDK_, a Java 21 compatible JDK should be selected. + * In _Project Structure > Project settings > Project > Language level_, either _SDK default_ or _21_ should be selected. + * Make sure that each module in _Project Structure > Project settings > Module_ uses the _Project default_ language level in _Sources > Language level_ and the _Project SDK_ in _Dependencies > Module SDK._ + * In _Settings > Gradle settings > Gralde Projects > Gradle_, the _Distribution_ should be set to _Wrapper_ and the _Gradle JVM_ should be set to _Project SDK._ + +4. We recommend installing the latest _SonarLint_ plugin in _Settings > Plugins_ to get real-time code quality analysis in your IDE. + +:::note + +You'll need [Eclipse](#eclipse) to edit Xtext (`*.xtext`) and MWE2 (`*.mwe2`) files and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`). +If you do not plan on making changes to such files, feel free to skip the Eclipse installation steps below. + +You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery. + +::: + +## Eclipse + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. + +2. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package. + +3. Launch Eclipse and create a new workspace. + +4. Open _Help > Eclipse Marketplace_ and install the following software: + * _EclEmma Java Code Coverage_ + * _EcoreTools : Ecore Diagram Editor_ + * _Sirius_ (ignore the warning during installation about the solution _Sirius_ not being available) + * _SonarLint_ + +5. Open _Window > Preferences_ and set the following preferences: + * _General > Workspace > Text file encoding_ should be _UTF-8_. + * _General > Workspace > New text file line delimiter_ should be _Unix_. + * Add the JDK 21 to _Java > Installed JREs_. + * Make sure JDK 21 is selected for _JavaSE-21_ at _Java > Installed JREs > Execution Environments_. + * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 21. Here, Buildship will show a yellow warning sign, which can be safely ignored. + * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _21_. + +6. Clone the project Git repository but _do not_ import it into Eclipse yet. + +7. Open a new terminal and run + ```bash posix2windows + ./gradlew prepareEclipse + ``` + in the cloned repository. + * This should complete without any compilation errors. + * To troubleshoot any error, see the [instructions about compiling Refinery](/develop/contributing#compiling). + +8. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. + * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. + * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8. + +## VS Code + +We recommend [VSCodium](https://github.com/VSCodium/vscodium) or [Visual Studio Code](https://code.visualstudio.com/) to work with the parts of Refinery that are written is TypeScript. + +1. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later). + +2. Install the following VS Code extensions: + * _EditorConfig for VS Code_ [[Open VSX](https://open-vsx.org/extension/EditorConfig/EditorConfig)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)] + * _ZipFS - a zip file system_ [[Open VSX](https://open-vsx.org/extension/arcanis/vscode-zipfs)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)] + * _ESLint_ [[Open VSX](https://open-vsx.org/extension/dbaeumer/vscode-eslint)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)] + * _XState VSCode_ [[Open VSX](https://open-vsx.org/extension/statelyai/stately-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)] + +3. Clone the project Git repository but _do not_ import it into VS Code yet. + +4. Run + ```bash posix2windows + ./gradlew installFrontend + ``` + to install all required Node.js tooling. + +5. Open the repository with _Open Folder…_ in VS Code. + * When asked, select that you _Trust_ the folder. + * When asked, enable using the TypeScript and ESLint tooling specified in the repository. diff --git a/subprojects/docs/src/develop/contributing/index.md b/subprojects/docs/src/develop/contributing/index.md new file mode 100644 index 00000000..aa0bdb2f --- /dev/null +++ b/subprojects/docs/src/develop/contributing/index.md @@ -0,0 +1,59 @@ +--- +SPDX-FileCopyrightText: 2024 The Refinery Authors +SPDX-License-Identifier: EPL-2.0 +sidebar_position: 1 +title: Contributing +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +# Contributing to Refinery + +You can clone the refinery repository from GitHub at https://github.com/graphs4value/refinery. +If you want to contribute code, we recommend [forking](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the repository on GitHub so that you can submit a [pull request](https://github.com/graphs4value/refinery/pulls) later. + +## Required tools + +Refinery is written in Java and TypeScript. To build Refinery, you'll need a **Java 21** compatible **Java Development Kit (JDK).** We recommend the [Adoptium Java 21 JDK](https://adoptium.net/) or the [Amazon Corretto Java 21 JDK](https://aws.amazon.com/corretto/). + +## Compiling Refinery {#compiling} + +To build Refinery, run the command +```bash posix2windows +./gradlew build +``` +in the cloned repository. + +This should complete without any compilation errors. + +If you get any errors about the JVM version, check whether the `JAVA_HOME` environment variable is set to the location of **JDK 21**. You can query the variable with + + + ```bash + echo $JAVA_HOME + ``` + + + ```bash + echo $Env:JAVA_HOME + ``` + + +To set the `JAVA_HOME` environmental variable, use + + + ```bash + export JAVA_HOME=/java/path/here + ``` + + + ```bash + $Env:JAVA_HOME="C:\java\path\here" + ``` + + + +If the build fails with a `Host name must not be empty` error, you [might need to remove the empty proxy configuration from your global `gradle.properties` file](https://stackoverflow.com/a/62128323). + +For further information, see the [supported build commands](/develop/contributing/commands) and the [instructions for setting up an IDE](/develop/contributing/ide-setup). diff --git a/subprojects/docs/src/plugins/remarkPosix2Windows.ts b/subprojects/docs/src/plugins/remarkPosix2Windows.ts new file mode 100644 index 00000000..66baca30 --- /dev/null +++ b/subprojects/docs/src/plugins/remarkPosix2Windows.ts @@ -0,0 +1,166 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + * + * This file is based on + * https://github.com/facebook/docusaurus/blob/e4ecffe41878728acff55a8370bd7440706c02f7/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts + * but was changed to conver shell commands to POSIX to Windows syntax. + */ + +import type { Code, Literal } from 'mdast'; +import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx'; +import type { Transformer } from 'unified'; +import type { Node, Parent } from 'unist'; +import { visit } from 'unist-util-visit'; + +function isLiteral(node: Node): node is Literal { + return node.type === 'mdxjsEsm'; +} + +function isTabImport(node: Node): boolean { + return isLiteral(node) && node.value.includes('@theme/Tabs'); +} + +function isParent(node: Node): node is Parent { + return 'children' in node && Array.isArray(node.children); +} + +function isCode(node: Node): node is Code { + return node.type === 'code'; +} + +function isPosix2Windows(node: Node): node is Code { + return isCode(node) && node.meta === 'posix2windows'; +} + +function createTabItem( + code: string, + node: Code, + value: string, + label: string, +): MdxJsxFlowElement { + return { + type: 'mdxJsxFlowElement', + name: 'TabItem', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'value', + value, + }, + { + type: 'mdxJsxAttribute', + name: 'label', + value: label, + }, + ], + children: [ + { + type: node.type, + lang: node.lang, + value: code, + }, + ], + }; +} + +function transformNode(node: Code): MdxJsxFlowElement[] { + const posixCode = node.value; + const windowsCode = posixCode.replaceAll(/(?<=^\w*)\.\//gm, '.\\'); + return [ + { + type: 'mdxJsxFlowElement', + name: 'Tabs', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'groupId', + value: 'posix2windows', + }, + ], + children: [ + createTabItem(posixCode, node, 'posix', 'Linux or macOS'), + createTabItem(windowsCode, node, 'windows', 'Windows (PowerShell)'), + ], + }, + ]; +} + +function createImportNode(): MdxjsEsm { + return { + type: 'mdxjsEsm', + value: + "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'", + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: { type: 'Identifier', name: 'Tabs' }, + }, + ], + source: { + type: 'Literal', + value: '@theme/Tabs', + raw: "'@theme/Tabs'", + }, + }, + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: { type: 'Identifier', name: 'TabItem' }, + }, + ], + source: { + type: 'Literal', + value: '@theme/TabItem', + raw: "'@theme/TabItem'", + }, + }, + ], + sourceType: 'module', + }, + }, + }; +} + +export default function remarkPosix2Windows(): Transformer { + return (root) => { + let transformed = false; + let alreadyImported = false; + visit(root, (node) => { + if (isTabImport(node)) { + alreadyImported = true; + } + if (isParent(node)) { + let index = 0; + while (index < node.children.length) { + const child = node.children[index]; + if (child !== undefined && isPosix2Windows(child)) { + const result = transformNode(child); + node.children.splice(index, 1, ...result); + index += result.length; + transformed = true; + } else { + index += 1; + } + } + } + }); + if (transformed && !alreadyImported) { + if (isParent(root)) { + root.children.unshift(createImportNode()); + } else { + throw new Error("Cannot import '@theme/Tabs'"); + } + } + }; +} -- cgit v1.2.3-54-g00ecf