├── .gitignore ├── GITFLOW_VERSION.md ├── ISSUE_TEMPLATE.md ├── LICENSE.txt ├── README.md ├── build.gradle.kts ├── docs ├── img │ ├── gitflow.png │ ├── import_options.png │ ├── import_project.png │ └── run_configuration.png └── project_setup.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src └── main ├── java └── gitflow │ ├── DefaultOptions.java │ ├── GitInitLineHandler.java │ ├── Gitflow.java │ ├── GitflowBranchUtil.java │ ├── GitflowBranchUtilManager.java │ ├── GitflowComponent.java │ ├── GitflowConfigUtil.java │ ├── GitflowConfigurable.java │ ├── GitflowImpl.java │ ├── GitflowInitOptions.java │ ├── GitflowMenu.java │ ├── GitflowOptionsFactory.java │ ├── GitflowState.java │ ├── GitflowVersionTester.java │ ├── IDEAUtils.java │ ├── JSONUtils.java │ ├── actions │ ├── AbstractBranchAction.java │ ├── AbstractPublishAction.java │ ├── AbstractStartAction.java │ ├── AbstractTrackAction.java │ ├── FinishBugfixAction.java │ ├── FinishFeatureAction.java │ ├── FinishHotfixAction.java │ ├── FinishReleaseAction.java │ ├── GitflowAction.java │ ├── GitflowActions.java │ ├── GitflowErrorsListener.java │ ├── GitflowLineHandler.java │ ├── GitflowPopupGroup.java │ ├── InitRepoAction.java │ ├── OpenGitflowPopup.java │ ├── PublishBugfixAction.java │ ├── PublishFeatureAction.java │ ├── PublishHotfixAction.java │ ├── PublishReleaseAction.java │ ├── ReInitRepoAction.java │ ├── RepoActions.java │ ├── StartBugfixAction.java │ ├── StartFeatureAction.java │ ├── StartHotfixAction.java │ ├── StartReleaseAction.java │ ├── TrackBugfixAction.java │ ├── TrackFeatureAction.java │ └── TrackReleaseAction.java │ └── ui │ ├── AbstractBranchStartDialog.form │ ├── AbstractBranchStartDialog.java │ ├── AbstractGitflowActionAckDialog.form │ ├── AbstractGitflowActionAckDialog.java │ ├── GitflowBranchChooseDialog.form │ ├── GitflowBranchChooseDialog.java │ ├── GitflowCloseTaskPanel.form │ ├── GitflowCloseTaskPanel.java │ ├── GitflowFinishActionAckDialog.java │ ├── GitflowInitOptionsDialog.form │ ├── GitflowInitOptionsDialog.java │ ├── GitflowOpenTaskPanel.form │ ├── GitflowOpenTaskPanel.java │ ├── GitflowOptionsForm.form │ ├── GitflowOptionsForm.java │ ├── GitflowPublishActionAckDialog.java │ ├── GitflowStartBugfixDialog.java │ ├── GitflowStartFeatureDialog.java │ ├── GitflowStartHotfixDialog.java │ ├── GitflowStatusBarWidgetFactory.java │ ├── GitflowTaskDialogPanelProvider.java │ ├── GitflowWidget.java │ ├── NotifyUtil.java │ └── UnsupportedVersionWidgetPresentation.java └── resources └── META-INF └── plugin.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | ### Gradle template 4 | .gradle 5 | /build/ 6 | 7 | # Ignore Gradle GUI config 8 | gradle-app.setting 9 | 10 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 11 | !gradle-wrapper.jar 12 | 13 | # Cache of project 14 | .gradletasknamecache 15 | 16 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 17 | # gradle/wrapper/gradle-wrapper.properties 18 | 19 | ### Java template 20 | # Compiled class file 21 | *.class 22 | 23 | # Log file 24 | *.log 25 | 26 | # BlueJ files 27 | *.ctxt 28 | 29 | # Mobile Tools for Java (J2ME) 30 | .mtj.tmp/ 31 | 32 | # Package Files # 33 | *.jar 34 | *.war 35 | *.nar 36 | *.ear 37 | *.zip 38 | *.tar.gz 39 | *.rar 40 | 41 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 42 | hs_err_pid* 43 | 44 | ### JetBrains template 45 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 46 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 47 | 48 | # User-specific stuff 49 | .idea/**/workspace.xml 50 | .idea/**/tasks.xml 51 | .idea/**/dictionaries 52 | .idea/**/shelf 53 | .idea/**/hotswap_agent.xml 54 | .idea/**/misc.xml 55 | .idea/**/checkstyle-idea.xml 56 | 57 | # Sensitive or high-churn files 58 | .idea/**/dataSources/ 59 | .idea/**/dataSources.ids 60 | .idea/**/dataSources.local.xml 61 | .idea/**/sqlDataSources.xml 62 | .idea/**/dynamic.xml 63 | .idea/**/uiDesigner.xml 64 | .idea/**/dbnavigator.xml 65 | 66 | .idea/**/gradle.xml 67 | .idea/**/libraries 68 | .idea/**/modules.xml 69 | **/*.iml 70 | .idea/libraries/**/*.xml 71 | 72 | # CMake 73 | cmake-build-debug/ 74 | cmake-build-release/ 75 | 76 | # Mongo Explorer plugin 77 | .idea/**/mongoSettings.xml 78 | 79 | # File-based project format 80 | *.iws 81 | 82 | # IntelliJ 83 | out/ 84 | 85 | # mpeltonen/sbt-idea plugin 86 | .idea_modules/ 87 | 88 | # JIRA plugin 89 | atlassian-ide-plugin.xml 90 | 91 | # Cursive Clojure plugin 92 | .idea/replstate.xml 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | # Editor-based Rest Client 101 | .idea/httpRequests 102 | 103 | # GitEye project file 104 | /.project 105 | 106 | .idea -------------------------------------------------------------------------------- /GITFLOW_VERSION.md: -------------------------------------------------------------------------------- 1 | The plugin requires that you have gitflow installed, specifically the [AVH edition](https://github.com/petervanderdoes/gitflow). This is because the [Vanilla Git Flow](https://github.com/nvie/gitflow) hasn't been maintained in years 2 | 3 | **How to check Git Flow version** 4 | 5 | run `git flow version` 6 | 7 | If it says `0.4.1` then you have the wrong version. You will have to uninstall it and then refer to [AVH edition](https://github.com/petervanderdoes/gitflow) docs for installation. 8 | 9 | 10 | **How to uninstall wrong version on OSX** 11 | 12 | If installed via `brew` then run `brew uninstall git-flow` 13 | 14 | 15 | **Mac/Linux users:** 16 | 17 | If you're running into issues like getting 18 | `Gitflow is not installed` 19 | or 20 | `git: 'flow' is not a git command. See 'git --help'.` 21 | 22 | Please be sure to check out [this thread](https://github.com/OpherV/gitflow4idea/issues/7) 23 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * **I'm submitting a ...** 2 | - [ ] bug report 3 | - [ ] feature request 4 | - [ ] puppy => You're not submitting a puppy. I already have one and he's [adorable](https://twitter.com/Opherv/status/974341249099542528) 5 | 6 | 7 | * **What is the current behavior?** 8 | 9 | 10 | 11 | * **Is this a bug? Sorry about that. If so give me explicit details how to reproduce:** 12 | 13 | 1. Open IntelliJ 14 | 2. ??? 15 | 3. Profit 16 | 17 | * **What is the expected behavior?** 18 | 19 | 20 | 21 | * **What is the motivation / use case for changing the behavior?** 22 | 23 | * **Please tell me about your environment:** 24 | 25 | - Gitflow4idea version: *find in IntelliJ settings plugins* 26 | - Gitflow version: run in terminal `>git flow version` 27 | 28 | - *IntelliJ Help -> about > click copy icon and paste here. Should look like this:* 29 | ~~~~ 30 | IntelliJ IDEA 2018.1.1 EAP (Community Edition) 31 | Build #IC-181.4445.4, built on March 29, 2018 32 | JRE: 1.8.0_152-release-1136-b27 x86_64 33 | JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o 34 | ~~~~ 35 | 36 | 37 | 38 | * **Other information** (e.g. detailed explanation, stacktrace, related issues, suggestions how to fix, links for me to have context words of praises, pictures of puppies (again with the puppy??) ) 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Flow Integration Plus for Intellij 2 | 3 | ### Available @ [JetBrains Plugins Repository][1] 4 | 5 | 6 | An intelliJ plugin providing a UI layer for git-flow, which in itself is a collection of Git extensions to provide high-level repository operations for Vincent [Driessen's branching model](http://nvie.com/git-model). 7 | 8 | ![screenshot](https://github.com/RubinCarter/gitflow4idea-fix/blob/develop/docs/img/gitflow.png) 9 | 10 | 11 | 12 | ## Getting started 13 | 14 | For the best introduction to get started with `git flow`, please read Jeff Kreeftmeijer's blog post: 15 | 16 | [http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/) 17 | 18 | Or have a look at this [cheat sheet](http://danielkummer.github.io/git-flow-cheatsheet/) by Daniel Kummer: 19 | 20 | Huge shoutout [to Kirill Likhodedov](https://github.com/klikh), who wrote much of the original git4idea plugin, without which this plugin could not exist 21 | 22 | ## Online Installation 23 | 24 | The plugin is available via the IntelliJ plugin manager. Just search for "Git Flow Integration Plus" to get the latest version! 25 | 26 | **The plugin requires that you have gitflow installed, specifically the [AVH edition](https://github.com/petervanderdoes/gitflow). This is because the [Vanilla Git Flow](https://github.com/nvie/gitflow) hasn't been maintained in years.** See this page [for details](https://github.com/RubinCarter/gitflow4idea-fix/blob/develop/GITFLOW_VERSION.md) 27 | 28 | ## Offline Installation 29 | download path: https://github.com/RubinCarter/gitflow4idea-fix/releases 30 | 31 | Installation document:https://www.jetbrains.com/help/idea/managing-plugins.html#install_plugin_from_disk 32 | 33 | **The plugin requires that you have gitflow installed, specifically the [AVH edition](https://github.com/petervanderdoes/gitflow). This is because the [Vanilla Git Flow](https://github.com/nvie/gitflow) hasn't been maintained in years.** See this page [for details](https://github.com/RubinCarter/gitflow4idea-fix/blob/develop/GITFLOW_VERSION.md) 34 | 35 | ## Caveats 36 | 37 | While the plugin is operational and contains all basic functions (init/feature/release/hotfix), it may contains bugs. With your help I'll be able to find and zap them all. 38 | 39 | ## Helping out 40 | 41 | This project is under active development. 42 | If you encounter any bug or an issue, I encourage you to add the them to the [Issues list](https://github.com/RubinCarter/gitflow4idea-fix/issues) on Github. 43 | Feedback and suggestions are also very welcome. 44 | 45 | ## License 46 | 47 | This plugin is under the [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html). 48 | Copyright 2013-2020, Opher Vishnia. 49 | 50 | ## Who and why 51 | 52 | This plugin was created by [Opher Vishnia](http://www.opherv.com), after I couldn't find any similar implementation. 53 | I saw this [suggestion page](http://youtrack.jetbrains.com/issue/IDEA-65491) on the JetBrains site has more than 220 likes and 80 comments, and decided to take up the gauntlet :) 54 | 55 | This plugin is forked from original https://github.com/OpherV/gitflow4idea . 56 | 57 | 58 | 59 | [1]: https://plugins.jetbrains.com/plugin/18320-git-flow-integration-plus 60 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("org.jetbrains.intellij") version "1.14.2" 4 | } 5 | 6 | repositories { 7 | mavenLocal() 8 | mavenCentral() 9 | } 10 | 11 | group = "gitflow4idea-plus" 12 | version = "0.8.0" 13 | 14 | java { 15 | sourceCompatibility = JavaVersion.VERSION_17 16 | targetCompatibility = JavaVersion.VERSION_17 17 | } 18 | 19 | dependencies { 20 | testImplementation("junit:junit:4.13.2") 21 | } 22 | 23 | intellij { 24 | version.set("2023.1") 25 | plugins.set(listOf("Git4Idea", "tasks")) 26 | updateSinceUntilBuild.set(false) 27 | } 28 | 29 | tasks { 30 | patchPluginXml { 31 | pluginId.set("Gitflow-Fix") 32 | pluginDescription.set(""" 33 |

Git Flow Integration for Intellij

34 | An intelliJ plugin providing a UI layer for git-flow, which in itself is a collection of Git extensions to provide high-level repository operations for Vincent Driessen's branching model 35 | """) 36 | version.set("${project.version}") 37 | sinceBuild.set("231.8109.175") 38 | changeNotes.set(""" 39 |

Changelog for 0.7.13

40 | 43 | 44 |

Changelog for 0.7.11

45 | 48 | 49 |

Changelog for 0.7.10

50 | 53 | 54 |

Changelog for 0.7.9

55 | 58 | 59 |

Changelog for 0.7.8

60 | 63 | 64 |

Changelog for 0.7.7

65 | 69 | 70 |

Changelog for 0.7.6

71 | 76 | 77 |

Changelog for 0.7.5

78 | 82 | 83 |

Changelog for 0.7.4

84 | 88 | 89 |

Changelog for 0.7.3

90 | 96 | 97 |

Changelog for 0.7.2

98 | 104 | 105 |

Changelog for 0.7.1

106 | 113 | 114 |

Changelog for 0.7.0

115 | 122 | 123 |

Changelog for 0.6.9

124 | 130 | 131 |

Changelog for 0.6.8

132 | 136 | 137 |

Note - if you see 'no gitflow' in the status bar you will need to re-init using git flow init -f

138 | """) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /docs/img/gitflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubinCarter/gitflow4idea-plus/30a4425426a5ce4bbdbca62eef42a984d3bf8509/docs/img/gitflow.png -------------------------------------------------------------------------------- /docs/img/import_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubinCarter/gitflow4idea-plus/30a4425426a5ce4bbdbca62eef42a984d3bf8509/docs/img/import_options.png -------------------------------------------------------------------------------- /docs/img/import_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubinCarter/gitflow4idea-plus/30a4425426a5ce4bbdbca62eef42a984d3bf8509/docs/img/import_project.png -------------------------------------------------------------------------------- /docs/img/run_configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubinCarter/gitflow4idea-plus/30a4425426a5ce4bbdbca62eef42a984d3bf8509/docs/img/run_configuration.png -------------------------------------------------------------------------------- /docs/project_setup.md: -------------------------------------------------------------------------------- 1 | # Setup Guide 2 | This document shall assist you in setting up the development project in IntelliJ IDEA. There are two ways of setting up the project: 3 | 1. Gradle Setup 4 | 2. "Classic" Setup 5 | 6 | ## Gradle Setup 7 | 8 | ### Prerequisites 9 | - The environment variable `JAVA_HOME` is set to a valid Java environment. 10 | - The *Gradle* plugin is enable in IntelliJ IDEA. 11 | 12 | ### Setup Steps 13 | 1. Fork the original repository and checkout the fork. 14 | 2. Import the project into IntelliJ IDEA. 15 | 3. Choose *"Import from external model" > Gradle*. 16 | 4. Set the following options in the import dialog: 17 | - *Use Auto Import* 18 | - *Create directories for empty content roots automatically* 19 | - *Use default gradle wrapper (recommended)* 20 | 21 | ![Import project dialog](./img/import_project.png?raw=true "Import Project Dialog") 22 | ![Import options dialog](./img/import_options.png?raw=true "Import Options Dialog") 23 | 24 | ### Run Configuration 25 | Add a new run configuration of type *Gradle* with the following settings: 26 | - Set the current project as *Gradle project* 27 | - In *Tasks* enter `runIde`. 28 | 29 | This should give you a basic run configuration which will start a new IntelliJ instance with the plugin deployed. 30 | 31 | ![Run configuration dialog](./img/run_configuration.png?raw=true "Run Configuration") 32 | 33 | ## "Classic" Setup 34 | 35 | ### 1. Make sure the plugin development plugin is enabled 36 | 37 | Start IDEA, go to *Settings -> Plugins* and make sure that `Plugin DevKit` is installed and enabled. 38 | If it's not, install it now. 39 | 40 | ### 2. Clone the project from GitHub 41 | 42 | Typically you check out your fork of the project on GitHub here. 43 | 44 | ### 3. Import the project into IDEA 45 | 46 | Select the *Import Project* option (e.g. by pressing shift twice and entering "import project") 47 | and navigate to the cloned repository directory when prompted. 48 | 49 | #### Model 50 | 51 | Chose "From existing sources" when prompted for a model. 52 | 53 | #### SDK Setup 54 | 55 | If you dont have a plugin SDK yet, click `+` to add an SDK and select *IntelliJ Platform Plugin SDK* 56 | 57 | 1. Navigate to your IDEA installation and select the installation directory. 58 | 2. Afterwards select a JDK when prompted 59 | 60 | Select your plugin SDK as the one to use. 61 | 62 | #### Other 63 | 64 | The remaining options can be left at default 65 | 66 | ### 4. Change the project type 67 | 68 | Open the projects iml file (it should be named `gitflow4idea.iml` by default) and replace its contents with this: 69 | 70 | ```xml 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ``` 83 | 84 | Then close and reopen the project to apply the changes. 85 | 86 | ### 5. Add git4idea dependency 87 | 88 | 1. Open the module settings and navigate to *Modules -> gitflow4idea (or your project name here)* and select the *Dependencies* tab. 89 | 2. Click add -> "JARs or directories" and add `git4idea.jar`. 90 | This can be found in your IDEA installation directory under `plugins/git4idea/lib`. 91 | 3. Change the scope of the added JAR to **provided**. 92 | 93 | ### 6. Create a run configuration 94 | 95 | Go to Run/Debug configurations and create a new configuration of the type `Plugin`. Under "Use classpath of module" select the project (`gitflow4idea` by default). 96 | Click run. A new IDEA instance should start with the plugin running. 97 | 98 | And that's it. You can now make changes to the source and run them. 99 | 100 | ### Notes & hints 101 | 102 | #### Language level 103 | 104 | This project is written to target Java 8, so make sure to set the project language level appropriately 105 | to avoid accidentally using newer features. You can do so in the module settings under "modules -> gitflow4idea -> sources -> Language level". 106 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubinCarter/gitflow4idea-plus/30a4425426a5ce4bbdbca62eef42a984d3bf8509/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/java/gitflow/DefaultOptions.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class DefaultOptions { 7 | private static final Map options; 8 | static 9 | { 10 | options = new HashMap(); 11 | options.put("RELEASE_customTagCommitMessage", "Tagging version %name%"); 12 | options.put("HOTFIX_customHotfixCommitMessage", "Tagging hotfix %name%"); 13 | } 14 | 15 | public static String getOption(String optionId){ 16 | return options.get(optionId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitInitLineHandler.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.execution.ExecutionException; 4 | import com.intellij.execution.configurations.GeneralCommandLine; 5 | import com.intellij.execution.process.OSProcessHandler; 6 | import com.intellij.execution.process.ProcessAdapter; 7 | import com.intellij.execution.process.ProcessEvent; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.util.Key; 10 | import com.intellij.openapi.util.registry.Registry; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import git4idea.commands.GitCommand; 13 | import git4idea.commands.GitLineHandler; 14 | import git4idea.commands.GitTextHandler; 15 | import git4idea.util.GitVcsConsoleWriter; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.annotations.Nullable; 18 | 19 | import java.io.BufferedWriter; 20 | import java.io.IOException; 21 | import java.io.OutputStreamWriter; 22 | 23 | 24 | public class GitInitLineHandler extends GitLineHandler { 25 | private final GitVcsConsoleWriter consoleWriter; 26 | 27 | private BufferedWriter writer; 28 | GitflowInitOptions _initOptions; 29 | 30 | public GitInitLineHandler(GitflowInitOptions initOptions, 31 | @NotNull Project project, @NotNull VirtualFile vcsRoot, 32 | @NotNull GitCommand command) { 33 | super(project, vcsRoot, command); 34 | consoleWriter = GitVcsConsoleWriter.getInstance(project); 35 | _initOptions = initOptions; 36 | } 37 | 38 | @Override 39 | protected OSProcessHandler createProcess(@NotNull GeneralCommandLine commandLine) throws ExecutionException { 40 | MyOSProcessHandler process = new MyOSProcessHandler(commandLine, this.myWithMediator && Registry.is("git.execute.with.mediator")); 41 | process.addProcessListener(new ProcessAdapter() { 42 | @Override 43 | public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { 44 | String s = event.getText(); 45 | GitInitLineHandler.this.onTextAvailable(s); 46 | } 47 | }); 48 | return process; 49 | } 50 | 51 | public void onTextAvailable(String s) { 52 | try { 53 | if (s.contains("name for production releases")) { 54 | consoleWriter.showCommandLine(_initOptions.getProductionBranch()); 55 | 56 | writer.write(_initOptions.getProductionBranch()); 57 | writer.write("\n"); 58 | writer.flush(); 59 | } 60 | 61 | if (s.contains("name for \"next release\"")) { 62 | consoleWriter.showCommandLine(_initOptions.getDevelopmentBranch()); 63 | 64 | writer.write(_initOptions.getDevelopmentBranch()); 65 | writer.write("\n"); 66 | writer.flush(); 67 | } 68 | 69 | if (s.contains("Feature branches")) { 70 | consoleWriter.showCommandLine(_initOptions.getFeaturePrefix()); 71 | 72 | writer.write(_initOptions.getFeaturePrefix()); 73 | writer.write("\n"); 74 | writer.flush(); 75 | } 76 | if (s.contains("Bugfix branches")) { 77 | consoleWriter.showCommandLine(_initOptions.getBugfixPrefix()); 78 | 79 | writer.write(_initOptions.getBugfixPrefix()); 80 | writer.write("\n"); 81 | writer.flush(); 82 | } 83 | if (s.contains("Release branches")) { 84 | consoleWriter.showCommandLine(_initOptions.getReleasePrefix()); 85 | 86 | writer.write(_initOptions.getReleasePrefix()); 87 | writer.write("\n"); 88 | writer.flush(); 89 | } 90 | if (s.contains("Hotfix branches")) { 91 | consoleWriter.showCommandLine(_initOptions.getHotfixPrefix()); 92 | 93 | writer.write(_initOptions.getHotfixPrefix()); 94 | writer.write("\n"); 95 | writer.flush(); 96 | } 97 | if (s.contains("Support branches")) { 98 | consoleWriter.showCommandLine(_initOptions.getSupportPrefix()); 99 | 100 | writer.write(_initOptions.getSupportPrefix()); 101 | writer.write("\n"); 102 | writer.flush(); 103 | } 104 | if (s.contains("Version tag")) { 105 | consoleWriter.showCommandLine(_initOptions.getVersionPrefix()); 106 | 107 | writer.write(_initOptions.getVersionPrefix()); 108 | writer.write("\n"); 109 | writer.flush(); 110 | } 111 | if (s.contains("Hooks and filters")) { 112 | writer.write("\n"); 113 | writer.flush(); 114 | } 115 | 116 | 117 | } catch (IOException e) { 118 | e.printStackTrace(); 119 | } 120 | } 121 | 122 | @Nullable 123 | @Override 124 | protected Process startProcess() throws ExecutionException { 125 | Process p = super.startProcess(); 126 | writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream())); 127 | return p; 128 | } 129 | 130 | @Override 131 | protected void processTerminated(int exitCode) { 132 | super.processTerminated(exitCode); 133 | } 134 | 135 | static class MyOSProcessHandler extends GitTextHandler.MyOSProcessHandler { 136 | MyOSProcessHandler(@NotNull GeneralCommandLine commandLine, 137 | boolean withMediator) throws ExecutionException { 138 | super(commandLine, withMediator); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/gitflow/Gitflow.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import git4idea.commands.Git; 5 | import git4idea.commands.GitCommandResult; 6 | import git4idea.commands.GitLineHandlerListener; 7 | import git4idea.repo.GitRemote; 8 | import git4idea.repo.GitRepository; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * @author Opher Vishnia / opherv.com / opherv@gmail.com 14 | */ 15 | public interface Gitflow extends Git { 16 | 17 | GitCommandResult initRepo(@NotNull GitRepository repository, 18 | GitflowInitOptions initOptions, 19 | @Nullable GitLineHandlerListener... listeners); 20 | 21 | GitCommandResult reInitRepo(@NotNull GitRepository repository, 22 | GitflowInitOptions initOptions, 23 | @Nullable GitLineHandlerListener... listeners); 24 | 25 | 26 | // feature 27 | 28 | GitCommandResult startFeature(@NotNull GitRepository repository, 29 | @NotNull String featureName, 30 | @Nullable String baseBranch, 31 | @Nullable GitLineHandlerListener... listeners); 32 | 33 | GitCommandResult finishFeature(@NotNull GitRepository repository, 34 | @NotNull String featureName, 35 | @Nullable GitLineHandlerListener... listeners); 36 | 37 | GitCommandResult publishFeature(@NotNull GitRepository repository, 38 | @NotNull String featureName, 39 | @Nullable GitLineHandlerListener... listeners); 40 | 41 | GitCommandResult pullFeature(@NotNull GitRepository repository, 42 | @NotNull String featureName, 43 | @NotNull GitRemote remote, 44 | @Nullable GitLineHandlerListener... listeners); 45 | 46 | GitCommandResult trackFeature(@NotNull GitRepository repository, 47 | @NotNull String featureName, 48 | @NotNull GitRemote remote, 49 | @Nullable GitLineHandlerListener... listeners); 50 | 51 | //release 52 | 53 | GitCommandResult startRelease(@NotNull GitRepository repository, 54 | @NotNull String releaseName, 55 | @Nullable GitLineHandlerListener... listeners); 56 | 57 | 58 | GitCommandResult finishRelease(@NotNull GitRepository repository, 59 | @NotNull String releaseName, 60 | @NotNull String tagMessage, 61 | @Nullable GitLineHandlerListener... listeners); 62 | 63 | 64 | GitCommandResult publishRelease(@NotNull GitRepository repository, 65 | @NotNull String releaseName, 66 | @Nullable GitLineHandlerListener... listeners); 67 | 68 | GitCommandResult trackRelease(@NotNull GitRepository repository, 69 | @NotNull String releaseName, 70 | @Nullable GitLineHandlerListener... listeners); 71 | 72 | //hotfix 73 | 74 | GitCommandResult startHotfix(@NotNull GitRepository repository, 75 | @NotNull String hotfixName, 76 | @Nullable String baseBranch, 77 | @Nullable GitLineHandlerListener... listeners); 78 | 79 | GitCommandResult finishHotfix(@NotNull GitRepository repository, 80 | @NotNull String hotfixName, 81 | @NotNull String tagMessage, 82 | @Nullable GitLineHandlerListener... listeners); 83 | 84 | GitCommandResult publishHotfix(@NotNull GitRepository repository, 85 | @NotNull String hotfixName, 86 | @Nullable GitLineHandlerListener... listeners); 87 | 88 | // Bugfix 89 | 90 | GitCommandResult startBugfix(@NotNull GitRepository repository, 91 | @NotNull String bugfixName, 92 | @Nullable String baseBranch, 93 | @Nullable GitLineHandlerListener... listeners); 94 | 95 | GitCommandResult finishBugfix(@NotNull GitRepository repository, 96 | @NotNull String bugfixName, 97 | @Nullable GitLineHandlerListener... listeners); 98 | 99 | GitCommandResult publishBugfix(@NotNull GitRepository repository, 100 | @NotNull String bugfixName, 101 | @Nullable GitLineHandlerListener... listeners); 102 | 103 | GitCommandResult pullBugfix(@NotNull GitRepository repository, 104 | @NotNull String bugfixName, 105 | @NotNull GitRemote remote, 106 | @Nullable GitLineHandlerListener... listeners); 107 | 108 | GitCommandResult trackBugfix(@NotNull GitRepository repository, 109 | @NotNull String bugfixName, 110 | @NotNull GitRemote remote, 111 | @Nullable GitLineHandlerListener... listeners); 112 | 113 | GitCommandResult version(@NotNull Project project, GitLineHandlerListener... listeners); 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowBranchUtilManager.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.Disposer; 5 | import git4idea.GitUtil; 6 | import git4idea.repo.GitRepository; 7 | 8 | import java.util.HashMap; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | /** 13 | * This class maps repos to their corresponding branch utils 14 | * Note that the static class is used across projects 15 | */ 16 | 17 | public class GitflowBranchUtilManager { 18 | private static HashMap repoBranchUtilMap; 19 | 20 | static public GitflowBranchUtil getBranchUtil(GitRepository repo){ 21 | if (repo != null && repoBranchUtilMap != null) { 22 | return repoBranchUtilMap.get(repo.getPresentableUrl()); 23 | } else { 24 | return null; 25 | } 26 | } 27 | 28 | static public void setupBranchUtil(Project project, GitRepository repo){ 29 | GitflowBranchUtil gitflowBranchUtil = new GitflowBranchUtil(project, repo); 30 | repoBranchUtilMap.put(repo.getPresentableUrl(), gitflowBranchUtil); 31 | // clean up 32 | Disposer.register(repo, () -> repoBranchUtilMap.remove(repo)); 33 | } 34 | 35 | /** 36 | * Repopulates the branchUtils for each repo 37 | * @param proj 38 | */ 39 | static public void update(Project proj){ 40 | if (repoBranchUtilMap == null){ 41 | repoBranchUtilMap = new HashMap(); 42 | } 43 | 44 | List gitRepositories = GitUtil.getRepositoryManager(proj).getRepositories(); 45 | for (GitRepository repo : gitRepositories) { 46 | GitflowBranchUtilManager.setupBranchUtil(proj, repo); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowComponent.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.Disposable; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.openapi.vcs.ProjectLevelVcsManager; 6 | import com.intellij.openapi.vcs.VcsListener; 7 | import com.intellij.openapi.vcs.VcsRoot; 8 | import com.intellij.openapi.wm.StatusBar; 9 | import com.intellij.openapi.wm.StatusBarWidget; 10 | import com.intellij.openapi.wm.WindowManager; 11 | import com.intellij.util.messages.MessageBus; 12 | import git4idea.GitVcs; 13 | import gitflow.ui.GitflowWidget; 14 | 15 | 16 | /** 17 | * @author Opher Vishnia / opherv.com / opherv@gmail.com 18 | * One instance per project 19 | */ 20 | public class GitflowComponent implements VcsListener, Disposable { 21 | Project myProject; 22 | GitflowWidget myGitflowWidget; 23 | MessageBus messageBus; 24 | 25 | public GitflowComponent(Project project) { 26 | myProject = project; 27 | messageBus = myProject.getMessageBus(); 28 | messageBus.connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, this); 29 | // Seems the event triggering this component happens after the directory mapping change 30 | directoryMappingChanged(); 31 | } 32 | 33 | @Override 34 | public void dispose() { 35 | // TODO: insert component disposal logic here 36 | } 37 | 38 | @Override 39 | public void directoryMappingChanged() { 40 | VcsRoot[] vcsRoots = ProjectLevelVcsManager.getInstance(myProject).getAllVcsRoots(); 41 | if (vcsRoots.length > 0 && vcsRoots[0].getVcs() instanceof GitVcs) { 42 | 43 | StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject); 44 | GitflowWidget widget = (GitflowWidget) statusBar.getWidget(GitflowWidget.class.getName()); 45 | if (widget != null) { 46 | widget.updateAsync(); 47 | } else { 48 | throw new NullPointerException("widget"); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowConfigUtil.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.Future; 5 | 6 | import com.intellij.openapi.application.ApplicationManager; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.util.Disposer; 9 | import com.intellij.openapi.vcs.VcsException; 10 | import com.intellij.openapi.vfs.VirtualFile; 11 | import git4idea.config.GitConfigUtil; 12 | import git4idea.repo.GitRepository; 13 | import gitflow.ui.NotifyUtil; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | /** 20 | * 21 | * 22 | * @author Opher Vishnia / opherv.com / opherv@gmail.com 23 | */ 24 | 25 | public class GitflowConfigUtil { 26 | 27 | public static final String BRANCH_MASTER = "gitflow.branch.master"; 28 | public static final String BRANCH_DEVELOP = "gitflow.branch.develop"; 29 | public static final String PREFIX_FEATURE = "gitflow.prefix.feature"; 30 | public static final String PREFIX_RELEASE = "gitflow.prefix.release"; 31 | public static final String PREFIX_HOTFIX = "gitflow.prefix.hotfix"; 32 | public static final String PREFIX_BUGFIX = "gitflow.prefix.bugfix"; 33 | public static final String PREFIX_SUPPORT = "gitflow.prefix.support"; 34 | public static final String PREFIX_VERSIONTAG = "gitflow.prefix.versiontag"; 35 | 36 | private static Map> gitflowConfigUtilMap = new HashMap>(); 37 | 38 | Project project; 39 | GitRepository repo; 40 | public String masterBranch; 41 | public String developBranch; 42 | public String featurePrefix; 43 | public String releasePrefix; 44 | public String hotfixPrefix; 45 | public String bugfixPrefix; 46 | public String supportPrefix; 47 | public String versiontagPrefix; 48 | 49 | public static GitflowConfigUtil getInstance(@NotNull Project project_, @NotNull GitRepository repo_) 50 | { 51 | GitflowConfigUtil instance; 52 | if (gitflowConfigUtilMap.containsKey(project_) && gitflowConfigUtilMap.get(project_).containsKey(repo_.getPresentableUrl())) { 53 | instance = gitflowConfigUtilMap.get(project_).get(repo_.getPresentableUrl()); 54 | } else { 55 | Map innerMap = new HashMap(); 56 | instance = new GitflowConfigUtil(project_, repo_); 57 | 58 | gitflowConfigUtilMap.put(project_, innerMap); 59 | innerMap.put(repo_.getPresentableUrl(), instance); 60 | 61 | //cleanup 62 | Disposer.register(repo_, () -> innerMap.remove(repo_)); 63 | Disposer.register(project_, () -> gitflowConfigUtilMap.remove(project_)); 64 | } 65 | 66 | return instance; 67 | } 68 | 69 | GitflowConfigUtil(Project project_, GitRepository repo_){ 70 | project = project_; 71 | repo = repo_; 72 | 73 | update(); 74 | } 75 | 76 | public void update(){ 77 | VirtualFile root = repo.getRoot(); 78 | 79 | try{ 80 | Future f = ApplicationManager.getApplication().executeOnPooledThread(() -> { 81 | try { 82 | masterBranch = GitConfigUtil.getValue(project, root, BRANCH_MASTER); 83 | developBranch = GitConfigUtil.getValue(project, root, BRANCH_DEVELOP); 84 | featurePrefix = GitConfigUtil.getValue(project, root, PREFIX_FEATURE); 85 | releasePrefix = GitConfigUtil.getValue(project, root, PREFIX_RELEASE); 86 | hotfixPrefix = GitConfigUtil.getValue(project, root, PREFIX_HOTFIX); 87 | bugfixPrefix = GitConfigUtil.getValue(project, root, PREFIX_BUGFIX); 88 | supportPrefix = GitConfigUtil.getValue(project, root, PREFIX_SUPPORT); 89 | versiontagPrefix = GitConfigUtil.getValue(project, root, PREFIX_VERSIONTAG); 90 | } catch (VcsException e) { 91 | NotifyUtil.notifyError(project, "Config error", e); 92 | } 93 | }); 94 | f.get(); 95 | 96 | } catch (InterruptedException e) { 97 | e.printStackTrace(); 98 | } catch (ExecutionException e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | 103 | 104 | public String getFeatureNameFromBranch(String branchName){ 105 | return branchName.substring(branchName.indexOf(featurePrefix)+featurePrefix.length(),branchName.length()); 106 | } 107 | 108 | public String getReleaseNameFromBranch(String branchName){ 109 | return branchName.substring(branchName.indexOf(releasePrefix) + releasePrefix.length(), branchName.length()); 110 | } 111 | 112 | public String getHotfixNameFromBranch(String branchName){ 113 | return branchName.substring(branchName.indexOf(hotfixPrefix) + hotfixPrefix.length(), branchName.length()); 114 | } 115 | 116 | public String getBugfixNameFromBranch(String branchName){ 117 | return branchName.substring(branchName.indexOf(bugfixPrefix)+bugfixPrefix.length(),branchName.length()); 118 | } 119 | 120 | public String getRemoteNameFromBranch(String branchName){ 121 | return branchName.substring(0,branchName.indexOf("/")); 122 | } 123 | 124 | public void setMasterBranch(String branchName) 125 | { 126 | masterBranch = branchName; 127 | VirtualFile root = repo.getRoot(); 128 | try { 129 | GitConfigUtil.setValue(project, root, BRANCH_MASTER, branchName); 130 | } catch (VcsException e) { 131 | NotifyUtil.notifyError(project, "Config error", e); 132 | } 133 | } 134 | 135 | public void setDevelopBranch(String branchName) { 136 | developBranch = branchName; 137 | VirtualFile root = repo.getRoot(); 138 | try { 139 | GitConfigUtil.setValue(project, root, BRANCH_DEVELOP, branchName); 140 | } catch (VcsException e) { 141 | NotifyUtil.notifyError(project, "Config error", e); 142 | } 143 | } 144 | 145 | public void setReleasePrefix(String prefix) { 146 | releasePrefix = prefix; 147 | VirtualFile root = repo.getRoot(); 148 | 149 | try { 150 | GitConfigUtil.setValue(project, root, PREFIX_RELEASE, prefix); 151 | } catch (VcsException e) { 152 | NotifyUtil.notifyError(project, "Config error", e); 153 | } 154 | } 155 | 156 | public void setFeaturePrefix(String prefix) { 157 | featurePrefix = prefix; 158 | VirtualFile root = repo.getRoot(); 159 | 160 | try { 161 | GitConfigUtil.setValue(project, root, PREFIX_FEATURE, prefix); 162 | } catch (VcsException e) { 163 | NotifyUtil.notifyError(project, "Config error", e); 164 | } 165 | } 166 | 167 | public void setHotfixPrefix(String prefix) { 168 | hotfixPrefix = prefix; 169 | VirtualFile root = repo.getRoot(); 170 | 171 | try { 172 | GitConfigUtil.setValue(project, root, PREFIX_HOTFIX, prefix); 173 | } catch (VcsException e) { 174 | NotifyUtil.notifyError(project, "Config error", e); 175 | } 176 | } 177 | 178 | public void setBugfixPrefix(String prefix) { 179 | bugfixPrefix = prefix; 180 | VirtualFile root = repo.getRoot(); 181 | 182 | try { 183 | GitConfigUtil.setValue(project, root, PREFIX_BUGFIX, prefix); 184 | } catch (VcsException e) { 185 | NotifyUtil.notifyError(project, "Config error", e); 186 | } 187 | } 188 | 189 | public void setSupportPrefix(String prefix) { 190 | supportPrefix = prefix; 191 | VirtualFile root = repo.getRoot(); 192 | 193 | try { 194 | GitConfigUtil.setValue(project, root, PREFIX_SUPPORT, prefix); 195 | } catch (VcsException e) { 196 | NotifyUtil.notifyError(project, "Config error", e); 197 | } 198 | } 199 | 200 | public void setVersionPrefix(String prefix) { 201 | versiontagPrefix = prefix; 202 | VirtualFile root = repo.getRoot(); 203 | 204 | try { 205 | GitConfigUtil.setValue(project, root, PREFIX_VERSIONTAG, prefix); 206 | } catch (VcsException e) { 207 | NotifyUtil.notifyError(project, "Config error", e); 208 | } 209 | } 210 | 211 | // this still reads from config because it always runs from an action and never from the EDT 212 | public String getBaseBranch(String branchName){ 213 | 214 | VirtualFile root = repo.getRoot(); 215 | 216 | String baseBranch=null; 217 | try{ 218 | baseBranch = GitConfigUtil.getValue(project, root, "gitflow.branch."+branchName+".base"); 219 | } 220 | catch (VcsException e) { 221 | NotifyUtil.notifyError(project, "Config error", e); 222 | } 223 | 224 | return baseBranch; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowConfigurable.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.ide.util.PropertiesComponent; 4 | import com.intellij.openapi.options.Configurable; 5 | import com.intellij.openapi.options.ConfigurationException; 6 | import com.intellij.openapi.project.Project; 7 | import gitflow.ui.GitflowOptionsForm; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.*; 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author Andreas Vogler (Andreas.Vogler@geneon.de) 17 | * @author Opher Vishnia (opherv@gmail.com) 18 | */ 19 | public class GitflowConfigurable implements Configurable { 20 | 21 | Project project; 22 | GitflowOptionsForm gitflowOptionsForm; 23 | PropertiesComponent propertiesComponent; 24 | Map, ArrayList>> gitflowOptions; 25 | Map optionDefaults; 26 | 27 | static GitflowConfigurable instance; 28 | 29 | public GitflowConfigurable(Project project) { 30 | gitflowOptions = GitflowOptionsFactory.getOptions(); 31 | propertiesComponent = PropertiesComponent.getInstance(project); 32 | optionDefaults = new HashMap(); 33 | this.project = project; 34 | instance = this; 35 | } 36 | 37 | static public GitflowConfigurable getInstance(){ 38 | return instance; 39 | } 40 | 41 | @Override 42 | public String getDisplayName() { 43 | return "Gitflow"; 44 | } 45 | 46 | @Nullable 47 | @Override 48 | public String getHelpTopic() { 49 | return null; 50 | } 51 | 52 | @Nullable 53 | @Override 54 | public JComponent createComponent() { 55 | gitflowOptionsForm = new GitflowOptionsForm(); 56 | return gitflowOptionsForm.getContentPane(); 57 | } 58 | 59 | public static boolean isOptionActive(Project project, String optionId){ 60 | return PropertiesComponent.getInstance(project).getBoolean(optionId+"_active"); 61 | } 62 | 63 | public static String getOptionTextString (Project project, String optionId){ 64 | String retValue = PropertiesComponent.getInstance(project).getValue(optionId+"_text"); 65 | if (retValue == null){ 66 | retValue = DefaultOptions.getOption(optionId); 67 | } 68 | return retValue; 69 | } 70 | 71 | @Override 72 | public boolean isModified() { 73 | // iterate over branch types (feature/release/hotfix/bugfix) 74 | for (GitflowOptionsFactory.TYPE type: GitflowOptionsFactory.TYPE.values()) { 75 | for (Map optionMap : gitflowOptions.get(type)) { 76 | String optionId = GitflowOptionsFactory.getOptionId(type, optionMap.get("key")); 77 | 78 | boolean isOptionActiveInForm = gitflowOptionsForm.isOptionActive(optionId); 79 | boolean savedOptionIsActive = propertiesComponent.getBoolean(optionId+"_active"); 80 | 81 | if (isOptionActiveInForm != savedOptionIsActive) return true; 82 | 83 | // option has text value 84 | if (optionMap.get("inputText") != null){ 85 | String textInForm = gitflowOptionsForm.getOptionText(optionId); 86 | String savedOptionText = propertiesComponent.getValue(optionId+"text"); 87 | if (textInForm.equals(savedOptionText) == false){ 88 | return true; 89 | } 90 | } 91 | 92 | } 93 | } 94 | 95 | return false; 96 | } 97 | 98 | @Override 99 | public void apply() throws ConfigurationException { 100 | // iterate over branch types (feature/release/hotfix/bugfix) 101 | for (GitflowOptionsFactory.TYPE type: GitflowOptionsFactory.TYPE.values()) { 102 | for (Map optionMap : gitflowOptions.get(type)) { 103 | String optionId = GitflowOptionsFactory.getOptionId(type, optionMap.get("key")); 104 | 105 | // set isActive value 106 | propertiesComponent.setValue(optionId+"_active", gitflowOptionsForm.isOptionActive(optionId)); 107 | 108 | // set text value, if relevant 109 | if (optionMap.get("inputText") != null){ 110 | propertiesComponent.setValue(optionId+"_text", gitflowOptionsForm.getOptionText(optionId)); 111 | } 112 | 113 | } 114 | } 115 | 116 | } 117 | 118 | @Override 119 | public void reset() { 120 | // iterate over branch types (feature/release/hotfix/bugfix) 121 | for (GitflowOptionsFactory.TYPE type: GitflowOptionsFactory.TYPE.values()) { 122 | for (Map optionMap : gitflowOptions.get(type)) { 123 | String optionId = GitflowOptionsFactory.getOptionId(type, optionMap.get("key")); 124 | boolean savedOptionIsActive = propertiesComponent.getBoolean(optionId+"_active"); 125 | gitflowOptionsForm.setOptionActive(optionId, savedOptionIsActive); 126 | 127 | // option has text value 128 | if (optionMap.get("inputText") != null){ 129 | String textInForm = gitflowOptionsForm.getOptionText(optionId); 130 | String savedOptionText = propertiesComponent.getValue(optionId+"text"); 131 | if (savedOptionText == null){ 132 | gitflowOptionsForm.setOptionText(optionId, optionMap.get("inputText")); 133 | } 134 | else{ 135 | gitflowOptionsForm.setOptionText(optionId, savedOptionText); 136 | } 137 | 138 | } 139 | 140 | } 141 | } 142 | gitflowOptionsForm.updateFormDisabledStatus(); 143 | } 144 | 145 | @Override 146 | public void disposeUIResources() { 147 | gitflowOptionsForm = null; 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowInitOptions.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | /** 4 | * @author Andreas Vogler (Andreas.Vogler@geneon.de) 5 | */ 6 | public class GitflowInitOptions { 7 | private boolean useDefaults; 8 | private String productionBranch; 9 | private String developmentBranch; 10 | private String featurePrefix; 11 | private String releasePrefix; 12 | private String hotfixPrefix; 13 | private String bugfixPrefix; 14 | private String supportPrefix; 15 | private String versionPrefix; 16 | 17 | public boolean isUseDefaults() { 18 | return useDefaults; 19 | } 20 | 21 | public void setUseDefaults(boolean useDefaults) { 22 | this.useDefaults = useDefaults; 23 | } 24 | 25 | public String getProductionBranch() { 26 | return productionBranch; 27 | } 28 | 29 | public void setProductionBranch(String productionBranch) { 30 | this.productionBranch = productionBranch; 31 | } 32 | 33 | public String getDevelopmentBranch() { 34 | return developmentBranch; 35 | } 36 | 37 | public void setDevelopmentBranch(String developmentBranch) { 38 | this.developmentBranch = developmentBranch; 39 | } 40 | 41 | public String getFeaturePrefix() { 42 | return featurePrefix; 43 | } 44 | 45 | public void setFeaturePrefix(String featurePrefix) { 46 | this.featurePrefix = featurePrefix; 47 | } 48 | 49 | public String getReleasePrefix() { 50 | return releasePrefix; 51 | } 52 | 53 | public void setReleasePrefix(String releasePrefix) { 54 | this.releasePrefix = releasePrefix; 55 | } 56 | 57 | public String getHotfixPrefix() { 58 | return hotfixPrefix; 59 | } 60 | 61 | public void setHotfixPrefix(String hotfixPrefix) { 62 | this.hotfixPrefix = hotfixPrefix; 63 | } 64 | 65 | public String getSupportPrefix() { 66 | return supportPrefix; 67 | } 68 | 69 | public void setSupportPrefix(String supportPrefix) { 70 | this.supportPrefix = supportPrefix; 71 | } 72 | 73 | public String getBugfixPrefix() { 74 | return bugfixPrefix; 75 | } 76 | 77 | public void setBugfixPrefix(String bugfixPrefix) { 78 | this.bugfixPrefix = bugfixPrefix; 79 | } 80 | 81 | public String getVersionPrefix() { 82 | return versionPrefix; 83 | } 84 | 85 | public void setVersionPrefix(String versionPrefix) { 86 | this.versionPrefix = versionPrefix; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowMenu.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.actionSystem.ActionGroup; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.project.Project; 7 | import gitflow.actions.GitflowPopupGroup; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class GitflowMenu extends ActionGroup { 12 | public GitflowMenu() { 13 | super("Gitflow", true); 14 | } 15 | 16 | @NotNull 17 | @Override 18 | public AnAction[] getChildren(@Nullable AnActionEvent anActionEvent) { 19 | if (anActionEvent == null) { 20 | return new AnAction[0]; 21 | } 22 | 23 | Project project = anActionEvent.getProject(); 24 | if (project == null) { 25 | return new AnAction[0]; 26 | } 27 | 28 | GitflowPopupGroup popupGroup = new GitflowPopupGroup(project, true); 29 | 30 | return popupGroup.getActionGroup().getChildren(anActionEvent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowOptionsFactory.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class GitflowOptionsFactory { 10 | private static final GitflowOptionsFactory instance = new GitflowOptionsFactory(); 11 | private Map, ArrayList>> options; 12 | private HashMap> optionsMap; 13 | 14 | public enum TYPE { 15 | FEATURE, RELEASE, HOTFIX, BUGFIX 16 | } 17 | 18 | //private constructor to avoid client applications to use constructor 19 | private GitflowOptionsFactory(){ 20 | options = new HashMap, ArrayList>>(); 21 | optionsMap = new HashMap>(); 22 | 23 | addBranchType(TYPE.FEATURE); 24 | addOption(TYPE.FEATURE, "Fetch from Origin", "fetchFromOrigin" , "-F"); 25 | addOption(TYPE.FEATURE, "Keep Local", "keepLocal", "--keeplocal"); 26 | addOption(TYPE.FEATURE, "Keep Remote", "keepRemote", "--keepremote"); 27 | addOption(TYPE.FEATURE, "Keep branch after performing finish", "keepBranch" , "-k"); 28 | addOption(TYPE.FEATURE, "Do not fast-forward when merging, always create commit", "noFastForward" , "--no-ff"); 29 | addOption(TYPE.FEATURE, "Push on finish feature", "pushOnFinish" , "--push"); 30 | // addOption(TYPE.FEATURE, "Squash feature during merge", "squash" , "-S"); 31 | 32 | addBranchType(TYPE.RELEASE); 33 | addOption(TYPE.RELEASE, "Fetch from Origin", "fetchFromOrigin" , "-F"); 34 | addOption(TYPE.RELEASE, "Push on finish release", "pushOnFinish" , "-p"); 35 | addOption(TYPE.RELEASE, "Keep Local", "keepLocal", "--keeplocal"); 36 | addOption(TYPE.RELEASE, "Keep Remote", "keepRemote", "--keepremote"); 37 | addOption(TYPE.RELEASE, "Keep branch after performing finish", "keepBranch" , "-k"); 38 | // addOption(TYPE.RELEASE, "Squash release during merge", "squash" , "-S"); 39 | addOption(TYPE.RELEASE, "Don't tag release", "dontTag" , "-n"); 40 | addOption(TYPE.RELEASE, "Use custom tag commit message", "customTagCommitMessage" , null, DefaultOptions.getOption("RELEASE_customTagCommitMessage") ,"Use %name% for the branch name"); 41 | 42 | addBranchType(TYPE.HOTFIX); 43 | addOption(TYPE.HOTFIX, "Fetch from Origin", "fetchFromOrigin" , "-F"); 44 | addOption(TYPE.HOTFIX, "Keep branch after performing finish", "keepBranch" , "-k"); 45 | addOption(TYPE.HOTFIX, "Push on finish Hotfix", "pushOnFinish" , "-p"); 46 | addOption(TYPE.HOTFIX, "Don't tag Hotfix", "dontTag" , "-n"); 47 | addOption(TYPE.HOTFIX, "Use custom hotfix commit message", "customHotfixCommitMessage" , null, DefaultOptions.getOption("HOTFIX_customHotfixCommitMessage") ,"Use %name% for the branch name"); 48 | 49 | addBranchType(TYPE.BUGFIX); 50 | addOption(TYPE.BUGFIX, "Fetch from Origin", "fetchFromOrigin" , "-F"); 51 | addOption(TYPE.BUGFIX, "Keep Local", "keepLocal", "--keeplocal"); 52 | addOption(TYPE.BUGFIX, "Keep Remote", "keepRemote", "--keepremote"); 53 | addOption(TYPE.BUGFIX, "Keep branch after performing finish", "keepBranch" , "-k"); 54 | addOption(TYPE.BUGFIX, "Do not fast-forward when merging, always create commit", "noFastForward" , "--no-ff"); 55 | // addOption(TYPE.BUGFIX, "Squash feature during merge", "squash" , "-S"); 56 | } 57 | 58 | private void addBranchType(Enum branchType){ 59 | options.put(branchType, new ArrayList>()); 60 | } 61 | 62 | private void addOption(Enum branchType, String description, String key, @Nullable String flag){ 63 | addOption(branchType, description, key, flag, null, null); 64 | } 65 | 66 | private void addOption(Enum branchType, String description, String key, @Nullable String flag, @Nullable String inputText, @Nullable String toolTip){ 67 | HashMap optionMap = new HashMap(); 68 | optionMap.put("description", description); 69 | optionMap.put("key", key); 70 | if (flag != null){ 71 | optionMap.put("flag", flag); 72 | } 73 | if (inputText != null){ 74 | optionMap.put("inputText", inputText); 75 | } 76 | if (toolTip != null){ 77 | optionMap.put("toolTip", toolTip); 78 | } 79 | 80 | String optionId = getOptionId(branchType, key); 81 | optionMap.put("id", optionId); 82 | optionsMap.put(optionId, optionMap); 83 | 84 | options.get(branchType).add(optionMap); 85 | } 86 | 87 | public static Map, ArrayList>> getOptions(){ 88 | return instance.options; 89 | } 90 | 91 | public static String getOptionId(Enum branchType, String key){ 92 | return branchType+"_"+key; 93 | } 94 | 95 | public static HashMap getOptionById(String optionId){ 96 | return instance.optionsMap.get(optionId); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowState.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent; 4 | import com.intellij.openapi.components.State; 5 | import com.intellij.openapi.components.Storage; 6 | import com.intellij.tasks.Task; 7 | import com.intellij.util.xmlb.XmlSerializerUtil; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.HashMap; 11 | 12 | /** 13 | * Persistent state for Gitflow component 14 | * Created by opherv on 8/17/16. 15 | */ 16 | 17 | @State( 18 | name = "GitflowState", storages = { 19 | @Storage( 20 | file = "$APP_CONFIG$/GitflowState.xml") 21 | }) 22 | public class GitflowState implements PersistentStateComponent { 23 | 24 | private HashMap taskBranches; 25 | 26 | 27 | public GitflowState() { 28 | taskBranches = new HashMap(); 29 | } 30 | 31 | 32 | public HashMap getTaskBranches() { 33 | return taskBranches; 34 | } 35 | 36 | public void setTaskBranches(HashMap taskBranches) { 37 | this.taskBranches = taskBranches; 38 | } 39 | 40 | @Nullable 41 | @Override 42 | public GitflowState getState() { 43 | return this; 44 | } 45 | 46 | @Override 47 | public void loadState(GitflowState state) { 48 | XmlSerializerUtil.copyBean(state, this); 49 | 50 | } 51 | 52 | public String getTaskBranch(Task task){ 53 | return taskBranches.get(task.getId()); 54 | } 55 | 56 | 57 | public void setTaskBranch(Task task, String branchName){ 58 | taskBranches.put(task.getId(), branchName); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/gitflow/GitflowVersionTester.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.diagnostic.Logger; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.util.Disposer; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | //import javax.annotation.Nullable; 11 | import java.util.Map; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | public class GitflowVersionTester { 15 | 16 | private static final Logger logger = Logger.getInstance(GitflowVersionTester.class); 17 | 18 | private static final Map testers = new ConcurrentHashMap<>(); 19 | 20 | public static GitflowVersionTester forProject(@NotNull Project project) { 21 | return testers.computeIfAbsent( 22 | project, 23 | p -> { 24 | if(!p.isDisposed()) { 25 | Disposer.register(p, () -> testers.remove(p)); 26 | } 27 | return new GitflowVersionTester(ApplicationManager.getApplication().getService(Gitflow.class), p); 28 | } 29 | ); 30 | } 31 | 32 | @NotNull private final Gitflow gitflow; 33 | @NotNull private final Project project; 34 | 35 | private String version = null; 36 | 37 | private GitflowVersionTester(@NotNull Gitflow gitflow, @NotNull Project project) { 38 | this.gitflow = gitflow; 39 | this.project = project; 40 | } 41 | 42 | /** 43 | *

Returns the installed {@code git-flow} version. The version 44 | * is loaded on the first call to this method and is determined 45 | * by looking at the output of a {@code git flow version} command.

46 | *

If the command fails, {@code null} is returned.

47 | * 48 | * @return the {@code git flow} version, or {@code null} 49 | */ 50 | // @Nullable 51 | public String getVersion() { 52 | return version; 53 | } 54 | 55 | /** 56 | * Returns true if the {@code git flow} version can be determined 57 | * and is any AVH version ({@code #contains("AVH")}) and 58 | * not the unmaintained NVIE version. 59 | * 60 | * @return true if we think the git flow version is an AVH version. 61 | */ 62 | public boolean isSupportedVersion() { 63 | return version != null && version.contains("AVH"); 64 | } 65 | 66 | public void init(){ 67 | String returnedVersion = null; 68 | try { 69 | returnedVersion = gitflow.version(project).getOutputOrThrow(); 70 | logger.info("git flow version: " + version); 71 | } catch (Exception e) { 72 | logger.error("Could not determine git flow version", e); 73 | } 74 | if (returnedVersion != null){ 75 | version = returnedVersion; 76 | } 77 | } 78 | 79 | public boolean hasVersionBeenTested(){ 80 | return version != null; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/gitflow/IDEAUtils.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.project.ProjectManager; 5 | import com.intellij.openapi.wm.WindowManager; 6 | 7 | import java.awt.*; 8 | 9 | public class IDEAUtils { 10 | public static Project getActiveProject(){ 11 | Project[] projects = ProjectManager.getInstance().getOpenProjects(); 12 | Project activeProject = null; 13 | for (Project project : projects) { 14 | Window window = WindowManager.getInstance().suggestParentWindow(project); 15 | if (window != null && window.isActive()) { 16 | activeProject = project; 17 | } 18 | } 19 | return activeProject; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/gitflow/JSONUtils.java: -------------------------------------------------------------------------------- 1 | package gitflow; 2 | 3 | import com.intellij.json.psi.JsonObject; 4 | import com.intellij.json.psi.JsonProperty; 5 | import com.intellij.json.psi.JsonPsiUtil; 6 | import com.intellij.json.psi.JsonValue; 7 | import org.apache.commons.lang3.ObjectUtils; 8 | 9 | import java.util.Optional; 10 | 11 | /** 12 | * @author rubin 2022年01月12日 13 | */ 14 | public class JSONUtils { 15 | 16 | @SuppressWarnings("unchecked") 17 | public static T getValue(JsonObject obj, String property, Class clazz) { 18 | String valueStr = JsonPsiUtil.stripQuotes(Optional.ofNullable(obj.findProperty(property)).map(JsonProperty::getValue).map(JsonValue::getText).orElse("")); 19 | if(clazz == String.class) { 20 | return (T)valueStr; 21 | } else if(clazz == Boolean.class) { 22 | return (T)Boolean.valueOf(valueStr); 23 | } 24 | return (T)valueStr; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/AbstractBranchAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.ActionUpdateThread; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import git4idea.repo.GitRepository; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public abstract class AbstractBranchAction extends GitflowAction { 9 | enum BranchType { 10 | Feature, Release, Bugfix, Hotfix 11 | } 12 | 13 | BranchType type; 14 | 15 | AbstractBranchAction(String actionName, BranchType type) { 16 | super(actionName); 17 | this.type = type; 18 | } 19 | 20 | AbstractBranchAction(GitRepository repo, String actionName, BranchType type) { 21 | super(repo, actionName); 22 | this.type = type; 23 | } 24 | 25 | 26 | @Override 27 | public void update(@NotNull AnActionEvent e) { 28 | if (branchUtil == null) { 29 | e.getPresentation().setEnabledAndVisible(false); 30 | return; 31 | } 32 | 33 | //Disable and hide when gitflow has not been setup 34 | if (branchUtil.hasGitflow() == false) { 35 | e.getPresentation().setEnabledAndVisible(false); 36 | return; 37 | } 38 | 39 | //Disable and hide when the branch-type is incorrect 40 | if (isActionAllowedForBranch() == false) { 41 | e.getPresentation().setEnabledAndVisible(false); 42 | } else { 43 | e.getPresentation().setEnabledAndVisible(true); 44 | } 45 | } 46 | 47 | protected boolean isActionAllowedForBranch() { 48 | switch (type) { 49 | case Feature: 50 | return branchUtil.isCurrentBranchFeature(); 51 | case Release: 52 | return branchUtil.isCurrentBranchRelease(); 53 | case Bugfix: 54 | return branchUtil.isCurrentBranchBugfix(); 55 | case Hotfix: 56 | return branchUtil.isCurrentBranchHotfix(); 57 | default: 58 | return false; 59 | } 60 | } 61 | 62 | @Override 63 | public @NotNull ActionUpdateThread getActionUpdateThread() { 64 | return ActionUpdateThread.EDT; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/AbstractPublishAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import git4idea.repo.GitRepository; 4 | 5 | public abstract class AbstractPublishAction extends AbstractBranchAction { 6 | AbstractPublishAction(String actionName, BranchType type) { 7 | super(actionName, type); 8 | } 9 | 10 | AbstractPublishAction(GitRepository repo, String actionName, BranchType type) { 11 | super(repo, actionName, type); 12 | } 13 | 14 | @Override 15 | protected boolean isActionAllowedForBranch() { 16 | if (!super.isActionAllowedForBranch()) { 17 | return false; 18 | } 19 | 20 | return !branchUtil.isCurrentBranchPublished(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/AbstractStartAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.ActionUpdateThread; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import git4idea.repo.GitRepository; 6 | import gitflow.GitflowBranchUtil; 7 | import gitflow.GitflowBranchUtilManager; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public abstract class AbstractStartAction extends GitflowAction { 11 | AbstractStartAction(String actionName) { 12 | super(actionName); 13 | } 14 | 15 | AbstractStartAction(GitRepository repo, String actionName) { 16 | super(repo, actionName); 17 | } 18 | 19 | 20 | @Override 21 | public void update(@NotNull AnActionEvent e) { 22 | GitflowBranchUtil branchUtil = GitflowBranchUtilManager.getBranchUtil(myRepo); 23 | if (branchUtil != null) { 24 | //Disable and hide when gitflow has not been setup 25 | if (branchUtil.hasGitflow() == false) { 26 | e.getPresentation().setEnabledAndVisible(false); 27 | } else { 28 | e.getPresentation().setEnabledAndVisible(true); 29 | } 30 | } 31 | } 32 | 33 | @Override 34 | public @NotNull ActionUpdateThread getActionUpdateThread() { 35 | return ActionUpdateThread.EDT; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/AbstractTrackAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import git4idea.repo.GitRepository; 4 | 5 | public abstract class AbstractTrackAction extends AbstractBranchAction { 6 | AbstractTrackAction(String actionName, BranchType type) { 7 | super(actionName, type); 8 | } 9 | 10 | AbstractTrackAction(GitRepository repo, String actionName, BranchType type) { 11 | super(repo, actionName, type); 12 | } 13 | 14 | @Override 15 | protected boolean isActionAllowedForBranch() { 16 | String prefix; 17 | switch (type) { 18 | case Feature: 19 | prefix = branchUtil.getPrefixFeature();; 20 | break; 21 | case Release: 22 | prefix = branchUtil.getPrefixRelease(); 23 | break; 24 | case Bugfix: 25 | prefix = branchUtil.getPrefixBugfix(); 26 | break; 27 | default: 28 | return false; 29 | } 30 | 31 | boolean noRemoteBranches = branchUtil.getRemoteBranchesWithPrefix(prefix).isEmpty(); 32 | boolean trackedAllBranches = branchUtil.areAllBranchesTracked(prefix); 33 | 34 | return noRemoteBranches == false && trackedAllBranches == false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/FinishBugfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import git4idea.branch.GitBranchUtil; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.GitflowConfigUtil; 11 | import gitflow.ui.GitflowFinishActionAckDialog; 12 | import gitflow.ui.NotifyUtil; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | public class FinishBugfixAction extends AbstractBranchAction { 16 | 17 | String customBugfixName =null; 18 | 19 | public FinishBugfixAction() { 20 | super("Finish Bugfix", BranchType.Bugfix); 21 | } 22 | 23 | public FinishBugfixAction(GitRepository repo) { 24 | super(repo, "Finish Bugfix", BranchType.Bugfix); 25 | } 26 | 27 | FinishBugfixAction(GitRepository repo, String name) { 28 | super(repo, "Finish Bugfix", BranchType.Bugfix); 29 | customBugfixName =name; 30 | } 31 | 32 | @Override 33 | public void actionPerformed(AnActionEvent e) { 34 | super.actionPerformed(e); 35 | 36 | GitflowFinishActionAckDialog ackDialog = new GitflowFinishActionAckDialog(myProject); 37 | ackDialog.show(); 38 | 39 | if(!ackDialog.isOK()) { 40 | return; 41 | } 42 | 43 | runReadAction(() -> { 44 | String currentBranchName = GitBranchUtil.getBranchNameOrRev(myRepo); 45 | if (currentBranchName.isEmpty()==false){ 46 | 47 | final AnActionEvent event=e; 48 | final String bugfixName; 49 | // Check if a bugfix name was specified, otherwise take name from current branch 50 | if (customBugfixName !=null){ 51 | bugfixName = customBugfixName; 52 | } 53 | else{ 54 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 55 | bugfixName = gitflowConfigUtil.getBugfixNameFromBranch(currentBranchName); 56 | } 57 | 58 | this.runAction(myProject, bugfixName); 59 | } 60 | }); 61 | 62 | } 63 | 64 | public void runAction(final Project project, final String bugfixName){ 65 | super.runAction(project, null, bugfixName, null); 66 | 67 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 68 | final FinishBugfixAction that = this; 69 | 70 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(project, myRepo); 71 | 72 | new Task.Backgroundable(myProject,"Finishing bugfix "+bugfixName,false){ 73 | @Override 74 | public void run(@NotNull ProgressIndicator indicator) { 75 | GitCommandResult result = myGitflow.finishBugfix(myRepo, bugfixName, errorLineHandler); 76 | 77 | //get the base branch for this bugfix 78 | final String baseBranch = gitflowConfigUtil.getBaseBranch(branchUtil.getPrefixBugfix()+bugfixName); 79 | 80 | if (result.success()) { 81 | String finishedBugfixMessage = String.format("The bugfix branch '%s%s' was merged into '%s'", branchUtil.getPrefixBugfix(), bugfixName, baseBranch); 82 | NotifyUtil.notifySuccess(myProject, bugfixName, finishedBugfixMessage); 83 | } 84 | else if(errorLineHandler.hasMergeError){ 85 | // (merge errors are handled in the onSuccess handler) 86 | } 87 | else { 88 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 89 | } 90 | 91 | myRepo.update(); 92 | 93 | } 94 | 95 | @Override 96 | public void onSuccess() { 97 | super.onSuccess(); 98 | 99 | //merge conflicts if necessary 100 | if (errorLineHandler.hasMergeError){ 101 | if (handleMerge(project)){ 102 | that.runAction(project, bugfixName); 103 | FinishBugfixAction completeFinishBugfixAction = new FinishBugfixAction(myRepo, bugfixName); 104 | } 105 | 106 | } 107 | 108 | } 109 | }.queue(); 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/FinishFeatureAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import git4idea.branch.GitBranchUtil; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.GitflowConfigUtil; 11 | import gitflow.ui.GitflowFinishActionAckDialog; 12 | import gitflow.ui.NotifyUtil; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | public class FinishFeatureAction extends AbstractBranchAction { 16 | 17 | String customFeatureName=null; 18 | 19 | public FinishFeatureAction() { 20 | super("Finish Feature", BranchType.Feature); 21 | } 22 | 23 | public FinishFeatureAction(GitRepository repo) { 24 | super(repo, "Finish Feature", BranchType.Feature); 25 | } 26 | 27 | FinishFeatureAction(GitRepository repo, String name) { 28 | super(repo, "Finish Feature", BranchType.Feature); 29 | customFeatureName=name; 30 | } 31 | 32 | @Override 33 | public void actionPerformed(AnActionEvent e) { 34 | super.actionPerformed(e); 35 | 36 | GitflowFinishActionAckDialog ackDialog = new GitflowFinishActionAckDialog(myProject); 37 | ackDialog.show(); 38 | 39 | if(!ackDialog.isOK()) { 40 | return; 41 | } 42 | 43 | runReadAction(() -> { 44 | String currentBranchName = GitBranchUtil.getBranchNameOrRev(myRepo); 45 | if (currentBranchName.isEmpty()==false){ 46 | 47 | final AnActionEvent event=e; 48 | final String featureName; 49 | // Check if a feature name was specified, otherwise take name from current branch 50 | if (customFeatureName!=null){ 51 | featureName = customFeatureName; 52 | } 53 | else{ 54 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 55 | featureName = gitflowConfigUtil.getFeatureNameFromBranch(currentBranchName); 56 | } 57 | 58 | this.runAction(myProject, featureName); 59 | } 60 | }); 61 | 62 | } 63 | 64 | public void runAction(final Project project, final String featureName){ 65 | super.runAction(project, null, featureName, null); 66 | 67 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 68 | final FinishFeatureAction that = this; 69 | 70 | //get the base branch for this feature 71 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(project, myRepo); 72 | 73 | new Task.Backgroundable(myProject,"Finishing feature "+featureName,false){ 74 | @Override 75 | public void run(@NotNull ProgressIndicator indicator) { 76 | final String baseBranch = gitflowConfigUtil.getBaseBranch(branchUtil.getPrefixFeature()+featureName); 77 | 78 | GitCommandResult result = myGitflow.finishFeature(myRepo,featureName,errorLineHandler); 79 | 80 | if (result.success()) { 81 | String finishedFeatureMessage = String.format("The feature branch '%s%s' was merged into '%s'", branchUtil.getPrefixFeature(), featureName, baseBranch); 82 | NotifyUtil.notifySuccess(myProject, featureName, finishedFeatureMessage); 83 | } 84 | else if(errorLineHandler.hasMergeError){ 85 | // (merge errors are handled in the onSuccess handler) 86 | } 87 | else { 88 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 89 | } 90 | 91 | myRepo.update(); 92 | 93 | } 94 | 95 | @Override 96 | public void onSuccess() { 97 | super.onSuccess(); 98 | 99 | //merge conflicts if necessary 100 | if (errorLineHandler.hasMergeError){ 101 | if (handleMerge(project)) { 102 | that.runAction(project, featureName); 103 | FinishFeatureAction completeFinishFeatureAction = new FinishFeatureAction(myRepo, featureName); 104 | } 105 | 106 | } 107 | 108 | } 109 | }.queue();; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/FinishHotfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.Messages; 8 | import git4idea.branch.GitBranchUtil; 9 | import git4idea.commands.GitCommandResult; 10 | import git4idea.repo.GitRepository; 11 | import gitflow.GitflowConfigUtil; 12 | import gitflow.GitflowConfigurable; 13 | import gitflow.ui.GitflowFinishActionAckDialog; 14 | import gitflow.ui.NotifyUtil; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | public class FinishHotfixAction extends AbstractBranchAction { 18 | 19 | public FinishHotfixAction() { 20 | super("Finish Hotfix", BranchType.Hotfix); 21 | } 22 | public FinishHotfixAction(GitRepository repo) { 23 | super(repo, "Finish Hotfix", BranchType.Hotfix); 24 | } 25 | 26 | @Override 27 | public void actionPerformed(AnActionEvent e) { 28 | super.actionPerformed(e); 29 | 30 | GitflowFinishActionAckDialog ackDialog = new GitflowFinishActionAckDialog(myProject); 31 | ackDialog.show(); 32 | 33 | if(!ackDialog.isOK()) { 34 | return; 35 | } 36 | 37 | runReadAction(() -> { 38 | String currentBranchName = GitBranchUtil.getBranchNameOrRev(myRepo); 39 | 40 | 41 | if (currentBranchName.isEmpty() == false){ 42 | 43 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 44 | //TODO HOTFIX NAME 45 | final String hotfixName = gitflowConfigUtil.getHotfixNameFromBranch(currentBranchName); 46 | 47 | final String tagMessage; 48 | String tagMessageTemplate = GitflowConfigurable.getOptionTextString(myProject, "HOTFIX_customHotfixCommitMessage").replace("%name%", hotfixName); 49 | 50 | if (GitflowConfigurable.isOptionActive(myProject, "HOTFIX_dontTag")) { 51 | tagMessage = ""; 52 | } 53 | else { 54 | tagMessage = Messages.showInputDialog(myProject, "Enter the tag message:", "Finish Hotfix", Messages.getQuestionIcon(), tagMessageTemplate, null); 55 | } 56 | 57 | this.runAction(e.getProject(), hotfixName, tagMessage); 58 | 59 | } 60 | }); 61 | 62 | } 63 | 64 | public void runAction(final Project project, final String hotfixName, final String tagMessage){ 65 | super.runAction(project, null, hotfixName, null); 66 | 67 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 68 | 69 | if (tagMessage!=null){ 70 | new Task.Backgroundable(myProject,"Finishing hotfix "+hotfixName,false){ 71 | @Override 72 | public void run(@NotNull ProgressIndicator indicator) { 73 | GitCommandResult result= myGitflow.finishHotfix(myRepo, hotfixName, tagMessage, errorLineHandler); 74 | 75 | if (result.success()) { 76 | String finishedHotfixMessage = String.format("The hotfix branch '%s%s' was merged into '%s' and '%s'", branchUtil.getPrefixHotfix(), hotfixName, branchUtil.getBranchnameDevelop(), branchUtil.getBranchnameMaster()); 77 | NotifyUtil.notifySuccess(myProject, hotfixName, finishedHotfixMessage); 78 | } 79 | else { 80 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 81 | } 82 | 83 | myRepo.update(); 84 | 85 | } 86 | }.queue(); 87 | } 88 | 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/FinishReleaseAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.ui.Messages; 7 | import git4idea.branch.GitBranchUtil; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.GitflowConfigUtil; 11 | import gitflow.GitflowConfigurable; 12 | import gitflow.ui.GitflowFinishActionAckDialog; 13 | import gitflow.ui.NotifyUtil; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | public class FinishReleaseAction extends AbstractBranchAction { 17 | 18 | String customReleaseName=null; 19 | String customtagMessage=null; 20 | 21 | FinishReleaseAction() { 22 | super("Finish Release", AbstractBranchAction.BranchType.Release); 23 | } 24 | 25 | FinishReleaseAction(GitRepository repo) { 26 | super(repo, "Finish Release", BranchType.Release); 27 | } 28 | 29 | FinishReleaseAction(String name, String tagMessage) { 30 | super("Finish Release", BranchType.Release); 31 | customReleaseName = name; 32 | customtagMessage = tagMessage; 33 | } 34 | 35 | @Override 36 | public void actionPerformed(AnActionEvent e) { 37 | super.actionPerformed(e); 38 | 39 | GitflowFinishActionAckDialog ackDialog = new GitflowFinishActionAckDialog(myProject); 40 | ackDialog.show(); 41 | 42 | if(!ackDialog.isOK()) { 43 | return; 44 | } 45 | 46 | runReadAction(() -> { 47 | String currentBranchName = GitBranchUtil.getBranchNameOrRev(myRepo); 48 | if (currentBranchName.isEmpty()==false){ 49 | 50 | final AnActionEvent event=e; 51 | 52 | final String tagMessage; 53 | final String releaseName; 54 | 55 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 56 | 57 | // Check if a release name was specified, otherwise take name from current branch 58 | releaseName = customReleaseName!=null ? customReleaseName:gitflowConfigUtil.getReleaseNameFromBranch(currentBranchName); 59 | 60 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 61 | 62 | String tagMessageTemplate = GitflowConfigurable.getOptionTextString(myProject, "RELEASE_customTagCommitMessage").replace("%name%", releaseName); 63 | String tagMessageDraft; 64 | 65 | boolean cancelAction=false; 66 | 67 | if (GitflowConfigurable.isOptionActive(myProject, "RELEASE_dontTag")) { 68 | tagMessage=""; 69 | } 70 | else if (customtagMessage!=null){ 71 | //probably repeating the release finish after a merge 72 | tagMessage=customtagMessage; 73 | } 74 | else{ 75 | tagMessageDraft = Messages.showInputDialog(myProject, "Enter the tag message:", "Finish Release", Messages.getQuestionIcon(), tagMessageTemplate, null); 76 | if (tagMessageDraft==null){ 77 | cancelAction=true; 78 | tagMessage=""; 79 | } 80 | else{ 81 | tagMessage=tagMessageDraft; 82 | } 83 | } 84 | 85 | 86 | if (!cancelAction){ 87 | 88 | new Task.Backgroundable(myProject,"Finishing release "+releaseName,false){ 89 | @Override 90 | public void run(@NotNull ProgressIndicator indicator) { 91 | GitCommandResult result = myGitflow.finishRelease(myRepo, releaseName, tagMessage, errorLineHandler); 92 | 93 | if (result.success()) { 94 | String finishedReleaseMessage = String.format("The release branch '%s%s' was merged into '%s' and '%s'", branchUtil.getPrefixRelease(), releaseName, branchUtil.getBranchnameDevelop(), branchUtil.getBranchnameMaster()); 95 | NotifyUtil.notifySuccess(myProject, releaseName, finishedReleaseMessage); 96 | } 97 | else if(errorLineHandler.hasMergeError){ 98 | // (merge errors are handled in the onSuccess handler) 99 | } 100 | else { 101 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 102 | } 103 | 104 | myRepo.update(); 105 | 106 | } 107 | 108 | @Override 109 | public void onSuccess() { 110 | super.onSuccess(); 111 | 112 | //merge conflicts if necessary 113 | if (errorLineHandler.hasMergeError){ 114 | if (handleMerge(myProject)) { 115 | FinishReleaseAction completeFinisReleaseAction = new FinishReleaseAction(releaseName, tagMessage); 116 | completeFinisReleaseAction.actionPerformed(event); 117 | } 118 | } 119 | } 120 | 121 | }.queue(); 122 | 123 | } 124 | } 125 | }); 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/GitflowAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.application.Application; 5 | import com.intellij.openapi.application.ApplicationManager; 6 | import com.intellij.openapi.components.ServiceManager; 7 | import com.intellij.openapi.project.DumbAwareAction; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.ui.Messages; 10 | import com.intellij.openapi.vcs.VcsException; 11 | import com.intellij.openapi.vfs.VirtualFileManager; 12 | import git4idea.branch.GitBranchUtil; 13 | import git4idea.merge.GitMerger; 14 | import git4idea.repo.GitRepository; 15 | import gitflow.Gitflow; 16 | import gitflow.GitflowBranchUtil; 17 | import gitflow.GitflowBranchUtilManager; 18 | import gitflow.IDEAUtils; 19 | import gitflow.ui.NotifyUtil; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import java.util.ArrayList; 23 | 24 | public abstract class GitflowAction extends DumbAwareAction { 25 | 26 | private static final long VFM_REFRESH_DELAY = 750L; 27 | 28 | Project myProject; 29 | Gitflow myGitflow = ApplicationManager.getApplication().getService(Gitflow.class); 30 | ArrayList repos = new ArrayList(); 31 | GitRepository myRepo; 32 | GitflowBranchUtil branchUtil; 33 | 34 | VirtualFileManager virtualFileMananger; 35 | 36 | GitflowAction( String actionName){ super(actionName); } 37 | 38 | GitflowAction(GitRepository repo, String actionName){ 39 | super(actionName); 40 | myRepo = repo; 41 | 42 | branchUtil = GitflowBranchUtilManager.getBranchUtil(myRepo); 43 | } 44 | 45 | @Override 46 | public void actionPerformed(AnActionEvent e) { 47 | Project project = IDEAUtils.getActiveProject(); 48 | 49 | // if repo isn't set explicitly, such as in the case of starting from keyboard shortcut, infer it 50 | if (myRepo == null){ 51 | myRepo = GitBranchUtil.guessRepositoryForOperation(project, e.getDataContext()); 52 | } 53 | setup(project); 54 | } 55 | 56 | private void setup(Project project){ 57 | myProject = project; 58 | virtualFileMananger = VirtualFileManager.getInstance(); 59 | repos.add(myRepo); 60 | 61 | branchUtil= GitflowBranchUtilManager.getBranchUtil(myRepo); 62 | } 63 | 64 | public void runAction(final Project project, final String baseBranchName, final String branchName, @Nullable final Runnable callInAwtLater){ 65 | setup(project); 66 | } 67 | 68 | //returns true if merge successful, false otherwise 69 | public boolean handleMerge(final Project project) { 70 | // FIXME As of 201.0 the async version of this method still doesn't make use of the callback, else we'd 71 | // simply use a FutureTask (which is a Runnable) and its get() method prior to launching the merge tool. 72 | virtualFileMananger.syncRefresh(); 73 | 74 | try { 75 | long start, end = System.currentTimeMillis(); 76 | do { 77 | start = end; 78 | // Hence this ugly hack, to let the time to intellij to catch up with the external changes made by the 79 | // CLI before being able to run the merge tool. Else the tool won't have the right state, won't display, 80 | // and the merge success Y/N dialog will appear directly! Anyway, in v193 500ms was sufficient, 81 | // but in v201 the right value seems to be in the [700-750]ms range (on the committer's machine). 82 | Thread.sleep(VFM_REFRESH_DELAY); 83 | 84 | GitflowActions.runMergeTool(project); // The window is modal, so we can measure how long it's opened. 85 | end = System.currentTimeMillis(); 86 | } while(end - start < 1000L); // Additional hack: a window open <1s obviously didn't open, let's try again. 87 | 88 | myRepo.update(); 89 | 90 | // And refreshing again so an onscreen file doesn't show in a conflicted state when the Y/N dialog show up. 91 | virtualFileMananger.syncRefresh(); 92 | Thread.sleep(VFM_REFRESH_DELAY); 93 | 94 | return askUserForMergeSuccess(project); 95 | } 96 | catch (InterruptedException ignored) { 97 | return false; 98 | } 99 | } 100 | 101 | private static boolean askUserForMergeSuccess(Project myProject) { 102 | //if merge was completed successfully, finish the action 103 | //note that if it wasn't intellij is left in the "merging state", and git4idea provides no UI way to resolve it 104 | //merging can be done via intellij itself or any other util 105 | int answer = Messages.showYesNoDialog(myProject, "Was the merge completed succesfully?", "Merge", Messages.getQuestionIcon()); 106 | if (answer==0){ 107 | GitMerger gitMerger=new GitMerger(myProject); 108 | 109 | try { 110 | gitMerger.mergeCommit(gitMerger.getMergingRoots()); 111 | } catch (VcsException e1) { 112 | NotifyUtil.notifyError(myProject, "Error", "Error committing merge result"); 113 | e1.printStackTrace(); 114 | } 115 | 116 | return true; 117 | } 118 | else{ 119 | 120 | NotifyUtil.notifyInfo(myProject,"Merge incomplete","To manually complete the merge choose VCS > Git > Resolve Conflicts.\n" + 121 | "Once done, commit the merged files.\n"); 122 | return false; 123 | } 124 | 125 | 126 | } 127 | 128 | protected void runReadAction(Runnable runnable) { 129 | Application application = ApplicationManager.getApplication(); 130 | application.runReadAction(runnable); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/GitflowActions.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.*; 4 | import com.intellij.openapi.project.Project; 5 | import git4idea.actions.GitResolveConflictsAction; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * All actions associated with Gitflow 11 | * 12 | * @author Opher Vishnia / opherv.com / opherv@gmail.com 13 | */ 14 | public class GitflowActions { 15 | 16 | public static void runMergeTool(Project project){ 17 | GitResolveConflictsAction resolveAction = new GitResolveConflictsAction(); 18 | AnActionEvent e = new AnActionEvent(null, new ProjectDataContext(project), ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0); 19 | resolveAction.actionPerformed(e); 20 | } 21 | 22 | 23 | /** 24 | * Simple wrapper containing just enough to let the conflicts resolver to launch 25 | * We could have transferred the DataContext or wrapped a HackyDataContext from the previous action, 26 | * but that would make the semantics terrible 27 | */ 28 | private final static class ProjectDataContext implements DataContext { 29 | private Project project; 30 | 31 | private ProjectDataContext(Project project) { 32 | this.project = project; 33 | } 34 | 35 | @Nullable 36 | @Override 37 | public Object getData(@NotNull String dataId) { 38 | if(CommonDataKeys.PROJECT.getName().equals(dataId)) { 39 | return project; 40 | } else { 41 | throw new UnsupportedOperationException(dataId); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/GitflowErrorsListener.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.Key; 5 | import gitflow.ui.NotifyUtil; 6 | 7 | public class GitflowErrorsListener extends GitflowLineHandler{ 8 | 9 | boolean hasMergeError=false; 10 | 11 | GitflowErrorsListener(Project project){ 12 | myProject=project; 13 | } 14 | 15 | @Override 16 | public void onLineAvailable(String line, Key outputType) { 17 | if (line.contains("'flow' is not a git command")) { 18 | NotifyUtil.notifyError(myProject, "Error", "Gitflow is not installed"); 19 | } 20 | if (line.contains("Not a gitflow-enabled repo yet")) { 21 | NotifyUtil.notifyError(myProject, "Error", "Not a gitflow-enabled repo yet. Please init git flow"); 22 | } 23 | if (line.contains("There were merge conflicts")){ 24 | hasMergeError=true; 25 | } 26 | } 27 | 28 | }; -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/GitflowLineHandler.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.Key; 5 | import git4idea.commands.GitLineHandlerListener; 6 | 7 | import java.util.ArrayList; 8 | 9 | //generic line handler (should handle errors etc) 10 | public abstract class GitflowLineHandler implements GitLineHandlerListener { 11 | ArrayList myErrors=new ArrayList(); 12 | Project myProject; 13 | 14 | @Override 15 | public void onLineAvailable(String line, Key outputType) { 16 | if (line.contains("fatal") || line.contains("Fatal")){ 17 | myErrors.add(line); 18 | } 19 | } 20 | 21 | @Override 22 | public void processTerminated(int exitCode) {} 23 | 24 | @Override 25 | public void startFailed(Throwable exception) {} 26 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/GitflowPopupGroup.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.ActionGroup; 4 | import com.intellij.openapi.actionSystem.DefaultActionGroup; 5 | import com.intellij.openapi.project.Project; 6 | import git4idea.GitUtil; 7 | import git4idea.repo.GitRepository; 8 | import git4idea.repo.GitRepositoryManager; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Iterator; 12 | import java.util.List; 13 | 14 | /** 15 | * ActionGroup for the Gitflow popup, constructs the actions for each repo source 16 | */ 17 | public class GitflowPopupGroup { 18 | 19 | Project myProject; 20 | DefaultActionGroup actionGroup; 21 | GitRepositoryManager myRepositoryManager; 22 | List gitRepositories; 23 | 24 | public GitflowPopupGroup(@NotNull Project project, boolean includeAdvanced) { 25 | myProject = project; 26 | 27 | //fetch all the git repositories from the project; 28 | myRepositoryManager = GitUtil.getRepositoryManager(project); 29 | gitRepositories = myRepositoryManager.getRepositories(); 30 | 31 | createActionGroup(includeAdvanced); 32 | } 33 | 34 | /** 35 | * Generates the popup actions for the widget 36 | */ 37 | private void createActionGroup(boolean includeAdvanced){ 38 | actionGroup = new DefaultActionGroup(); 39 | 40 | 41 | if (gitRepositories.size() == 1){ 42 | ActionGroup repoActions = 43 | (new RepoActions(myProject, gitRepositories.get(0))) 44 | .getRepoActionGroup(includeAdvanced); 45 | actionGroup.addAll(repoActions); 46 | } 47 | else{ 48 | for (GitRepository repo : gitRepositories) { 49 | RepoActions repoActions = new RepoActions(myProject, repo); 50 | actionGroup.add(repoActions); 51 | } 52 | } 53 | } 54 | 55 | public ActionGroup getActionGroup (){ 56 | 57 | return actionGroup; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/InitRepoAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.util.Key; 7 | import git4idea.commands.GitCommandResult; 8 | import git4idea.repo.GitRepository; 9 | import gitflow.GitflowBranchUtil; 10 | import gitflow.GitflowBranchUtilManager; 11 | import gitflow.GitflowInitOptions; 12 | import gitflow.ui.GitflowInitOptionsDialog; 13 | import gitflow.ui.NotifyUtil; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | public class InitRepoAction extends GitflowAction { 17 | 18 | InitRepoAction() { 19 | this( "Init Repo"); 20 | } 21 | 22 | InitRepoAction(String actionName) { 23 | this(null, "Init Repo"); 24 | } 25 | 26 | InitRepoAction(GitRepository repo) { 27 | this(repo,"Init Repo"); 28 | } 29 | 30 | InitRepoAction(GitRepository repo, String actionName) { 31 | super(repo, actionName); 32 | } 33 | 34 | @Override 35 | public void update(@NotNull AnActionEvent e) { 36 | GitflowBranchUtil branchUtil = GitflowBranchUtilManager.getBranchUtil(myRepo); 37 | if (branchUtil != null) { 38 | // Only show when gitflow isn't setup 39 | if (branchUtil.hasGitflow()) { 40 | e.getPresentation().setEnabledAndVisible(false); 41 | } else { 42 | e.getPresentation().setEnabledAndVisible(true); 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | public void actionPerformed(AnActionEvent e) { 49 | super.actionPerformed(e); 50 | 51 | GitflowInitOptionsDialog optionsDialog = new GitflowInitOptionsDialog(myProject, branchUtil.getLocalBranchNames()); 52 | optionsDialog.show(); 53 | 54 | if(optionsDialog.isOK()) { 55 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 56 | final GitflowLineHandler localLineHandler = getLineHandler(); 57 | final GitflowInitOptions initOptions = optionsDialog.getOptions(); 58 | 59 | new Task.Backgroundable(myProject, getTitle(),false){ 60 | @Override 61 | public void run(@NotNull ProgressIndicator indicator) { 62 | GitCommandResult result = 63 | executeCommand(initOptions, errorLineHandler, 64 | localLineHandler); 65 | 66 | if (result.success()) { 67 | String successMessage = getSuccessMessage(); 68 | NotifyUtil.notifySuccess(myProject, "", successMessage); 69 | } else { 70 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 71 | } 72 | 73 | //update the widget 74 | myProject.getMessageBus().syncPublisher(GitRepository.GIT_REPO_CHANGE).repositoryChanged(myRepo); 75 | myRepo.update(); 76 | } 77 | }.queue(); 78 | } 79 | 80 | } 81 | 82 | protected String getSuccessMessage() { 83 | return "Initialized gitflow in repo " + myRepo.getRoot().getPresentableName(); 84 | } 85 | 86 | protected GitCommandResult executeCommand(GitflowInitOptions initOptions, 87 | GitflowErrorsListener errorLineHandler, 88 | GitflowLineHandler localLineHandler) { 89 | return myGitflow.initRepo(myRepo, initOptions, errorLineHandler, localLineHandler); 90 | } 91 | 92 | protected String getTitle() { 93 | return "Initializing Repo"; 94 | } 95 | 96 | protected GitflowLineHandler getLineHandler() { 97 | return new LineHandler(); 98 | } 99 | 100 | 101 | private class LineHandler extends GitflowLineHandler { 102 | @Override 103 | public void onLineAvailable(String line, Key outputType) { 104 | if (line.contains("Already initialized for gitflow")){ 105 | myErrors.add("Repo already initialized for gitflow"); 106 | } 107 | 108 | } 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/OpenGitflowPopup.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.openapi.wm.WindowManager; 6 | 7 | import gitflow.ui.GitflowWidget; 8 | 9 | public class OpenGitflowPopup extends GitflowAction { 10 | 11 | OpenGitflowPopup() { 12 | super("Gitflow Operations Popup..."); 13 | } 14 | 15 | @Override 16 | public void actionPerformed(AnActionEvent e) { 17 | // TODO calling super will cause a NPE, if no repo is set up. Since we only need the project, we take it directly from the event 18 | // super.actionPerformed(e); 19 | Project currentProject = e.getProject(); 20 | 21 | GitflowWidget widget = GitflowWidget.findWidgetInstance(currentProject); 22 | if (widget != null) 23 | widget.showPopupInCenterOf(WindowManager.getInstance().getFrame(currentProject)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/PublishBugfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRepository; 8 | import gitflow.GitflowConfigUtil; 9 | import gitflow.ui.GitflowFinishActionAckDialog; 10 | import gitflow.ui.GitflowPublishActionAckDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class PublishBugfixAction extends AbstractPublishAction { 15 | 16 | PublishBugfixAction(){ 17 | super("Publish Bugfix", BranchType.Bugfix); 18 | } 19 | 20 | PublishBugfixAction(GitRepository repo){ 21 | super(repo, "Publish Bugfix", BranchType.Bugfix); 22 | } 23 | 24 | @Override 25 | public void actionPerformed(AnActionEvent anActionEvent) { 26 | super.actionPerformed(anActionEvent); 27 | 28 | GitflowPublishActionAckDialog ackDialog = new GitflowPublishActionAckDialog(myProject); 29 | ackDialog.show(); 30 | 31 | if(!ackDialog.isOK()) { 32 | return; 33 | } 34 | 35 | runReadAction(() -> { 36 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 37 | final String bugfixName = gitflowConfigUtil.getBugfixNameFromBranch(branchUtil.getCurrentBranchName()); 38 | 39 | new Task.Backgroundable(myProject,"Publishing bugfix "+bugfixName,false){ 40 | @Override 41 | public void run(@NotNull ProgressIndicator indicator) { 42 | GitCommandResult result = myGitflow.publishBugfix(myRepo, bugfixName,new GitflowErrorsListener(myProject)); 43 | if (result.success()) { 44 | String publishedBugfixMessage = String.format("A new remote branch '%s%s' was created", branchUtil.getPrefixBugfix(), bugfixName); 45 | NotifyUtil.notifySuccess(myProject, bugfixName, publishedBugfixMessage); 46 | } 47 | else { 48 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 49 | } 50 | myRepo.update(); 51 | } 52 | }.queue(); 53 | }); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/PublishFeatureAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRepository; 8 | import gitflow.GitflowConfigUtil; 9 | import gitflow.ui.GitflowPublishActionAckDialog; 10 | import gitflow.ui.NotifyUtil; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class PublishFeatureAction extends AbstractPublishAction { 14 | PublishFeatureAction(){ 15 | super("Publish Feature", BranchType.Feature); 16 | } 17 | 18 | PublishFeatureAction(GitRepository repo){ 19 | super(repo, "Publish Feature", BranchType.Feature); 20 | } 21 | 22 | @Override 23 | public void actionPerformed(AnActionEvent anActionEvent) { 24 | super.actionPerformed(anActionEvent); 25 | 26 | GitflowPublishActionAckDialog ackDialog = new GitflowPublishActionAckDialog(myProject); 27 | ackDialog.show(); 28 | 29 | if(!ackDialog.isOK()) { 30 | return; 31 | } 32 | 33 | runReadAction(() -> { 34 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 35 | final String featureName= gitflowConfigUtil.getFeatureNameFromBranch(branchUtil.getCurrentBranchName()); 36 | 37 | new Task.Backgroundable(myProject,"Publishing feature "+featureName,false){ 38 | @Override 39 | public void run(@NotNull ProgressIndicator indicator) { 40 | GitCommandResult result = myGitflow.publishFeature(myRepo, featureName,new GitflowErrorsListener(myProject)); 41 | 42 | if (result.success()) { 43 | String publishedFeatureMessage = String.format("A new remote branch '%s%s' was created", branchUtil.getPrefixFeature(), featureName); 44 | NotifyUtil.notifySuccess(myProject, featureName, publishedFeatureMessage); 45 | } 46 | else { 47 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 48 | } 49 | 50 | myRepo.update(); 51 | 52 | 53 | } 54 | }.queue(); 55 | }); 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/PublishHotfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRepository; 8 | import gitflow.GitflowConfigUtil; 9 | import gitflow.ui.GitflowPublishActionAckDialog; 10 | import gitflow.ui.NotifyUtil; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class PublishHotfixAction extends AbstractPublishAction { 14 | PublishHotfixAction() { 15 | super("Publish Hotfix", BranchType.Hotfix); 16 | } 17 | 18 | PublishHotfixAction(GitRepository repo) { 19 | super(repo, "Publish Hotfix", BranchType.Hotfix); 20 | } 21 | 22 | @Override 23 | public void actionPerformed(AnActionEvent anActionEvent) { 24 | super.actionPerformed(anActionEvent); 25 | 26 | GitflowPublishActionAckDialog ackDialog = new GitflowPublishActionAckDialog(myProject); 27 | ackDialog.show(); 28 | 29 | if(!ackDialog.isOK()) { 30 | return; 31 | } 32 | 33 | runReadAction(() -> { 34 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 35 | final String hotfixName = gitflowConfigUtil.getHotfixNameFromBranch(branchUtil.getCurrentBranchName()); 36 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 37 | 38 | new Task.Backgroundable(myProject, "Publishing hotfix " + hotfixName, false) { 39 | @Override 40 | public void run(@NotNull ProgressIndicator indicator) { 41 | GitCommandResult result = myGitflow.publishHotfix(myRepo, hotfixName, errorLineHandler); 42 | 43 | if (result.success()) { 44 | String publishedHotfixMessage = String.format("A new remote branch '%s%s' was created", branchUtil.getPrefixHotfix(), hotfixName); 45 | NotifyUtil.notifySuccess(myProject, hotfixName, publishedHotfixMessage); 46 | } else { 47 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 48 | } 49 | 50 | myRepo.update(); 51 | } 52 | }.queue(); 53 | }); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/PublishReleaseAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRepository; 8 | import gitflow.GitflowConfigUtil; 9 | import gitflow.ui.GitflowPublishActionAckDialog; 10 | import gitflow.ui.NotifyUtil; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class PublishReleaseAction extends AbstractPublishAction { 14 | 15 | PublishReleaseAction(){ 16 | super("Publish Release", BranchType.Release); 17 | } 18 | 19 | PublishReleaseAction(GitRepository repo){ 20 | super(repo,"Publish Release", BranchType.Release); 21 | } 22 | 23 | @Override 24 | public void actionPerformed(AnActionEvent anActionEvent) { 25 | super.actionPerformed(anActionEvent); 26 | 27 | GitflowPublishActionAckDialog ackDialog = new GitflowPublishActionAckDialog(myProject); 28 | ackDialog.show(); 29 | 30 | if(!ackDialog.isOK()) { 31 | return; 32 | } 33 | 34 | runReadAction(() -> { 35 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 36 | final String releaseName= gitflowConfigUtil.getReleaseNameFromBranch(branchUtil.getCurrentBranchName()); 37 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 38 | 39 | new Task.Backgroundable(myProject,"Publishing release "+releaseName,false){ 40 | @Override 41 | public void run(@NotNull ProgressIndicator indicator) { 42 | GitCommandResult result = myGitflow.publishRelease(myRepo, releaseName, errorLineHandler); 43 | 44 | if (result.success()) { 45 | String publishedReleaseMessage = String.format("A new remote branch '%s%s' was created", branchUtil.getPrefixRelease(), releaseName); 46 | NotifyUtil.notifySuccess(myProject, releaseName, publishedReleaseMessage); 47 | } 48 | else { 49 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 50 | } 51 | 52 | myRepo.update(); 53 | } 54 | }.queue(); 55 | }); 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/ReInitRepoAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import git4idea.commands.GitCommandResult; 5 | import git4idea.repo.GitRepository; 6 | import gitflow.GitflowInitOptions; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class ReInitRepoAction extends InitRepoAction { 10 | ReInitRepoAction() { 11 | super("Re-init Repo"); 12 | } 13 | 14 | ReInitRepoAction(GitRepository repo) { 15 | super(repo, "Re-init Repo"); 16 | } 17 | 18 | @Override 19 | public void update(@NotNull AnActionEvent e) { 20 | gitflow.GitflowBranchUtil branchUtil = gitflow.GitflowBranchUtilManager.getBranchUtil(myRepo); 21 | 22 | // Only show when gitflow is setup 23 | if (branchUtil !=null && branchUtil.hasGitflow()) { 24 | e.getPresentation().setEnabledAndVisible(true); 25 | } else { 26 | e.getPresentation().setEnabledAndVisible(false); 27 | } 28 | } 29 | 30 | @Override 31 | protected String getSuccessMessage() { 32 | return "Re-initialized gitflow in repo " + myRepo.getRoot().getPresentableName(); 33 | } 34 | 35 | @Override 36 | protected GitCommandResult executeCommand(GitflowInitOptions initOptions, 37 | GitflowErrorsListener errorLineHandler, 38 | GitflowLineHandler localLineHandler) { 39 | return myGitflow.reInitRepo(myRepo, initOptions, errorLineHandler, localLineHandler); 40 | } 41 | 42 | @Override 43 | protected String getTitle() { 44 | return "Re-initializing Repo"; 45 | } 46 | 47 | @Override 48 | protected GitflowLineHandler getLineHandler() { 49 | return new GitflowErrorsListener(myProject); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/RepoActions.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.dvcs.ui.BranchActionGroup; 4 | import com.intellij.dvcs.ui.PopupElementWithAdditionalInfo; 5 | import com.intellij.openapi.actionSystem.*; 6 | import com.intellij.openapi.fileEditor.FileEditorManagerEvent; 7 | import com.intellij.openapi.fileEditor.FileEditorManagerListener; 8 | import com.intellij.openapi.project.Project; 9 | import git4idea.branch.GitBranchUtil; 10 | import git4idea.repo.GitRepository; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import javax.swing.*; 15 | import java.util.ArrayList; 16 | import java.util.Iterator; 17 | 18 | class RepoActions extends BranchActionGroup implements PopupElementWithAdditionalInfo, FileEditorManagerListener { 19 | Project myProject; 20 | GitRepository myRepo; 21 | 22 | RepoActions(@NotNull Project project, @NotNull GitRepository repo) { 23 | myProject = project; 24 | myRepo = repo; 25 | 26 | String repoName = repo.getRoot().getPresentableName(); 27 | getTemplatePresentation().setText(repoName, false); // no mnemonics 28 | this.updateFavoriteIcon(); 29 | project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, this); 30 | } 31 | 32 | public ArrayList getRepoActions(boolean includeAdvanced){ 33 | ArrayList actionList = new ArrayList(); 34 | 35 | actionList.add(new InitRepoAction(myRepo)); 36 | 37 | //FEATURE ACTIONS 38 | actionList.add(new Separator("Feature")); 39 | actionList.add(new StartFeatureAction(myRepo)); 40 | actionList.add(new FinishFeatureAction(myRepo)); 41 | actionList.add(new PublishFeatureAction(myRepo)); 42 | actionList.add(new TrackFeatureAction(myRepo)); 43 | 44 | //RELEASE ACTIONS 45 | actionList.add(new Separator("Release")); 46 | actionList.add(new StartReleaseAction(myRepo)); 47 | actionList.add(new FinishReleaseAction(myRepo)); 48 | actionList.add(new PublishReleaseAction(myRepo)); 49 | actionList.add(new TrackReleaseAction(myRepo)); 50 | 51 | //BUGFIX ACTIONS 52 | actionList.add(new Separator("Bugfix")); 53 | actionList.add(new StartBugfixAction(myRepo)); 54 | actionList.add(new FinishBugfixAction(myRepo)); 55 | actionList.add(new PublishBugfixAction(myRepo)); 56 | actionList.add(new TrackBugfixAction(myRepo)); 57 | 58 | //HOTFIX ACTIONS 59 | actionList.add(new Separator("Hotfix")); 60 | actionList.add(new StartHotfixAction(myRepo)); 61 | actionList.add(new FinishHotfixAction(myRepo)); 62 | actionList.add(new PublishHotfixAction(myRepo)); 63 | 64 | if (includeAdvanced) { 65 | actionList.add(new Separator("Advanced")); 66 | 67 | actionList.add(new ActionGroup("Advanced", true) { 68 | @NotNull 69 | @Override 70 | public AnAction[] getChildren(@Nullable AnActionEvent anActionEvent) { 71 | AnAction initRepoAction = new ReInitRepoAction(myRepo); 72 | return new AnAction[] { initRepoAction }; 73 | } 74 | }); 75 | } 76 | 77 | return actionList; 78 | } 79 | 80 | public DefaultActionGroup getRepoActionGroup(boolean includeAdvanced){ 81 | DefaultActionGroup actionGroup = new DefaultActionGroup(); 82 | 83 | for (AnAction action : this.getRepoActions(includeAdvanced)) { 84 | actionGroup.add(action); 85 | } 86 | 87 | return actionGroup; 88 | } 89 | 90 | @NotNull 91 | @Override 92 | public AnAction[] getChildren(@Nullable AnActionEvent e) { 93 | ArrayList children = this.getRepoActions(false); 94 | return children.toArray(new AnAction[children.size()]); 95 | } 96 | 97 | @Override 98 | @Nullable 99 | public String getInfoText() { 100 | return "what's this"; 101 | } 102 | 103 | public void updateFavoriteIcon(){ 104 | SwingUtilities.invokeLater(() -> { 105 | boolean isFavorite = GitBranchUtil.getCurrentRepository(myProject) == myRepo; 106 | setFavorite(isFavorite); 107 | }); 108 | } 109 | 110 | @Override 111 | public void selectionChanged(@NotNull FileEditorManagerEvent event) { 112 | this.updateFavoriteIcon(); 113 | } 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/StartBugfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.DialogWrapper; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.ui.GitflowStartBugfixDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | public class StartBugfixAction extends AbstractStartAction { 16 | 17 | public StartBugfixAction() { 18 | super("Start Bugfix"); 19 | } 20 | public StartBugfixAction(GitRepository repo) { 21 | super(repo, "Start Bugfix"); 22 | } 23 | 24 | @Override 25 | public void actionPerformed(AnActionEvent e) { 26 | super.actionPerformed(e); 27 | 28 | GitflowStartBugfixDialog dialog = new GitflowStartBugfixDialog(myProject, myRepo); 29 | dialog.show(); 30 | 31 | if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return; 32 | 33 | final String bugfixName = dialog.getNewBranchName(); 34 | final String baseBranchName = dialog.getBaseBranchName(); 35 | 36 | this.runAction(e.getProject(), baseBranchName, bugfixName, null); 37 | } 38 | 39 | @Override 40 | public void runAction(final Project project, final String baseBranchName, final String bugfixName, @Nullable final Runnable callInAwtLater){ 41 | super.runAction(project, baseBranchName, bugfixName, callInAwtLater); 42 | 43 | new Task.Backgroundable(myProject, "Starting bugfix " + bugfixName, false) { 44 | @Override 45 | public void run(@NotNull ProgressIndicator indicator) { 46 | final GitCommandResult commandResult = createBugfixBranch(baseBranchName, bugfixName); 47 | if (callInAwtLater != null && commandResult.success()) { 48 | callInAwtLater.run(); 49 | } 50 | } 51 | }.queue(); 52 | } 53 | 54 | private GitCommandResult createBugfixBranch(String baseBranchName, String bugfixName) { 55 | GitflowErrorsListener errorListener = new GitflowErrorsListener(myProject); 56 | GitCommandResult result = myGitflow.startBugfix(myRepo, bugfixName, baseBranchName, errorListener); 57 | 58 | if (result.success()) { 59 | String startedBugfixMessage = String.format("A new branch '%s%s' was created, based on '%s'", branchUtil.getPrefixBugfix(), bugfixName, baseBranchName); 60 | NotifyUtil.notifySuccess(myProject, bugfixName, startedBugfixMessage); 61 | } else { 62 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 63 | } 64 | 65 | myRepo.update(); 66 | virtualFileMananger.asyncRefresh(null); //update editors 67 | return result; 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/StartFeatureAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.DialogWrapper; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.ui.GitflowStartFeatureDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | public class StartFeatureAction extends AbstractStartAction { 16 | 17 | public StartFeatureAction() { 18 | super("Start Feature"); 19 | } 20 | public StartFeatureAction(GitRepository repo) { 21 | super(repo, "Start Feature"); 22 | } 23 | 24 | @Override 25 | public void actionPerformed(AnActionEvent e) { 26 | super.actionPerformed(e); 27 | 28 | GitflowStartFeatureDialog dialog = new GitflowStartFeatureDialog(myProject, myRepo); 29 | dialog.show(); 30 | 31 | if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return; 32 | 33 | final String featureName = dialog.getNewBranchName(); 34 | final String baseBranchName = dialog.getBaseBranchName(); 35 | 36 | this.runAction(e.getProject(), baseBranchName, featureName, null); 37 | } 38 | 39 | public void runAction(final Project project, final String baseBranchName, final String featureName, @Nullable final Runnable callInAwtLater){ 40 | super.runAction(project, baseBranchName, featureName, callInAwtLater); 41 | 42 | new Task.Backgroundable(myProject, "Starting feature " + featureName, false) { 43 | @Override 44 | public void run(@NotNull ProgressIndicator indicator) { 45 | final GitCommandResult commandResult = createFeatureBranch(baseBranchName, featureName); 46 | if (callInAwtLater != null && commandResult.success()) { 47 | callInAwtLater.run(); 48 | } 49 | } 50 | }.queue(); 51 | } 52 | 53 | private GitCommandResult createFeatureBranch(String baseBranchName, String featureName) { 54 | GitflowErrorsListener errorListener = new GitflowErrorsListener(myProject); 55 | GitCommandResult result = myGitflow.startFeature(myRepo, featureName, baseBranchName, errorListener); 56 | 57 | if (result.success()) { 58 | String startedFeatureMessage = String.format("A new branch '%s%s' was created, based on '%s'", branchUtil.getPrefixFeature(), featureName, baseBranchName); 59 | NotifyUtil.notifySuccess(myProject, featureName, startedFeatureMessage); 60 | } else { 61 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 62 | } 63 | 64 | myRepo.update(); 65 | virtualFileMananger.asyncRefresh(null); //update editors 66 | return result; 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/StartHotfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.DialogWrapper; 8 | import git4idea.commands.GitCommandResult; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.ui.GitflowStartHotfixDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | 16 | public class StartHotfixAction extends AbstractStartAction { 17 | 18 | public StartHotfixAction(GitRepository repo) { 19 | super(repo, "Start Hotfix"); 20 | } 21 | 22 | public StartHotfixAction() { 23 | super("Start Hotfix"); 24 | } 25 | 26 | @Override 27 | public void actionPerformed(AnActionEvent e) { 28 | super.actionPerformed(e); 29 | 30 | GitflowStartHotfixDialog dialog = new GitflowStartHotfixDialog(myProject, myRepo); 31 | dialog.show(); 32 | 33 | if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return; 34 | 35 | final String hotfixName = dialog.getNewBranchName(); 36 | final String baseBranchName = dialog.getBaseBranchName(); 37 | 38 | this.runAction(e.getProject(), baseBranchName, hotfixName, null); 39 | } 40 | 41 | public void runAction(final Project project, final String baseBranchName, final String hotfixName, @Nullable final Runnable callInAwtLater){ 42 | super.runAction(project, baseBranchName, hotfixName, callInAwtLater); 43 | 44 | new Task.Backgroundable(myProject, "Starting hotfix " + hotfixName, false) { 45 | @Override 46 | public void run(@NotNull ProgressIndicator indicator) { 47 | final GitCommandResult commandResult = createHotfixBranch(baseBranchName, hotfixName); 48 | if (callInAwtLater != null && commandResult.success()) { 49 | callInAwtLater.run(); 50 | } 51 | } 52 | }.queue(); 53 | } 54 | 55 | private GitCommandResult createHotfixBranch(String baseBranchName, String hotfixBranchName) { 56 | GitflowErrorsListener errorListener = new GitflowErrorsListener(myProject); 57 | GitCommandResult result = myGitflow.startHotfix(myRepo, hotfixBranchName, baseBranchName, errorListener); 58 | 59 | if (result.success()) { 60 | String startedHotfixMessage = String.format("A new hotfix '%s%s' was created, based on '%s'", 61 | branchUtil.getPrefixHotfix(), hotfixBranchName, baseBranchName); 62 | NotifyUtil.notifySuccess(myProject, hotfixBranchName, startedHotfixMessage); 63 | } else { 64 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 65 | } 66 | 67 | myRepo.update(); 68 | 69 | return result; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/StartReleaseAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import com.intellij.openapi.ui.Messages; 7 | import git4idea.commands.GitCommandResult; 8 | import git4idea.repo.GitRepository; 9 | import git4idea.validators.GitNewBranchNameValidator; 10 | import gitflow.ui.NotifyUtil; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class StartReleaseAction extends AbstractStartAction { 15 | 16 | StartReleaseAction() { 17 | super("Start Release"); 18 | } 19 | 20 | StartReleaseAction(GitRepository repo) { 21 | super(repo,"Start Release"); 22 | } 23 | 24 | @Override 25 | public void actionPerformed(AnActionEvent e) { 26 | super.actionPerformed(e); 27 | 28 | final String releaseName = Messages.showInputDialog(myProject, "Enter the name of new release:", "New Release", Messages.getQuestionIcon(), "", 29 | GitNewBranchNameValidator.newInstance(repos)); 30 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 31 | 32 | if (releaseName == null){ 33 | // user clicked cancel 34 | } 35 | else if (releaseName.isEmpty()){ 36 | Messages.showWarningDialog(myProject, "You must provide a name for the release", "Whoops"); 37 | } 38 | else { 39 | new Task.Backgroundable(myProject,"Starting release "+releaseName,false){ 40 | @Override 41 | public void run(@NotNull ProgressIndicator indicator) { 42 | GitCommandResult result= myGitflow.startRelease(myRepo, releaseName, errorLineHandler); 43 | 44 | if (result.success()) { 45 | String startedReleaseMessage = String.format("A new release '%s%s' was created, based on '%s'", branchUtil.getPrefixRelease(), releaseName, branchUtil.getBranchnameDevelop()); 46 | NotifyUtil.notifySuccess(myProject, releaseName, startedReleaseMessage); 47 | } 48 | else { 49 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 50 | } 51 | 52 | myRepo.update(); 53 | 54 | } 55 | }.queue(); 56 | 57 | } 58 | 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/TrackBugfixAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRemote; 8 | import git4idea.repo.GitRepository; 9 | import gitflow.GitflowConfigUtil; 10 | import gitflow.ui.GitflowBranchChooseDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Iterator; 16 | 17 | public class TrackBugfixAction extends AbstractTrackAction { 18 | 19 | TrackBugfixAction() { 20 | super("Track Bugfix", BranchType.Bugfix); 21 | } 22 | 23 | TrackBugfixAction(GitRepository repo) { 24 | super(repo, "Track Bugfix", BranchType.Bugfix); 25 | } 26 | 27 | @Override 28 | public void actionPerformed(AnActionEvent e) { 29 | super.actionPerformed(e); 30 | 31 | ArrayList remoteBranches = branchUtil.getRemoteBranchNames(); 32 | ArrayList remoteBugfixBranches = new ArrayList(); 33 | 34 | //get only the branches with the proper prefix 35 | for (Iterator i = remoteBranches.iterator(); i.hasNext(); ) { 36 | String item = i.next(); 37 | if (item.contains(branchUtil.getPrefixBugfix())) { 38 | remoteBugfixBranches.add(item); 39 | } 40 | } 41 | 42 | if (remoteBranches.size() > 0) { 43 | GitflowBranchChooseDialog branchChoose = new GitflowBranchChooseDialog(myProject, remoteBugfixBranches); 44 | 45 | branchChoose.show(); 46 | if (branchChoose.isOK()) { 47 | runReadAction(() -> { 48 | String branchName = branchChoose.getSelectedBranchName(); 49 | 50 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 51 | final String bugfixName = gitflowConfigUtil.getBugfixNameFromBranch(branchName); 52 | final GitRemote remote = branchUtil.getRemoteByBranch(branchName); 53 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 54 | 55 | new Task.Backgroundable(myProject, "Tracking bugfix " + bugfixName, false) { 56 | @Override 57 | public void run(@NotNull ProgressIndicator indicator) { 58 | GitCommandResult result = myGitflow.trackBugfix(myRepo, bugfixName, remote, errorLineHandler); 59 | if (result.success()) { 60 | String trackedBugfixMessage = String.format("A new branch '%s%s' was created", branchUtil.getPrefixBugfix(), bugfixName); 61 | NotifyUtil.notifySuccess(myProject, bugfixName, trackedBugfixMessage); 62 | } else { 63 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 64 | } 65 | myRepo.update(); 66 | } 67 | }.queue(); 68 | }); 69 | } 70 | } else { 71 | NotifyUtil.notifyError(myProject, "Error", "No remote branches"); 72 | } 73 | 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/TrackFeatureAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRemote; 8 | import git4idea.repo.GitRepository; 9 | import gitflow.GitflowConfigUtil; 10 | import gitflow.ui.GitflowBranchChooseDialog; 11 | import gitflow.ui.NotifyUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Iterator; 16 | 17 | public class TrackFeatureAction extends AbstractTrackAction { 18 | 19 | TrackFeatureAction(){ 20 | super("Track Feature", BranchType.Feature); 21 | } 22 | 23 | TrackFeatureAction(GitRepository repo){ 24 | super(repo,"Track Feature", BranchType.Feature); 25 | } 26 | 27 | @Override 28 | public void actionPerformed(AnActionEvent e) { 29 | super.actionPerformed(e); 30 | 31 | ArrayList remoteBranches = branchUtil.getRemoteBranchNames(); 32 | ArrayList remoteFeatureBranches = new ArrayList(); 33 | 34 | //get only the branches with the proper prefix 35 | for(Iterator i = remoteBranches.iterator(); i.hasNext(); ) { 36 | String item = i.next(); 37 | if (item.contains(branchUtil.getPrefixFeature())){ 38 | remoteFeatureBranches.add(item); 39 | } 40 | } 41 | 42 | if (remoteBranches.size()>0){ 43 | GitflowBranchChooseDialog branchChoose = new GitflowBranchChooseDialog(myProject,remoteFeatureBranches); 44 | 45 | branchChoose.show(); 46 | if (branchChoose.isOK()){ 47 | runReadAction(() -> { 48 | String branchName= branchChoose.getSelectedBranchName(); 49 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 50 | final String featureName = gitflowConfigUtil.getFeatureNameFromBranch(branchName); 51 | final GitRemote remote = branchUtil.getRemoteByBranch(branchName); 52 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 53 | 54 | new Task.Backgroundable(myProject,"Tracking feature "+featureName,false){ 55 | @Override 56 | public void run(@NotNull ProgressIndicator indicator) { 57 | GitCommandResult result = myGitflow.trackFeature(myRepo, featureName, remote, errorLineHandler); 58 | 59 | if (result.success()) { 60 | String trackedFeatureMessage = String.format("A new branch '%s%s' was created", branchUtil.getPrefixFeature(), featureName); 61 | NotifyUtil.notifySuccess(myProject, featureName, trackedFeatureMessage); 62 | } 63 | else { 64 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 65 | } 66 | 67 | myRepo.update(); 68 | 69 | } 70 | }.queue(); 71 | }); 72 | } 73 | } 74 | else { 75 | NotifyUtil.notifyError(myProject, "Error", "No remote branches"); 76 | } 77 | 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/actions/TrackReleaseAction.java: -------------------------------------------------------------------------------- 1 | package gitflow.actions; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.progress.ProgressIndicator; 5 | import com.intellij.openapi.progress.Task; 6 | import git4idea.commands.GitCommandResult; 7 | import git4idea.repo.GitRepository; 8 | import gitflow.GitflowConfigUtil; 9 | import gitflow.ui.GitflowBranchChooseDialog; 10 | import gitflow.ui.NotifyUtil; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Iterator; 15 | 16 | public class TrackReleaseAction extends AbstractTrackAction { 17 | 18 | TrackReleaseAction(){ 19 | super("Track Release", BranchType.Release); 20 | } 21 | 22 | TrackReleaseAction(GitRepository repo){ 23 | super(repo,"Track Release", BranchType.Release); 24 | } 25 | 26 | @Override 27 | public void actionPerformed(AnActionEvent e) { 28 | super.actionPerformed(e); 29 | 30 | ArrayList remoteBranches = branchUtil.getRemoteBranchNames(); 31 | ArrayList remoteReleaseBranches = new ArrayList(); 32 | 33 | //get only the branches with the proper prefix 34 | for(Iterator i = remoteBranches.iterator(); i.hasNext(); ) { 35 | String item = i.next(); 36 | if (item.contains(branchUtil.getPrefixRelease())){ 37 | remoteReleaseBranches.add(item); 38 | } 39 | } 40 | 41 | if (remoteBranches.size()>0){ 42 | GitflowBranchChooseDialog branchChoose = new GitflowBranchChooseDialog(myProject,remoteReleaseBranches); 43 | 44 | branchChoose.show(); 45 | if (branchChoose.isOK()){ 46 | runReadAction(() -> { 47 | String branchName= branchChoose.getSelectedBranchName(); 48 | GitflowConfigUtil gitflowConfigUtil = GitflowConfigUtil.getInstance(myProject, myRepo); 49 | final String releaseName = gitflowConfigUtil.getReleaseNameFromBranch(branchName); 50 | final GitflowErrorsListener errorLineHandler = new GitflowErrorsListener(myProject); 51 | 52 | new Task.Backgroundable(myProject,"Tracking release "+releaseName,false){ 53 | @Override 54 | public void run(@NotNull ProgressIndicator indicator) { 55 | GitCommandResult result = myGitflow.trackRelease(myRepo, releaseName, errorLineHandler); 56 | 57 | if (result.success()) { 58 | String trackedReleaseMessage = String.format(" A new remote tracking branch '%s%s' was created", branchUtil.getPrefixRelease(), releaseName); 59 | NotifyUtil.notifySuccess(myProject, releaseName, trackedReleaseMessage); 60 | } 61 | else { 62 | NotifyUtil.notifyError(myProject, "Error", result.getErrorOutputAsJoinedString() + "Please have a look at the Version Control console for more details"); 63 | } 64 | 65 | myRepo.update(); 66 | } 67 | }.queue(); 68 | }); 69 | } 70 | } 71 | else { 72 | NotifyUtil.notifyError(myProject, "Error", "No remote branches"); 73 | } 74 | 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/AbstractBranchStartDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/AbstractBranchStartDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.DialogWrapper; 5 | import com.intellij.openapi.ui.ValidationInfo; 6 | 7 | import javax.swing.*; 8 | import javax.swing.event.DocumentEvent; 9 | import javax.swing.event.DocumentListener; 10 | 11 | import git4idea.remote.GitRememberedInputs; 12 | import git4idea.repo.GitRepository; 13 | import gitflow.GitflowBranchUtil; 14 | import gitflow.GitflowBranchUtilManager; 15 | 16 | /** 17 | * Base class for a "start" dialog. Such a dialog prompts the user to enter a name for a new branch 18 | * and select a base branch. See {@link GitflowStartFeatureDialog} for an example implementation. 19 | */ 20 | public abstract class AbstractBranchStartDialog extends DialogWrapper { 21 | 22 | private JPanel contentPane; 23 | private JTextField branchNameTextField; 24 | private JComboBox branchFromCombo; 25 | private JLabel branchNameLabel; 26 | private JLabel spacesLabel; 27 | private JLabel branchFromTitle; 28 | 29 | private Project project; 30 | protected GitRepository myRepo; 31 | private GitflowBranchUtil gitflowBranchUtil; 32 | 33 | public AbstractBranchStartDialog(Project project, GitRepository repo) { 34 | super(project, false); 35 | this.project = project; 36 | this.myRepo = repo; 37 | this.gitflowBranchUtil = GitflowBranchUtilManager.getBranchUtil(repo); 38 | 39 | init(); 40 | final String label = getLabel(); 41 | setTitle("New " + label + "..."); 42 | branchNameLabel.setText(String.format("Enter a name for the new %s...", label)); 43 | setModal(true); 44 | 45 | //set the base branch combo 46 | branchFromCombo.setModel(gitflowBranchUtil.createBranchComboModel(getDefaultBranch())); 47 | 48 | branchNameTextField.getDocument().addDocumentListener(new DocumentListener() { 49 | public void changedUpdate(DocumentEvent e) { 50 | validateBranchName(); 51 | } 52 | public void removeUpdate(DocumentEvent e) { 53 | validateBranchName(); 54 | } 55 | public void insertUpdate(DocumentEvent e) { 56 | validateBranchName(); 57 | } 58 | 59 | public void validateBranchName() { 60 | if (branchNameTextField.getText().contains(" ")){ 61 | spacesLabel.setVisible(true); 62 | } 63 | else{ 64 | spacesLabel.setVisible(false); 65 | } 66 | 67 | if (branchNameTextField.getText().contains("&")){ 68 | AbstractBranchStartDialog.super.setOKActionEnabled(false); 69 | } 70 | else{ 71 | AbstractBranchStartDialog.super.setOKActionEnabled(true); 72 | } 73 | } 74 | }); 75 | 76 | if (showBranchFromCombo() == false){ 77 | branchFromTitle.setVisible(false); 78 | branchFromCombo.setVisible(false); 79 | } 80 | } 81 | 82 | protected boolean showBranchFromCombo(){ 83 | return true; 84 | } 85 | 86 | @Override 87 | public JComponent getPreferredFocusedComponent() { 88 | return branchNameTextField; 89 | } 90 | 91 | /** 92 | * @return The name of the new branch as specified by the user 93 | */ 94 | public String getNewBranchName() { 95 | return branchNameTextField.getText().trim().replaceAll(" ", "_"); 96 | } 97 | 98 | /** 99 | * @return The name of the base branch (the branch on which the new hotfix or feature should be 100 | * based on) 101 | */ 102 | public String getBaseBranchName() { 103 | GitflowBranchUtil.ComboEntry selectedBranch = (GitflowBranchUtil.ComboEntry) branchFromCombo.getModel().getSelectedItem(); 104 | return selectedBranch.getBranchName(); 105 | } 106 | 107 | /** 108 | * @return The label for this dialog (e.g. "hotfix" or "feature"). Will be used for the window 109 | * title and other labels. 110 | */ 111 | protected abstract String getLabel(); 112 | 113 | /** 114 | * @return The name of the default branch, i.e. the branch that is selected by default when 115 | * opening the dialog. 116 | */ 117 | protected abstract String getDefaultBranch(); 118 | 119 | protected Project getProject() { 120 | return this.project; 121 | } 122 | 123 | @Override 124 | protected ValidationInfo doValidate() { 125 | boolean isBranchNameSpecified = branchNameTextField.getText().trim().length() > 0; 126 | if (!isBranchNameSpecified) { 127 | return new ValidationInfo("No name specified", branchNameTextField); 128 | } else { 129 | return null; 130 | } 131 | } 132 | 133 | @Override 134 | protected JComponent createCenterPanel() { 135 | return contentPane; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/AbstractGitflowActionAckDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/AbstractGitflowActionAckDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.DialogWrapper; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import javax.swing.*; 8 | 9 | /** 10 | * @author rubin 2023年07月27日 11 | */ 12 | public abstract class AbstractGitflowActionAckDialog extends DialogWrapper { 13 | private JPanel contentPanel; 14 | private JLabel ackTextLabel; 15 | 16 | public AbstractGitflowActionAckDialog(@Nullable Project project) { 17 | super(project, true); 18 | 19 | setModal(true); 20 | 21 | setTitle("Ack"); 22 | init(); 23 | ackTextLabel.setText(getAckText()); 24 | } 25 | 26 | @Override 27 | protected @Nullable JComponent createCenterPanel() { 28 | return contentPanel; 29 | } 30 | 31 | protected String getAckText() { 32 | return ""; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowBranchChooseDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowBranchChooseDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.DialogWrapper; 5 | import com.intellij.openapi.ui.ValidationInfo; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import javax.swing.*; 9 | import javax.swing.event.DocumentEvent; 10 | import javax.swing.event.DocumentListener; 11 | import javax.swing.table.DefaultTableModel; 12 | import javax.swing.table.TableRowSorter; 13 | import java.util.List; 14 | import java.util.stream.IntStream; 15 | 16 | /** 17 | * Dialog for choosing branches 18 | * 19 | * @author Opher Vishnia / opherv.com / opherv@gmail.com 20 | */ 21 | 22 | public class GitflowBranchChooseDialog extends DialogWrapper { 23 | private JPanel contentPane; 24 | private JTextField searchField; 25 | //using a single column table because it has built in sorting and filtering capabilities. 26 | private JTable branchList; 27 | private JScrollPane scrollpane; 28 | private JPanel branchPanel; 29 | 30 | public GitflowBranchChooseDialog(Project project, List branchNames) { 31 | super(project, true); 32 | 33 | setModal(true); 34 | 35 | setTitle("Choose Branch"); 36 | initBranchList(branchNames); 37 | init(); 38 | } 39 | 40 | @Nullable 41 | @Override 42 | protected ValidationInfo doValidate() { 43 | if (branchList.getSelectedRow() == -1) { 44 | return new ValidationInfo("No branch selected!"); 45 | } else { 46 | return null; 47 | } 48 | } 49 | 50 | @Nullable 51 | @Override 52 | protected JComponent createCenterPanel() { 53 | return contentPane; 54 | } 55 | 56 | public String getSelectedBranchName() { 57 | int selectedRow = branchList.getSelectedRow(); 58 | return (String) branchList.getValueAt(selectedRow, 0); 59 | } 60 | 61 | private void initBranchList(List branchNames) { 62 | branchList.setTableHeader(null); 63 | DefaultTableModel model = (DefaultTableModel) branchList.getModel(); 64 | //only one column. No Header. 65 | model.setColumnCount(1); 66 | for (String branchName : branchNames) { 67 | model.addRow(new String[]{branchName}); 68 | } 69 | //sort on first (and only column) 70 | TableRowSorter rowSorter = new TableRowSorter<>(); 71 | rowSorter.setModel(model); 72 | branchList.setRowSorter(rowSorter); 73 | branchList.getRowSorter().toggleSortOrder(0); 74 | //add filtering capabilities. 75 | searchField.getDocument().addDocumentListener( 76 | new DocumentListener() { 77 | @Override 78 | public void insertUpdate(DocumentEvent documentEvent) { 79 | filter(); 80 | } 81 | 82 | @Override 83 | public void removeUpdate(DocumentEvent documentEvent) { 84 | filter(); 85 | } 86 | 87 | @Override 88 | public void changedUpdate(DocumentEvent documentEvent) { 89 | filter(); 90 | } 91 | 92 | private void filter() { 93 | String text = searchField.getText(); 94 | if (text.trim().length() == 0) { 95 | rowSorter.setRowFilter(null); 96 | } else { 97 | rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text)); 98 | } 99 | } 100 | } 101 | ); 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowCloseTaskPanel.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowCloseTaskPanel.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vcs.VcsTaskHandler; 7 | import com.intellij.tasks.Task; 8 | import com.intellij.tasks.TaskManager; 9 | import com.intellij.tasks.impl.TaskManagerImpl; 10 | import com.intellij.tasks.ui.TaskDialogPanel; 11 | import git4idea.repo.GitRepository; 12 | import gitflow.GitflowBranchUtil; 13 | import gitflow.GitflowBranchUtilManager; 14 | import gitflow.GitflowConfigurable; 15 | import gitflow.GitflowState; 16 | import gitflow.actions.FinishBugfixAction; 17 | import gitflow.actions.FinishFeatureAction; 18 | import gitflow.actions.FinishHotfixAction; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import javax.swing.*; 22 | 23 | public class GitflowCloseTaskPanel extends TaskDialogPanel { 24 | private JPanel myPanel; 25 | private JCheckBox finishFeatureCheckbox; 26 | private JCheckBox finishHotfixCheckbox; 27 | private JPanel finishHotfixPanel; 28 | private JTextField tagMessageTextField; 29 | private JPanel finishFeaturePanel; 30 | private JPanel finishBugfixPanel; 31 | private JCheckBox finishBugfixCheckBox; 32 | 33 | private Project myProject; 34 | private Task myTask; 35 | private GitRepository myRepo; 36 | private GitflowBranchUtil gitflowBranchUtil; 37 | private TaskManagerImpl myTaskManager; 38 | private VcsTaskHandler myVcsTaskHandler; 39 | private String tagMessage; 40 | 41 | final private GitflowState gitflowState; 42 | 43 | GitflowCloseTaskPanel(Project project, Task task, GitRepository repo){ 44 | myProject = project; 45 | myTask = task; 46 | myRepo = repo; 47 | gitflowState = ApplicationManager.getApplication().getService(GitflowState.class); 48 | 49 | gitflowBranchUtil = GitflowBranchUtilManager.getBranchUtil(myRepo); 50 | myTaskManager = (TaskManagerImpl) TaskManager.getManager(project); 51 | VcsTaskHandler[] vcsTaskHAndlers = VcsTaskHandler.getAllHandlers(project); 52 | if (vcsTaskHAndlers.length > 0){ 53 | //todo handle case of multiple vcs handlers 54 | myVcsTaskHandler = vcsTaskHAndlers[0]; 55 | } 56 | 57 | 58 | String branchName = myVcsTaskHandler != null 59 | ? myVcsTaskHandler.cleanUpBranchName(myTaskManager.constructDefaultBranchName(task)) 60 | : myTaskManager.suggestBranchName(task); 61 | 62 | if (GitflowConfigurable.isOptionActive(project, "HOTFIX_dontTag")) { 63 | tagMessage=""; 64 | tagMessageTextField.setEnabled(false); 65 | tagMessageTextField.setToolTipText("Hotfix tagging is disabled in Gitflow options"); 66 | 67 | } 68 | else{ 69 | tagMessage = GitflowConfigurable.getOptionTextString(project, "HOTFIX_customHotfixCommitMessage").replace("%name%", branchName); 70 | tagMessageTextField.setToolTipText(null); 71 | } 72 | 73 | tagMessageTextField.setText(tagMessage); 74 | 75 | } 76 | 77 | @NotNull 78 | @Override 79 | public JComponent getPanel() { 80 | String taskBranchName = gitflowState.getTaskBranch(myTask); 81 | if (taskBranchName != null) { 82 | myPanel.setVisible(true); 83 | if (gitflowBranchUtil.isBranchFeature(taskBranchName)) { 84 | finishFeaturePanel.setVisible(true); 85 | finishHotfixPanel.setVisible(false); 86 | finishBugfixPanel.setVisible(false); 87 | } else if (gitflowBranchUtil.isBranchHotfix(taskBranchName)) { 88 | finishFeaturePanel.setVisible(false); 89 | finishHotfixPanel.setVisible(true); 90 | finishBugfixPanel.setVisible(false); 91 | } else if (gitflowBranchUtil.isBranchBugfix(taskBranchName)) { 92 | finishFeaturePanel.setVisible(false); 93 | finishHotfixPanel.setVisible(false); 94 | finishBugfixPanel.setVisible(true); 95 | } 96 | } 97 | else{ 98 | myPanel.setVisible(false); 99 | } 100 | 101 | return myPanel; 102 | } 103 | 104 | @Override 105 | public void commit() { 106 | String taskFullBranchName = gitflowState.getTaskBranch(myTask); 107 | 108 | // test if current task is a gitflow task 109 | if (taskFullBranchName != null) { 110 | String taskBranchName = gitflowBranchUtil.stripFullBranchName(taskFullBranchName); 111 | 112 | if (finishFeatureCheckbox.isSelected()) { 113 | FinishFeatureAction action = new FinishFeatureAction(myRepo); 114 | action.runAction(myProject, taskBranchName); 115 | } else if (finishHotfixCheckbox.isSelected()) { 116 | FinishHotfixAction action = new FinishHotfixAction(myRepo); 117 | action.runAction(myProject, taskBranchName, tagMessageTextField.getText()); 118 | } else if (finishBugfixCheckBox.isSelected()) { 119 | FinishBugfixAction action = new FinishBugfixAction(myRepo); 120 | action.runAction(myProject, taskBranchName); 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowFinishActionAckDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * @author rubin 2023年07月27日 8 | */ 9 | public class GitflowFinishActionAckDialog extends AbstractGitflowActionAckDialog { 10 | public GitflowFinishActionAckDialog(@Nullable Project project) { 11 | super(project); 12 | } 13 | 14 | @Override 15 | protected String getAckText() { 16 | return "Are you sure you want to Finish?"; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowInitOptionsDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.ui.DialogWrapper; 5 | import com.intellij.openapi.ui.ValidationInfo; 6 | import com.intellij.openapi.util.text.StringUtil; 7 | import com.intellij.ui.CollectionComboBoxModel; 8 | import gitflow.GitflowBranchUtil; 9 | import gitflow.GitflowInitOptions; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import javax.swing.*; 13 | import java.awt.event.ItemEvent; 14 | import java.awt.event.ItemListener; 15 | import java.util.Arrays; 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | /** 20 | * @author Andreas Vogler (Andreas.Vogler@geneon.de) 21 | */ 22 | 23 | public class GitflowInitOptionsDialog extends DialogWrapper { 24 | private JPanel contentPane; 25 | private JCheckBox useNonDefaultConfigurationCheckBox; 26 | 27 | private JComboBox productionBranchComboBox; 28 | private JComboBox developmentBranchComboBox; 29 | private JTextField featurePrefixTextField; 30 | private JTextField releasePrefixTextField; 31 | private JTextField hotfixPrefixTextField; 32 | private JTextField supportPrefixTextField; 33 | private JTextField versionPrefixTextField; 34 | private JTextField bugfixPrefixTextField; 35 | 36 | private List localBranches; 37 | 38 | public GitflowInitOptionsDialog(Project project, List _localBranches) { 39 | super(project); 40 | localBranches = _localBranches; 41 | 42 | setTitle("Options for gitflow init"); 43 | setLocalBranchesComboBox(false); 44 | 45 | init(); 46 | useNonDefaultConfigurationCheckBox.addItemListener(new ItemListener() { 47 | @Override 48 | public void itemStateChanged(ItemEvent e) { 49 | enableFields(e.getStateChange()==ItemEvent.SELECTED); 50 | } 51 | }); 52 | } 53 | 54 | private void setLocalBranchesComboBox(boolean isNonDefault){ 55 | if (isNonDefault){ 56 | developmentBranchComboBox.setModel(new CollectionComboBoxModel<>(localBranches)); 57 | productionBranchComboBox.setModel(new CollectionComboBoxModel<>(localBranches)); 58 | } else { 59 | developmentBranchComboBox.setModel(new CollectionComboBoxModel<>(Collections.singletonList("develop"))); 60 | productionBranchComboBox.setModel(new CollectionComboBoxModel<>(Collections.singletonList("master"))); 61 | } 62 | } 63 | 64 | private void enableFields(boolean enable) { 65 | setLocalBranchesComboBox(enable); 66 | 67 | productionBranchComboBox.setEnabled(enable); 68 | developmentBranchComboBox.setEnabled(enable); 69 | featurePrefixTextField.setEnabled(enable); 70 | releasePrefixTextField.setEnabled(enable); 71 | hotfixPrefixTextField.setEnabled(enable); 72 | supportPrefixTextField.setEnabled(enable); 73 | bugfixPrefixTextField.setEnabled(enable); 74 | versionPrefixTextField.setEnabled(enable); 75 | } 76 | 77 | public boolean useNonDefaultConfiguration() 78 | { 79 | return useNonDefaultConfigurationCheckBox.isSelected(); 80 | } 81 | 82 | public GitflowInitOptions getOptions() 83 | { 84 | GitflowInitOptions options = new GitflowInitOptions(); 85 | 86 | options.setUseDefaults(!useNonDefaultConfigurationCheckBox.isSelected()); 87 | options.setProductionBranch((String) productionBranchComboBox.getSelectedItem()); 88 | options.setDevelopmentBranch((String) developmentBranchComboBox.getSelectedItem()); 89 | options.setFeaturePrefix(featurePrefixTextField.getText()); 90 | options.setReleasePrefix(releasePrefixTextField.getText()); 91 | options.setHotfixPrefix(hotfixPrefixTextField.getText()); 92 | options.setBugfixPrefix(bugfixPrefixTextField.getText()); 93 | options.setSupportPrefix(supportPrefixTextField.getText()); 94 | options.setVersionPrefix(versionPrefixTextField.getText()); 95 | 96 | return options; 97 | } 98 | 99 | @Nullable 100 | @Override 101 | protected ValidationInfo doValidate() { 102 | String message = "Please fill all branch names and prefixes"; 103 | 104 | if(useNonDefaultConfiguration()) { 105 | if(productionBranchComboBox.getSelectedItem().equals(developmentBranchComboBox.getSelectedItem())) { 106 | return new ValidationInfo("Production and development branch must be distinct branches", developmentBranchComboBox); 107 | } 108 | if (StringUtil.isEmptyOrSpaces(featurePrefixTextField.getText())) { 109 | return new ValidationInfo(message, featurePrefixTextField); 110 | } 111 | if (StringUtil.isEmptyOrSpaces(releasePrefixTextField.getText())) { 112 | return new ValidationInfo(message, releasePrefixTextField); 113 | } 114 | if (StringUtil.isEmptyOrSpaces(hotfixPrefixTextField.getText())) { 115 | return new ValidationInfo(message, hotfixPrefixTextField); 116 | } 117 | if (StringUtil.isEmptyOrSpaces(supportPrefixTextField.getText())) { 118 | return new ValidationInfo(message, supportPrefixTextField); 119 | } 120 | if (StringUtil.isEmptyOrSpaces(bugfixPrefixTextField.getText())) { 121 | return new ValidationInfo(message, bugfixPrefixTextField); 122 | } 123 | } 124 | 125 | return null; 126 | } 127 | 128 | @Nullable 129 | @Override 130 | protected JComponent createCenterPanel() { 131 | return contentPane; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowOpenTaskPanel.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowOptionsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowOptionsForm.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import gitflow.GitflowOptionsFactory; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.ItemEvent; 9 | import java.awt.event.ItemListener; 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author Andreas Vogler (Andreas.Vogler@geneon.de) 16 | * @author Opher Vishnia (opherv@gmail.com) 17 | */ 18 | public class GitflowOptionsForm implements ItemListener { 19 | 20 | private JPanel contentPane; 21 | private JPanel releasePanel; 22 | private JPanel featurePanel; 23 | private JPanel hotfixPanel; 24 | private JPanel bugfixPanel; 25 | 26 | Map, ArrayList>> gitflowOptions; 27 | Map optionComponents; 28 | 29 | private class OptionComponent{ 30 | public JComponent checkbox; 31 | public JComponent textfield; 32 | 33 | public OptionComponent(JComponent checkboxComponent, @Nullable JComponent textfieldComponent){ 34 | this.checkbox = checkboxComponent; 35 | this.textfield = textfieldComponent; 36 | } 37 | } 38 | 39 | public GitflowOptionsForm(){ 40 | gitflowOptions = GitflowOptionsFactory.getOptions(); 41 | 42 | optionComponents = new HashMap(); 43 | featurePanel.setLayout(new BoxLayout(featurePanel, BoxLayout.Y_AXIS)); 44 | hotfixPanel.setLayout(new BoxLayout(hotfixPanel, BoxLayout.Y_AXIS)); 45 | releasePanel.setLayout(new BoxLayout(releasePanel, BoxLayout.Y_AXIS)); 46 | bugfixPanel.setLayout(new BoxLayout(bugfixPanel, BoxLayout.Y_AXIS)); 47 | 48 | HashMap branchTypeToPanel = new HashMap(); 49 | 50 | branchTypeToPanel.put(GitflowOptionsFactory.TYPE.FEATURE, featurePanel); 51 | branchTypeToPanel.put(GitflowOptionsFactory.TYPE.RELEASE, releasePanel); 52 | branchTypeToPanel.put(GitflowOptionsFactory.TYPE.HOTFIX, hotfixPanel); 53 | branchTypeToPanel.put(GitflowOptionsFactory.TYPE.BUGFIX, bugfixPanel); 54 | 55 | for (GitflowOptionsFactory.TYPE type: GitflowOptionsFactory.TYPE.values()) { 56 | JPanel optionPanel = branchTypeToPanel.get(type); 57 | 58 | for (Map optionMap : gitflowOptions.get(type)) { 59 | JPanel optionRow = new JPanel(); 60 | optionRow.setLayout(new BoxLayout(optionRow, BoxLayout.X_AXIS)); 61 | optionRow.setAlignmentX(Component.LEFT_ALIGNMENT); 62 | 63 | JCheckBox checkbox = new JCheckBox(); 64 | String checkboxText = optionMap.get("description"); 65 | if (optionMap.get("flag") != null){ 66 | checkboxText += " (" + optionMap.get("flag") + ")"; 67 | } 68 | checkbox.setText(checkboxText); 69 | checkbox.setMargin(new Insets(0, 0, 0, 20)); 70 | checkbox.addItemListener(this); 71 | optionRow.add(checkbox); 72 | 73 | JTextField textField = null; 74 | 75 | // some options have input text 76 | if (optionMap.get("inputText") != null) { 77 | textField = new JTextField(); 78 | textField.setText(optionMap.get("inputText")); 79 | textField.setToolTipText(optionMap.get("toolTip")); 80 | optionRow.add(textField); 81 | } 82 | 83 | optionPanel.add(optionRow); 84 | 85 | // keep a reference for the components for future use 86 | OptionComponent optionComponent = new OptionComponent(checkbox, textField); 87 | optionComponents.put(GitflowOptionsFactory.getOptionId(type, optionMap.get("key")), optionComponent); 88 | } 89 | } 90 | } 91 | 92 | 93 | public JPanel getContentPane() { 94 | return contentPane; 95 | } 96 | 97 | /** Listens to the check boxes. */ 98 | public void itemStateChanged(ItemEvent e) { 99 | this.updateFormDisabledStatus(); 100 | } 101 | 102 | public void updateFormDisabledStatus(){ 103 | JCheckBox dontTagRelease = (JCheckBox) optionComponents.get("RELEASE_dontTag").checkbox; 104 | JCheckBox customTagCommitMessageCheckbox = (JCheckBox) optionComponents.get("RELEASE_customTagCommitMessage").checkbox; 105 | JTextField customTagCommitMessageTexfield = (JTextField) optionComponents.get("RELEASE_customTagCommitMessage").textfield; 106 | 107 | JCheckBox dontTagHotfix = (JCheckBox) optionComponents.get("HOTFIX_dontTag").checkbox; 108 | JCheckBox customHotfixCommitMessageCheckbox = (JCheckBox) optionComponents.get("HOTFIX_customHotfixCommitMessage").checkbox; 109 | JTextField customHotfixCommitMessageTextfield = (JTextField) optionComponents.get("HOTFIX_customHotfixCommitMessage").textfield; 110 | 111 | //disable\enable the finish release tag commit message according to the checkbox state 112 | 113 | if (customTagCommitMessageCheckbox.isSelected() && dontTagRelease.isSelected()==false) { 114 | customTagCommitMessageTexfield.setEditable(true); 115 | customTagCommitMessageTexfield.setEnabled(true); 116 | } 117 | else{ 118 | customTagCommitMessageTexfield.setEditable(false); 119 | } 120 | 121 | if (dontTagRelease.isSelected()) { 122 | customTagCommitMessageCheckbox.setEnabled(false); 123 | customTagCommitMessageTexfield.setEnabled(false); 124 | } 125 | else{ 126 | customTagCommitMessageCheckbox.setEnabled(true); 127 | if( customTagCommitMessageCheckbox.isSelected()){ 128 | customTagCommitMessageTexfield.setEnabled(true); 129 | customTagCommitMessageTexfield.setEditable(true); 130 | } 131 | } 132 | 133 | //disable\enable the finish hotfix tag commit message according to the checkbox state 134 | if (customHotfixCommitMessageCheckbox.isSelected()) { 135 | customHotfixCommitMessageTextfield.setEditable(true); 136 | customHotfixCommitMessageTextfield.setEnabled(true); 137 | } 138 | else{ 139 | customHotfixCommitMessageTextfield.setEditable(false); 140 | } 141 | 142 | if (dontTagHotfix.isSelected()) { 143 | customHotfixCommitMessageCheckbox.setEnabled(false); 144 | customHotfixCommitMessageTextfield.setEnabled(false); 145 | } 146 | else{ 147 | customHotfixCommitMessageCheckbox.setEnabled(true); 148 | if( customHotfixCommitMessageCheckbox.isSelected()){ 149 | customHotfixCommitMessageTextfield.setEnabled(true); 150 | customHotfixCommitMessageTextfield.setEditable(true); 151 | } 152 | } 153 | } 154 | 155 | public boolean isOptionActive(String optionId){ 156 | return ((JCheckBox) optionComponents.get(optionId).checkbox).isSelected(); 157 | } 158 | 159 | public String getOptionText(String optionId){ 160 | String text = null; 161 | JTextField textField = (JTextField) optionComponents.get(optionId).textfield; 162 | if (textField != null){ 163 | text = textField.getText(); 164 | } 165 | 166 | return text; 167 | } 168 | 169 | public void setOptionActive(String optionId, boolean selected){ 170 | ((JCheckBox) optionComponents.get(optionId).checkbox).setSelected(selected); 171 | } 172 | 173 | public void setOptionText(String optionId, String text){ 174 | ((JTextField) optionComponents.get(optionId).textfield).setText(text); 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowPublishActionAckDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * @author rubin 2023年07月27日 8 | */ 9 | public class GitflowPublishActionAckDialog extends AbstractGitflowActionAckDialog { 10 | public GitflowPublishActionAckDialog(@Nullable Project project) { 11 | super(project); 12 | } 13 | 14 | @Override 15 | protected String getAckText() { 16 | return "Are you sure you want to Publish?"; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowStartBugfixDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import git4idea.repo.GitRepository; 5 | import gitflow.GitflowConfigUtil; 6 | import gitflow.ui.AbstractBranchStartDialog; 7 | 8 | public class GitflowStartBugfixDialog extends AbstractBranchStartDialog { 9 | 10 | public GitflowStartBugfixDialog(Project project, GitRepository repo) { 11 | super(project, repo); 12 | } 13 | 14 | @Override 15 | protected String getLabel() { 16 | return "bugfix"; 17 | } 18 | 19 | @Override 20 | protected String getDefaultBranch() { 21 | return GitflowConfigUtil.getInstance(getProject(), myRepo).developBranch; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowStartFeatureDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | 5 | import git4idea.repo.GitRepository; 6 | import gitflow.GitflowConfigUtil; 7 | import gitflow.ui.AbstractBranchStartDialog; 8 | 9 | public class GitflowStartFeatureDialog extends AbstractBranchStartDialog { 10 | 11 | public GitflowStartFeatureDialog(Project project, GitRepository repo) { 12 | super(project, repo); 13 | } 14 | 15 | @Override 16 | protected String getLabel() { 17 | return "feature"; 18 | } 19 | 20 | @Override 21 | protected String getDefaultBranch() { 22 | return GitflowConfigUtil.getInstance(getProject(), myRepo).developBranch; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowStartHotfixDialog.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import git4idea.repo.GitRepository; 5 | import gitflow.GitflowConfigUtil; 6 | import gitflow.ui.AbstractBranchStartDialog; 7 | 8 | public class GitflowStartHotfixDialog extends AbstractBranchStartDialog { 9 | 10 | public GitflowStartHotfixDialog(Project project, GitRepository repo) { 11 | super(project, repo); 12 | } 13 | 14 | protected boolean showBranchFromCombo(){ 15 | return false; 16 | } 17 | 18 | @Override 19 | protected String getLabel() { 20 | return "hotfix"; 21 | } 22 | 23 | @Override 24 | protected String getDefaultBranch() { 25 | return GitflowConfigUtil.getInstance(getProject(), myRepo).masterBranch; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowStatusBarWidgetFactory.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.Disposer; 5 | import com.intellij.openapi.wm.StatusBar; 6 | import com.intellij.openapi.wm.StatusBarWidget; 7 | import com.intellij.openapi.wm.StatusBarWidgetFactory; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class GitflowStatusBarWidgetFactory implements StatusBarWidgetFactory { 12 | 13 | @NotNull 14 | @Override 15 | public String getId() { 16 | return "gitflowWidget"; 17 | } 18 | 19 | @Nls 20 | @NotNull 21 | @Override 22 | public String getDisplayName() { 23 | return "GitFlow status bar"; 24 | } 25 | 26 | @Override 27 | public boolean isAvailable(@NotNull Project project) { 28 | return true; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public StatusBarWidget createWidget(@NotNull Project project) { 34 | GitflowWidget gitflowWidget = new GitflowWidget(project); 35 | return gitflowWidget; 36 | } 37 | 38 | @Override 39 | public void disposeWidget(@NotNull StatusBarWidget widget) { 40 | Disposer.dispose(widget); 41 | } 42 | 43 | @Override 44 | public boolean canBeEnabledOn(@NotNull StatusBar statusBar) { 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/GitflowTaskDialogPanelProvider.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.tasks.LocalTask; 5 | import com.intellij.tasks.TaskManager; 6 | import com.intellij.tasks.actions.vcs.VcsTaskDialogPanelProvider; 7 | import com.intellij.tasks.ui.TaskDialogPanel; 8 | import git4idea.branch.GitBranchUtil; 9 | import git4idea.repo.GitRepository; 10 | import gitflow.GitflowBranchUtil; 11 | import gitflow.GitflowBranchUtilManager; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | 16 | public class GitflowTaskDialogPanelProvider extends VcsTaskDialogPanelProvider { 17 | 18 | @Nullable 19 | @Override 20 | public TaskDialogPanel getOpenTaskPanel(@NotNull Project project, @NotNull LocalTask task) { 21 | GitRepository currentRepo = GitBranchUtil.getCurrentRepository(project); 22 | GitflowBranchUtil branchUtil = GitflowBranchUtilManager.getBranchUtil(currentRepo); 23 | if (branchUtil.hasGitflow()) { 24 | return TaskManager.getManager(project).isVcsEnabled() ? new GitflowOpenTaskPanel(project, task, currentRepo) : null; 25 | } 26 | else{ 27 | return null; 28 | } 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public TaskDialogPanel getCloseTaskPanel(@NotNull Project project, @NotNull LocalTask task) { 34 | GitRepository currentRepo = GitBranchUtil.getCurrentRepository(project); 35 | GitflowBranchUtil branchUtil = GitflowBranchUtilManager.getBranchUtil(currentRepo); 36 | 37 | if (branchUtil.hasGitflow()) { 38 | return TaskManager.getManager(project).isVcsEnabled() ? new GitflowCloseTaskPanel(project, task, currentRepo) : null; 39 | } 40 | else{ 41 | return null; 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/NotifyUtil.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.notification.NotificationGroup; 4 | import com.intellij.notification.NotificationGroupManager; 5 | import com.intellij.notification.NotificationType; 6 | import com.intellij.openapi.project.Project; 7 | 8 | public class NotifyUtil 9 | { 10 | private static final NotificationGroup TOOLWINDOW_NOTIFICATION = NotificationGroupManager.getInstance() 11 | .getNotificationGroup("Gitflow Errors WINDOW"); 12 | private static final NotificationGroup STICKY_NOTIFICATION = NotificationGroupManager.getInstance() 13 | .getNotificationGroup("Gitflow Errors STICKY"); 14 | private static final NotificationGroup BALLOON_NOTIFICATION = NotificationGroupManager.getInstance() 15 | .getNotificationGroup("Gitflow Notifications"); 16 | 17 | public static void notifySuccess(Project project, String title, String message) { 18 | notify(NotificationType.INFORMATION, BALLOON_NOTIFICATION, project, title, message); 19 | } 20 | 21 | public static void notifyInfo(Project project, String title, String message) { 22 | notify(NotificationType.INFORMATION, TOOLWINDOW_NOTIFICATION, project, title, message); 23 | } 24 | 25 | public static void notifyError(Project project, String title, String message) { 26 | notify(NotificationType.ERROR, TOOLWINDOW_NOTIFICATION, project, title, message); 27 | } 28 | 29 | public static void notifyError(Project project, String title, Exception exception) { 30 | notify(NotificationType.ERROR, STICKY_NOTIFICATION, project, title, exception.getMessage()); 31 | } 32 | 33 | private static void notify(NotificationType type, NotificationGroup group, Project project, String title, String message) { 34 | group.createNotification(title, message, type).notify(project); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/gitflow/ui/UnsupportedVersionWidgetPresentation.java: -------------------------------------------------------------------------------- 1 | package gitflow.ui; 2 | 3 | import com.intellij.ide.BrowserUtil; 4 | import com.intellij.openapi.ui.MessageDialogBuilder; 5 | import com.intellij.openapi.ui.Messages; 6 | import com.intellij.openapi.wm.StatusBarWidget; 7 | import com.intellij.util.Consumer; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.awt.event.MouseEvent; 12 | 13 | public class UnsupportedVersionWidgetPresentation implements StatusBarWidget.TextPresentation { 14 | 15 | @NotNull 16 | @Override 17 | public String getText() { 18 | return "Unsupported Git Flow Version"; 19 | } 20 | 21 | @Override 22 | public float getAlignment() { 23 | return 0; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public String getTooltipText() { 29 | return "Click for details"; 30 | } 31 | 32 | @Nullable 33 | @Override 34 | public Consumer getClickConsumer() { 35 | return mouseEvent -> { 36 | MessageDialogBuilder.YesNo builder = MessageDialogBuilder.yesNo("Unsupported Git Flow version", "The Git Flow CLI version installed isn't supported by the Git Flow Integration plugin") 37 | .yesText("More information (open browser)") 38 | .noText("no"); 39 | if (builder.ask(mouseEvent.getComponent())) { 40 | BrowserUtil.browse("https://github.com/OpherV/gitflow4idea/blob/develop/GITFLOW_VERSION.md"); 41 | } 42 | }; 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Git Flow Integration Plus 4 | SET_BY_GRADLE 5 | SET_BY_GRADLE 6 | SET_BY_GRADLE 7 | VCS Integration 8 | Rubin Carter 9 | 10 | com.intellij.modules.vcs 11 | com.intellij.tasks 12 | Git4Idea 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 25 | 26 | 28 | 29 | 33 | 37 | 41 | 45 | 46 | 50 | 54 | 58 | 62 | 63 | 67 | 71 | 72 | 76 | 77 | 81 | 82 | 86 | 87 | 91 | 92 | 96 | 97 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | --------------------------------------------------------------------------------