# Directory Structure ``` ├── .github │ ├── dependabot.yml │ ├── readme │ │ └── demo.gif │ └── workflows │ ├── build.yml │ ├── release.yml │ └── run-ui-tests.yml ├── .gitignore ├── .idea │ └── gradle.xml ├── .run │ ├── Run Plugin.run.xml │ ├── Run Tests.run.xml │ └── Run Verifications.run.xml ├── build.gradle.kts ├── CHANGELOG.md ├── gradle │ ├── libs.versions.toml │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── qodana.yml ├── README.md ├── settings.gradle.kts └── src ├── main │ ├── kotlin │ │ └── com │ │ └── github │ │ └── gschrader │ │ └── openinrunconfig │ │ ├── actions │ │ │ └── RunWithFilePathAction.kt │ │ └── MyBundle.kt │ └── resources │ ├── messages │ │ └── MyBundle.properties │ └── META-INF │ └── plugin.xml └── test ├── kotlin │ └── com │ └── github │ └── gschrader │ └── openinrunconfig │ └── MyPluginTest.kt └── testData └── rename ├── foo_after.xml └── foo.xml ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` .gradle .idea .intellijPlatform .qodana build ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # open-in-run-config-idea-plugin  [](https://plugins.jetbrains.com/plugin/27881) [](https://plugins.jetbrains.com/plugin/27881) ## Plugin Overview <!-- Plugin description --> The **Open in Run Config** plugin allows you to quickly run any Java application configuration with a selected file as a program argument. It's essentially a productivity tool that eliminates the need to manually edit run configurations when you want to pass a file path to your application. <!-- Plugin description end -->  ## What It Does 1. **Context Menu Integration**: Adds a "Project Application" action to the context menu when you right-click on a file in the Project view or other file browsers in IntelliJ IDEA. 2. **Configuration Selection**: When triggered, it shows a popup list of all available Java Application run configurations in your project. 3. **Automatic File Path Injection**: Once you select a run configuration, it: - Creates a temporary copy of the selected configuration - Automatically adds the selected file's path as a program argument - Runs the configuration immediately 4. **Smart Handling**: - Only works with Java Application configurations (not other types like JUnit, etc.) - Preserves all original configuration settings (working directory, environment variables, etc.) - Creates temporary configurations that don't clutter your permanent run configurations - Handles both cases where the configuration already has program arguments and where it doesn't ## Use Cases This plugin is particularly useful when you have applications that: - Process files (like parsers, converters, analyzers) - Need file paths as command-line arguments - Are frequently run with different input files Instead of manually editing run configurations each time, you can simply right-click on any file and run your application with that file as input. ``` -------------------------------------------------------------------------------- /src/test/testData/rename/foo_after.xml: -------------------------------------------------------------------------------- ``` <root> <a2>Foo</a2> </root> ``` -------------------------------------------------------------------------------- /src/test/testData/rename/foo.xml: -------------------------------------------------------------------------------- ``` <root> <a<caret>1>Foo</a1> </root> ``` -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- ```kotlin plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } rootProject.name = "open-in-run-config-idea-plugin" ``` -------------------------------------------------------------------------------- /qodana.yml: -------------------------------------------------------------------------------- ```yaml # Qodana configuration: # https://www.jetbrains.com/help/qodana/qodana-yaml.html version: "1.0" linter: jetbrains/qodana-jvm-community:2024.3 projectJDK: "21" profile: name: qodana.recommended exclude: - name: All paths: - .qodana ``` -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- ``` distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ``` -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- ```markdown <!-- Keep a Changelog guide -> https://keepachangelog.com --> # open-in-run-config-idea-plugin Changelog ## [Unreleased] ### Added - Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) ``` -------------------------------------------------------------------------------- /src/test/kotlin/com/github/gschrader/openinrunconfig/MyPluginTest.kt: -------------------------------------------------------------------------------- ```kotlin package com.github.gschrader.openinrunconfig import com.intellij.testFramework.TestDataPath import com.intellij.testFramework.fixtures.BasePlatformTestCase @TestDataPath("\$CONTENT_ROOT/src/test/testData") class MyPluginTest : BasePlatformTestCase() { fun testt() { } } ``` -------------------------------------------------------------------------------- /src/main/resources/messages/MyBundle.properties: -------------------------------------------------------------------------------- ``` runWithFilePath=Project Application selectConfiguration=Select Configuration to Run noConfigurationsAvailable=No run configurations are available in this project. configurationNotSupported=Configuration ''{0}'' does not support program parameters. executionError=Error executing configuration: {0} ``` -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- ```yaml # Dependabot configuration: # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: # Maintain dependencies for Gradle dependencies - package-ecosystem: "gradle" directory: "/" schedule: interval: "daily" # Maintain dependencies for GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" ``` -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- ``` <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="GradleMigrationSettings" migrationVersion="1" /> <component name="GradleSettings"> <option name="linkedExternalProjectsSettings"> <GradleProjectSettings> <option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="modules"> <set> <option value="$PROJECT_DIR$" /> </set> </option> </GradleProjectSettings> </option> </component> </project> ``` -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gschrader/openinrunconfig/MyBundle.kt: -------------------------------------------------------------------------------- ```kotlin package com.github.gschrader.openinrunconfig import com.intellij.DynamicBundle import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.PropertyKey @NonNls private const val BUNDLE = "messages.MyBundle" object MyBundle : DynamicBundle(BUNDLE) { @JvmStatic fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = getMessage(key, *params) @Suppress("unused") @JvmStatic fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = getLazyMessage(key, *params) } ``` -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- ```toml [versions] # libraries junit = "4.13.2" opentest4j = "1.3.0" # plugins changelog = "2.2.1" intelliJPlatform = "2.5.0" kotlin = "2.1.20" kover = "0.9.1" qodana = "2024.3.4" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } opentest4j = { group = "org.opentest4j", name = "opentest4j", version.ref = "opentest4j" } [plugins] changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } intelliJPlatform = { id = "org.jetbrains.intellij.platform", version.ref = "intelliJPlatform" } kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } ``` -------------------------------------------------------------------------------- /.run/Run Tests.run.xml: -------------------------------------------------------------------------------- ``` <component name="ProjectRunConfigurationManager"> <configuration default="false" name="Run Tests" type="GradleRunConfiguration" factoryName="Gradle"> <log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" /> <ExternalSystemSettings> <option name="executionName" /> <option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalSystemIdString" value="GRADLE" /> <option name="scriptParameters" value="" /> <option name="taskDescriptions"> <list /> </option> <option name="taskNames"> <list> <option value="check" /> </list> </option> <option name="vmOptions" value="" /> </ExternalSystemSettings> <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> <DebugAllEnabled>false</DebugAllEnabled> <RunAsTest>true</RunAsTest> <method v="2" /> </configuration> </component> ``` -------------------------------------------------------------------------------- /.run/Run Plugin.run.xml: -------------------------------------------------------------------------------- ``` <component name="ProjectRunConfigurationManager"> <configuration default="false" name="Run Plugin" type="GradleRunConfiguration" factoryName="Gradle"> <log_file alias="IDE logs" path="$PROJECT_DIR$/build/idea-sandbox/*/log/idea.log" show_all="true" /> <ExternalSystemSettings> <option name="executionName" /> <option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalSystemIdString" value="GRADLE" /> <option name="scriptParameters" value="" /> <option name="taskDescriptions"> <list /> </option> <option name="taskNames"> <list> <option value="runIde" /> </list> </option> <option name="vmOptions" value="" /> </ExternalSystemSettings> <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> <DebugAllEnabled>false</DebugAllEnabled> <RunAsTest>false</RunAsTest> <method v="2" /> </configuration> </component> ``` -------------------------------------------------------------------------------- /.run/Run Verifications.run.xml: -------------------------------------------------------------------------------- ``` <component name="ProjectRunConfigurationManager"> <configuration default="false" name="Run Verifications" type="GradleRunConfiguration" factoryName="Gradle"> <log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" /> <ExternalSystemSettings> <option name="executionName" /> <option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalSystemIdString" value="GRADLE" /> <option name="scriptParameters" value="" /> <option name="taskDescriptions"> <list /> </option> <option name="taskNames"> <list> <option value="verifyPlugin" /> </list> </option> <option name="vmOptions" value="" /> </ExternalSystemSettings> <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> <DebugAllEnabled>false</DebugAllEnabled> <RunAsTest>false</RunAsTest> <method v="2" /> </configuration> </component> ``` -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- ``` <!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html --> <idea-plugin> <id>com.github.gschrader.openinrunconfig</id> <name>Open in Run Config</name> <vendor>gschrader</vendor> <description><![CDATA[ The <b>Open in Run Config</b> plugin allows you to quickly run any Java application configuration with a selected file as a program argument. It's essentially a productivity tool that eliminates the need to manually edit run configurations when you want to pass a file path to your application. ]]></description> <depends>com.intellij.modules.platform</depends> <depends>com.intellij.modules.java</depends> <resource-bundle>messages.MyBundle</resource-bundle> <actions> <action id="RunWithFilePathAction" class="com.github.gschrader.openinrunconfig.actions.RunWithFilePathAction" text="Project Application" description="Run with the selected file path as program argument"> <add-to-group group-id="UsageView.Popup" anchor="last"/> <add-to-group group-id="RevealGroup" anchor="last"/> </action> </actions> </idea-plugin> ``` -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- ``` # IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup = com.github.gschrader.openinrunconfig pluginName = open-in-run-config pluginRepositoryUrl = https://github.com/gschrader/open-in-run-config-idea-plugin # SemVer format -> https://semver.org pluginVersion = 0.0.4 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 242 pluginUntilBuild = 252.* # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType = IC platformVersion = 2024.2.5 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP platformPlugins = # Example: platformBundledPlugins = com.intellij.java platformBundledPlugins = com.intellij.java, org.jetbrains.kotlin # Gradle Releases -> https://github.com/gradle/gradle/releases gradleVersion = 8.13 # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib kotlin.stdlib.default.dependency = false # Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html org.gradle.configuration-cache = true # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html org.gradle.caching = true ``` -------------------------------------------------------------------------------- /.github/workflows/run-ui-tests.yml: -------------------------------------------------------------------------------- ```yaml # GitHub Actions Workflow for launching UI tests on Linux, Windows, and Mac in the following steps: # - Prepare and launch IDE with your plugin and robot-server plugin, which is needed to interact with the UI. # - Wait for IDE to start. # - Run UI tests with a separate Gradle task. # # Please check https://github.com/JetBrains/intellij-ui-test-robot for information about UI tests with IntelliJ Platform. # # Workflow is triggered manually. name: Run UI Tests on: workflow_dispatch jobs: testUI: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - os: ubuntu-latest runIde: | export DISPLAY=:99.0 Xvfb -ac :99 -screen 0 1920x1080x16 & gradle runIdeForUiTests & - os: windows-latest runIde: start gradlew.bat runIdeForUiTests - os: macos-latest runIde: ./gradlew runIdeForUiTests & steps: # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Setup Gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 # Run IDEA prepared for UI testing - name: Run IDE run: ${{ matrix.runIde }} # Wait for IDEA to be started - name: Health Check uses: jtalk/url-health-check-action@v4 with: url: http://127.0.0.1:8082 max-attempts: 15 retry-delay: 30s # Run tests - name: Tests run: ./gradlew test ``` -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- ``` @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @rem SPDX-License-Identifier: Apache-2.0 @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ``` -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- ```yaml # GitHub Actions Workflow created for handling the release process based on the draft release prepared with the Build workflow. # Running the publishPlugin task requires all following secrets to be provided: PUBLISH_TOKEN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD, CERTIFICATE_CHAIN. # See https://plugins.jetbrains.com/docs/intellij/plugin-signing.html for more information. name: Release on: release: types: [prereleased, released] jobs: # Prepare and publish the plugin to JetBrains Marketplace repository release: name: Publish Plugin runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: # Free GitHub Actions Environment Disk Space - name: Maximize Build Space # jlumbroso/[email protected]: uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: false large-packages: false # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 with: ref: ${{ github.event.release.tag_name }} # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Setup Gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 # Set environment variables - name: Export Properties id: properties shell: bash run: | CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d' ${{ github.event.release.body }} EOM )" echo "changelog<<EOF" >> $GITHUB_OUTPUT echo "$CHANGELOG" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT # Update the Unreleased section with the current release note - name: Patch Changelog if: ${{ steps.properties.outputs.changelog != '' }} env: CHANGELOG: ${{ steps.properties.outputs.changelog }} run: | ./gradlew patchChangelog --release-note="$CHANGELOG" # Publish the plugin to JetBrains Marketplace - name: Publish Plugin env: PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} run: ./gradlew publishPlugin # Upload artifact as a release asset - name: Upload Release Asset env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* # Create a pull request - name: Create Pull Request if: ${{ steps.properties.outputs.changelog != '' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | VERSION="${{ github.event.release.tag_name }}" BRANCH="changelog-update-$VERSION" LABEL="release changelog" git config user.email "[email protected]" git config user.name "GitHub Action" git checkout -b $BRANCH git commit -am "Changelog update - $VERSION" git push --set-upstream origin $BRANCH gh label create "$LABEL" \ --description "Pull requests with release changelog update" \ --force \ || true gh pr create \ --title "Changelog update - \`$VERSION\`" \ --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ --label "$LABEL" \ --head $BRANCH ``` -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- ```kotlin import org.jetbrains.changelog.Changelog import org.jetbrains.changelog.markdownToHTML import org.jetbrains.intellij.platform.gradle.TestFrameworkType plugins { id("java") // Java support alias(libs.plugins.kotlin) // Kotlin support alias(libs.plugins.intelliJPlatform) // IntelliJ Platform Gradle Plugin alias(libs.plugins.changelog) // Gradle Changelog Plugin alias(libs.plugins.qodana) // Gradle Qodana Plugin alias(libs.plugins.kover) // Gradle Kover Plugin } group = providers.gradleProperty("pluginGroup").get() version = providers.gradleProperty("pluginVersion").get() // Set the JVM language level used to build the project. kotlin { jvmToolchain(21) } // Configure project's dependencies repositories { mavenCentral() // IntelliJ Platform Gradle Plugin Repositories Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-repositories-extension.html intellijPlatform { defaultRepositories() } } // Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog dependencies { testImplementation(libs.junit) testImplementation(libs.opentest4j) // IntelliJ Platform Gradle Plugin Dependencies Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html intellijPlatform { create(providers.gradleProperty("platformType"), providers.gradleProperty("platformVersion")) // Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins. bundledPlugins(providers.gradleProperty("platformBundledPlugins").map { it.split(',') }) // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace. plugins(providers.gradleProperty("platformPlugins").map { it.split(',') }) testFramework(TestFrameworkType.Platform) } } // Configure IntelliJ Platform Gradle Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html intellijPlatform { pluginConfiguration { name = providers.gradleProperty("pluginName") version = providers.gradleProperty("pluginVersion") // Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { val start = "<!-- Plugin description -->" val end = "<!-- Plugin description end -->" with(it.lines()) { if (!containsAll(listOf(start, end))) { throw GradleException("Plugin description section not found in README.md:\n$start ... $end") } subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) } } val changelog = project.changelog // local variable for configuration cache compatibility // Get the latest available change notes from the changelog file changeNotes = providers.gradleProperty("pluginVersion").map { pluginVersion -> with(changelog) { renderItem( (getOrNull(pluginVersion) ?: getUnreleased()) .withHeader(false) .withEmptySections(false), Changelog.OutputType.HTML, ) } } ideaVersion { sinceBuild = providers.gradleProperty("pluginSinceBuild") untilBuild = providers.gradleProperty("pluginUntilBuild") } } signing { certificateChain = providers.environmentVariable("CERTIFICATE_CHAIN") privateKey = providers.environmentVariable("PRIVATE_KEY") password = providers.environmentVariable("PRIVATE_KEY_PASSWORD") } publishing { token = providers.environmentVariable("PUBLISH_TOKEN") // The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel channels = providers.gradleProperty("pluginVersion").map { listOf(it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }) } } pluginVerification { ides { recommended() } } } // Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin changelog { groups.empty() repositoryUrl = providers.gradleProperty("pluginRepositoryUrl") } // Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration kover { reports { total { xml { onCheck = true } } } } tasks { wrapper { gradleVersion = providers.gradleProperty("gradleVersion").get() } publishPlugin { dependsOn(patchChangelog) } } intellijPlatformTesting { runIde { register("runIdeForUiTests") { task { jvmArgumentProviders += CommandLineArgumentProvider { listOf( "-Drobot-server.port=8082", "-Dide.mac.message.dialogs.as.sheets=false", "-Djb.privacy.policy.text=<!--999.999-->", "-Djb.consents.confirmation.enabled=false", ) } } plugins { robotServerPlugin() } } } } ``` -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gschrader/openinrunconfig/actions/RunWithFilePathAction.kt: -------------------------------------------------------------------------------- ```kotlin package com.github.gschrader.openinrunconfig.actions import com.github.gschrader.openinrunconfig.MyBundle import com.intellij.execution.CommonProgramRunConfigurationParameters import com.intellij.execution.ProgramRunnerUtil import com.intellij.execution.RunManager import com.intellij.execution.application.ApplicationConfiguration import com.intellij.execution.configurations.RunConfiguration import com.intellij.execution.executors.DefaultRunExecutor import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.project.Project import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.openapi.vfs.VirtualFile import javax.swing.Icon class RunWithFilePathAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return val virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return val runManager = RunManager.getInstance(project) val allSettings = runManager.allSettings val configurations = allSettings .filter { (it.configuration.type.id == "Application" || it.configuration.type.id == "JetRunConfigurationType") && !it.isTemporary } .map { it.configuration } if (configurations.isEmpty()) { Messages.showInfoMessage( project, MyBundle.message("noConfigurationsAvailable"), MyBundle.message("runWithFilePath") ) return } val popup = JBPopupFactory.getInstance().createListPopup( ConfigurationListPopupStep(configurations, virtualFile, project) ) popup.showInBestPositionFor(e.dataContext) } override fun update(e: AnActionEvent) { val project = e.project val virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) // Enable action only if we have a project e.presentation.isEnabledAndVisible = project != null && virtualFile != null } override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT private class ConfigurationListPopupStep( private val configurations: List<RunConfiguration>, private val virtualFile: VirtualFile, private val project: Project ) : BaseListPopupStep<RunConfiguration>(MyBundle.message("selectConfiguration"), configurations) { override fun getTextFor(value: RunConfiguration): String = value.name override fun getIconFor(value: RunConfiguration): Icon? = value.icon override fun onChosen(selectedValue: RunConfiguration, finalChoice: Boolean): PopupStep<*>? { if (finalChoice) { runConfigurationWithFilePath(selectedValue, virtualFile, project) } return PopupStep.FINAL_CHOICE } private fun runConfigurationWithFilePath(configuration: RunConfiguration, file: VirtualFile, project: Project) { val runManager = RunManager.getInstance(project) try { // Create a temporary copy of the configuration val factory = configuration.factory ?: run { Messages.showErrorDialog( project, MyBundle.message("configurationNotSupported", configuration.name), MyBundle.message("runWithFilePath") ) return } val tempSettings = runManager.createConfiguration( "${configuration.name} (with ${file.name})", factory ) val tempConfiguration = tempSettings.configuration // Copy settings from original configuration to temporary one copyConfigurationSettings(configuration, tempConfiguration) // Add the file path as a program argument to the temporary configuration val filePath = file.path val success = addProgramArgument(tempConfiguration, filePath) if (!success) { Messages.showWarningDialog( project, MyBundle.message("configurationNotSupported", configuration.name), MyBundle.message("runWithFilePath") ) return } // Set the configuration as temporary tempSettings.isTemporary = true // Add the temporary configuration to the run manager so it persists runManager.addConfiguration(tempSettings) // Set it as the selected configuration runManager.selectedConfiguration = tempSettings // Execute the temporary configuration val executor = DefaultRunExecutor.getRunExecutorInstance() ProgramRunnerUtil.executeConfiguration(tempSettings, executor) } catch (e: Exception) { Messages.showErrorDialog( project, MyBundle.message("executionError", e.message ?: "Unknown error"), MyBundle.message("runWithFilePath") ) } } private fun copyConfigurationSettings(source: RunConfiguration, target: RunConfiguration) { if (source is ApplicationConfiguration && target is ApplicationConfiguration) { target.programParameters = source.programParameters target.workingDirectory = source.workingDirectory target.mainClassName = source.mainClassName target.envs = HashMap(source.envs) target.isPassParentEnvs = source.isPassParentEnvs target.configurationModule.module = source.configurationModule.module } } private fun addProgramArgument(configuration: RunConfiguration, argument: String): Boolean { if (configuration is CommonProgramRunConfigurationParameters) { val currentParams = configuration.programParameters val newParams = if (currentParams.isNullOrEmpty()) { "\"$argument\"" } else { "$currentParams \"$argument\"" } configuration.programParameters = newParams return true } return false } } } ``` -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- ```yaml # GitHub Actions Workflow is created for testing and preparing the plugin release in the following steps: # - Validate Gradle Wrapper. # - Run 'test' and 'verifyPlugin' tasks. # - Run Qodana inspections. # - Run the 'buildPlugin' task and prepare artifact for further tests. # - Run the 'runPluginVerifier' task. # - Create a draft release. # # The workflow is triggered on push and pull_request events. # # GitHub Actions reference: https://help.github.com/en/actions # ## JBIJPPTPL name: Build on: # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g., for dependabot pull requests) push: branches: [ main ] # Trigger the workflow on any pull request pull_request: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: # Prepare environment and build the plugin build: name: Build runs-on: ubuntu-latest outputs: version: ${{ steps.properties.outputs.version }} changelog: ${{ steps.properties.outputs.changelog }} pluginVerifierHomeDir: ${{ steps.properties.outputs.pluginVerifierHomeDir }} steps: # Free GitHub Actions Environment Disk Space - name: Maximize Build Space # jlumbroso/[email protected]: uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: false large-packages: false # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Setup Gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 # Set environment variables - name: Export Properties id: properties shell: bash run: | PROPERTIES="$(./gradlew properties --console=plain -q)" VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" echo "version=$VERSION" >> $GITHUB_OUTPUT echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT echo "changelog<<EOF" >> $GITHUB_OUTPUT echo "$CHANGELOG" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT # Build plugin - name: Build plugin run: ./gradlew buildPlugin # Prepare plugin archive content for creating artifact - name: Prepare Plugin Artifact id: artifact shell: bash run: | cd ${{ github.workspace }}/build/distributions FILENAME=`ls *.zip` unzip "$FILENAME" -d content echo "filename=${FILENAME:0:-4}" >> $GITHUB_OUTPUT # Store already-built plugin as an artifact for downloading - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ steps.artifact.outputs.filename }} path: ./build/distributions/content/*/* # Run tests and upload a code coverage report test: name: Test needs: [ build ] runs-on: ubuntu-latest steps: # Free GitHub Actions Environment Disk Space - name: Maximize Build Space uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: false large-packages: false # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Setup Gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 # Run tests - name: Run Tests run: ./gradlew check # Collect Tests Result of failed tests - name: Collect Tests Result if: ${{ failure() }} uses: actions/upload-artifact@v4 with: name: tests-result path: ${{ github.workspace }}/build/reports/tests # Upload the Kover report to CodeCov - name: Upload Code Coverage Report uses: codecov/codecov-action@v5 with: files: ${{ github.workspace }}/build/reports/kover/report.xml # Run Qodana inspections and provide report inspectCode: name: Inspect code needs: [ build ] runs-on: ubuntu-latest permissions: contents: write checks: write pull-requests: write steps: # Free GitHub Actions Environment Disk Space - name: Maximize Build Space uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: false large-packages: false # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit fetch-depth: 0 # a full history is required for pull request analysis # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Run Qodana inspections - name: Qodana - Code Inspection uses: JetBrains/[email protected] with: cache-default-branch-only: true # Run plugin structure verification along with IntelliJ Plugin Verifier verify: name: Verify plugin needs: [ build ] runs-on: ubuntu-latest steps: # Free GitHub Actions Environment Disk Space - name: Maximize Build Space uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: tool-cache: false large-packages: false # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 # Set up Java environment for the next steps - name: Setup Java uses: actions/setup-java@v4 with: distribution: zulu java-version: 21 # Setup Gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 # Cache Plugin Verifier IDEs - name: Setup Plugin Verifier IDEs Cache uses: actions/cache@v4 with: path: ${{ needs.build.outputs.pluginVerifierHomeDir }}/ides key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} # Run Verify Plugin task and IntelliJ Plugin Verifier tool - name: Run Plugin Verification tasks run: ./gradlew verifyPlugin -Dplugin.verifier.home.dir=${{ needs.build.outputs.pluginVerifierHomeDir }} # Collect Plugin Verifier Result - name: Collect Plugin Verifier Result if: ${{ always() }} uses: actions/upload-artifact@v4 with: name: pluginVerifier-result path: ${{ github.workspace }}/build/reports/pluginVerifier # Prepare a draft release for GitHub Releases page for the manual verification # If accepted and published, release workflow would be triggered releaseDraft: name: Release draft if: github.event_name != 'pull_request' needs: [ build, test, inspectCode, verify ] runs-on: ubuntu-latest permissions: contents: write steps: # Check out the current repository - name: Fetch Sources uses: actions/checkout@v4 # Remove old release drafts by using the curl request for the available releases with a draft flag - name: Remove Old Release Drafts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh api repos/{owner}/{repo}/releases \ --jq '.[] | select(.draft == true) | .id' \ | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} # Create a new release draft which is not publicly visible and requires manual acceptance - name: Create Release Draft env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release create "v${{ needs.build.outputs.version }}" \ --draft \ --title "v${{ needs.build.outputs.version }}" \ --notes "$(cat << 'EOM' ${{ needs.build.outputs.changelog }} EOM )" ```