├── .gitignore ├── LICENSE ├── README.md ├── rules ├── BUILD ├── WORKSPACE ├── def.bzl ├── private │ ├── BUILD │ ├── fswatch_and_install_intellij_files_mac.sh.template │ ├── install_intellij_files.py.template │ ├── intellij_module.bzl │ ├── intellij_project.bzl │ ├── pysrc │ │ └── rules_intellij_generate.py │ └── pytest │ │ └── rules_intellij_generate_test.py └── tools │ └── bazel.rc ├── rules_intellij_generate.iml └── scenarios ├── .bazelversion ├── 01_one_class ├── BUILD ├── README.txt └── src │ └── oneclass │ └── A.java ├── 02_one_class_and_one_test ├── BUILD ├── README.txt ├── src │ └── one_class_and_one_test │ │ └── B.java └── test │ └── one_class_and_one_test │ └── BTest.java ├── 03_basic ├── BUILD ├── README.txt ├── dolphin │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── basic │ │ │ └── dolphin │ │ │ └── Echolocation.java │ │ └── test │ │ └── java │ │ └── basic │ │ └── dolphin │ │ └── EcholocationTest.java ├── gorilla │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── basic │ │ │ └── gorilla │ │ │ └── KnuckleWalking.java │ │ └── test │ │ └── java │ │ └── basic │ │ └── gorilla │ │ └── KnuckleWalkingTest.java ├── human │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── basic │ │ │ └── human │ │ │ └── OpposableThumbs.java │ │ └── test │ │ └── java │ │ └── basic │ │ └── human │ │ └── OpposableThumbsTest.java ├── mammal │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── basic │ │ │ └── mammal │ │ │ └── WarmBlood.java │ │ └── test │ │ └── java │ │ └── basic │ │ └── mammal │ │ └── WarmBloodTest.java └── primate │ ├── BUILD │ └── src │ ├── main │ └── java │ │ └── basic │ │ └── primate │ │ └── ColorVision.java │ └── test │ └── java │ └── basic │ └── primate │ └── ColorVisionTest.java ├── 04_transitive_via_export ├── BUILD ├── README.txt ├── child │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── transitive_via_export │ │ │ └── parent │ │ │ └── Child.java │ │ └── test │ │ └── java │ │ └── transitive_via_export │ │ └── parent │ │ └── ChildTest.java ├── grandparent │ ├── BUILD │ └── src │ │ ├── main │ │ └── java │ │ │ └── transitive_via_export │ │ │ └── grandparent │ │ │ └── Grandparent.java │ │ └── test │ │ └── java │ │ └── transitive_via_export │ │ └── grandparent │ │ └── GrandparentTest.java └── parent │ ├── BUILD │ └── src │ ├── main │ └── java │ │ └── transitive_via_export │ │ └── parent │ │ └── Parent.java │ └── test │ └── java │ └── transitive_via_export │ └── parent │ └── ParentTest.java ├── 05_annotation_processor ├── BUILD ├── README.txt ├── class_generator │ ├── BUILD │ └── src │ │ └── main │ │ ├── java │ │ └── annotation_processor │ │ │ └── class_generator │ │ │ ├── ClassGeneratorAnnotationProcessor.java │ │ │ └── GenClass.java │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── javax.annotation.processing.Processor ├── text_file_generator │ ├── BUILD │ └── src │ │ └── main │ │ ├── java │ │ └── annotation_processor │ │ │ └── text_file_generator │ │ │ ├── GenTextFile.java │ │ │ └── TextFileGeneratorAnnotationProcessor.java │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── javax.annotation.processing.Processor └── usage │ ├── BUILD │ └── src │ ├── main │ └── java │ │ └── annotation_processor │ │ └── usage │ │ └── Usage.java │ └── test │ └── java │ └── annotation_processor │ └── usage │ └── UsageTest.java ├── 06_protobuf_messages ├── BUILD ├── README.txt ├── html_email │ ├── BUILD │ └── src │ │ └── main │ │ └── proto │ │ └── html_email.proto ├── plain_email │ ├── BUILD │ └── src │ │ └── main │ │ └── proto │ │ └── plain_email.proto └── usage │ ├── BUILD │ └── src │ ├── main │ └── java │ │ └── protobuf_messages │ │ └── usage │ │ └── Usage.java │ └── test │ └── java │ └── protobuf_messages │ └── usage │ └── UsageTest.java ├── 07_grpc ├── BUILD ├── README.txt └── src │ ├── main │ ├── java │ │ └── fortune_grpc │ │ │ └── FortuneService.java │ └── proto │ │ └── fortune.proto │ └── test │ └── java │ └── fortune_grpc │ └── FortuneServiceTest.java ├── 08_auto_value ├── BUILD ├── README.txt └── src │ ├── main │ └── java │ │ └── house │ │ └── House.java │ └── test │ └── java │ └── house │ └── HouseTest.java ├── 09_python ├── BUILD ├── README.txt ├── src │ └── echo.py └── test │ └── echo_test.py ├── 12_kotlin ├── BUILD ├── README.txt ├── child │ ├── BUILD │ ├── src │ │ └── kotlin_example │ │ │ └── child │ │ │ └── Child.kt │ └── test │ │ └── kotlin_example │ │ └── child │ │ └── ChildTest.kt └── parent │ ├── BUILD │ ├── src │ └── kotlin_example │ │ └── parent │ │ └── Parent.kt │ └── test │ └── kotlin_example │ └── parent │ └── ParentTest.kt ├── 13_minor_features ├── BUILD ├── README.txt ├── iml_types.xml ├── intellij_project_files │ └── misc.xml ├── some_file.txt ├── src │ └── minor_features │ │ └── B.java └── test │ └── minor_features │ └── BTest.java ├── 14_all_dependency_types ├── BUILD ├── README.txt ├── child2_custom │ └── BUILD ├── child_data │ └── BUILD ├── child_dep │ └── BUILD ├── child_src │ ├── BUILD │ └── child.sh ├── custom2.bzl ├── parent │ ├── BUILD │ ├── parent.sh │ └── parent.txt └── parent2_custom │ ├── BUILD │ └── parent2.sh ├── 15_typescript_rules_multi_tsc ├── BUILD ├── deps │ ├── package-lock.json │ └── package.json ├── intellij_project_files │ ├── inspectionProfiles │ │ └── Project_Default.xml │ └── misc.xml ├── long-gen │ ├── BUILD │ ├── src │ │ └── long-gen.ts │ └── test │ │ └── long-gen-test.ts ├── package-lock.json ├── package.json ├── print-timestamp │ ├── BUILD │ └── src │ │ └── print-timestamp.ts ├── run_single_mocha_test.sh ├── tsconfig.json └── workspace_xml_fragments │ └── workspace.RunManager.fragment.xml ├── BUILD ├── WORKSPACE ├── iml_types.xml ├── intellij_project_files ├── compiler.xml └── misc.xml ├── scenario_tests ├── BUILD └── pytest │ ├── all_tests.py │ ├── s01_one_class_test.py │ ├── s02_one_class_and_one_test.py │ ├── s03_basic_test.py │ ├── s04_transitive_with_export_test.py │ ├── s05_annotation_processor_test.py │ ├── s06_protobuf_messages_test.py │ ├── s07_grpc_test.py │ ├── s08_auto_value_test.py │ ├── s09_python_test.py │ ├── s12_kotlin_test.py │ ├── s13_minor_features_test.py │ ├── s14_all_dependency_types_test.py │ └── scenario_test_support.py └── tools └── bazel.rc /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | out/ 3 | .idea/ 4 | *.iml 5 | !rules_intellij_generate.iml 6 | .DS_Store 7 | *.pyc 8 | node_modules 9 | workspace.xml 10 | .rig_sha1 11 | .python-version 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rules_intellij_generate 2 | 3 | Alpha: rule definitions and behavior may change on short notice. 4 | 5 | Examines your bazel build and generates a complete set of Intellij project configuration files. This is an alternative 6 | approach vs [bazelbuild/intellij](https://github.com/bazelbuild/intellij), and akin to the old 7 | [pants/idea](https://github.com/pantsbuild/pants/blob/d30cca1e0ecb9cc0e1b7e2cd0ff6e7e077e62a52/src/python/pants/backend/project_info/tasks/idea_gen.py) integration. 8 | 9 | - _`**/*.iml`_: Intellij module files are based on iml templates under your control, to which this rule adds module and 10 | jar dependency entries based on examination of your bazel build target relationships. 11 | - _`.idea/modules.xml`_: Automatically creates the Intellij file used to identify all modules in your project. 12 | - _`.idea/workspace.xml`_: “component” entries you define will be placed in your workspace.xml file. 13 | - _`.idea/**/*.xml`_: Intellij project-level files, such as run configurations and source formatting rules, may be 14 | committed to your repo and will be placed under the .idea directory, meaning these may be easily shared across a team. 15 | 16 | ## Example usage 17 | 18 | This repo is split into the [core rules](rules), and a [series of scenarios](scenarios) meant to show how the rules may be typically 19 | applied, that also form the basis of the [scenario tests](scenarios/scenario_tests/pytest). There is a README in the 20 | root of each scenario with a brief description of its purpose. 21 | 22 | ## Background and Motivation 23 | 24 | bazel/intellij originates from Google’s internal approach to Intellij integration. It’s based on a plug-in that puts 25 | bazel operations at the center of how the IDE does its work. 26 | 27 | Many people use this plugin happily and successfully, but its bazel-first philosophy is not without its problems, 28 | very well-expressed in 29 | [this github issue (recommended reading)](https://github.com/bazelbuild/intellij/issues/179#issuecomment-350295025). 30 | Bazel/intellij maintainers state that exploitation 31 | of Intellij’s module system is a non-goal, whereas for this project it’s a key goal. 32 | 33 | The rules_intellij_generate philosophy sees bazel and Intellij as equal partners interacting at arm’s length. It 34 | willingly countenances small compromises away from “bazel purity” so that (for example) the IDE’s code modularity 35 | features are useful in development. Intellij should work for teams that also use bazel, in the most efficient and 36 | fully-realized manner as possible. 37 | 38 | ## Features 39 | 40 | - Uses bazel project configuration to generate an intellij project during the bazel build run 41 | - Maps bazel packages to Intellij modules 42 | - Maps bazel-specified jar dependencies to Intellij module jar library dependencies 43 | - Integration point is plain old Intellij config files - there’s no Intellij plugin 44 | - Express any Intellij module configuration/settings via an entry in iml-types.xml 45 | ([example](scenarios/iml_types.xml)) 46 | - Support for distribution, from files in your workspace, of project-level Intellij xml config 47 | ([example](scenarios/intellij_project_files)) 48 | - Reference to bazel build output locations in Intellij configuration possible via template variables 49 | 50 | ## Usage 51 | 52 | Once `intellij_module` targets are defined, and an `intellij_project` target exists, run the `intellij_project` 53 | target: this generates the intellij configuration files archive for your project, in sandboxed form. You will need 54 | to run the `install_intellij_files_script`, found under `bazel-bin`, in order for these files to be installed 55 | in your workspace. 56 | 57 | You may want to try this out using the scenarios. Once installed, any scenario should be loadable into Intellij, 58 | by opening up its directory in the IDE as a new project. 59 | 60 | ## Python 61 | 62 | This project has a dependency on python. For now please make sure you have a python 3 interpreter that's findable 63 | by the core-bazel [default toolchain support for python](https://github.com/bazelbuild/rules_python/blob/master/proposals/2019-02-12-design-for-a-python-toolchain.md#default-toolchain). 64 | 65 | If you are using pyenv, install a modern 3.X interpreter, and make it findable by the bazel/python default 66 | toolchain support using: 67 | 68 | ``` 69 | pyenv global 3.7.0 70 | ``` 71 | 72 | Where "3.7.0" is the version of your python 3 interpreter. 73 | -------------------------------------------------------------------------------- /rules/BUILD: -------------------------------------------------------------------------------- 1 | # empty -------------------------------------------------------------------------------- /rules/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name="rules_intellij_generate") 2 | 3 | -------------------------------------------------------------------------------- /rules/def.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_intellij_generate//private:intellij_project.bzl", _intellij_project = "intellij_project") 2 | load("@rules_intellij_generate//private:intellij_module.bzl", _intellij_module = "intellij_module") 3 | 4 | intellij_project = _intellij_project 5 | intellij_module = _intellij_module 6 | -------------------------------------------------------------------------------- /rules/private/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//private:__subpackages__"]) 2 | 3 | # === EXPORTS === 4 | 5 | py_binary( 6 | name = "intellij_generate_project_files", 7 | main = "rules_intellij_generate.py", 8 | srcs = ["pysrc/rules_intellij_generate.py"], 9 | visibility = ["//visibility:public"], 10 | ) 11 | 12 | exports_files([ 13 | "fswatch_and_install_intellij_files_mac.sh.template", 14 | "install_intellij_files.py.template" 15 | ]) 16 | 17 | # === PRIVATE === 18 | 19 | py_library( 20 | name = "py_lib", 21 | srcs = ["pysrc/rules_intellij_generate.py"], 22 | ) 23 | 24 | py_test( 25 | name = "py_test", 26 | srcs = glob(["pytest/**/*.py"]), 27 | main = "rules_intellij_generate_test.py", 28 | imports = ["pysrc"], 29 | deps = [ 30 | ":py_lib" 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /rules/private/fswatch_and_install_intellij_files_mac.sh.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | which fswatch > /dev/null 4 | 5 | if [ $? -ne 0 ]; then 6 | echo "fswatch not found, please install it via homebrew:" 7 | echo " brew install fswatch" 8 | exit 1 9 | fi 10 | 11 | set -e 12 | 13 | this_dir=$(dirname $0) 14 | fswatch -0 --event=OwnerModified "$this_dir/intellij_files" | xargs -0 -n 1 -I {} "$this_dir/install_intellij_files_script" 15 | 16 | -------------------------------------------------------------------------------- /rules/private/install_intellij_files.py.template: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Read in the intellij file archive, and write out individual intellij config files under the project workspace 5 | """ 6 | 7 | import os 8 | import sys 9 | from subprocess import Popen, PIPE 10 | 11 | execution_directory = os.getcwd() 12 | script_directory = os.path.dirname(os.path.realpath(__file__)) 13 | workspace_path = os.path.join(execution_directory, "WORKSPACE") 14 | rig_sha1_path = os.path.join(execution_directory, ".rig_sha1") 15 | intellij_files_path = os.path.join(script_directory, "intellij_files") 16 | 17 | def get_subcommand_output(call_arr): 18 | p = Popen(call_arr, stdin=PIPE, stdout=PIPE, stderr=PIPE) 19 | output, err = p.communicate() 20 | if p.returncode != 0: 21 | sys.stderr.write("Subcommand unexpectedly failed: %s" % call_arr) 22 | sys.exit(1) 23 | return output 24 | 25 | def read_file(path): 26 | f = open(path, "r") 27 | content = f.read() 28 | f.close() 29 | return content 30 | 31 | def write_file(path, content): 32 | f = open(path, "w") 33 | f.write(content) 34 | f.close() 35 | 36 | if not os.path.isfile(workspace_path): 37 | sys.stderr.write("This script must be run from the workspace root, please change to that directory and re-run.\n") 38 | sys.exit(1) 39 | 40 | if not os.path.isfile(intellij_files_path): 41 | sys.stderr.write("Archive of intellij files not found at path: '%s'\n" % intellij_files_path) 42 | sys.exit(1) 43 | 44 | custom_substitutions = { 45 | # BEFORE_CUSTOM_VARS 46 | # _CUSTOM_ENV_VARS_GO_HERE 47 | # AFTER_CUSTOM_VARS 48 | } 49 | 50 | 51 | # Execute "bazel info", and transform the variable names in the output into 52 | # BAZEL_INFO_VARIABLE_NAME style. 53 | bazel_info = {} 54 | for line in get_subcommand_output(["_BAZELEXE_", "info"]).splitlines(): 55 | parts = map(lambda part: part.strip(), line.split(":", 1)) 56 | key = "BAZEL_INFO_" + parts[0].upper().replace("-", "_") 57 | value = parts[1] 58 | bazel_info[key] = value 59 | 60 | general_substitutions = {} 61 | general_substitutions.update(custom_substitutions) 62 | general_substitutions.update(bazel_info) 63 | 64 | 65 | # Determine files to process. 66 | # If no .rig_sha1 file is in place from the previous run, process all files in the archive. 67 | # If there is a .rig_sha1, load its contents, and determine what files have changed from the 68 | # previous run, and only process those different files. 69 | sha_section, rest_of_file = read_file(intellij_files_path).split("__SHA1_DIVIDER__\n", 1) 70 | sha1_lines = set(sha_section.splitlines()) 71 | 72 | if os.path.isfile(rig_sha1_path): 73 | print("Will only write intellij files that differ from previous run") 74 | existing_sha1_lines = set(read_file(rig_sha1_path).splitlines()) 75 | sha1_lines = existing_sha1_lines.symmetric_difference(sha1_lines) 76 | 77 | files_to_process = sorted(set(map(lambda l: l.split(" ", 1)[0].strip(), sha1_lines))) 78 | if len(files_to_process) > 0: 79 | print("Writing %d intellij files..." % len(files_to_process)) 80 | else: 81 | print("No intellij files differ from previous run") 82 | 83 | file_contents_section, symlink_section = rest_of_file.split("__SYMLINK_DIVIDER__\n", 1) 84 | 85 | relative_file_path_to_content = {} 86 | for entry in file_contents_section.split("__FILE_DIVIDER__\n"): 87 | relative_path, content = entry.split("\n", 1) 88 | relative_file_path_to_content[relative_path] = content 89 | 90 | files_to_process = filter(lambda f: f in relative_file_path_to_content.keys(), files_to_process) 91 | 92 | symlinks = {} 93 | symlink_entries = map(lambda line: line.split("|",1), filter(lambda l:len(l)>0, symlink_section.split("\n"))) 94 | for symlink_entry in symlink_entries: 95 | symlinks[symlink_entry[0]] = symlink_entry[1] 96 | 97 | dot_idea_dir = os.path.dirname(filter(lambda f: f.endswith(".idea/modules.xml"), relative_file_path_to_content.keys())[0]) 98 | 99 | # Check for symlink existence and content, create/overwrite if incorrect 100 | for symlink_src in symlinks: 101 | symlink_dest = symlinks[symlink_src] 102 | 103 | for k in general_substitutions: 104 | symlink_src = symlink_src.replace("${%s}" % k, general_substitutions[k]) 105 | symlink_dest = symlink_dest.replace("${%s}" % k, general_substitutions[k]) 106 | 107 | if os.path.islink(symlink_dest) and os.readlink(symlink_dest) == symlink_src: 108 | continue 109 | 110 | if (os.path.islink(symlink_dest) or os.path.isfile(symlink_dest)) and os.readlink(symlink_dest) != symlink_src: 111 | os.remove(symlink_dest) 112 | 113 | os.symlink(symlink_src, symlink_dest) 114 | 115 | # Split the workspace.xml file into one workspace file per "component" in the file. 116 | # This will create files like .idea/workspace.RunManager.xml 117 | intellij_workspace_xml_path = os.path.join(dot_idea_dir, "workspace.xml") 118 | if os.path.isfile(intellij_workspace_xml_path): 119 | workspace_fragment_to_content = {} 120 | current_fragment_name = None 121 | current_content = "" 122 | for line in read_file(intellij_workspace_xml_path).splitlines(): 123 | if "" in line: 124 | current_fragment_name = None 125 | current_content = "" 126 | continue 127 | 128 | if "" in line: 135 | workspace_fragment_to_content[current_fragment_name] = current_content 136 | current_fragment_name = None 137 | current_content = "" 138 | 139 | if len(current_content) > 0: 140 | workspace_fragment_to_content[current_fragment_name] = current_content 141 | 142 | for workspace_fragment in workspace_fragment_to_content: 143 | write_file( 144 | os.path.join(dot_idea_dir, "workspace.%s.fragment.xml" % workspace_fragment), 145 | workspace_fragment_to_content[workspace_fragment]) 146 | 147 | 148 | # Write out files to their repective relative paths under the bazel workspace. 149 | # Of note: 150 | # - .iml files will be placed in their bazel package-originating directories, 151 | # i.e. alongside the BUILD file 152 | # - other files are written under .idea, such as .idea/workspace.xml, .idea/modules.xml, etc 153 | # - template variables are replaced here. for example, 154 | # ${BAZEL_INFO_EXECUTION_ROOT} 155 | # would be replace with the "execution root" value found by running "bazel info". 156 | # This is how, for example, jars that bazel places in its output directories are available 157 | # within intellij config files. 158 | for relative_path in files_to_process: 159 | relative_dir = os.path.dirname(relative_path) 160 | 161 | all_substitutions = {} 162 | all_substitutions.update(general_substitutions) 163 | all_substitutions["BAZEL_PACKAGE_GENFILES"] = \ 164 | "%s/%s" % (general_substitutions["BAZEL_INFO_BAZEL_GENFILES"], relative_dir) 165 | 166 | file_content = relative_file_path_to_content[relative_path] 167 | for k in all_substitutions: 168 | file_content = file_content.replace("${%s}" % k, all_substitutions[k]) 169 | 170 | print("Writing intellij file '%s' (%d bytes)" % (relative_path, len(file_content))) 171 | 172 | if not os.path.isdir(relative_dir) and len(relative_dir) > 0: 173 | os.makedirs(relative_dir) 174 | 175 | write_file(relative_path, file_content) 176 | 177 | 178 | # In the previous step, workspace.xml fragment files may have been written out as well. 179 | # This would have over-written workspace xml fragments already extracted. 180 | # Re-compose workspace.xml by gluing together the contents of the fragment files. 181 | workspace_xml_fragments = [] 182 | for path in os.listdir(dot_idea_dir): 183 | if path.startswith("workspace.") and path.endswith(".fragment.xml"): 184 | workspace_xml_fragments.append(read_file(os.path.join(dot_idea_dir, path))) 185 | intellij_workspace_xml_content = \ 186 | "\n".join([ 187 | "", 188 | ""] + 189 | workspace_xml_fragments + 190 | [""]) 191 | 192 | print("Writing intellij workspace file '%s' (%d bytes)" % (intellij_workspace_xml_path, len(intellij_workspace_xml_content))) 193 | write_file(intellij_workspace_xml_path, intellij_workspace_xml_content) 194 | 195 | # Finally, "remember" the digests of the files from this archive, in .rig_sha1 196 | print("Saving intellij file sha1's in '%s'" % rig_sha1_path) 197 | write_file(rig_sha1_path, sha_section) 198 | -------------------------------------------------------------------------------- /rules/private/intellij_module.bzl: -------------------------------------------------------------------------------- 1 | IntellijModuleConfig = provider( 2 | fields = { 3 | "iml_type": "the type of iml file to use, defined in the iml_types xml file", 4 | "module_name_override": "optional string that overrides the default module name" 5 | } 6 | ) 7 | 8 | def _impl(ctx): 9 | return [IntellijModuleConfig( 10 | iml_type=ctx.attr.iml_type, 11 | module_name_override=ctx.attr.module_name_override)] 12 | 13 | intellij_module = rule( 14 | implementation = _impl, 15 | attrs = { 16 | "iml_type": attr.string(mandatory=True, 17 | doc=""" 18 | The name of a key in the iml types xml file. rules_intellij_generate.py will 19 | look up this entry, and use its xml contents as the basis of the Intellij module 20 | file for this bazel package/Intellij module. 21 | """), 22 | "module_name_override": attr.string(default="", 23 | doc=""" 24 | By default, the Intellij module name is the directory name of the package 25 | (a directory contining a BUILD file). If another module name is deisred, 26 | or (in particular), if there would otherwise be duplicate-named modules, 27 | a situation not allowed by Intellij. 28 | """), 29 | } 30 | ) 31 | -------------------------------------------------------------------------------- /rules/private/intellij_project.bzl: -------------------------------------------------------------------------------- 1 | load(":intellij_module.bzl", "IntellijModuleConfig") 2 | 3 | BazelPackageDep = provider( 4 | fields = { 5 | "bazel_package": "package name", 6 | "label_name": "label name", 7 | "attr_name": "the attribute name through which the dependency was established", 8 | "depends_on_bazel_package": "the bazel package depends on this other package", 9 | } 10 | ) 11 | 12 | BazelPackageDeps = provider( 13 | fields = { 14 | "all": "all bazel package dependencies", 15 | } 16 | ) 17 | 18 | JarDep = provider( 19 | fields = { 20 | "bazel_package": "package name of the target", 21 | "label_name": "label name of the target that generated this jar", 22 | "generated_by_build": "is this file generated by the build, or already-existing?", 23 | "relative_jar_path": "the path to the jar from the execroot", 24 | "owner_workspace_root": "the workspace root of the owner of the jar", 25 | } 26 | ) 27 | 28 | JarDeps = provider( 29 | fields = { 30 | "all": "all jars for module", 31 | } 32 | ) 33 | 34 | DeclaredIntellijModule = provider( 35 | fields = { 36 | "bazel_package": "the bazel package that this module represents", 37 | "module_name_override": "intellij module name, must be unique across the project", 38 | "iml_type": "the type of iml file to use, defined in the iml_types xml file", 39 | } 40 | ) 41 | 42 | ProjectData = provider( 43 | fields = [ 44 | "bazel_package_deps", 45 | "build_managed_label_matchlist", 46 | "iml_types_path", 47 | "jar_deps", 48 | "module_dependency_matchlist", 49 | "modules", 50 | "project_root_files_paths", 51 | "project_root_files_path_ignore_prefix", 52 | "root_bazel_package", 53 | "symlinks", 54 | "test_lib_label_matchlist", 55 | "workspace_xml_fragment_paths", 56 | ] 57 | ) 58 | 59 | def _target_attrs_from_struct(a_struct): 60 | """Returns the attrs of a_struct that have a list of Targets""" 61 | attr_name_to_targets = {} 62 | 63 | for attr_candidate_name in dir(a_struct): 64 | 65 | if attr_candidate_name == "to_json" or attr_candidate_name == "to_proto": 66 | continue 67 | 68 | attr_candidate = getattr(a_struct, attr_candidate_name) 69 | 70 | # TODO: also should work for single-target attrs - scenario test for this (custom attrs...) 71 | if type(attr_candidate) == "list" and len(attr_candidate) > 0 and type(attr_candidate[0]) == "Target": 72 | attr_name_to_targets[attr_candidate_name] = attr_candidate 73 | 74 | return attr_name_to_targets 75 | 76 | def _gather_bazel_package_dependencies(target, ctx): 77 | """Recurse through target dependencies, and accumulate all package-to-package dependencies. 78 | 79 | A bazel package dependency, for the purposes of this rules project, is established when a target in 80 | one package relates to a target in another package, via a target attribute that contains a reference 81 | to a label in the other package.""" 82 | all_bazel_package_dependencies = {} 83 | 84 | attr_name_to_targets = _target_attrs_from_struct(ctx.rule.attr) 85 | for attr_name in attr_name_to_targets: 86 | for d in attr_name_to_targets[attr_name]: 87 | if BazelPackageDeps in d: 88 | all_bazel_package_dependencies.update(d[BazelPackageDeps].all) 89 | 90 | if target.label.workspace_root == "" and \ 91 | d.label.workspace_root == "" and \ 92 | target.label.package != d.label.package: 93 | 94 | # make sure we only ever have one copy of this we pass through in the json. 95 | key = "%s;%s;%s;%s" % (target.label.package, target.label.name, attr_name, d.label.package) 96 | 97 | if key not in all_bazel_package_dependencies: 98 | all_bazel_package_dependencies[key] = \ 99 | BazelPackageDep( 100 | bazel_package=target.label.package, 101 | label_name=target.label.name, 102 | attr_name=attr_name, 103 | depends_on_bazel_package=d.label.package) 104 | 105 | return [BazelPackageDeps(all=all_bazel_package_dependencies)] 106 | 107 | _gather_bazel_package_dependencies_aspect = aspect( 108 | implementation = _gather_bazel_package_dependencies, 109 | attr_aspects = ["*"], 110 | ) 111 | 112 | def _declared_modules(ctx): 113 | """All modules 'declared' in the project, i.e. per intellij_module target.""" 114 | 115 | all_modules = [] 116 | for intellij_module in ctx.attr.modules: 117 | all_modules.append( 118 | DeclaredIntellijModule( 119 | bazel_package=intellij_module.label.package, 120 | module_name_override=intellij_module[IntellijModuleConfig].module_name_override, 121 | iml_type=intellij_module[IntellijModuleConfig].iml_type)) 122 | return all_modules 123 | 124 | def _jar_dep(labeled, jar): 125 | return JarDep( 126 | bazel_package=labeled.label.package, 127 | label_name=labeled.label.name, 128 | 129 | # is_source means "Returns true if this is a source file, i.e. it is not generated." 130 | # We use this to distinguish between build-generated jars, and "external" jars 131 | 132 | generated_by_build=not jar.is_source, 133 | relative_jar_path=jar.path, 134 | owner_workspace_root=jar.owner.workspace_root) 135 | 136 | def _jar_dep_key(j): 137 | # make sure we only ever have one copy of this we pass through in the json. 138 | return "%s;%s;%s;%s;%s" % (j.bazel_package, j.label_name, j.relative_jar_path, j.generated_by_build, j.owner_workspace_root) 139 | 140 | def _jar_deps(target, ctx): 141 | """Walk all dependencies and gather up associations between bazel packages and jars.""" 142 | 143 | # We must use transitive_runtime_jars, to get at the full jars, at the moment 144 | # see https://stackoverflow.com/a/45942563 145 | 146 | all_jar_deps = {} 147 | 148 | if JavaInfo in target: 149 | for jar in target[JavaInfo].transitive_runtime_jars.to_list(): 150 | j = _jar_dep(target, jar) 151 | key = _jar_dep_key(j) 152 | all_jar_deps[key] = j 153 | if JarDeps in target: 154 | all_jar_deps.update(target[JarDeps].all) 155 | 156 | attr_name_to_targets = _target_attrs_from_struct(ctx.rule.attr) 157 | for attr_name in attr_name_to_targets: 158 | for d in attr_name_to_targets[attr_name]: 159 | if JarDeps in d: 160 | all_jar_deps.update(d[JarDeps].all) 161 | if JavaInfo in d: 162 | for jar in d[JavaInfo].transitive_runtime_jars.to_list(): 163 | j = _jar_dep(target, jar) 164 | key = _jar_dep_key(j) 165 | all_jar_deps[key] = j 166 | 167 | return [JarDeps(all=all_jar_deps)] 168 | 169 | _gather_jar_deps_aspect = aspect( 170 | implementation = _jar_deps, 171 | attr_aspects = ["*"], 172 | ) 173 | 174 | def _all_jar_deps(ctx): 175 | all_jar_deps = {} 176 | 177 | for dep in ctx.attr.deps: 178 | all_jar_deps.update(dep[JarDeps].all) 179 | 180 | keys_sorted = sorted(all_jar_deps.keys()) 181 | results = [] 182 | for k in keys_sorted: 183 | results.append(all_jar_deps[k]) 184 | return results 185 | 186 | def _bazel_package_deps(ctx): 187 | all_deps = {} 188 | for dep in ctx.attr.deps: 189 | all_deps.update(dep[BazelPackageDeps].all) 190 | keys_sorted = sorted(all_deps.keys()) 191 | results = [] 192 | for k in keys_sorted: 193 | results.append(all_deps[k]) 194 | return results 195 | 196 | def _impl(ctx): 197 | """Main rule method""" 198 | project_data_json_file = ctx.actions.declare_file("project-data.json") 199 | iml_types_file = ctx.attr.iml_types_file.files.to_list()[0] 200 | 201 | inputs = [ 202 | iml_types_file, 203 | project_data_json_file, 204 | ] 205 | 206 | # gather up all top-level project files - the xml files that will go under the .idea directory 207 | paths = [] 208 | if hasattr(ctx.attr.project_root_filegroup, "files"): 209 | inputs.extend(ctx.attr.project_root_filegroup.files.to_list()) 210 | for f in ctx.attr.project_root_filegroup.files.to_list(): 211 | paths.append(f.path) 212 | 213 | # gather up all workspace fragment files - these will be used as parts of .idea/workspace.xml 214 | workspace_xml_fragment_paths = [] 215 | if hasattr(ctx.attr.workspace_xml_fragments_filegroup, "files"): 216 | inputs.extend(ctx.attr.workspace_xml_fragments_filegroup.files.to_list()) 217 | for f in ctx.attr.workspace_xml_fragments_filegroup.files.to_list(): 218 | workspace_xml_fragment_paths.append(f.path) 219 | 220 | # call out and gather data about this build, traversing build targets to find package dependencies and jars. 221 | project_data = ProjectData( 222 | root_bazel_package = ctx.label.package, 223 | bazel_package_deps = _bazel_package_deps(ctx), 224 | module_dependency_matchlist = ctx.attr.module_dependency_matchlist, 225 | jar_deps = _all_jar_deps(ctx), 226 | build_managed_label_matchlist = ctx.attr.build_managed_label_matchlist, 227 | test_lib_label_matchlist = ctx.attr.test_lib_label_matchlist, 228 | iml_types_path = iml_types_file.path, 229 | modules = _declared_modules(ctx), 230 | project_root_files_paths = paths, 231 | project_root_files_path_ignore_prefix = ctx.attr.project_root_filegroup_ignore_prefix, 232 | workspace_xml_fragment_paths = workspace_xml_fragment_paths, 233 | symlinks = ctx.attr.symlinks 234 | ) 235 | 236 | # this json file is the "input" to the python transformation executable action 237 | ctx.actions.write( 238 | output=project_data_json_file, 239 | content=project_data.to_json()) 240 | 241 | # execute the python script that transforms the input project data, 242 | # to an archive files containing all "managed" intellij configuration files. 243 | ctx.actions.run( 244 | executable = ctx.executable._intellij_generate_project_files, 245 | arguments = [ 246 | project_data_json_file.path, 247 | ctx.outputs.intellij_files.path 248 | ], 249 | inputs = inputs, 250 | outputs = [ctx.outputs.intellij_files], 251 | progress_message = "Generating intellij project files: %s" % ctx.outputs.intellij_files.path) 252 | 253 | # build up a list of custom substitution variables that the install script will 254 | # use to transform the (templated) files into the intellij archive into 255 | # final intellij config files 256 | all_substitutions = {} 257 | all_substitutions.update(ctx.attr.custom_substitutions) 258 | 259 | custom_env_vars_str = "" 260 | for k in all_substitutions: 261 | # note: the "tools" attribute magically causes expand_location to see the dependencies specified there 262 | # see https://stackoverflow.com/a/44025866 263 | custom_env_vars_str += "'%s':'%s',\n" % (k, ctx.expand_location(all_substitutions[k])) 264 | 265 | if custom_env_vars_str == "": 266 | custom_env_vars_str = "# (note: no custom substitutions defined)" 267 | 268 | ctx.actions.expand_template( 269 | output=ctx.outputs.install_intellij_files_script, 270 | template=ctx.file._install_script_template_file, 271 | substitutions={ 272 | "# _CUSTOM_ENV_VARS_GO_HERE": custom_env_vars_str, 273 | "_BAZELEXE_": ctx.attr.bazelexec, 274 | }, 275 | is_executable=True) 276 | 277 | ctx.actions.expand_template( 278 | output=ctx.outputs.fswatch_and_install_intellij_files_mac_sh, 279 | template=ctx.file._fswatch_and_install_intellij_files_mac_template_file, 280 | substitutions={}, 281 | is_executable=True) 282 | 283 | 284 | intellij_project = rule( 285 | implementation = _impl, 286 | attrs = { 287 | "_intellij_generate_project_files": attr.label( 288 | default=Label("//private:intellij_generate_project_files"), 289 | executable=True, 290 | cfg="target"), 291 | 292 | "_install_script_template_file": attr.label( 293 | default=Label("//private:install_intellij_files.py.template"), allow_single_file=True), 294 | 295 | "_fswatch_and_install_intellij_files_mac_template_file": attr.label( 296 | default=Label("//private:fswatch_and_install_intellij_files_mac.sh.template"), allow_single_file=True), 297 | 298 | "bazelexec": attr.string( 299 | default='bazel', 300 | doc=""" 301 | The install_intellij_files script gets information about the version of bazel you are using. 302 | If you are using something like bazelisk, you can specify ./bazelisk instead of a system bazel. 303 | """), 304 | 305 | "deps": attr.label_list( 306 | default=[], 307 | aspects=[_gather_bazel_package_dependencies_aspect, _gather_jar_deps_aspect], 308 | doc=""" 309 | This is the list of targets that the aspects will walk, to gather information about target 310 | and jar dependencies. 311 | 312 | So, these targets are what determine what packages are related, and therefore, 313 | what Intellij modules are related. 314 | """), 315 | 316 | "module_dependency_matchlist": attr.string_list( 317 | default=[ # in the attr docs...srcs/data/deps are the three principle types of dependencies 318 | '{"attr":"data"}', 319 | '{"attr":"deps"}', 320 | '{"attr":"srcs"}', 321 | ], doc=""" 322 | A series of match rules on a source target, one of its attributes names, and a target that it depends on, 323 | which decides what entries drive the determination of bazel package dependnencies, and therefore, 324 | intellij module dependencies. 325 | 326 | An entry in the matchlist is a stringified json document of the form: 327 | 328 | {"package":"foo","attr":"deps","to_package":"bar"} 329 | 330 | This example would be very restrictive: only module dependencies flowing from package foo to package bar, 331 | via an attribute on foo called deps, would impact how the Intellij project is constructed. 332 | 333 | Wildcards are possible: 334 | 335 | {"package":"foo","attr":"deps","to_package":"*"} 336 | 337 | The now means: consider all dependencies found flowing from foo, via attr deps. 338 | 339 | The equivalent shorthand: 340 | 341 | {"package":"foo","attr":"deps"} 342 | 343 | Any ommitted attribute is treated as an implicit * / "match all", so: 344 | 345 | {"attr":"zorg"} 346 | 347 | means all dependencies established from any package, to any other package, via the attribute name "zorg", 348 | will be used to construct Intellij module dependencies. 349 | """), 350 | 351 | "build_managed_label_matchlist": attr.string_list(default=[], 352 | doc=""" 353 | A matcher list of the form 354 | 355 | {"package":"*","label_name":"java_grpc"} 356 | 357 | which determines what jars, that are generated based on code in 358 | the project, are "bazel-managed" - that is to say, Intellij 359 | does not attempt any sort of compilation related to these jars. 360 | 361 | The most prominent example is protobuf-codegen. Users need 362 | the generated code, compiled, and jar'd, to be available in order 363 | to sensibly develop code based on these proto defintions. 364 | 365 | Assuming all java proto codegen targets are named "java_proto", 366 | this match rule will cause all proto jars to be included as 367 | module jar libraries: 368 | 369 | {"label_name":"java_proto"} 370 | """), 371 | 372 | "test_lib_label_matchlist": attr.string_list(default=[], 373 | doc=""" 374 | A matcher list of the form 375 | 376 | {"package":"*","label_name":"java_test"} 377 | 378 | which determines what jar libraries are marked as "Test" libraries 379 | in Intellij modules. Note: any jars that are dependencies of 380 | non-test targets in the same module/bazel package, will cause 381 | the jar dependency to be marked as a "Compile" jar library. 382 | """), 383 | 384 | "custom_substitutions": attr.string_dict(default={}, 385 | doc=""" 386 | Variables that may be used in intellij xml files and templates, which 387 | are committed into the client project. At intellij project file 388 | installation time, these variables are substituted for their values, 389 | specified here. 390 | """), 391 | 392 | "iml_types_file": attr.label(mandatory=True, allow_single_file=True, 393 | doc = """ 394 | A file containing iml type names, and xml contents that form the basis of 395 | intellij module files, for a given iml type. 396 | """), 397 | 398 | "project_root_filegroup": attr.label(default=None, 399 | doc=""" 400 | Filegroup of files that will be placed under the .idea directory - 401 | i.e. the intellij project directory. 402 | """), 403 | 404 | "project_root_filegroup_ignore_prefix": attr.string( 405 | doc=""" 406 | Prefix that should be stripped off the project_root_filegroup files, before they're placed under the .idea 407 | directory. 408 | 409 | (This is not the most elegant idea, but I can't think of a better approach for accomplishing this goal, 410 | at the moment) 411 | """), 412 | 413 | "workspace_xml_fragments_filegroup": attr.label(default=None, 414 | doc=""" 415 | A filegroup of xml files that should each correspond to 416 | a workspace.xml "component". These should be named with 417 | the component name in the middle of the filename, ex: 418 | 419 | workspace.RunManager.xml 420 | 421 | The installer will overwrite any components with these names. 422 | 423 | This way, it's possible to control the contents of (only) parts 424 | of workspace.xml, and let other parts be managed directly by 425 | Intellij. 426 | """), 427 | "modules": attr.label_list(default=[], 428 | doc=""" 429 | intellij_module targets must be added here in order to appear in the intellij project. 430 | """), 431 | 432 | "symlinks": attr.string_dict(default={}), 433 | 434 | "tools": attr.label_list(default=[], allow_files=True), 435 | }, 436 | 437 | outputs={ 438 | "intellij_files": "intellij_files", 439 | "install_intellij_files_script": "install_intellij_files_script", 440 | "fswatch_and_install_intellij_files_mac_sh": "fswatch_and_install_intellij_files_mac.sh", 441 | }, 442 | ) 443 | -------------------------------------------------------------------------------- /rules/private/pytest/rules_intellij_generate_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from rules_intellij_generate import * 4 | 5 | 6 | class RulesIntellijGenerateTest(unittest.TestCase): 7 | 8 | def test_xml_indent(self): 9 | a_element = parse_xml("") 10 | a_element.append(parse_xml("1")) 11 | a_element.append(parse_xml("9")) 12 | a_element.append(parse_xml("2")) 13 | a_element.append(parse_xml("3")) 14 | a_element.append(parse_xml("4")) 15 | a_element.append(parse_xml("5")) 16 | self.assertEqual( 17 | "\n".join( 18 | [ 19 | "", 20 | " 1", 21 | " ", 22 | " 9", 23 | " ", 24 | " 2", 25 | " 3", 26 | " 4", 27 | " ", 28 | " ", 29 | " 5", 30 | " ", 31 | " ", 32 | "", 33 | "" 34 | ]), ET.tostring(xml_indent(a_element)).decode("utf-8")) 35 | 36 | def test_iml_paths(self): 37 | root_intellij_module = { 38 | "bazel_package": "", 39 | "module_name": "foo", 40 | "iml_type": "java" 41 | } 42 | 43 | regular_intellij_module = { 44 | "bazel_package": "some_package/bar", 45 | "iml_type": "java" 46 | } 47 | 48 | self.assertEqual("foo.iml", iml_path_from_declared_intellij_module(root_intellij_module, "foo")) 49 | self.assertEqual("some_package/bar/bar.iml", iml_path_from_declared_intellij_module(regular_intellij_module, "")) 50 | 51 | def test_check_unique_intellij_module_names(self): 52 | check_unique_intellij_module_names([ 53 | {"bazel_package": "a/foo"}, 54 | {"bazel_package": "b/bar"}, 55 | ], "the_root_package") 56 | 57 | check_unique_intellij_module_names([ 58 | {"bazel_package": "a/foo"}, 59 | {"bazel_package": "b/foo", "module_name_override": "bar"}, 60 | ], "the_root_package") 61 | 62 | def do_non_unique_module_names(): 63 | check_unique_intellij_module_names([ 64 | {"bazel_package": "a/foo"}, 65 | {"bazel_package": "b/foo"}, 66 | ], "the_root_package") 67 | 68 | self.assertRaises(DuplicateModuleNameException, do_non_unique_module_names) 69 | 70 | def do_override_to_non_unique_module_names(): 71 | check_unique_intellij_module_names([ 72 | {"bazel_package": "a/foo"}, 73 | {"bazel_package": "b/bar", "module_name_override": "foo"}, 74 | ], "the_root_package") 75 | 76 | self.assertRaises(DuplicateModuleNameException, do_override_to_non_unique_module_names) 77 | 78 | 79 | def test_basic_composer_and_conversion_to_xml(self): 80 | iml_types_xml = """ 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | """.strip() 93 | 94 | expected_root_iml_content = """ 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | """.strip() + "\n" 103 | 104 | declared_intellij_module = { 105 | "bazel_package": "some_package/bar", 106 | "iml_type": "java" 107 | } 108 | 109 | self.assertEqual( 110 | {"some_package/bar/bar.iml": expected_root_iml_content}, 111 | composers_to_xmls( 112 | make_bazel_package_iml_composers( 113 | iml_types_xml, 114 | [declared_intellij_module]), "root_package")) 115 | 116 | def test_insert_jar_dep_into_iml_element_as_module_library(self): 117 | iml_base_content = """ 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | """.strip() + "\n" 127 | 128 | expected_content_1 = """ 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | """.strip() + "\n" 147 | 148 | element1 = parse_xml(iml_base_content) 149 | insert_jar_dep_into_iml_element_as_module_library( 150 | element1, 151 | "some/lib.jar", 152 | is_test_mode=False) 153 | 154 | self.assertEqual(expected_content_1, convert_xml_element_to_pretty_printed_xml_string(element1)) 155 | 156 | expected_content_2 = """ 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | """.strip() + "\n" 175 | 176 | element2 = parse_xml(iml_base_content) 177 | insert_jar_dep_into_iml_element_as_module_library( 178 | element2, 179 | "some/lib.jar", 180 | is_test_mode=True) 181 | 182 | self.assertEqual(expected_content_2, convert_xml_element_to_pretty_printed_xml_string(element2)) 183 | 184 | def test_add_jar_libraries(self): 185 | iml_base_content = """ 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | """.strip() + "\n" 194 | 195 | element = parse_xml(iml_base_content) 196 | insert_all_jar_libraries( 197 | {"foo": IntellijModuleComposer({}, element)}, 198 | ['{"label_name":"managed_by_build_tool"}'], 199 | ['{"package":"fo*","label_name":"some_test_lib_label_name"}'], 200 | [ 201 | { 202 | "bazel_package": "foo", 203 | "label_name": "not_managed_by_build_tool", 204 | "test_mode": True, 205 | "generated_by_build": True, 206 | "relative_jar_path": "some/relative/path/off/the/execroot/a-was-generated-by-the-build.jar", 207 | "owner_workspace_root": "" 208 | }, 209 | { 210 | "bazel_package": "foo", 211 | "label_name": "some_test_lib_label_name", 212 | "test_mode": True, 213 | "generated_by_build": False, 214 | "relative_jar_path": "some/relative/path/off/the/execroot/b-show-up-in-test-mode-only.jar", 215 | "owner_workspace_root": "external" 216 | }, 217 | { 218 | "bazel_package": "foo", 219 | "label_name": "some_label_name", 220 | "test_mode": False, 221 | "generated_by_build": False, 222 | "relative_jar_path": "some/relative/path/off/the/execroot/c-show-up-in-non-test-mode-only.jar", 223 | "owner_workspace_root": "external" 224 | }, 225 | { 226 | "bazel_package": "foo", 227 | "label_name": "some_test_lib_label_name", 228 | "test_mode": True, 229 | "generated_by_build": False, 230 | "relative_jar_path": "some/relative/path/off/the/execroot/d-show-up-in-both-modes.jar", 231 | "owner_workspace_root": "external" 232 | }, 233 | { 234 | "bazel_package": "foo", 235 | "label_name": "some_label_name", 236 | "test_mode": False, 237 | "generated_by_build": False, 238 | "relative_jar_path": "some/relative/path/off/the/execroot/d-show-up-in-both-modes.jar", 239 | "owner_workspace_root": "external" 240 | }, 241 | { 242 | "bazel_package": "foo", 243 | "label_name": "managed_by_build_tool", 244 | "test_mode": False, 245 | "generated_by_build": True, 246 | "relative_jar_path": "some/relative/path/off/the/execroot/e-was-generated-by-the-build.jar", 247 | "owner_workspace_root": "" 248 | }, 249 | ]) 250 | 251 | # - libs generated by the build: 252 | # ...that are generated outside of this workspace, are considered, 253 | # ...that have label names that are declared to be managed by the build, are considered 254 | # ...(or thus,) that are buildable by the ide, are not considered, 255 | # - libs only discovered via test mode are scope="TEST" 256 | # - libs that are present in both test mode and non-test mode, are considered compile dependencies (so, no scope attribute) 257 | 258 | expected_content = """ 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | """.strip() + "\n" 303 | self.assertEqual(expected_content, convert_xml_element_to_pretty_printed_xml_string(element)) 304 | 305 | def match_parse_failure(): 306 | JarDependencyMatcher('xyxyx') 307 | 308 | self.assertRaises(JarDependencyMatchFormatException, match_parse_failure) 309 | 310 | def test_determine_module_deps(self): 311 | # basic match/no-match 312 | self.assertEqual({"a_package": ["b_package", "e_package"]}, 313 | determine_package_deps([{"bazel_package": "a_package", 314 | "label_name": "x_label_name", 315 | "attr_name": "deps", 316 | "depends_on_bazel_package": "b_package"}, 317 | {"bazel_package": "c_package", 318 | "label_name": "x_label_name", 319 | "attr_name": "NOMATCH", 320 | "depends_on_bazel_package": "d_package"}, 321 | {"bazel_package": "a_package", 322 | "label_name": "x_label_name", 323 | "attr_name": "deps", 324 | "depends_on_bazel_package": "e_package"}], 325 | [ModuleDependencyMatcher('{"attr":"deps"}')], 326 | "the_root_package")) 327 | 328 | # filesystem-like wildcarding 329 | self.assertEqual({"a_package": ["b_package", "e_package"]}, 330 | determine_package_deps([{"bazel_package": "a_package", 331 | "label_name": "x_label_name", 332 | "attr_name": "deps", 333 | "depends_on_bazel_package": "b_package"}, 334 | {"bazel_package": "c_package", 335 | "label_name": "x_label_name", 336 | "attr_name": "NOMATCH", 337 | "depends_on_bazel_package": "d_package"}, 338 | {"bazel_package": "a_package", 339 | "label_name": "x_label_name", 340 | "attr_name": "deps", 341 | "depends_on_bazel_package": "e_package"}], 342 | [ModuleDependencyMatcher('{"attr":"de*"}')], 343 | "the_root_package")) 344 | 345 | # match on multiple attrs 346 | self.assertEqual({"a_package": ["b_package"], 347 | "c_package": ["b_package"]}, 348 | determine_package_deps([{"bazel_package": "a_package", 349 | "label_name": "x_label_name", 350 | "attr_name": "deps", 351 | "depends_on_bazel_package": "b_package"}, 352 | {"bazel_package": "c_package", 353 | "label_name": "x_label_name", 354 | "attr_name": "deps", 355 | "depends_on_bazel_package": "b_package"}, 356 | {"bazel_package": "a_package", 357 | "label_name": "x_label_name", 358 | "attr_name": "deps", 359 | "depends_on_bazel_package": "e_package"}], 360 | [ModuleDependencyMatcher('{"to_package":"b_package", "attr":"deps"}')], 361 | "the_root_package")) 362 | 363 | def match_parse_failure(): 364 | ModuleDependencyMatcher('xyxyx') 365 | self.assertRaises(ModuleDependencyMatchFormatException, match_parse_failure) 366 | 367 | def test_convert_bazel_package_deps_to_intellij_module_deps(self): 368 | defined_modules = [ 369 | {"bazel_package": "z/foo"}, 370 | {"bazel_package": "z/bar"}, 371 | {"bazel_package": "z/a"}, 372 | {"bazel_package": "z/bbb", "module_name_override": "b"}, 373 | {"bazel_package": "z/c"}, 374 | {"bazel_package": "d"}, 375 | {"bazel_package": ""}, 376 | ] 377 | 378 | self.assertEqual({ 379 | "z/foo": ["a", "b"], 380 | "z/bar": ["c", "d"] 381 | }, convert_bazel_package_deps_to_intellij_module_deps({ 382 | "z/foo": ["z/a", "z/bbb", "z/not_available_in_list"], 383 | "z/bar": ["z/c", "d"] 384 | }, defined_modules, "yyy")) 385 | 386 | # root package 387 | self.assertEqual({ 388 | "": ["a"] 389 | }, convert_bazel_package_deps_to_intellij_module_deps({ 390 | "": ["z/a"], 391 | }, defined_modules, "yyy")) 392 | 393 | def test_insert_bazel_package_dep_into_iml_element_as_module_dep(self): 394 | iml_base_content = """ 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | """.strip() + "\n" 404 | 405 | expected_content = """ 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | """.strip() + "\n" 417 | 418 | element1 = parse_xml(iml_base_content) 419 | insert_bazel_package_dep_into_iml_element_as_module_dep(element1, "bar") 420 | insert_bazel_package_dep_into_iml_element_as_module_dep(element1, "zzz") 421 | 422 | self.assertEqual(expected_content, convert_xml_element_to_pretty_printed_xml_string(element1)) 423 | 424 | def test_add_bazel_package_deps(self): 425 | iml_base_content = """ 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | """.strip() + "\n" 435 | 436 | expected_content = """ 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | """.strip() + "\n" 448 | 449 | element = parse_xml(iml_base_content) 450 | insert_all_module_deps( 451 | {"foo": IntellijModuleComposer({}, element)}, 452 | {"foo": ["bar", "zzz"]}) 453 | 454 | self.assertEqual(expected_content, convert_xml_element_to_pretty_printed_xml_string(element)) 455 | 456 | def test_make_modules_xml(self): 457 | expected_content = """ 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | """.strip() + "\n" 466 | 467 | self.assertEqual( 468 | expected_content, 469 | make_modules_xml("root/subroot", ["root/subroot/foo/subfoo.iml", "root/subroot/bar.iml"])) 470 | 471 | def test_xmls_to_sha1s(self): 472 | self.assertEqual( 473 | {"bar.iml": "4d18aab61d7c4874a70ff4750f1e066291fff399", 474 | "foo.iml": "13e190a16a3937a346f2f2104210a9d0af775cec"}, 475 | xmls_to_sha1s({"bar.iml": "", "foo.iml": ""})) 476 | 477 | def test_intellij_files_archive(self): 478 | expected_archive_contents = """ 479 | sha1bar bar.iml 480 | sha1foo foo.iml 481 | __SHA1_DIVIDER__ 482 | bar.iml 483 | 484 | __FILE_DIVIDER__ 485 | foo.iml 486 | 487 | __SYMLINK_DIVIDER__ 488 | some_execroot_file|symlink_under_project_file 489 | """.strip() 490 | self.assertEqual( 491 | expected_archive_contents, 492 | make_intellij_files_archive( 493 | {"sha1foo": "foo.iml", 494 | "sha1bar": "bar.iml"}, 495 | {"foo.iml": "", "bar.iml": ""}, 496 | {"some_execroot_file":"symlink_under_project_file"})) 497 | 498 | 499 | # TODO: test that workspace xml fragment paths are relative to .idea 500 | 501 | if __name__ == '__main__': 502 | suite = unittest.TestSuite() 503 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(RulesIntellijGenerateTest)) 504 | 505 | # python unit test main's must end with this or the test will exit with status code 0, 506 | # and thus it will not fail the bazel test run if there's a test failure. 507 | return_value = not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful() 508 | sys.exit(return_value) 509 | -------------------------------------------------------------------------------- /rules/tools/bazel.rc: -------------------------------------------------------------------------------- 1 | test --test_output=errors --action_env="GTEST_COLOR=1" 2 | -------------------------------------------------------------------------------- /rules_intellij_generate.iml: -------------------------------------------------------------------------------- 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 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /scenarios/.bazelversion: -------------------------------------------------------------------------------- 1 | 0.24.1 2 | -------------------------------------------------------------------------------- /scenarios/01_one_class/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 5 | 6 | java_binary( 7 | name = "run_A", 8 | main_class="oneclass.A", 9 | srcs = glob(["src/**/*.java"]), 10 | ) 11 | 12 | java_library( 13 | name="lib", 14 | srcs = glob(["src/**/*.java"]), 15 | ) 16 | 17 | intellij_module(name="iml", iml_type="java-simple") 18 | 19 | intellij_project( 20 | name="project_01", 21 | deps=[":lib"], 22 | iml_types_file="//:iml_types.xml", 23 | project_root_filegroup="//:automatically_placed_intellij_project_files", 24 | project_root_filegroup_ignore_prefix="intellij_project_files", 25 | modules=[":iml"] 26 | ) 27 | -------------------------------------------------------------------------------- /scenarios/01_one_class/README.txt: -------------------------------------------------------------------------------- 1 | The simplest possible java project. 2 | 3 | Layout is not maven-standard. 4 | -------------------------------------------------------------------------------- /scenarios/01_one_class/src/oneclass/A.java: -------------------------------------------------------------------------------- 1 | package oneclass; 2 | 3 | class A { 4 | public static void main(String[] args) { 5 | System.out.println("hello from A"); 6 | } 7 | } -------------------------------------------------------------------------------- /scenarios/02_one_class_and_one_test/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 6 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 7 | 8 | java_library( 9 | name="java_lib", 10 | srcs = glob(["src/**/*.java"]), 11 | ) 12 | 13 | java_library( 14 | name="java_test_lib", 15 | srcs = glob(["test/**/*.java"]), 16 | deps=[":java_lib"] + JUNIT5_MINIMAL_DEPS, 17 | ) 18 | 19 | junit5_all_in_package_test( 20 | name="java_tests", 21 | java_package="one_class_and_one_test", 22 | runtime_deps=[":java_test_lib"] 23 | ) 24 | 25 | intellij_module(name="iml", iml_type="java-simple") 26 | 27 | intellij_project( 28 | name="project_02", 29 | deps=[":java_test_lib"], 30 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 31 | iml_types_file="//:iml_types.xml", 32 | project_root_filegroup="//:automatically_placed_intellij_project_files", 33 | project_root_filegroup_ignore_prefix="intellij_project_files", 34 | modules=[":iml"] 35 | ) 36 | -------------------------------------------------------------------------------- /scenarios/02_one_class_and_one_test/README.txt: -------------------------------------------------------------------------------- 1 | The simplest possible java project that has tests. 2 | 3 | Layout is not maven-standard. 4 | -------------------------------------------------------------------------------- /scenarios/02_one_class_and_one_test/src/one_class_and_one_test/B.java: -------------------------------------------------------------------------------- 1 | package one_class_and_one_test; 2 | 3 | class B { 4 | public int theNumber() { 5 | return 77; 6 | } 7 | } -------------------------------------------------------------------------------- /scenarios/02_one_class_and_one_test/test/one_class_and_one_test/BTest.java: -------------------------------------------------------------------------------- 1 | package one_class_and_one_test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class BTest { 8 | @Test 9 | public void the_number() { 10 | assertEquals(77, new B().theNumber()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scenarios/03_basic/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | intellij_project( 5 | name="project_03", 6 | deps=[ 7 | "//03_basic/dolphin:java_test_lib", 8 | "//03_basic/gorilla:java_test_lib", 9 | "//03_basic/human:java_test_lib", 10 | "//03_basic/primate:java_test_lib", 11 | "//03_basic/mammal:java_test_lib", 12 | ], 13 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 14 | iml_types_file="//:iml_types.xml", 15 | project_root_filegroup="//:automatically_placed_intellij_project_files", 16 | project_root_filegroup_ignore_prefix="intellij_project_files", 17 | modules=[ 18 | "//03_basic/dolphin:iml", 19 | "//03_basic/gorilla:iml", 20 | "//03_basic/human:iml", 21 | "//03_basic/mammal:iml", 22 | "//03_basic/primate:iml", 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /scenarios/03_basic/README.txt: -------------------------------------------------------------------------------- 1 | - standard maven layout (see: https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html) 2 | - a few modules that are interdependent: 3 | 4 | mammal 5 | | 6 | |-- primate 7 | | | 8 | | |-- gorilla 9 | | |-- human 10 | | 11 | -- dolphin 12 | 13 | - main methods in species-level modules 14 | -------------------------------------------------------------------------------- /scenarios/03_basic/dolphin/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//03_basic:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//03_basic/mammal:java_lib", 12 | ] 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | 21 | "//03_basic/mammal:java_lib", 22 | ] + JUNIT5_MINIMAL_DEPS, 23 | ) 24 | 25 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 26 | junit5_all_in_package_test( 27 | name="java_tests", 28 | java_package="basic.dolphin", 29 | runtime_deps=[":java_test_lib"] 30 | ) 31 | 32 | intellij_module(name="iml", iml_type="java-maven-style") 33 | -------------------------------------------------------------------------------- /scenarios/03_basic/dolphin/src/main/java/basic/dolphin/Echolocation.java: -------------------------------------------------------------------------------- 1 | package basic.dolphin; 2 | 3 | import basic.mammal.WarmBlood; 4 | 5 | public class Echolocation extends WarmBlood { 6 | } -------------------------------------------------------------------------------- /scenarios/03_basic/dolphin/src/test/java/basic/dolphin/EcholocationTest.java: -------------------------------------------------------------------------------- 1 | package basic.dolphin; 2 | 3 | import basic.mammal.WarmBlood; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | class EcholocationTest { 9 | @Test 10 | public void ancestry() { 11 | assertTrue(WarmBlood.class.isAssignableFrom(Echolocation.class)); 12 | } 13 | } -------------------------------------------------------------------------------- /scenarios/03_basic/gorilla/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//03_basic:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//03_basic/primate:java_lib", 12 | ] 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | 21 | "//03_basic/mammal:java_lib", 22 | "//03_basic/primate:java_lib", 23 | ] + JUNIT5_MINIMAL_DEPS, 24 | ) 25 | 26 | junit5_all_in_package_test( 27 | name="java_tests", 28 | java_package="basic.gorilla", 29 | runtime_deps=[":java_test_lib"] 30 | ) 31 | 32 | intellij_module(name="iml", iml_type="java-maven-style") 33 | -------------------------------------------------------------------------------- /scenarios/03_basic/gorilla/src/main/java/basic/gorilla/KnuckleWalking.java: -------------------------------------------------------------------------------- 1 | package basic.gorilla; 2 | 3 | import basic.primate.ColorVision; 4 | 5 | public class KnuckleWalking extends ColorVision { 6 | } -------------------------------------------------------------------------------- /scenarios/03_basic/gorilla/src/test/java/basic/gorilla/KnuckleWalkingTest.java: -------------------------------------------------------------------------------- 1 | package basic.gorilla; 2 | 3 | import basic.mammal.WarmBlood; 4 | import basic.primate.ColorVision; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | class KnuckleWalkingTest { 10 | @Test 11 | public void ancestry() { 12 | assertTrue(ColorVision.class.isAssignableFrom(KnuckleWalking.class)); 13 | assertTrue(WarmBlood.class.isAssignableFrom(KnuckleWalking.class)); 14 | } 15 | } -------------------------------------------------------------------------------- /scenarios/03_basic/human/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//03_basic:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//03_basic/primate:java_lib", 12 | ] 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | 21 | "//03_basic/mammal:java_lib", 22 | "//03_basic/primate:java_lib", 23 | ] + JUNIT5_MINIMAL_DEPS, 24 | ) 25 | 26 | junit5_all_in_package_test( 27 | name="java_tests", 28 | java_package="basic.human", 29 | runtime_deps=[":java_test_lib"] 30 | ) 31 | 32 | intellij_module(name="iml", iml_type="java-maven-style") 33 | -------------------------------------------------------------------------------- /scenarios/03_basic/human/src/main/java/basic/human/OpposableThumbs.java: -------------------------------------------------------------------------------- 1 | package basic.human; 2 | 3 | import basic.primate.ColorVision; 4 | 5 | public class OpposableThumbs extends ColorVision { 6 | } -------------------------------------------------------------------------------- /scenarios/03_basic/human/src/test/java/basic/human/OpposableThumbsTest.java: -------------------------------------------------------------------------------- 1 | package basic.human; 2 | 3 | import basic.mammal.WarmBlood; 4 | import basic.primate.ColorVision; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | class OpposableThumbsTest { 10 | @Test 11 | public void ancestry() { 12 | assertTrue(ColorVision.class.isAssignableFrom(OpposableThumbs.class)); 13 | assertTrue(WarmBlood.class.isAssignableFrom(OpposableThumbs.class)); 14 | } 15 | } -------------------------------------------------------------------------------- /scenarios/03_basic/mammal/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//03_basic:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | ) 11 | 12 | java_library( 13 | name="java_test_lib", 14 | srcs = glob(["src/test/java/**/*.java"]), 15 | deps=[":java_lib"] + JUNIT5_MINIMAL_DEPS, 16 | ) 17 | 18 | junit5_all_in_package_test( 19 | name="java_tests", 20 | java_package="basic.mammal", 21 | runtime_deps=[":java_test_lib"] 22 | ) 23 | 24 | intellij_module(name="iml", iml_type="java-maven-style") 25 | -------------------------------------------------------------------------------- /scenarios/03_basic/mammal/src/main/java/basic/mammal/WarmBlood.java: -------------------------------------------------------------------------------- 1 | package basic.mammal; 2 | 3 | public class WarmBlood { 4 | } -------------------------------------------------------------------------------- /scenarios/03_basic/mammal/src/test/java/basic/mammal/WarmBloodTest.java: -------------------------------------------------------------------------------- 1 | package basic.mammal; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | class WarmBloodTest { 6 | @Test 7 | public void does_nothing() { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scenarios/03_basic/primate/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//03_basic:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//03_basic/mammal:java_lib", 12 | ] 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | 21 | "//03_basic/mammal:java_lib", 22 | ] + JUNIT5_MINIMAL_DEPS, 23 | ) 24 | 25 | junit5_all_in_package_test( 26 | name="java_tests", 27 | java_package="basic.primate", 28 | runtime_deps=[":java_test_lib"] 29 | ) 30 | 31 | intellij_module(name="iml", iml_type="java-maven-style") 32 | -------------------------------------------------------------------------------- /scenarios/03_basic/primate/src/main/java/basic/primate/ColorVision.java: -------------------------------------------------------------------------------- 1 | package basic.primate; 2 | 3 | import basic.mammal.WarmBlood; 4 | 5 | public class ColorVision extends WarmBlood { 6 | } -------------------------------------------------------------------------------- /scenarios/03_basic/primate/src/test/java/basic/primate/ColorVisionTest.java: -------------------------------------------------------------------------------- 1 | package basic.primate; 2 | 3 | import basic.mammal.WarmBlood; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | class ColorVisionTest { 9 | @Test 10 | public void ancestry() { 11 | assertTrue(WarmBlood.class.isAssignableFrom(ColorVision.class)); 12 | } 13 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | 5 | intellij_project( 6 | name="project_04", 7 | deps=["//04_transitive_via_export/child:java_test_lib"], 8 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 9 | iml_types_file="//:iml_types.xml", 10 | project_root_filegroup="//:automatically_placed_intellij_project_files", 11 | project_root_filegroup_ignore_prefix="intellij_project_files", 12 | modules=[ 13 | "//04_transitive_via_export/grandparent:iml", 14 | "//04_transitive_via_export/parent:iml", 15 | "//04_transitive_via_export/child:iml", 16 | ] 17 | ) 18 | -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/README.txt: -------------------------------------------------------------------------------- 1 | This scenario simulates the issue I ran across in the course of using the 2 | appengine bazel rules, in which the java servlet library is exported: 3 | 4 | https://github.com/bazelbuild/rules_appengine/blob/master/appengine/BUILD#L2 5 | 6 | This causes the servlet library to be available to AppEngine servlets. In 7 | order to build a working intellij module, we therefore need that exported 8 | jar's classes to be available to module code. 9 | 10 | Also see the java_library documentation on exports: 11 | https://docs.bazel.build/versions/master/be/java.html#java_library.exports 12 | 13 | Open question: should java_library exports be exposed as intellij dependency exports, 14 | or (current state) be expressed as simple library dependencies in child modules? 15 | -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/child/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//04_transitive_via_export:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//04_transitive_via_export/parent:java_lib" 12 | ], 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | ] + JUNIT5_MINIMAL_DEPS, 21 | ) 22 | 23 | junit5_all_in_package_test( 24 | name="java_tests", 25 | java_package="transitive_via_export.child", 26 | runtime_deps=[":java_test_lib"] 27 | ) 28 | 29 | intellij_module(name="iml", iml_type="java-maven-style") 30 | -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/child/src/main/java/transitive_via_export/parent/Child.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.parent; 2 | 3 | class Child { 4 | public boolean canIUseGuava() { 5 | // demonstrates use of guava, 6 | // only accessible because the grandparent exports the library 7 | 8 | try { 9 | Class.forName("com.google.common.base.Strings"); 10 | return true; 11 | } catch (ClassNotFoundException e) { 12 | return false; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/child/src/test/java/transitive_via_export/parent/ChildTest.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.parent; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertFalse; 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | class ChildTest { 10 | @Test 11 | public void print_hello_three_times() { 12 | assertTrue(new Child().canIUseGuava()); 13 | } 14 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/grandparent/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//04_transitive_via_export:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "@com_google_guava_guava//jar", 12 | ], 13 | exports = [ 14 | "@com_google_guava_guava//jar" 15 | ], 16 | ) 17 | 18 | java_library( 19 | name="java_test_lib", 20 | srcs = glob(["src/test/java/**/*.java"]), 21 | deps=[ 22 | ":java_lib", 23 | ] + JUNIT5_MINIMAL_DEPS, 24 | ) 25 | 26 | junit5_all_in_package_test( 27 | name="java_tests", 28 | java_package="transitive_via_export.grandparent", 29 | runtime_deps=[":java_test_lib"] 30 | ) 31 | 32 | intellij_module(name="iml", iml_type="java-maven-style") 33 | -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/grandparent/src/main/java/transitive_via_export/grandparent/Grandparent.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.grandparent; 2 | 3 | import com.google.common.base.Strings; 4 | 5 | class Grandparent { 6 | public String hello3times() { 7 | // demonstrates use of guava 8 | 9 | try { 10 | Class.forName("com.google.common.base.Strings"); 11 | } catch (ClassNotFoundException e) { 12 | throw new RuntimeException(e); 13 | } 14 | 15 | return Strings.repeat("hello", 3); 16 | } 17 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/grandparent/src/test/java/transitive_via_export/grandparent/GrandparentTest.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.grandparent; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | class GrandparentTest { 8 | @Test 9 | public void print_hello_three_times() { 10 | assertEquals("hellohellohello", new Grandparent().hello3times()); 11 | } 12 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/parent/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//04_transitive_via_export:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//04_transitive_via_export/grandparent:java_lib" 12 | ], 13 | ) 14 | 15 | java_library( 16 | name="java_test_lib", 17 | srcs = glob(["src/test/java/**/*.java"]), 18 | deps=[ 19 | ":java_lib", 20 | ] + JUNIT5_MINIMAL_DEPS, 21 | ) 22 | 23 | junit5_all_in_package_test( 24 | name="java_tests", 25 | java_package="transitive_via_export.parent", 26 | runtime_deps=[":java_test_lib"] 27 | ) 28 | 29 | intellij_module(name="iml", iml_type="java-maven-style") 30 | -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/parent/src/main/java/transitive_via_export/parent/Parent.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.parent; 2 | 3 | import com.google.common.base.Strings; 4 | 5 | class Parent { 6 | public String hello4times() { 7 | // demonstrates use of guava, 8 | // only accessible because the grandparent exports the library 9 | 10 | try { 11 | Class.forName("com.google.common.base.Strings"); 12 | } catch (ClassNotFoundException e) { 13 | throw new RuntimeException(e); 14 | } 15 | 16 | return Strings.repeat("hello", 4); 17 | } 18 | } -------------------------------------------------------------------------------- /scenarios/04_transitive_via_export/parent/src/test/java/transitive_via_export/parent/ParentTest.java: -------------------------------------------------------------------------------- 1 | package transitive_via_export.parent; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | class ParentTest { 8 | @Test 9 | public void print_hello_three_times() { 10 | assertEquals("hellohellohellohello", new Parent().hello4times()); 11 | } 12 | } -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | 5 | intellij_project( 6 | name="project_05", 7 | deps=["//05_annotation_processor/usage:java_test_lib"], 8 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 9 | iml_types_file="//:iml_types.xml", 10 | project_root_filegroup="//:automatically_placed_intellij_project_files", 11 | project_root_filegroup_ignore_prefix="intellij_project_files", 12 | modules=[ 13 | "//05_annotation_processor/class_generator:iml", 14 | "//05_annotation_processor/text_file_generator:iml", 15 | "//05_annotation_processor/usage:iml", 16 | ] 17 | ) 18 | -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/README.txt: -------------------------------------------------------------------------------- 1 | In an earlier version of this library, Annotation processing had deep integration 2 | with the intellij rules, however this (generating compiler.xml) turned out to be 3 | of modest benefit, and in practice the end-user experience was not great. 4 | 5 | In this newer version of the library, the approach is to just provide compiler.xml as 6 | an automatically-copied project file. This scenario + test is kept as a demonstration 7 | of how it works (as simple as it is). 8 | -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/class_generator/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//05_annotation_processor:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | java_plugin( 6 | name="annotation_processor", 7 | srcs = glob(["src/main/java/**/*.java"]), 8 | processor_class = "annotation_processor.class_generator.ClassGeneratorAnnotationProcessor", 9 | resources = ["src/main/resources/META-INF/services/javax.annotation.processing.Processor"], 10 | generates_api = 1, # must be specified or dependent targets will not see gen'd classfiles 11 | ) 12 | 13 | intellij_module(name="iml", iml_type="java-maven-style-with-resources") -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/class_generator/src/main/java/annotation_processor/class_generator/ClassGeneratorAnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.class_generator; 2 | 3 | import javax.annotation.processing.AbstractProcessor; 4 | import javax.annotation.processing.RoundEnvironment; 5 | import javax.annotation.processing.SupportedAnnotationTypes; 6 | import javax.annotation.processing.SupportedSourceVersion; 7 | import javax.lang.model.SourceVersion; 8 | import javax.lang.model.element.Element; 9 | import javax.lang.model.element.Name; 10 | import javax.lang.model.element.TypeElement; 11 | import javax.tools.Diagnostic; 12 | import javax.tools.JavaFileObject; 13 | import java.io.IOException; 14 | import java.io.PrintWriter; 15 | import java.util.Set; 16 | 17 | import static java.lang.String.format; 18 | 19 | @SupportedSourceVersion(SourceVersion.RELEASE_8) 20 | @SupportedAnnotationTypes("annotation_processor.class_generator.GenClass") 21 | public class ClassGeneratorAnnotationProcessor extends AbstractProcessor { 22 | @Override 23 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 24 | for (TypeElement annotation : annotations) { 25 | for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(annotation)) { 26 | GenClass genClassAnnotation = annotatedElement.getAnnotation(GenClass.class); 27 | if (genClassAnnotation == null) { 28 | continue; 29 | } 30 | String genClassName = genClassAnnotation.genClassName(); 31 | Name annotatedClass = annotatedElement.getSimpleName(); 32 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, 33 | format("found GenClass annotation on class '%s', " + 34 | "generating class '%s'", annotatedClass, genClassName)); 35 | try { 36 | JavaFileObject builderFile = processingEnv.getFiler().createSourceFile("somepackage." + genClassName); 37 | try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { 38 | out.write("package somepackage;\n"); 39 | out.write("\n"); 40 | out.write(format("public class %s {\n", genClassName)); 41 | out.write(" public int foo = 77;\n"); 42 | out.write("}\n"); 43 | } 44 | } catch (IOException e) { 45 | throw new RuntimeException(e); 46 | } 47 | } 48 | } 49 | return false; 50 | } 51 | } -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/class_generator/src/main/java/annotation_processor/class_generator/GenClass.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.class_generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.SOURCE) 9 | @Target(ElementType.TYPE) 10 | public @interface GenClass { 11 | String genClassName(); 12 | } 13 | -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/class_generator/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | annotation_processor.class_generator.ClassGeneratorAnnotationProcessor -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/text_file_generator/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//05_annotation_processor:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | java_plugin( 6 | name="annotation_processor", 7 | srcs = glob(["src/main/java/**/*.java"]), 8 | processor_class = "annotation_processor.text_file_generator.TextFileGeneratorAnnotationProcessor", 9 | resources = ["src/main/resources/META-INF/services/javax.annotation.processing.Processor"], 10 | ) 11 | 12 | intellij_module(name="iml", iml_type="java-maven-style-with-resources") -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/text_file_generator/src/main/java/annotation_processor/text_file_generator/GenTextFile.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.text_file_generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.SOURCE) 9 | @Target(ElementType.TYPE) 10 | public @interface GenTextFile { 11 | String genTextFileName(); 12 | } 13 | -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/text_file_generator/src/main/java/annotation_processor/text_file_generator/TextFileGeneratorAnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.text_file_generator; 2 | 3 | import javax.annotation.processing.AbstractProcessor; 4 | import javax.annotation.processing.RoundEnvironment; 5 | import javax.annotation.processing.SupportedAnnotationTypes; 6 | import javax.annotation.processing.SupportedSourceVersion; 7 | import javax.lang.model.SourceVersion; 8 | import javax.lang.model.element.Element; 9 | import javax.lang.model.element.Name; 10 | import javax.lang.model.element.TypeElement; 11 | import javax.tools.Diagnostic; 12 | import javax.tools.FileObject; 13 | import javax.tools.JavaFileObject; 14 | import javax.tools.StandardLocation; 15 | import java.io.IOException; 16 | import java.io.PrintWriter; 17 | import java.util.Set; 18 | 19 | import static java.lang.String.format; 20 | 21 | @SupportedSourceVersion(SourceVersion.RELEASE_8) 22 | @SupportedAnnotationTypes("annotation_processor.class_generator.GenClass") 23 | public class TextFileGeneratorAnnotationProcessor extends AbstractProcessor { 24 | @Override 25 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 26 | for (TypeElement annotation : annotations) { 27 | for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(annotation)) { 28 | GenTextFile genTextFileAnnotation = annotatedElement.getAnnotation(GenTextFile.class); 29 | if (genTextFileAnnotation == null) { 30 | continue; 31 | } 32 | String genTextFileName = genTextFileAnnotation.genTextFileName(); 33 | Name annotatedClass = annotatedElement.getSimpleName(); 34 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, 35 | format("found GenTextFile annotation on class '%s', " + 36 | "generating text file '%s'", annotatedClass, genTextFileName)); 37 | try { 38 | FileObject builderFile = processingEnv.getFiler().createResource( 39 | StandardLocation.SOURCE_OUTPUT, 40 | "text_files", 41 | genTextFileName); 42 | try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { 43 | out.write(format("content of text file %s\n", genTextFileName)); 44 | } 45 | } catch (IOException e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | } 50 | return false; 51 | } 52 | } -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/text_file_generator/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | annotation_processor.text_file_generator.TextFileGeneratorAnnotationProcessor -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/usage/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//05_annotation_processor/class_generator:annotation_processor", 12 | "//05_annotation_processor/text_file_generator:annotation_processor", 13 | ], 14 | ) 15 | 16 | java_library( 17 | name="java_test_lib", 18 | srcs = glob(["src/test/java/**/*.java"]), 19 | deps=[ 20 | ":java_lib", 21 | 22 | "//05_annotation_processor/class_generator:annotation_processor", 23 | "//05_annotation_processor/text_file_generator:annotation_processor", 24 | ] + JUNIT5_MINIMAL_DEPS, 25 | ) 26 | 27 | junit5_all_in_package_test( 28 | name="java_tests", 29 | java_package="annotation_processor.usage", 30 | runtime_deps=[":java_test_lib"] 31 | ) 32 | 33 | intellij_module(name="iml", iml_type="java-maven-style") 34 | -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/usage/src/main/java/annotation_processor/usage/Usage.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.usage; 2 | 3 | import annotation_processor.class_generator.GenClass; 4 | import annotation_processor.text_file_generator.GenTextFile; 5 | 6 | @GenTextFile(genTextFileName = "this_is_a_text_file.txt") 7 | @GenClass(genClassName = "ThisIsAClassname") 8 | class Usage { 9 | 10 | } -------------------------------------------------------------------------------- /scenarios/05_annotation_processor/usage/src/test/java/annotation_processor/usage/UsageTest.java: -------------------------------------------------------------------------------- 1 | package annotation_processor.usage; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import somepackage.ThisIsAClassname; 5 | 6 | import java.net.URL; 7 | import java.nio.file.Files; 8 | import java.nio.file.Paths; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | import static org.junit.jupiter.api.Assertions.assertNotNull; 12 | 13 | public class UsageTest { 14 | @Test 15 | public void gen_class() { 16 | assertEquals(77, new ThisIsAClassname().foo); 17 | } 18 | 19 | @Test 20 | public void gen_text_file() throws Exception { 21 | // this test fails in the bazel test //... run, 22 | // but I'm not sure how to fix it. How do we get this_is_a_text_file.txt to be available via classloader? 23 | if (System.getenv().containsKey("TEST_WORKSPACE")) { 24 | return; 25 | } 26 | 27 | URL resource = getClass().getClassLoader().getResource("generated/text_files/this_is_a_text_file.txt"); 28 | assertNotNull(resource); 29 | String content = new String(Files.readAllBytes(Paths.get(resource.toURI()))); 30 | assertEquals("content of text file this_is_a_text_file.txt\n", content); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | 5 | intellij_project( 6 | name="project_06", 7 | deps=["//06_protobuf_messages/usage:java_test_lib"], 8 | build_managed_label_matchlist=['{"label_name":"java_proto"}'], 9 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 10 | iml_types_file="//:iml_types.xml", 11 | project_root_filegroup="//:automatically_placed_intellij_project_files", 12 | project_root_filegroup_ignore_prefix="intellij_project_files", 13 | modules=[ 14 | "//06_protobuf_messages/html_email:iml", 15 | "//06_protobuf_messages/plain_email:iml", 16 | "//06_protobuf_messages/usage:iml", 17 | ] 18 | ) 19 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/README.txt: -------------------------------------------------------------------------------- 1 | Demonstration of use of protobuf bazel tasks, 2 | and how the generated code integrates with an 3 | intellij project. 4 | 5 | Messages only, no RPC. 6 | 7 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/html_email/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | proto_library( 6 | name = "proto", 7 | srcs = ["src/main/proto/html_email.proto"], 8 | deps = [ 9 | "//06_protobuf_messages/plain_email:proto", 10 | 11 | # bring in "well known proto" descriptor.proto. 12 | # This was enabled only recently, via this PR: https://github.com/google/protobuf/pull/3594 13 | "@com_google_protobuf//:descriptor_proto" 14 | ], 15 | ) 16 | 17 | java_proto_library( 18 | name = "java_proto", 19 | deps = [":proto"], 20 | ) 21 | 22 | intellij_module(name="iml", iml_type="java-maven-style") 23 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/html_email/src/main/proto/html_email.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package html_email; 3 | 4 | // This example is also a demonstration of use of proto extensions. 5 | // As of this writing, there has only recently been a merge of this 6 | // fix, to make "well known protos" work: 7 | // https://github.com/google/protobuf/pull/3594 8 | // Which makes it so one can pull in well-known protos in a bazel build. 9 | // see https://github.com/google/protobuf/pull/3594/files 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | // see https://github.com/bazelbuild/bazel/issues/2039#issuecomment-258896609 13 | // "Protobuf import statements must be fully qualified, relative to the current 14 | // workspace (I believe), and relative to the importer workspace this is the 15 | // path to the importee." 16 | import "06_protobuf_messages/plain_email/src/main/proto/plain_email.proto"; 17 | 18 | message SearchIndex { 19 | bool should_index = 1; 20 | } 21 | 22 | extend google.protobuf.FieldOptions { 23 | SearchIndex search_index = 50000; 24 | } 25 | 26 | message HtmlEmail { 27 | plain_email.PlainEmail plain_email = 1; 28 | string body_html = 2 [(search_index).should_index=true]; 29 | } -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/plain_email/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | proto_library( 6 | name = "proto", 7 | srcs = ["src/main/proto/plain_email.proto"], 8 | ) 9 | 10 | java_proto_library( 11 | name = "java_proto", 12 | deps = [":proto"], 13 | ) 14 | 15 | intellij_module(name="iml", iml_type="java-maven-style") 16 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/plain_email/src/main/proto/plain_email.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package plain_email; 3 | 4 | message Identity { 5 | string name = 1; 6 | string email = 2; 7 | } 8 | 9 | message PlainEmail { 10 | Identity from = 1; 11 | Identity to = 2; 12 | string body_text = 3; 13 | } -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/usage/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | 7 | java_library( 8 | name="java_lib", 9 | srcs = glob(["src/main/java/**/*.java"]), 10 | deps=[ 11 | "//06_protobuf_messages/plain_email:java_proto", 12 | "//06_protobuf_messages/html_email:java_proto", 13 | 14 | "@com_google_protobuf//:protobuf_java", 15 | ], 16 | ) 17 | 18 | java_library( 19 | name="java_test_lib", 20 | srcs = glob(["src/test/java/**/*.java"]), 21 | deps=[ 22 | ":java_lib", 23 | 24 | "//06_protobuf_messages/plain_email:java_proto", 25 | "//06_protobuf_messages/html_email:java_proto", 26 | 27 | "@com_google_protobuf//:protobuf_java", 28 | ] + JUNIT5_MINIMAL_DEPS, 29 | ) 30 | 31 | junit5_all_in_package_test( 32 | name="java_tests", 33 | java_package="protobuf_messages.usage", 34 | runtime_deps=[":java_test_lib"] 35 | ) 36 | 37 | intellij_module(name="iml", iml_type="java-maven-style") 38 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/usage/src/main/java/protobuf_messages/usage/Usage.java: -------------------------------------------------------------------------------- 1 | package protobuf_messages.usage; 2 | 3 | import com.google.protobuf.DescriptorProtos; 4 | import com.google.protobuf.Descriptors; 5 | import html_email.HtmlEmailOuterClass.HtmlEmail; 6 | import plain_email.PlainEmailOuterClass.Identity; 7 | import plain_email.PlainEmailOuterClass.PlainEmail; 8 | 9 | import java.util.List; 10 | 11 | import static java.lang.String.format; 12 | 13 | class Usage { 14 | public PlainEmail makePlainEmail() { 15 | return PlainEmail.newBuilder() 16 | .setFrom(Identity.newBuilder() 17 | .setName("Mom") 18 | .setEmail("mom@example.com") 19 | .build()) 20 | .setTo(Identity.newBuilder() 21 | .setName("Kid") 22 | .setEmail("kid@example.com") 23 | .build()) 24 | .setBodyText("hi how are you doing today?") 25 | .build(); 26 | } 27 | 28 | public HtmlEmail makeHtmlEmail() { 29 | PlainEmail plainEmail = makePlainEmail(); 30 | return HtmlEmail.newBuilder() 31 | .setBodyHtml(format("%s", plainEmail.getBodyText())) 32 | .setPlainEmail(plainEmail) 33 | .build(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scenarios/06_protobuf_messages/usage/src/test/java/protobuf_messages/usage/UsageTest.java: -------------------------------------------------------------------------------- 1 | package protobuf_messages.usage; 2 | 3 | import com.google.protobuf.Descriptors; 4 | import html_email.HtmlEmailOuterClass; 5 | import html_email.HtmlEmailOuterClass.HtmlEmail; 6 | import html_email.HtmlEmailOuterClass.SearchIndex; 7 | import org.junit.jupiter.api.Test; 8 | import plain_email.PlainEmailOuterClass.Identity; 9 | import plain_email.PlainEmailOuterClass.PlainEmail; 10 | 11 | import java.util.Map; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | 15 | public class UsageTest { 16 | @Test 17 | public void plain_email() { 18 | assertEquals(PlainEmail.newBuilder() 19 | .setFrom(Identity.newBuilder() 20 | .setName("Mom") 21 | .setEmail("mom@example.com") 22 | .build()) 23 | .setTo(Identity.newBuilder() 24 | .setName("Kid") 25 | .setEmail("kid@example.com") 26 | .build()) 27 | .setBodyText("hi how are you doing today?") 28 | .build(), 29 | new Usage().makePlainEmail()); 30 | } 31 | 32 | @Test 33 | public void html_email() { 34 | HtmlEmail actual = new Usage().makeHtmlEmail(); 35 | assertEquals(HtmlEmail.newBuilder() 36 | .setBodyHtml("hi how are you doing today?") 37 | .setPlainEmail(PlainEmail.newBuilder() 38 | .setFrom(Identity.newBuilder() 39 | .setName("Mom") 40 | .setEmail("mom@example.com") 41 | .build()) 42 | .setTo(Identity.newBuilder() 43 | .setName("Kid") 44 | .setEmail("kid@example.com") 45 | .build()) 46 | .setBodyText("hi how are you doing today?") 47 | .build()) 48 | .build(), 49 | actual); 50 | 51 | // demonstration of retrieval of an option 52 | Map.Entry optionEntry = 53 | actual.getDescriptorForType().findFieldByNumber(HtmlEmail.BODY_HTML_FIELD_NUMBER) 54 | .getOptions().getAllFieldsRaw().entrySet().iterator().next(); 55 | 56 | assertEquals("search_index", optionEntry.getKey().getName()); 57 | assertEquals(SearchIndex.newBuilder().setShouldIndex(true).build(), optionEntry.getValue()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /scenarios/07_grpc/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 4 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 5 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 6 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 7 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 8 | 9 | proto_library( 10 | name = "proto", 11 | srcs = [ 12 | "src/main/proto/fortune.proto" 13 | ], 14 | deps = [ 15 | "@com_google_protobuf//:descriptor_proto", 16 | ] 17 | ) 18 | 19 | java_proto_library( 20 | name = "java_proto", 21 | deps = [":proto"], 22 | ) 23 | 24 | # see https://groups.google.com/forum/#!topic/bazel-discuss/75DSeUTYBxE 25 | # 26 | # from https://github.com/grpc/grpc-java/issues/2756 27 | # Args: 28 | # name: (str) A unique name for this rule. Required. 29 | # srcs: (list) a single proto_library target that contains the schema of the 30 | # service. Required. 31 | # deps: (list) a single java_proto_library target for the proto_library in 32 | # srcs. Required. 33 | # flavor: (str) "normal" (default) for normal proto runtime. "lite" 34 | # for the lite runtime. 35 | # visibility: (list) the visibility list 36 | java_grpc_library( 37 | name = "java_grpc", 38 | deps = [":java_proto"], 39 | srcs = [ 40 | ":proto", 41 | ], 42 | ) 43 | 44 | java_library( 45 | name="java_lib", 46 | srcs = glob(["src/main/java/**/*.java"]), 47 | deps = [ 48 | ":java_proto", 49 | ":java_grpc", 50 | 51 | "@io_grpc_grpc_java//stub", 52 | "@com_google_protobuf//:protobuf_java", 53 | ] 54 | ) 55 | 56 | java_library( 57 | name="java_test_lib", 58 | srcs = glob(["src/test/java/**/*.java"]), 59 | deps=[ 60 | ":java_lib", 61 | ":java_proto", 62 | 63 | "@io_grpc_grpc_java//stub", 64 | "@com_google_protobuf//:protobuf_java", 65 | ] + JUNIT5_MINIMAL_DEPS, 66 | ) 67 | 68 | junit5_all_in_package_test( 69 | name="java_tests", 70 | java_package="fortune_grpc", 71 | runtime_deps=[":java_test_lib"] 72 | ) 73 | 74 | intellij_module(name="iml", iml_type="java-maven-style") 75 | 76 | intellij_project( 77 | name="project_07", 78 | deps=[":java_test_lib"], 79 | build_managed_label_matchlist=['{"label_name":"java_proto"}', '{"label_name":"java_grpc"}'], 80 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 81 | iml_types_file="//:iml_types.xml", 82 | project_root_filegroup="//:automatically_placed_intellij_project_files", 83 | project_root_filegroup_ignore_prefix="intellij_project_files", 84 | modules=[":iml"] 85 | ) 86 | -------------------------------------------------------------------------------- /scenarios/07_grpc/README.txt: -------------------------------------------------------------------------------- 1 | Demonstration of generation of grpc stubs. 2 | 3 | Builds on the protobuf scenario. 4 | -------------------------------------------------------------------------------- /scenarios/07_grpc/src/main/java/fortune_grpc/FortuneService.java: -------------------------------------------------------------------------------- 1 | package fortune_grpc; 2 | 3 | import fortune.Fortune.GetFortuneRequest; 4 | import fortune.Fortune.GetFortuneResponse; 5 | import fortune.FortuneServiceGrpc.FortuneServiceImplBase; 6 | import io.grpc.stub.StreamObserver; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | 11 | import static java.lang.String.format; 12 | 13 | public class FortuneService extends FortuneServiceImplBase { 14 | private static Map FORTUNE_NUMBER_TO_MESSAGE = 15 | new LinkedHashMap() {{ 16 | put(0, "You laugh now, wait till you get home."); 17 | put(1, "Wouldn't it be ironic...to die in the living room?"); 18 | put(2, "About time I got out of that cookie."); 19 | put(3, "Your resemblance to a muppet will prevent the world from taking you seriously."); 20 | put(4, "You will be hungry again in one hour."); 21 | put(5, "run."); 22 | }}; 23 | 24 | @Override 25 | public void getFortune(GetFortuneRequest request, StreamObserver responseObserver) { 26 | if (!FORTUNE_NUMBER_TO_MESSAGE.containsKey(request.getFortuneNumber())) { 27 | throw new IllegalStateException(format("invalid fortune number: %s", request.getFortuneNumber())); 28 | } 29 | 30 | responseObserver.onNext( 31 | GetFortuneResponse.newBuilder() 32 | .setFortuneContent(FORTUNE_NUMBER_TO_MESSAGE.get(request.getFortuneNumber())) 33 | .build() 34 | ); 35 | responseObserver.onCompleted(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scenarios/07_grpc/src/main/proto/fortune.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package fortune; 3 | 4 | import "google/protobuf/descriptor.proto"; 5 | 6 | message GetFortuneRequest { 7 | int32 fortune_number = 1; 8 | } 9 | 10 | message Truth { 11 | bool is_the_fortune_actually_real = 1; 12 | } 13 | 14 | extend google.protobuf.FieldOptions { 15 | Truth the_truth = 50000; 16 | } 17 | 18 | message GetFortuneResponse { 19 | string fortune_content = 1 [(the_truth).is_the_fortune_actually_real=true]; 20 | } 21 | 22 | service FortuneService { 23 | rpc GetFortune (GetFortuneRequest) returns (GetFortuneResponse) {} 24 | } -------------------------------------------------------------------------------- /scenarios/07_grpc/src/test/java/fortune_grpc/FortuneServiceTest.java: -------------------------------------------------------------------------------- 1 | package fortune_grpc; 2 | 3 | import com.google.protobuf.Descriptors; 4 | import fortune.Fortune; 5 | import fortune.Fortune.GetFortuneRequest; 6 | import fortune.Fortune.GetFortuneResponse; 7 | import io.grpc.stub.StreamObserver; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static java.util.Arrays.asList; 15 | import static java.util.stream.Collectors.toList; 16 | import static org.junit.jupiter.api.Assertions.assertEquals; 17 | 18 | public class FortuneServiceTest { 19 | @Test 20 | public void get_fortune() { 21 | List results = new ArrayList<>(); 22 | FortuneService fortuneService = new FortuneService(); 23 | 24 | FakeStreamObserver responseObserver = new FakeStreamObserver<>(); 25 | fortuneService.getFortune(GetFortuneRequest.newBuilder() 26 | .setFortuneNumber(4) 27 | .build(), 28 | responseObserver); 29 | 30 | assertEquals( 31 | asList("You will be hungry again in one hour."), 32 | responseObserver.results.stream().map(GetFortuneResponse::getFortuneContent).collect(toList())); 33 | 34 | 35 | GetFortuneResponse actual = responseObserver.results.get(0); 36 | // demonstration of retrieval of an option 37 | Map.Entry optionEntry = 38 | actual.getDescriptorForType().findFieldByNumber(Fortune.Truth.IS_THE_FORTUNE_ACTUALLY_REAL_FIELD_NUMBER) 39 | .getOptions().getAllFieldsRaw().entrySet().iterator().next(); 40 | 41 | assertEquals("the_truth", optionEntry.getKey().getName()); 42 | assertEquals(Fortune.Truth.newBuilder().setIsTheFortuneActuallyReal(true).build(), optionEntry.getValue()); 43 | } 44 | 45 | class FakeStreamObserver implements StreamObserver { 46 | public List results = new ArrayList<>(); 47 | 48 | @Override 49 | public void onNext(T value) { 50 | results.add(value); 51 | } 52 | 53 | @Override 54 | public void onError(Throwable t) { 55 | throw new UnsupportedOperationException(); 56 | } 57 | 58 | @Override 59 | public void onCompleted() { 60 | // no-op 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /scenarios/08_auto_value/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 5 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 6 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 7 | 8 | # see https://www.kchodorow.com/blog/2016/11/12/using-autovalue-with-bazel/ 9 | java_plugin( 10 | name = "autovalue_plugin", 11 | generates_api = 1, 12 | processor_class = "com.google.auto.value.processor.AutoValueProcessor", 13 | deps = ["@com_google_auto_value//jar"], 14 | ) 15 | 16 | java_library( 17 | name="java_lib", 18 | srcs = glob(["src/main/java/**/*.java"]), 19 | deps=[ 20 | ":autovalue_plugin", 21 | 22 | "@com_google_auto_value//jar", 23 | ], 24 | ) 25 | 26 | java_library( 27 | name="java_test_lib", 28 | srcs = glob(["src/test/java/**/*.java"]), 29 | deps=[":java_lib"] + JUNIT5_MINIMAL_DEPS, 30 | ) 31 | 32 | junit5_all_in_package_test( 33 | name="java_tests", 34 | java_package="house", 35 | runtime_deps=[":java_test_lib"] 36 | ) 37 | 38 | intellij_module(name="iml", iml_type="java-maven-style") 39 | 40 | intellij_project( 41 | name="project_08", 42 | deps=[":java_test_lib"], 43 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 44 | iml_types_file="//:iml_types.xml", 45 | project_root_filegroup="//:automatically_placed_intellij_project_files", 46 | project_root_filegroup_ignore_prefix="intellij_project_files", 47 | modules=[":iml"] 48 | ) 49 | -------------------------------------------------------------------------------- /scenarios/08_auto_value/README.txt: -------------------------------------------------------------------------------- 1 | Demonstration of use of auto value, which uses annotation processing. 2 | -------------------------------------------------------------------------------- /scenarios/08_auto_value/src/main/java/house/House.java: -------------------------------------------------------------------------------- 1 | package house; 2 | 3 | import com.google.auto.value.AutoValue; 4 | 5 | @AutoValue 6 | public abstract class House { 7 | public abstract String color(); 8 | public abstract int floors(); 9 | 10 | public static House.Builder builder() { 11 | return new AutoValue_House.Builder(); 12 | } 13 | 14 | @AutoValue.Builder 15 | public abstract static class Builder { 16 | public abstract House.Builder setColor(String color); 17 | public abstract House.Builder setFloors(int numFloors); 18 | 19 | public abstract House build(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scenarios/08_auto_value/src/test/java/house/HouseTest.java: -------------------------------------------------------------------------------- 1 | package house; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class HouseTest { 8 | @Test 9 | public void build_it() { 10 | House house = House.builder().setColor("red").setFloors(3).build(); 11 | assertEquals("red", house.color()); 12 | assertEquals(3, house.floors()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /scenarios/09_python/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 5 | 6 | py_library( 7 | name = "py_lib", 8 | srcs = ["src/echo.py"], 9 | ) 10 | 11 | py_library( 12 | name = "py_test_lib", 13 | srcs = ["test/echo_test.py"], 14 | deps = [":py_lib"], 15 | ) 16 | 17 | py_test( 18 | name = "echo_test", 19 | srcs = ["test/echo_test.py"], 20 | deps = [":py_lib"], 21 | ) 22 | 23 | intellij_module(name="iml", iml_type="python-simple") 24 | 25 | intellij_project( 26 | name="project_09", 27 | deps=[":py_test_lib"], 28 | iml_types_file="//:iml_types.xml", 29 | project_root_filegroup="//:automatically_placed_intellij_project_files", 30 | project_root_filegroup_ignore_prefix="intellij_project_files", 31 | modules=[":iml"] 32 | ) 33 | -------------------------------------------------------------------------------- /scenarios/09_python/README.txt: -------------------------------------------------------------------------------- 1 | A simple python project. The iml must contain a "python facet" 2 | in order to take advantage of pycharm Intellij features. 3 | -------------------------------------------------------------------------------- /scenarios/09_python/src/echo.py: -------------------------------------------------------------------------------- 1 | def echo(x): 2 | return "echoing: %s" % x 3 | -------------------------------------------------------------------------------- /scenarios/09_python/test/echo_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import sys, os 4 | sys.path.append(os.path.join(os.path.dirname(__file__), '../src')) 5 | 6 | from echo import echo 7 | 8 | class EchoTest(unittest.TestCase): 9 | def test_echo(self): 10 | self.assertEqual("echoing: yy", echo ("yy")) -------------------------------------------------------------------------------- /scenarios/12_kotlin/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | 5 | intellij_project( 6 | name="project_12", 7 | deps=[ 8 | "//12_kotlin/child:kt_test_lib", 9 | "//12_kotlin/parent:kt_test_lib" 10 | ], 11 | test_lib_label_matchlist=['{"label_name":"kt_test_lib"}'], 12 | iml_types_file="//:iml_types.xml", 13 | project_root_filegroup="//:automatically_placed_intellij_project_files", 14 | project_root_filegroup_ignore_prefix="intellij_project_files", 15 | modules=[ 16 | "//12_kotlin/child:iml", 17 | "//12_kotlin/parent:iml", 18 | ] 19 | ) 20 | -------------------------------------------------------------------------------- /scenarios/12_kotlin/README.txt: -------------------------------------------------------------------------------- 1 | Demonstration of kotlin, making use of rules_kotlin. 2 | 3 | This is more or less like a plain java example, but 4 | with these special rules, and the Kotlin facet in 5 | iml files. 6 | -------------------------------------------------------------------------------- /scenarios/12_kotlin/child/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") 7 | 8 | kt_jvm_library( 9 | name = "kt_lib", 10 | srcs = glob(["src/**/*.kt"]), 11 | deps=[ 12 | "//12_kotlin/parent:kt_lib", 13 | ] 14 | ) 15 | 16 | kt_jvm_library( 17 | name="kt_test_lib", 18 | srcs = glob(["test/**/*.kt"]), 19 | deps=[ 20 | ":kt_lib", 21 | ] + JUNIT5_MINIMAL_DEPS, 22 | ) 23 | 24 | junit5_all_in_package_test( 25 | name="kt_tests", 26 | java_package="kotlin_example", 27 | runtime_deps=[":kt_test_lib"] 28 | ) 29 | 30 | intellij_module(name="iml", iml_type="kotlin-simple") -------------------------------------------------------------------------------- /scenarios/12_kotlin/child/src/kotlin_example/child/Child.kt: -------------------------------------------------------------------------------- 1 | package kotlin_example.child 2 | 3 | import kotlin_example.parent.Parent 4 | import java.lang.String.format 5 | 6 | class Child { 7 | fun sayHello(): String { 8 | return "hello" 9 | } 10 | 11 | fun sayHelloAndLa(): String { 12 | return sayHello() + Parent().la4times() 13 | } 14 | } -------------------------------------------------------------------------------- /scenarios/12_kotlin/child/test/kotlin_example/child/ChildTest.kt: -------------------------------------------------------------------------------- 1 | package kotlin_example.child 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class ChildTest { 7 | @Test 8 | fun `say hello`() { 9 | assertEquals("hello", Child().sayHello()) 10 | } 11 | 12 | @Test 13 | fun `say hello and la 4 times`() { 14 | assertEquals("hellolalalala", Child().sayHelloAndLa()) 15 | } 16 | } -------------------------------------------------------------------------------- /scenarios/12_kotlin/parent/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 6 | load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") 7 | 8 | kt_jvm_library( 9 | name = "kt_lib", 10 | srcs = glob(["src/**/*.kt"]), 11 | deps = [ 12 | "@com_google_guava_guava//jar", 13 | ] 14 | ) 15 | 16 | kt_jvm_library( 17 | name="kt_test_lib", 18 | srcs = glob(["test/**/*.kt"]), 19 | deps=[ 20 | ":kt_lib", 21 | ] + JUNIT5_MINIMAL_DEPS, 22 | ) 23 | 24 | junit5_all_in_package_test( 25 | name="kt_tests", 26 | java_package="kotlin_example", 27 | runtime_deps=[":kt_test_lib"] 28 | ) 29 | 30 | intellij_module(name="iml", iml_type="kotlin-simple") -------------------------------------------------------------------------------- /scenarios/12_kotlin/parent/src/kotlin_example/parent/Parent.kt: -------------------------------------------------------------------------------- 1 | package kotlin_example.parent 2 | 3 | import com.google.common.base.Strings 4 | 5 | class Parent { 6 | fun la4times(): String { 7 | return Strings.repeat("la", 4) 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /scenarios/12_kotlin/parent/test/kotlin_example/parent/ParentTest.kt: -------------------------------------------------------------------------------- 1 | package kotlin_example.parent 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class ParentTest { 7 | @Test 8 | fun `la 4 times`() { 9 | assertEquals("lalalala", Parent().la4times()) 10 | } 11 | } -------------------------------------------------------------------------------- /scenarios/13_minor_features/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_junit5//:def.bzl", "JUNIT5_MINIMAL_DEPS") 4 | load("@rules_junit5//:def.bzl", "junit5_all_in_package_test") 5 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 6 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 7 | 8 | java_library( 9 | name="java_lib", 10 | srcs = glob(["src/**/*.java"]), 11 | ) 12 | 13 | java_library( 14 | name="java_test_lib", 15 | srcs = glob(["test/**/*.java"]), 16 | deps=[":java_lib"] + JUNIT5_MINIMAL_DEPS, 17 | ) 18 | 19 | junit5_all_in_package_test( 20 | name="java_tests", 21 | java_package="minor_features", 22 | runtime_deps=[":java_test_lib"] 23 | ) 24 | 25 | filegroup( 26 | name="automatically_placed_intellij_project_files", 27 | srcs=glob(["intellij_project_files/**/*.xml"]) 28 | ) 29 | 30 | intellij_module(name="iml", iml_type="java-simple2", module_name_override="13_mymodulename") 31 | 32 | intellij_project( 33 | name="project_13", 34 | bazelexec="my-bazel-script", 35 | deps=[":java_test_lib"], 36 | test_lib_label_matchlist=['{"label_name":"java_test_lib"}'], 37 | custom_substitutions={ 38 | "MY_BICYCLE_COLOR": "red", 39 | "SOME_FILE": "$(location :some_file.txt)" 40 | }, 41 | iml_types_file=":iml_types.xml", 42 | project_root_filegroup=":automatically_placed_intellij_project_files", 43 | project_root_filegroup_ignore_prefix="13_minor_features/intellij_project_files", 44 | modules=[":iml"], 45 | tools=[":some_file.txt"], 46 | ) 47 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/README.txt: -------------------------------------------------------------------------------- 1 | This scenario demonstrates minor features: 2 | - module name overriding 3 | - custom substitutions 4 | - default substitutions (e.g. bazel package) 5 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/iml_types.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/intellij_project_files/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/some_file.txt: -------------------------------------------------------------------------------- 1 | which has this content 2 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/src/minor_features/B.java: -------------------------------------------------------------------------------- 1 | package minor_features; 2 | 3 | class B { 4 | public int theNumber() { 5 | return 77; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /scenarios/13_minor_features/test/minor_features/BTest.java: -------------------------------------------------------------------------------- 1 | package minor_features; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class BTest { 8 | @Test 9 | public void the_number() { 10 | assertEquals(77, new B().theNumber()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | intellij_project( 5 | name="project_14", 6 | deps=[ 7 | "//14_all_dependency_types/child_data:child_data", 8 | "//14_all_dependency_types/child_dep:child_dep", 9 | "//14_all_dependency_types/child_src:child_src", 10 | 11 | "//14_all_dependency_types/child2_custom:from_child2", 12 | "//14_all_dependency_types/parent2_custom:lib", 13 | ], 14 | iml_types_file="//:iml_types.xml", 15 | project_root_filegroup="//:automatically_placed_intellij_project_files", 16 | project_root_filegroup_ignore_prefix="intellij_project_files", 17 | modules=[ 18 | "//14_all_dependency_types/child_data:iml", 19 | "//14_all_dependency_types/child_dep:iml", 20 | "//14_all_dependency_types/child_src:iml", 21 | "//14_all_dependency_types/parent:iml", 22 | 23 | "//14_all_dependency_types/child2_custom:iml", 24 | "//14_all_dependency_types/parent2_custom:iml", 25 | ], 26 | module_dependency_matchlist = [ 27 | '{"attr":"data"}', 28 | '{"attr":"deps"}', 29 | '{"attr":"srcs"}', 30 | 31 | '{"attr":"gorps"}', 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/README.txt: -------------------------------------------------------------------------------- 1 | A package relationship established by any of the three types of dependencies: 2 | data, 3 | deps, 4 | srcs 5 | Will result in the intellij integration determining that there exists a dependency relationship 6 | among the intellij modules that correspond to the bazel packages in question. 7 | 8 | https://docs.bazel.build/versions/master/build-ref.html#types_of_dependencies 9 | 10 | This also demonstrates how the "depdendency attrs" may be changed / customized. 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/child2_custom/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | load("//14_all_dependency_types:custom2.bzl", "custom2") 5 | 6 | custom2( 7 | name = "from_child2", 8 | gorps = ["//14_all_dependency_types/parent2_custom:lib"] 9 | ) 10 | 11 | intellij_module(name="iml", iml_type="java-simple") 12 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/child_data/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | sh_library( 6 | name = "child_data", 7 | data = ["//14_all_dependency_types/parent:parent.txt"], 8 | ) 9 | 10 | intellij_module(name="iml", iml_type="java-simple") 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/child_dep/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | sh_library( 6 | name = "child_dep", 7 | deps = ["//14_all_dependency_types/parent:parent"], 8 | ) 9 | 10 | intellij_module(name="iml", iml_type="java-simple") 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/child_src/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | sh_library( 6 | name = "child_src", 7 | srcs = ["//14_all_dependency_types/parent:parent.sh"] 8 | ) 9 | 10 | intellij_module(name="iml", iml_type="java-simple") 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/child_src/child.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo "hi, i'm the child." 4 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/custom2.bzl: -------------------------------------------------------------------------------- 1 | def _impl(ctx): 2 | pass 3 | 4 | custom2 = rule( 5 | implementation = _impl, 6 | attrs = { 7 | "gorps": attr.label_list(), 8 | }, 9 | outputs={}, 10 | ) 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/parent/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | sh_library( 6 | name = "parent", 7 | srcs = ["parent.sh"], 8 | data = ["parent.txt"], 9 | ) 10 | 11 | intellij_module(name="iml", iml_type="java-simple") 12 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/parent/parent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo "hi, i'm the parent. btw there's nothing java-related about this at all." 4 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/parent/parent.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sconover/rules_intellij_generate/f738a6306637b72a04ff80a0dfd9e70980bb08c1/scenarios/14_all_dependency_types/parent/parent.txt -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/parent2_custom/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 4 | 5 | sh_library( 6 | name = "lib", 7 | srcs = ["parent2.sh"], 8 | ) 9 | 10 | intellij_module(name="iml", iml_type="java-simple") 11 | -------------------------------------------------------------------------------- /scenarios/14_all_dependency_types/parent2_custom/parent2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo "hi, i'm the parent. btw there's nothing java-related about this at all." 4 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_intellij_generate//:def.bzl", "intellij_project") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 5 | 6 | exports_files(["tsconfig.json", "run_single_mocha_test.sh"]) 7 | 8 | intellij_module(name="iml", iml_type="web-simple") 9 | 10 | filegroup( 11 | name="automatically_placed_intellij_project_files_for_ts", 12 | srcs=glob(["intellij_project_files/**/*.xml"]) 13 | ) 14 | 15 | filegroup( 16 | name="workspace_xml_fragments", 17 | srcs=glob(["workspace_xml_fragments/*.xml"]) 18 | ) 19 | 20 | intellij_project( 21 | name="project_10", 22 | iml_types_file="//:iml_types.xml", 23 | project_root_filegroup=":automatically_placed_intellij_project_files_for_ts", 24 | project_root_filegroup_ignore_prefix="15_typescript_rules_multi_tsc/intellij_project_files", 25 | workspace_xml_fragments_filegroup=":workspace_xml_fragments", 26 | deps=[ 27 | "//15_typescript_rules_multi_tsc/long-gen:tsc", 28 | "//15_typescript_rules_multi_tsc/print-timestamp:tsc", 29 | ], 30 | modules=[ 31 | ":iml", 32 | "//15_typescript_rules_multi_tsc/long-gen:iml", 33 | "//15_typescript_rules_multi_tsc/print-timestamp:iml", 34 | ], 35 | symlinks={ 36 | "${BAZEL_INFO_EXECUTION_ROOT}/external/node_modules_15_typescript_rules_multi_tsc/node_modules": "15_typescript_rules_multi_tsc/node_modules", 37 | "${BAZEL_INFO_EXECUTION_ROOT}/external/node_modules_15_typescript_rules_multi_tsc/package.json": "15_typescript_rules_multi_tsc/package.json", 38 | "${BAZEL_INFO_EXECUTION_ROOT}/external/node_modules_15_typescript_rules_multi_tsc/package-lock.json": "15_typescript_rules_multi_tsc/package-lock.json", 39 | }, 40 | ) 41 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-rules-multi-tsc-example", 3 | "version": "0.0.0", 4 | "scripts": {}, 5 | "private": true, 6 | "dependencies": { 7 | "long": "4.0.0", 8 | "bson": "4.0.1", 9 | "buffer": "5.2.1" 10 | }, 11 | "devDependencies": { 12 | "@types/mocha": "5.2.5", 13 | "@types/chai": "4.1.7", 14 | "mocha": "5.2.0", 15 | "chai": "4.1.0", 16 | "typescript": "3.2.2", 17 | "ts-node": "7.0.1", 18 | "@types/long": "4.0.0", 19 | "@types/bson": "1.0.11", 20 | "rollup": "0.67.4", 21 | "rollup-plugin-alias": "1.5.1", 22 | "rollup-plugin-node-resolve": "3.4.0", 23 | "rollup-plugin-commonjs": "9.2.0", 24 | "rollup-plugin-includepaths": "0.2.3", 25 | "uglify-es": "3.3.9", 26 | "tsconfig-paths": "3.7.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/intellij_project_files/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/intellij_project_files/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/long-gen/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_multi_tsc//:def.bzl", "tsc") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 5 | 6 | tsc( 7 | name="tsc", 8 | ts_path="lgen", 9 | srcs=glob(["src/*.ts"]), 10 | deps=[ 11 | "@node_modules_15_typescript_rules_multi_tsc//:default_typings", 12 | ], 13 | 14 | node_executable="@node//:bin/node", 15 | tsc_script="@node_modules_15_typescript_rules_multi_tsc//:node_modules/typescript/lib/tsc.js", 16 | tsconfig_json="//15_typescript_rules_multi_tsc:tsconfig.json", 17 | ) 18 | 19 | filegroup(name = "src_file", srcs = ["src/long-gen.ts"]) 20 | filegroup(name = "test_file", srcs = ["test/long-gen-test.ts"]) 21 | 22 | sh_library( 23 | name = "ts_lib", 24 | srcs = [":src_file"], 25 | data = [ 26 | "@node//:bin/node", 27 | "@node_modules_15_typescript_rules_multi_tsc//:all_files", 28 | ":src_file", 29 | ], 30 | ) 31 | 32 | sh_test( 33 | name = "ts_test", 34 | srcs = ["//15_typescript_rules_multi_tsc:run_single_mocha_test.sh"], 35 | deps = [":ts_lib"], 36 | args = [ 37 | "external/node_modules_15_typescript_rules_multi_tsc/node_modules", 38 | "$(location @node//:bin/node)", 39 | "$(location //15_typescript_rules_multi_tsc:tsconfig.json)", 40 | "$(location @node_modules_15_typescript_rules_multi_tsc//:node_modules/mocha/bin/mocha)", 41 | "$(location :test_file)" 42 | ], 43 | data = [ 44 | "@node//:bin/node", 45 | "//15_typescript_rules_multi_tsc:tsconfig.json", 46 | "@node_modules_15_typescript_rules_multi_tsc//:all_files", 47 | "@node_modules_15_typescript_rules_multi_tsc//:node_modules/mocha/bin/mocha", 48 | ":src_file", 49 | ":test_file", 50 | ], 51 | ) 52 | 53 | intellij_module(name="iml", iml_type="web-simple") 54 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/long-gen/src/long-gen.ts: -------------------------------------------------------------------------------- 1 | import * as Long from "long" 2 | 3 | export function longGen(): Long { 4 | return new Long(77777) 5 | } 6 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/long-gen/test/long-gen-test.ts: -------------------------------------------------------------------------------- 1 | import * as Long from "long" 2 | import {longGen} from "lgen/long-gen" 3 | import {assert} from "chai" 4 | import "mocha" // this MUST be imported or ts compilation will fail because mocha won't be aware of the mocha types 5 | 6 | suite("long-gen suite", () => { 7 | test("long-gen returns a long with 7's", () => { 8 | assert.deepEqual(longGen(), new Long(77777)) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/package-lock.json: -------------------------------------------------------------------------------- 1 | /private/var/tmp/_bazel_sc/db911cb03fe700319ffc76f57730fb32/execroot/rules_intellij_generate_scenarios/external/node_modules_15_typescript_rules_multi_tsc/package-lock.json -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/package.json: -------------------------------------------------------------------------------- 1 | /private/var/tmp/_bazel_sc/db911cb03fe700319ffc76f57730fb32/execroot/rules_intellij_generate_scenarios/external/node_modules_15_typescript_rules_multi_tsc/package.json -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/print-timestamp/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | load("@rules_multi_tsc//:def.bzl", "tsc") 4 | load("@rules_intellij_generate//:def.bzl", "intellij_module") 5 | 6 | tsc( 7 | name="tsc", 8 | srcs=glob(["src/*.ts"]), 9 | deps=[ 10 | "@node_modules_15_typescript_rules_multi_tsc//:default_typings", 11 | "//15_typescript_rules_multi_tsc/long-gen:tsc", 12 | ], 13 | 14 | node_executable="@node//:bin/node", 15 | tsc_script="@node_modules_15_typescript_rules_multi_tsc//:node_modules/typescript/lib/tsc.js", 16 | tsconfig_json="//15_typescript_rules_multi_tsc:tsconfig.json", 17 | ) 18 | 19 | intellij_module(name="iml", iml_type="web-simple") 20 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/print-timestamp/src/print-timestamp.ts: -------------------------------------------------------------------------------- 1 | import {longGen} from "lgen/long-gen" 2 | import {Timestamp} from "bson" 3 | 4 | export function printTimestamp() { 5 | const l = longGen() 6 | const t = Timestamp.fromBits(l.low, l.high) 7 | console.log(t) 8 | } 9 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/run_single_mocha_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | node_path=$1 4 | node_js=$2 5 | tsconfig_json_path=$3 6 | mocha_bin=$4 7 | test_path=$5 8 | 9 | # see https://github.com/TypeStrong/ts-node/issues/561#issuecomment-375836931 10 | # ..and https://www.sitepoint.com/community/t/ts-node-how-to-use-tsconfig-paths-with-node-modules/300468/6 11 | 12 | exec env NODE_PATH=$node_path TS_NODE_PROJECT=$tsconfig_json_path $node_js $mocha_bin --ui tdd --require ts-node/register --require tsconfig-paths/register $test_path 13 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "lib": [ 10 | "es2015", 11 | "dom" 12 | ], 13 | "noImplicitAny": true, 14 | "suppressImplicitAnyIndexErrors": true, 15 | "outDir": "../whatever", 16 | "baseUrl": ".", 17 | "skipDefaultLibCheck": true, 18 | "allowSyntheticDefaultImports": true, 19 | "paths": { 20 | "lgen/*": [ 21 | "long-gen/src/*" 22 | ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scenarios/15_typescript_rules_multi_tsc/workspace_xml_fragments/workspace.RunManager.fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | project 35 | 36 | 37 | true 38 | 39 | 40 | 42 | 43 | 44 | tdd 45 | --require ts-node/register --require tsconfig-paths/register 46 | DIRECTORY 47 | 48 | false 49 | 50 | 51 | -------------------------------------------------------------------------------- /scenarios/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//:__subpackages__"]) 2 | 3 | exports_files(["iml_types.xml"]) 4 | 5 | filegroup( 6 | name="automatically_placed_intellij_project_files", 7 | srcs=glob(["intellij_project_files/**/*.xml"]) 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /scenarios/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name="rules_intellij_generate_scenarios") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 4 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 5 | 6 | maven_jar(name="com_google_guava_guava", artifact="com.google.guava:guava:19.0") 7 | maven_jar(name="com_google_auto_value", artifact="com.google.auto.value:auto-value:1.5.2") 8 | 9 | local_repository( 10 | name = "rules_intellij_generate", 11 | path = "../rules", 12 | ) 13 | 14 | rules_junit5_sha = "e86a061d86ccb695f705d32c70804f9dc2f4d760" 15 | http_archive( 16 | name = "rules_junit5", 17 | url = "https://github.com/sconover/rules_junit5/archive/%s.tar.gz" % rules_junit5_sha, 18 | strip_prefix = "rules_junit5-%s" % rules_junit5_sha, 19 | ) 20 | load("@rules_junit5//:def.bzl", "junit5_repositories") 21 | junit5_repositories() 22 | 23 | 24 | http_archive( 25 | name = "com_google_protobuf", 26 | strip_prefix = "protobuf-3.11.0", 27 | urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.11.0.tar.gz"], 28 | ) 29 | http_archive( 30 | name = "com_google_protobuf_javalite", 31 | strip_prefix = "protobuf-javalite", 32 | urls = ["https://github.com/google/protobuf/archive/javalite.zip"], 33 | ) 34 | 35 | http_archive( 36 | name = "io_grpc_grpc_java", 37 | urls = ["https://github.com/grpc/grpc-java/archive/fd7d2e5eb4dd020bb892278c78f7b3ef901232c1.zip"], 38 | strip_prefix = "grpc-java-fd7d2e5eb4dd020bb892278c78f7b3ef901232c1", 39 | ) 40 | load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") 41 | grpc_java_repositories( 42 | omit_com_google_guava=True, 43 | omit_com_google_protobuf=True, 44 | omit_com_google_protobuf_javalite=True, 45 | ) 46 | 47 | # see https://github.com/bazelbuild/rules_nodejs 48 | 49 | # rules_nodejs depends on bazel_skylib 50 | # Bazel doesn't support transitive workspace deps so you must copy this. 51 | http_archive( 52 | name = "bazel_skylib", 53 | url = "https://github.com/bazelbuild/bazel-skylib/archive/0.3.1.zip", 54 | strip_prefix = "bazel-skylib-0.3.1", 55 | sha256 = "95518adafc9a2b656667bbf517a952e54ce7f350779d0dd95133db4eb5c27fb1", 56 | ) 57 | 58 | git_repository( 59 | name = "build_bazel_rules_nodejs", 60 | remote = "https://github.com/bazelbuild/rules_nodejs.git", 61 | tag = "0.27.12", # 2019-04-09. check for the latest tag when you install 62 | ) 63 | 64 | load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") 65 | load("@build_bazel_rules_nodejs//:defs.bzl", "npm_install") 66 | 67 | 68 | # for all js/ts-related examples 69 | http_archive( 70 | name = "node", 71 | url = "https://nodejs.org/dist/v10.14.2/node-v10.14.2-darwin-x64.tar.gz", 72 | strip_prefix = "node-v10.14.2-darwin-x64", 73 | build_file_content=""" 74 | exports_files([ 75 | "bin/node", 76 | ]) 77 | """ 78 | ) 79 | 80 | # 12_kotlin 81 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 82 | 83 | rules_kotlin_version = "legacy-1.3.0-rc3" 84 | rules_kotlin_sha = "54678552125753d9fc0a37736d140f1d2e69778d3e52cf454df41a913b964ede" 85 | http_archive( 86 | name = "io_bazel_rules_kotlin", 87 | urls = ["https://github.com/bazelbuild/rules_kotlin/archive/%s.zip" % rules_kotlin_version], 88 | type = "zip", 89 | strip_prefix = "rules_kotlin-%s" % rules_kotlin_version, 90 | sha256 = rules_kotlin_sha, 91 | ) 92 | 93 | load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains") 94 | kotlin_repositories() 95 | kt_register_toolchains() 96 | 97 | 98 | # 15_typescript_rules_multi_tsc 99 | new_local_repository( 100 | name="node_modules_15_typescript_rules_multi_tsc", 101 | path="15_typescript_rules_multi_tsc/deps", 102 | build_file_content=""" 103 | exports_files([ 104 | "package.json", 105 | "package-lock.json", 106 | "node_modules/mocha/bin/mocha", 107 | "node_modules/typescript/lib/tsc.js", 108 | ]) 109 | 110 | filegroup( 111 | name = "all_files", 112 | srcs = glob([ 113 | "node_modules/**", 114 | ]), 115 | visibility = ["//visibility:public"], 116 | ) 117 | 118 | filegroup( 119 | name = "default_typings", 120 | srcs = glob([ 121 | "node_modules/@types/**", 122 | ]), 123 | visibility = ["//visibility:public"], 124 | ) 125 | """ 126 | ) 127 | 128 | rules_multi_tsc_version = "b532865f32eff58338f6a9822adaa7d3142c845d" 129 | 130 | http_archive( 131 | name = "rules_multi_tsc", 132 | urls = ["https://github.com/sconover/rules_multi_tsc/archive/%s.zip" % rules_multi_tsc_version], 133 | type = "zip", 134 | strip_prefix = "rules_multi_tsc-%s/rules" % rules_multi_tsc_version 135 | ) 136 | 137 | http_archive( 138 | name = "rules_python", 139 | sha256 = "e5470e92a18aa51830db99a4d9c492cc613761d5bdb7131c04bd92b9834380f6", 140 | strip_prefix = "rules_python-4b84ad270387a7c439ebdccfd530e2339601ef27", 141 | urls = ["https://github.com/bazelbuild/rules_python/archive/4b84ad270387a7c439ebdccfd530e2339601ef27.tar.gz"], 142 | ) 143 | 144 | http_archive( 145 | name = "zlib", 146 | build_file = "@com_google_protobuf//:third_party/zlib.BUILD", 147 | sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff", 148 | strip_prefix = "zlib-1.2.11", 149 | urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"], 150 | ) 151 | -------------------------------------------------------------------------------- /scenarios/iml_types.xml: -------------------------------------------------------------------------------- 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 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /scenarios/intellij_project_files/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /scenarios/intellij_project_files/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//scenario_tests:__subpackages__"]) 2 | 3 | py_test( 4 | name = "py_tests", 5 | srcs = glob(["pytest/**/*.py"]), 6 | main = "all_tests.py", 7 | data=[ 8 | "//01_one_class:intellij_files", 9 | "//02_one_class_and_one_test:intellij_files", 10 | "//03_basic:intellij_files", 11 | "//04_transitive_via_export:intellij_files", 12 | "//05_annotation_processor:intellij_files", 13 | "//06_protobuf_messages:intellij_files", 14 | "//07_grpc:intellij_files", 15 | "//08_auto_value:intellij_files", 16 | "//09_python:intellij_files", 17 | "//12_kotlin:intellij_files", 18 | "//13_minor_features:intellij_files", 19 | "//13_minor_features:install_intellij_files_script", 20 | "//14_all_dependency_types:intellij_files", 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/all_tests.py: -------------------------------------------------------------------------------- 1 | import unittest, sys 2 | from s01_one_class_test import S01OneClassTest 3 | from s02_one_class_and_one_test import S02OneClassAndOneTest 4 | from s03_basic_test import S03BasicTest 5 | from s04_transitive_with_export_test import S04TransitiveWithExportTest 6 | from s05_annotation_processor_test import S05AnnotationProcessorTest 7 | from s06_protobuf_messages_test import S06ProtobufMessagesTest 8 | from s07_grpc_test import S07GrpcTest 9 | from s08_auto_value_test import S08AutoValueTest 10 | from s09_python_test import S09PythonTest 11 | from s12_kotlin_test import S12KotlinTest 12 | from s13_minor_features_test import S13MinorFeaturesTest 13 | from s14_all_dependency_types_test import S14AllDependencyTypesTest 14 | 15 | if __name__ == '__main__': 16 | suite = unittest.TestSuite() 17 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S01OneClassTest)) 18 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S02OneClassAndOneTest)) 19 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S03BasicTest)) 20 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S04TransitiveWithExportTest)) 21 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S05AnnotationProcessorTest)) 22 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S06ProtobufMessagesTest)) 23 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S07GrpcTest)) 24 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S08AutoValueTest)) 25 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S08AutoValueTest)) 26 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S09PythonTest)) 27 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S12KotlinTest)) 28 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S13MinorFeaturesTest)) 29 | suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(S14AllDependencyTypesTest)) 30 | 31 | # python unit test main's must end with this or the test will exit with status code 0, 32 | # and thus it will not fail the bazel test run if there's a test failure. 33 | return_value = not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful() 34 | sys.exit(return_value) 35 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s01_one_class_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S01OneClassTest(unittest.TestCase): 5 | 6 | archive = load_archive("01_one_class/intellij_files") 7 | 8 | iml_content = archive["01_one_class/01_one_class.iml"] 9 | modules_xml_content = archive["01_one_class/.idea/modules.xml"] 10 | 11 | def test_source_folders(self): 12 | self.assertEqual([ 13 | "file://$MODULE_DIR$/out/production/generated", 14 | "file://$MODULE_DIR$/out/test/generated_tests", 15 | "file://$MODULE_DIR$/src", 16 | "file://$MODULE_DIR$/test" 17 | ], xpath_attribute_list(self.iml_content, "./component/content/sourceFolder", "url")) 18 | 19 | self.assertEqual( 20 | ["false", "true", "false", "true"], 21 | xpath_attribute_list(self.iml_content, "./component/content/sourceFolder", "isTestSource")) 22 | 23 | def test_output_folders(self): 24 | self.assertEqual( 25 | ["file://$MODULE_DIR$/out/production"], 26 | xpath_attribute_list(self.iml_content, "./component/output", "url")) 27 | 28 | self.assertEqual( 29 | ["file://$MODULE_DIR$/out/test"], 30 | xpath_attribute_list(self.iml_content, "./component/output-test", "url")) 31 | 32 | def test_libraries(self): 33 | self.assertEqual( 34 | [], 35 | xpath_attribute_list(self.iml_content, 36 | "./component/orderEntry[@type='module-library']/library/CLASSES/root", 37 | "url")) 38 | 39 | def test_modules_xml(self): 40 | self.assertEqual(["file://$PROJECT_DIR$/01_one_class.iml"], 41 | xpath_attribute_list(self.modules_xml_content, "./component/modules/module", "fileurl")) 42 | 43 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s02_one_class_and_one_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S02OneClassAndOneTest(unittest.TestCase): 5 | 6 | archive = load_archive("02_one_class_and_one_test/intellij_files") 7 | 8 | iml_content = archive["02_one_class_and_one_test/02_one_class_and_one_test.iml"] 9 | 10 | def test_source_folders(self): 11 | self.assertEqual([ 12 | "file://$MODULE_DIR$/out/production/generated", 13 | "file://$MODULE_DIR$/out/test/generated_tests", 14 | "file://$MODULE_DIR$/src", 15 | "file://$MODULE_DIR$/test" 16 | ], xpath_attribute_list(self.iml_content, "./component/content/sourceFolder", "url")) 17 | 18 | self.assertEqual( 19 | ["false", "true", "false", "true"], 20 | xpath_attribute_list(self.iml_content, "./component/content/sourceFolder", "isTestSource")) 21 | 22 | def test_output_folders(self): 23 | self.assertEqual( 24 | ["file://$MODULE_DIR$/out/production"], 25 | xpath_attribute_list(self.iml_content, "./component/output", "url")) 26 | 27 | self.assertEqual( 28 | ["file://$MODULE_DIR$/out/test"], 29 | xpath_attribute_list(self.iml_content, "./component/output-test", "url")) 30 | 31 | def test_libraries(self): 32 | self.assertEqual([], find_all_plain_jar_libraries(self.iml_content)) 33 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.iml_content)) 34 | 35 | 36 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s03_basic_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S03BasicTest(unittest.TestCase): 5 | 6 | archive = load_archive("03_basic/intellij_files") 7 | 8 | dolphin_iml_content = archive["03_basic/dolphin/dolphin.iml"] 9 | human_iml_content = archive["03_basic/human/human.iml"] 10 | gorilla_iml_content = archive["03_basic/gorilla/gorilla.iml"] 11 | primate_iml_content = archive["03_basic/primate/primate.iml"] 12 | mammal_iml_content = archive["03_basic/mammal/mammal.iml"] 13 | 14 | modules_xml_content = archive["03_basic/.idea/modules.xml"] 15 | 16 | def test_source_folders_sample(self): 17 | self.assertEqual([ 18 | "file://$MODULE_DIR$/out/production/generated", 19 | "file://$MODULE_DIR$/out/test/generated_tests", 20 | "file://$MODULE_DIR$/src/main/java", 21 | "file://$MODULE_DIR$/src/test/java" 22 | ], xpath_attribute_list(self.dolphin_iml_content, "./component/content/sourceFolder", "url")) 23 | 24 | self.assertEqual( 25 | ["false", "true", "false", "true"], 26 | xpath_attribute_list(self.dolphin_iml_content, "./component/content/sourceFolder", "isTestSource")) 27 | 28 | def test_output_folders(self): 29 | self.assertEqual( 30 | ["file://$MODULE_DIR$/out/production"], 31 | xpath_attribute_list(self.dolphin_iml_content, "./component/output", "url")) 32 | 33 | self.assertEqual( 34 | ["file://$MODULE_DIR$/out/test"], 35 | xpath_attribute_list(self.dolphin_iml_content, "./component/output-test", "url")) 36 | 37 | def test_libraries(self): 38 | self.assertEqual([], find_all_plain_jar_libraries(self.dolphin_iml_content)) 39 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.dolphin_iml_content)) 40 | 41 | def test_module_dependencies(self): 42 | self.assertEqual([], 43 | xpath_attribute_list(self.mammal_iml_content, 44 | "./component/orderEntry[@type='module']", 45 | "module-name")) 46 | 47 | self.assertEqual(["mammal"], 48 | xpath_attribute_list(self.primate_iml_content, 49 | "./component/orderEntry[@type='module']", 50 | "module-name")) 51 | 52 | self.assertEqual(["mammal"], 53 | xpath_attribute_list(self.dolphin_iml_content, 54 | "./component/orderEntry[@type='module']", 55 | "module-name")) 56 | 57 | self.assertEqual(["mammal", "primate"], 58 | xpath_attribute_list(self.human_iml_content, 59 | "./component/orderEntry[@type='module']", 60 | "module-name")) 61 | 62 | self.assertEqual(["mammal", "primate"], 63 | xpath_attribute_list(self.gorilla_iml_content, 64 | "./component/orderEntry[@type='module']", 65 | "module-name")) 66 | 67 | def test_modules_xml(self): 68 | self.assertEqual([ 69 | "file://$PROJECT_DIR$/dolphin/dolphin.iml", 70 | "file://$PROJECT_DIR$/gorilla/gorilla.iml", 71 | "file://$PROJECT_DIR$/human/human.iml", 72 | "file://$PROJECT_DIR$/mammal/mammal.iml", 73 | "file://$PROJECT_DIR$/primate/primate.iml", 74 | ], xpath_attribute_list(self.modules_xml_content, "./component/modules/module", "fileurl")) 75 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s04_transitive_with_export_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S04TransitiveWithExportTest(unittest.TestCase): 5 | 6 | archive = load_archive("04_transitive_via_export/intellij_files") 7 | 8 | grandparent_iml_content = archive["04_transitive_via_export/grandparent/grandparent.iml"] 9 | parent_iml_content = archive["04_transitive_via_export/parent/parent.iml"] 10 | child_iml_content = archive["04_transitive_via_export/child/child.iml"] 11 | 12 | def test_compile_deps_dont_show_up_in_test_deps(self): 13 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.child_iml_content)) 14 | 15 | def test_sample_jar_dependencies(self): 16 | self.assertEqual([ 17 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_guava/jar/guava-19.0.jar!/" 18 | ], find_all_plain_jar_libraries(self.grandparent_iml_content)) 19 | 20 | self.assertEqual([ 21 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_guava/jar/guava-19.0.jar!/" 22 | ], find_all_plain_jar_libraries(self.parent_iml_content)) 23 | 24 | self.assertEqual([ 25 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_guava/jar/guava-19.0.jar!/" 26 | ], find_all_plain_jar_libraries(self.child_iml_content)) 27 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s05_annotation_processor_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S05AnnotationProcessorTest(unittest.TestCase): 5 | 6 | archive = load_archive("05_annotation_processor/intellij_files") 7 | 8 | usage_iml_content = archive["05_annotation_processor/usage/usage.iml"] 9 | compiler_xml_content = archive["05_annotation_processor/.idea/compiler.xml"] 10 | 11 | def test_annotation_processor_config(self): 12 | self.assertEqual( 13 | ["foo_profile", "my_idea_auto_value_annotation_processor_profile"], 14 | xpath_attribute_list(self.compiler_xml_content, "./component/annotationProcessing/profile", "name")) 15 | 16 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.usage_iml_content)) 17 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s06_protobuf_messages_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from scenario_test_support import * 4 | 5 | 6 | class S06ProtobufMessagesTest(unittest.TestCase): 7 | archive = load_archive("06_protobuf_messages/intellij_files") 8 | 9 | usage_iml_content = archive["06_protobuf_messages/usage/usage.iml"] 10 | 11 | def test_libraries(self): 12 | self.assertEqual([ 13 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/com_google_protobuf/libdescriptor_proto-speed.jar!/", 14 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/06_protobuf_messages/html_email/libproto-speed.jar!/", 15 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/06_protobuf_messages/plain_email/libproto-speed.jar!/", 16 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/com_google_protobuf/libprotobuf_java.jar!/", 17 | ], find_all_plain_jar_libraries(self.usage_iml_content)) 18 | 19 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.usage_iml_content)) 20 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s07_grpc_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import re 3 | from scenario_test_support import * 4 | 5 | class S07GrpcTest(unittest.TestCase): 6 | maxDiff = None 7 | 8 | archive = load_archive("07_grpc/intellij_files") 9 | 10 | fortune_grpc_iml_content = archive["07_grpc/07_grpc.iml"] 11 | 12 | def test_libraries(self): 13 | self.assertEqual([ 14 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_errorprone_error_prone_annotations/error_prone_annotations-X.X.X.jar!/", 15 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_failureaccess/failureaccess-X.X.X.jar!/", 16 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_code_gson_gson/gson-X.X.X.jar!/", 17 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_guava/jar/guava-X.X.jar!/", 18 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_jXobjc_jXobjc_annotations/jXobjc-annotations-X.X.jar!/", 19 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_code_findbugs_jsrX/jsrX-X.X.X.jar!/", 20 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/io_grpc_grpc_java/api/libapi.jar!/", 21 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/io_grpc_grpc_java/context/libcontext.jar!/", 22 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/com_google_protobuf/libdescriptor_proto-speed.jar!/", 23 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/X_grpc/libjava_grpc.jar!/", 24 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/X_grpc/libproto-speed.jar!/", 25 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/io_grpc_grpc_java/protobuf-lite/libprotobuf-lite.jar!/", 26 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/io_grpc_grpc_java/protobuf/libprotobuf.jar!/", 27 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/com_google_protobuf/libprotobuf_java.jar!/", 28 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/com_google_protobuf/libprotobuf_java_util.jar!/", 29 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/bazel-out/darwin-fastbuild/bin/external/io_grpc_grpc_java/stub/libstub.jar!/", 30 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_api_grpc_proto_google_common_protos/proto-google-common-protos-X.X.X.jar!/", 31 | ], list(map(lambda x: re.sub(r"[0-9]+", "X", x), find_all_plain_jar_libraries(self.fortune_grpc_iml_content)))) 32 | 33 | self.assertEqual(junit5_jars(), find_all_test_jar_libraries(self.fortune_grpc_iml_content)) 34 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s08_auto_value_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S08AutoValueTest(unittest.TestCase): 5 | 6 | archive = load_archive("08_auto_value/intellij_files") 7 | 8 | compiler_xml_content = archive["08_auto_value/.idea/compiler.xml"] 9 | 10 | def test_source_folders(self): 11 | self.assertEqual([ 12 | "foo_profile", "my_idea_auto_value_annotation_processor_profile" 13 | ], xpath_attribute_list(self.compiler_xml_content, "./component/annotationProcessing/profile", "name")) 14 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s09_python_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S09PythonTest(unittest.TestCase): 5 | 6 | archive = load_archive("09_python/intellij_files") 7 | 8 | iml_content = archive["09_python/09_python.iml"] 9 | 10 | def test_python_facet(self): 11 | self.assertEqual(["Python"], xpath_attribute_list(self.iml_content, "./component/facet", "name")) 12 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s12_kotlin_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S12KotlinTest(unittest.TestCase): 5 | maxDiff = None 6 | 7 | archive = load_archive("12_kotlin/intellij_files") 8 | 9 | parent_iml_content = archive["12_kotlin/parent/parent.iml"] 10 | child_iml_content = archive["12_kotlin/child/child.iml"] 11 | 12 | def test_kotlin_facet(self): 13 | self.assertEqual(["Kotlin"], xpath_attribute_list(self.parent_iml_content, "./component/facet", "name")) 14 | self.assertEqual(["Kotlin"], xpath_attribute_list(self.child_iml_content, "./component/facet", "name")) 15 | 16 | 17 | def test_source_folders(self): 18 | expected = [ 19 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_google_guava_guava/jar/guava-19.0.jar!/", 20 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar!/", 21 | ] 22 | 23 | self.assertEqual(expected, find_all_plain_jar_libraries(self.child_iml_content)) 24 | self.assertEqual(expected, find_all_plain_jar_libraries(self.parent_iml_content)) 25 | 26 | def test_module_dependencies(self): 27 | self.assertEqual(["parent"], 28 | xpath_attribute_list(self.child_iml_content, 29 | "./component/orderEntry[@type='module']", 30 | "module-name")) 31 | 32 | self.assertEqual([], 33 | xpath_attribute_list(self.parent_iml_content, 34 | "./component/orderEntry[@type='module']", 35 | "module-name")) 36 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s13_minor_features_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | 5 | class S13MinorFeaturesTest(unittest.TestCase): 6 | archive = load_archive("13_minor_features/intellij_files") 7 | 8 | iml_content = archive["13_minor_features/13_mymodulename.iml"] 9 | 10 | def test_source_folders(self): 11 | self.assertEqual([ 12 | "file://$MODULE_DIR$/out/production/generated", 13 | "file://$MODULE_DIR$/out/test/generated_tests", 14 | "file://$MODULE_DIR$/src", 15 | "file://$MODULE_DIR$/test", 16 | "file://$MODULE_DIR$/${MY_BICYCLE_COLOR}", 17 | "file://$MODULE_DIR$/${SOME_FILE}", 18 | "file://${BAZEL_PACKAGE_GENFILES}", 19 | ], xpath_attribute_list(self.iml_content, "./component/content/sourceFolder", "url")) 20 | 21 | def test_provide_bash_exports_for_custom_substitutions(self): 22 | script_content = read_file(generated_file_path("13_minor_features/install_intellij_files_script")) 23 | custom_vars_in_python = script_content.split("# BEFORE_CUSTOM_VARS")[1].split("# AFTER_CUSTOM_VARS")[0] 24 | 25 | self.assertEqual( 26 | "'MY_BICYCLE_COLOR':'red',\n" + 27 | "'SOME_FILE':'13_minor_features/some_file.txt',", 28 | custom_vars_in_python.strip()) 29 | 30 | self.assertContains(script_content, 31 | 'for line in get_subcommand_output(["my-bazel-script", "info"]).splitlines()') 32 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/s14_all_dependency_types_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from scenario_test_support import * 3 | 4 | class S14AllDependencyTypesTest(unittest.TestCase): 5 | 6 | archive = load_archive("14_all_dependency_types/intellij_files") 7 | 8 | child_data_iml_content = archive["14_all_dependency_types/child_data/child_data.iml"] 9 | child_dep_iml_content = archive["14_all_dependency_types/child_dep/child_dep.iml"] 10 | child_src_iml_content = archive["14_all_dependency_types/child_src/child_src.iml"] 11 | parent_iml_content = archive["14_all_dependency_types/parent/parent.iml"] 12 | 13 | child2_custom_iml_content = archive["14_all_dependency_types/child2_custom/child2_custom.iml"] 14 | 15 | def test_module_dependencies(self): 16 | self.assertEqual([], 17 | xpath_attribute_list(self.parent_iml_content, 18 | "./component/orderEntry[@type='module']", 19 | "module-name")) 20 | 21 | self.assertEqual(["parent"], 22 | xpath_attribute_list(self.child_src_iml_content, 23 | "./component/orderEntry[@type='module']", 24 | "module-name")) 25 | 26 | self.assertEqual(["parent"], 27 | xpath_attribute_list(self.child_data_iml_content, 28 | "./component/orderEntry[@type='module']", 29 | "module-name")) 30 | 31 | self.assertEqual(["parent2_custom"], 32 | xpath_attribute_list(self.child2_custom_iml_content, 33 | "./component/orderEntry[@type='module']", 34 | "module-name")) 35 | -------------------------------------------------------------------------------- /scenarios/scenario_tests/pytest/scenario_test_support.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | import os 3 | 4 | dir_path = os.path.dirname(os.path.realpath(__file__)) 5 | 6 | 7 | def is_bazel_run(): 8 | return "TEST_WORKSPACE" in os.environ 9 | 10 | 11 | def read_file(path): 12 | f = open(path, "r") 13 | content = f.read() 14 | f.close() 15 | return content 16 | 17 | 18 | def parse_xml(xml_str): 19 | return ET.fromstring(xml_str) 20 | 21 | 22 | def xpath_list(xml_str, xpath): 23 | return parse_xml(xml_str).findall(xpath) 24 | 25 | 26 | # unfortunately ElementTree doesn't handle returning xpath attribute values, this is a workaround. 27 | def xpath_attribute_list(xml_str, xpath, attribute_name): 28 | return list(map(lambda e: e.get(attribute_name), parse_xml(xml_str).findall(xpath))) 29 | 30 | 31 | def generated_file_path(relative_path): 32 | return relative_path \ 33 | if is_bazel_run() \ 34 | else os.path.join(dir_path, "../../bazel-bin/%s" % relative_path) 35 | 36 | def load_archive(intellij_files_archive_path): 37 | intellij_files_archive_path = generated_file_path(intellij_files_archive_path) 38 | 39 | entries = read_file(intellij_files_archive_path) \ 40 | .split("__SYMLINK_DIVIDER__\n", 1)[0] \ 41 | .split("__SHA1_DIVIDER__\n", 1)[1] \ 42 | .split("\n__FILE_DIVIDER__\n") 43 | 44 | relative_path_to_content = {} 45 | for entry in entries: 46 | parts = entry.split("\n", 1) 47 | relative_path_to_content[parts[0]] = parts[1] 48 | 49 | return relative_path_to_content 50 | 51 | def find_all_plain_jar_libraries(iml_content): 52 | return list(map(lambda e: e.find("./library/CLASSES/root").get("url"), 53 | filter(lambda e: e.get("type") == "module-library" and "scope" not in e.keys(), 54 | parse_xml(iml_content).findall("./component/orderEntry")))) 55 | 56 | def find_all_test_jar_libraries(iml_content): 57 | return list(map(lambda e: e.find("./library/CLASSES/root").get("url"), 58 | filter(lambda e: e.get("type") == "module-library" and e.get("scope") == "TEST", 59 | parse_xml(iml_content).findall("./component/orderEntry")))) 60 | 61 | def junit5_jars(): 62 | return [ 63 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_apiguardian_apiguardian_api/jar/apiguardian-api-1.0.0.jar!/", 64 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_junit_jupiter_junit_jupiter_api/jar/junit-jupiter-api-5.0.1.jar!/", 65 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_junit_platform_junit_platform_commons/jar/junit-platform-commons-1.0.1.jar!/", 66 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_junit_platform_junit_platform_engine/jar/junit-platform-engine-1.0.1.jar!/", 67 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_junit_platform_junit_platform_launcher/jar/junit-platform-launcher-1.0.1.jar!/", 68 | "jar://${BAZEL_INFO_EXECUTION_ROOT}/external/org_opentest4j_opentest4j/jar/opentest4j-1.0.0.jar!/"] 69 | -------------------------------------------------------------------------------- /scenarios/tools/bazel.rc: -------------------------------------------------------------------------------- 1 | build --strategy=KotlinCompile=worker 2 | test --test_output=errors --action_env="GTEST_COLOR=1" 3 | --------------------------------------------------------------------------------