├── .gitattributes ├── .gitignore ├── LICENSE ├── README.adoc ├── eclipse-rtccli-format-settings.xml ├── migration.properties └── rtc2git.cli.extension ├── .classpath ├── .gitignore ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs ├── org.eclipse.jdt.ui.prefs └── org.eclipse.m2e.core.prefs ├── META-INF └── MANIFEST.MF ├── build.properties ├── launch └── rtc2git.launch ├── plugin.xml ├── pom.xml ├── rtc.cli.extended.product ├── rtc2git.target ├── src ├── org │ └── slf4j │ │ └── impl │ │ └── StaticLoggerBinder.java └── to │ └── rtc │ └── cli │ └── migrate │ ├── ChangeSet.java │ ├── HistoryEntryVisitor.java │ ├── LoggingPrintStream.java │ ├── MigrateTo.java │ ├── MigrateToOptions.java │ ├── Migrator.java │ ├── RtcChangeSet.java │ ├── RtcMigrator.java │ ├── RtcTag.java │ ├── RtcTagList.java │ ├── RtcWorkItem.java │ ├── StreamOutput.java │ ├── Tag.java │ ├── TagCreationDateComparator.java │ ├── command │ ├── AcceptCommandDelegate.java │ ├── LoadCommandDelegate.java │ └── RtcCommandDelegate.java │ ├── git │ ├── GitMigrator.java │ ├── MigrateToGit.java │ └── MigrateToGitOptions.java │ └── util │ ├── CommitCommentTranslator.java │ ├── Files.java │ └── JazzignoreTranslator.java └── src_test └── to └── rtc └── cli └── migrate ├── RtcTagListTest.java ├── git ├── GitMigratorTest.java ├── GitPlainTest.java └── MigrateToGitTest.java └── util ├── CommitCommentTranslatorTest.java └── JazzignoreTranslatorTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.md text 7 | *.java text 8 | *.properties text 9 | *.launch text 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | # OSX hidden files 15 | .DS_Store 16 | 17 | # intelliJ IDE 18 | .idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 rtcTo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Tool to migrate from IBM RTC to Git 2 | :project-full-path: rtcTo/rtc2gitcli 3 | :github-branch: master 4 | :rtcversion: 6.0.4 5 | :rtc2gitwiki: https://github.com/rtcTo/rtc2git/wiki 6 | :rtc2gitcliwiki: https://github.com/rtcTo/rtc2gitcli/wiki 7 | image:https://img.shields.io/badge/license-MIT-blue.svg["MIT License", link="https://github.com/{project-full-path}/blob/{github-branch}/LICENSE"] 8 | image:https://img.shields.io/badge/Java-8-blue.svg["Supported Versions", link="https://travis-ci.org/{project-full-path}"] 9 | 10 | A tool made for migrating code from an existing https://jazz.net/products/rational-team-concert/[IBM RTC] into a Git repository. 11 | Inspired by https://github.com/{project-full-path}[rtc2git], but written in Java and hopefully faster. It is implemented as `scm cli` plugin. 12 | 13 | 14 | == Prerequirements 15 | - *https://jazz.net/downloads/rational-team-concert/releases/{rtcversion}?p=allDownloads[SCM Tools]* from IBM. To avoid an 16 | account creation on jazz.net site, you could use http://bugmenot.com/[bugmenot] (see also wiki page ({rtc2gitwiki}/configure-RTC-CLI[configure RTC CLI]) 17 | - Eclipse configured with scm tools as target platform (see wiki {rtc2gitcliwiki}/configure-target-platform[configure scm tools target platform]) 18 | 19 | == Usage 20 | - create an source RTC workspace with flow target and components as wanted -> `SOURCE_WORKSPACE` 21 | - create an target RTC workspace with `SOURCE_WORKPSACE` as flow target -> `TARGET_WORKSPACE` 22 | - check comments at {rtc2gitcliwiki}/configure-rtc-workspaces[configure rtc workspaces] 23 | - open shell or cmd 24 | - step into the target directory 25 | - load the initial target workspace: 26 | 27 | [source,bash] 28 | ---- 29 | scm load -r -u -P 30 | ---- 31 | 32 | Execute the actual migration: 33 | 34 | [source,bash] 35 | ---- 36 | scm migrate-to-git -r -u -P -m 37 | ---- 38 | 39 | == How does it work? 40 | 1. It initalizes an empty git repository and clones it 41 | 2. In this repository, it loads `TARGET_WORKSPACE` RTC workspace 42 | 3. Every change set is accepted 43 | 4. If there is a baseline on the change set, a tag is created on git 44 | 5. The change set is committed to git 45 | 46 | === Setup Eclipse development environment 47 | In order to enhance the the migration tool, fix a bug that you may encounter or simply want to run it from your eclipse, here are the steps to set up a development environment: 48 | 49 | - Import Code Style (Window->Preferences->Java->Code Style->Formatter) `eclipse-rtccli-format-settings.xml` in order to have a common coding style (you can skip this step if you only want to run it) 50 | - Configure SCMTools Target Platform described here in the {rtc2gitcliwiki}/configure-target-platform[wiki]. Point to the folder where your `scm.exe`/`lscm.bat` is 51 | (If you use eclipse classic aka non javaee eclipse, install the Eclipse Plugin Development Tools as described {rtc2gitcliwiki}/configure-target-platform#help---there-is-no-target-platform[here]) 52 | - Clone this repo and import it in eclipse as maven project 53 | - Open `pom.xml` and follow the hint to install the missing maven connector 54 | - Update maven project using [ALT]+[F5] 55 | - By this point the project shouldnt contain any errors (make sure you have still your created target platform in window preference selected) 56 | - You should have an launch-configuration named rtc2git -> start it 57 | - In your console window you should see _"Help for: scm migrate-to-git"_ 58 | - Open the launch-config and edit the command in arguments/program arguments 59 | 60 | In case you use RTC Version 6+ (and have the error Problem running 'help', unknown Subcommand...), please follow the instructions of this https://github.com/rtcTo/rtc2gitcli/issues/44#issuecomment-396727582[issue-comment] in order to run rtc2gitcli. 61 | 62 | == Wiki 63 | For more details {rtc2gitcliwiki}[visit our wiki] 64 | 65 | == Links for JGit 66 | - http://download.eclipse.org/jgit/docs/jgit-3.3.0.201403021825-r/apidocs/?d[api docs] 67 | - https://github.com/centic9/jgit-cookbook[jgit cookbook] 68 | - http://wiki.eclipse.org/JGit/User_Guide[User Guide] 69 | 70 | == Contribute & Feedback 71 | Feel free to report and/or fix https://github.com/rtcTo/rtc2gitcli/issues[issues] or create new pull requests 72 | -------------------------------------------------------------------------------- /eclipse-rtccli-format-settings.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 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 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 | -------------------------------------------------------------------------------- /migration.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Contains all needed information used while migrate from RTC to git 3 | # uncomment and change the defaults as needed. 4 | # 5 | 6 | # User name and email address for the default git user if not defined 7 | # by the RTC check-in information 8 | # 9 | #user.email=rtc2git@rtc.to 10 | #user.name=RTC 2 git 11 | 12 | # Optional - Set encoding of files (For example encoding = UTF-8) 13 | # See "https://github.com/rtcTo/rtc2git/wiki/Encoding" for further instructions 14 | # 15 | #file.encoding=UTF-8 16 | 17 | # Optional, defines a baseline name filter 18 | # 19 | # Here you define a regex for baselines that should be tagged in git. 20 | # By default no tags are created. 21 | # 22 | # Example for all baselines 23 | # rtc.baseline.include=^(.*)$ 24 | # 25 | #rtc.baseline.include= 26 | 27 | # Optional, defines a work item number format to apply on each work item bound to 28 | # the specific RTC changeset (if any) 29 | # 30 | # In case you have migrated your workitems to another issue system (like jira/github/bitbucket) 31 | # by using rtc2jira, you can define a prefix for the commit-message, in order that previously 32 | # linked rtc commits get linked to the new issue system. 33 | # 34 | # Example for a Jira project: AP- (Project has the key AP and is followed by a dash) 35 | # rtc.workitem.number.format=AP-%s 36 | # 37 | # For more detailed information about smart commits see: 38 | # https://confluence.atlassian.com/jiracloud/processing-jira-issues-with-commit-messages-740098538.html 39 | # 40 | #rtc.workitem.number.format=%s 41 | 42 | # Optional, defines the delimiter between multiple formatted RTC work item numbers. The default is 43 | # a single space if not defined. 44 | # 45 | #rtc.workitem.number.delimiter= 46 | 47 | # Optional commit message search/replace pairs being applied to to commit comment before the 48 | # actual commit. The entries have to be in pairs of commit.message.regex.X/commit.message.replacement.X 49 | # where X must be a unique decimal number. 50 | # 51 | #commit.message.regex.1=^(.*)$ 52 | #commit.message.replacement.1=$1 53 | 54 | # Optional, defines the final commit message format where as the first parameter represents the 55 | # result of the rtc.workitem.* replacement and the second parameter contains the result of the 56 | # commit.message.* result. The result will be trimmed. 57 | # 58 | #commit.message.format=%1s %2s 59 | 60 | # Optional, specifies the line(s) which are added to .gitattributes 61 | # Define a semicolon-separated list of lines 62 | # 63 | # Example: 64 | # gitattributes=# handle text files; * text=auto; *.sql text 65 | # 66 | #gitattributes= 67 | 68 | # Ignore big (binary) files 69 | # Define a semicolon-separated list of extensions to be generally ignored 70 | # 71 | # Example: 72 | # ignore.file.extensions=.zip; .jar; .exe; .dll 73 | # 74 | #ignore.file.extensions= 75 | 76 | # Optional: global .gitignore entries 77 | # Define a semicolon-separated list of additional .gitignore entries being added 78 | # 79 | # Example: 80 | # global.gitignore.entries=/projectX/WebContent/node_modules; *.ignored 81 | # 82 | #global.gitignore.entries= 83 | 84 | # Maximum number of streams to open at a time. Open packs count against the process limits 85 | # 86 | #packedgitopenfiles=128 87 | 88 | # Maximum number bytes of heap memory to dedicate to caching pack file data 89 | # 90 | #packedgitlimit=10m 91 | 92 | # Size in bytes of a single window read in from the pack file 93 | # 94 | #packedgitwindowsize=8k 95 | 96 | # Enables use of Java NIO virtual memory mapping for windows; false reads entire window 97 | # into a byte[] with standard read calls 98 | # 99 | #packedgitmmap=false 100 | 101 | # maximum number of bytes to cache in delta base cache for inflated, recently accessed 102 | # objects, without delta chains 103 | # 104 | #deltabasecachelimit=10m 105 | 106 | # new byte limit for objects that must be streamed. Objects smaller than this size can be 107 | # obtained as a contiguous byte array, while objects bigger than this size require using an 108 | # 109 | #streamfilethreshold=50m 110 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.classpath: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /bin_test/ 3 | /lib/ 4 | /target/ 5 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cli.extension 4 | NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse. 5 | 6 | 7 | 8 | org.eclipse.jdt.core.javabuilder 9 | 10 | 11 | org.eclipse.pde.ManifestBuilder 12 | 13 | 14 | org.eclipse.pde.SchemaBuilder 15 | 16 | 17 | org.eclipse.m2e.core.maven2Builder 18 | 19 | 20 | 21 | org.eclipse.m2e.core.maven2Nature 22 | org.eclipse.pde.PluginNature 23 | org.eclipse.jdt.core.javanature 24 | 25 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.6 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 13 | org.eclipse.jdt.core.compiler.source=1.6 14 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false 15 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 16 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 17 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 18 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 19 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 20 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 21 | org.eclipse.jdt.core.formatter.alignment_for_assignment=0 22 | org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 23 | org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 24 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 25 | org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 26 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 27 | org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 28 | org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 29 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 30 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 31 | org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 32 | org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 33 | org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 34 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 35 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 36 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 37 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 38 | org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 39 | org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 40 | org.eclipse.jdt.core.formatter.blank_lines_after_package=1 41 | org.eclipse.jdt.core.formatter.blank_lines_before_field=0 42 | org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 43 | org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 44 | org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 45 | org.eclipse.jdt.core.formatter.blank_lines_before_method=1 46 | org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 47 | org.eclipse.jdt.core.formatter.blank_lines_before_package=0 48 | org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 49 | org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 50 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 51 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 52 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 53 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 54 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 55 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 56 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 57 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 58 | org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line 59 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 60 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 61 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 62 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false 63 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false 64 | org.eclipse.jdt.core.formatter.comment.format_block_comments=true 65 | org.eclipse.jdt.core.formatter.comment.format_header=false 66 | org.eclipse.jdt.core.formatter.comment.format_html=true 67 | org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true 68 | org.eclipse.jdt.core.formatter.comment.format_line_comments=true 69 | org.eclipse.jdt.core.formatter.comment.format_source_code=true 70 | org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true 71 | org.eclipse.jdt.core.formatter.comment.indent_root_tags=true 72 | org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert 73 | org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert 74 | org.eclipse.jdt.core.formatter.comment.line_length=120 75 | org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true 76 | org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true 77 | org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false 78 | org.eclipse.jdt.core.formatter.compact_else_if=true 79 | org.eclipse.jdt.core.formatter.continuation_indentation=2 80 | org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 81 | org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off 82 | org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on 83 | org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false 84 | org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true 85 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true 86 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true 87 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true 88 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true 89 | org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true 90 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 91 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 92 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true 93 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true 94 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false 95 | org.eclipse.jdt.core.formatter.indentation.size=4 96 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert 97 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert 98 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert 99 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert 100 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert 101 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert 102 | org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert 103 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 104 | org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert 105 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert 106 | org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert 107 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 108 | org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert 109 | org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert 110 | org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert 111 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert 112 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert 113 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert 114 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert 115 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert 116 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert 117 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert 118 | org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert 119 | org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert 120 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert 121 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert 122 | org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert 123 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert 124 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert 125 | org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert 126 | org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert 127 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert 128 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert 129 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert 130 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert 131 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert 132 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert 133 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert 134 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert 135 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert 136 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert 137 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert 138 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert 139 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert 140 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert 141 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert 142 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert 143 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert 144 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert 145 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert 146 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert 147 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert 148 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert 149 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert 150 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert 151 | org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert 152 | org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert 153 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert 154 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert 155 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert 156 | org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert 157 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert 158 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert 159 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert 160 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert 161 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert 162 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert 163 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert 164 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert 165 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert 166 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert 167 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert 168 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert 169 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert 170 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert 171 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert 172 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert 173 | org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert 174 | org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert 175 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert 176 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert 177 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert 178 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert 179 | org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert 180 | org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert 181 | org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert 182 | org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert 183 | org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert 184 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert 185 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert 186 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert 187 | org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert 188 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert 189 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert 190 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert 191 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert 192 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert 193 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert 194 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert 195 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert 196 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert 197 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert 198 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert 199 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert 200 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert 201 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert 202 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert 203 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert 204 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert 205 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert 206 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert 207 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert 208 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert 209 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert 210 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert 211 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert 212 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert 213 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert 214 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert 215 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert 216 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert 217 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert 218 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert 219 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert 220 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert 221 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert 222 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert 223 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert 224 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert 225 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert 226 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert 227 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert 228 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert 229 | org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert 230 | org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert 231 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert 232 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert 233 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert 234 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert 235 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert 236 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert 237 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert 238 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert 239 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert 240 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert 241 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert 242 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert 243 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert 244 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert 245 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert 246 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert 247 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert 248 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert 249 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert 250 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert 251 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert 252 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert 253 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert 254 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert 255 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert 256 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert 257 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert 258 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert 259 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert 260 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert 261 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert 262 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert 263 | org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert 264 | org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert 265 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert 266 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert 267 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert 268 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert 269 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert 270 | org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert 271 | org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert 272 | org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert 273 | org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert 274 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert 275 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert 276 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert 277 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert 278 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert 279 | org.eclipse.jdt.core.formatter.join_lines_in_comments=true 280 | org.eclipse.jdt.core.formatter.join_wrapped_lines=true 281 | org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false 282 | org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false 283 | org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false 284 | org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false 285 | org.eclipse.jdt.core.formatter.lineSplit=120 286 | org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false 287 | org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false 288 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 289 | org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 290 | org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true 291 | org.eclipse.jdt.core.formatter.tabulation.char=tab 292 | org.eclipse.jdt.core.formatter.tabulation.size=4 293 | org.eclipse.jdt.core.formatter.use_on_off_tags=false 294 | org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false 295 | org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true 296 | org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true 297 | org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true 298 | org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter 299 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true 3 | formatter_profile=_Eclipse (rtccli) 4 | formatter_settings_version=12 5 | sp_cleanup.format_source_code=true 6 | sp_cleanup.organize_imports=true 7 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: RTC to GIT export extension 4 | Bundle-SymbolicName: to.rtc.cli.migrate;singleton:=true 5 | Bundle-Version: 1.0.1 6 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 7 | Require-Bundle: com.ibm.team.filesystem.cli.core, 8 | com.ibm.team.filesystem.client, 9 | com.ibm.team.filesystem.common, 10 | com.ibm.team.filesystem.rcp.core, 11 | com.ibm.team.process.client, 12 | com.ibm.team.process.common, 13 | com.ibm.team.repository.client, 14 | com.ibm.team.repository.common, 15 | com.ibm.team.scm.client, 16 | com.ibm.team.scm.common, 17 | com.ibm.team.workitem.common, 18 | org.eclipse.core.resources, 19 | org.eclipse.core.runtime, 20 | com.ibm.team.filesystem.cli.client 21 | Import-Package: com.ibm.team.filesystem.cli.client, 22 | com.ibm.team.repository.common.json, 23 | com.ibm.team.rtc.cli.infrastructure.internal.core, 24 | com.ibm.team.rtc.cli.infrastructure.internal.parser, 25 | com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions 26 | Bundle-ClassPath: to.rtc.cli.migration.jar, 27 | lib/commons-codec-1.4.jar, 28 | lib/commons-logging-1.1.1.jar, 29 | lib/hamcrest-core-1.3.jar, 30 | lib/httpclient-4.1.3.jar, 31 | lib/httpcore-4.1.4.jar, 32 | lib/JavaEWAH-0.7.9.jar, 33 | lib/jsch-0.1.50.jar, 34 | lib/junit-4.12.jar, 35 | lib/slf4j-api-1.7.2.jar, 36 | lib/org.eclipse.jgit-4.3.1.201605051710-r.jar 37 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/build.properties: -------------------------------------------------------------------------------- 1 | source.to.rtc.cli.migration.jar = src/ 2 | output.to.rtc.cli.migration.jar = bin/ 3 | bin.includes = META-INF/,\ 4 | to.rtc.cli.migration.jar,\ 5 | plugin.xml,\ 6 | lib/commons-codec-1.4.jar,\ 7 | lib/commons-logging-1.1.1.jar,\ 8 | lib/hamcrest-core-1.3.jar,\ 9 | lib/httpclient-4.1.3.jar,\ 10 | lib/httpcore-4.1.4.jar,\ 11 | lib/JavaEWAH-0.7.9.jar,\ 12 | lib/jsch-0.1.50.jar,\ 13 | lib/junit-4.12.jar,\ 14 | lib/slf4j-api-1.7.2.jar,\ 15 | lib/org.eclipse.jgit-4.3.1.201605051710-r.jar 16 | jars.compile.order = to.rtc.cli.migration.jar 17 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/launch/rtc2git.launch: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | to.rtc 6 | cli.extension 7 | 1.0.1 8 | 9 | 10 | org.eclipse.jgit 11 | org.eclipse.jgit 12 | 4.3.1.201605051710-r 13 | runtime 14 | 15 | 16 | junit 17 | junit 18 | 4.13.2 19 | test 20 | 21 | 22 | 23 | 1.6 24 | 1.6 25 | 26 | 27 | bin 28 | bin_test 29 | src 30 | src_test 31 | 32 | 33 | maven-eclipse-plugin 34 | 2.10 35 | 36 | true 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-dependency-plugin 42 | 2.1 43 | 44 | 45 | copy-dependencies 46 | process-sources 47 | 48 | copy-dependencies 49 | 50 | 51 | ${basedir}/lib 52 | true 53 | true 54 | true 55 | 56 | 57 | 58 | 59 | 60 | 61 | https://github.com/rtcTo/rtc2gitcli 62 | RTC to git migration extension 63 | 64 | rtc.to 65 | https://rtc.to 66 | 67 | 68 | git@github.com:rtcTo/rtc2gitcli.git 69 | git@github.com:rtcTo/rtc2gitcli.git 70 | git@github.com:rtcTo/rtc2gitcli.git 71 | 72 | 73 | 74 | MIT License 75 | http://www.opensource.org/licenses/mit-license.php 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/rtc.cli.extended.product: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --launcher.suppressErrors 11 | -data 12 | @noDefault 13 | 14 | -Xmx512m 15 | -Xshareclasses 16 | -Xquickstart 17 | -Dosgi.requiredJavaVersion=1.5 18 | 19 | -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts 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 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/rtc2git.target: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/org/slf4j/impl/StaticLoggerBinder.java: -------------------------------------------------------------------------------- 1 | package org.slf4j.impl; 2 | 3 | import org.slf4j.ILoggerFactory; 4 | import org.slf4j.Logger; 5 | import org.slf4j.helpers.NOPLogger; 6 | 7 | /** 8 | * Default NoOp logger binder implementation to satisfy minimum requirements. 9 | * 10 | * @author patrick.reinhart 11 | */ 12 | public enum StaticLoggerBinder implements ILoggerFactory { 13 | INSTANCE; 14 | 15 | public static StaticLoggerBinder getSingleton() { 16 | return StaticLoggerBinder.INSTANCE; 17 | } 18 | 19 | public ILoggerFactory getLoggerFactory() { 20 | return this; 21 | } 22 | 23 | @Override 24 | public Logger getLogger(String name) { 25 | return NOPLogger.NOP_LOGGER; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/ChangeSet.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents a change set 7 | * 8 | * @author florian.buehlmann 9 | * @author patrick.reinhart 10 | */ 11 | public interface ChangeSet { 12 | /** 13 | * Returns the comment of the change set. 14 | * 15 | * @return the changeset comment 16 | */ 17 | public String getComment(); 18 | 19 | /** 20 | * Returns the change set creator name. 21 | * 22 | * @return the creator of the change set 23 | */ 24 | public String getCreatorName(); 25 | 26 | /** 27 | * Returns the email address of the change set creator. 28 | * 29 | * @return the creator email address 30 | */ 31 | public String getEmailAddress(); 32 | 33 | /** 34 | * Returns the change set creation time stamp. 35 | * 36 | * @return the creation date time stamp 37 | */ 38 | public long getCreationDate(); 39 | 40 | /** 41 | * Returns the list of all work items connected to that change set. 42 | * 43 | * @return the referenced work items 44 | */ 45 | public List getWorkItems(); 46 | 47 | /** 48 | * Represents a work item reference 49 | */ 50 | public interface WorkItem { 51 | /** 52 | * Returns the unique number of the work item. 53 | * 54 | * @return the work item number 55 | */ 56 | public long getNumber(); 57 | 58 | /** 59 | * Returns the work item description. 60 | * 61 | * @return the work description 62 | */ 63 | public String getText(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/HistoryEntryVisitor.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogBaselineEntryDTO; 8 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogChangeSetEntryDTO; 9 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogComponentEntryDTO; 10 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogEntryDTO; 11 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogWorkItemEntryDTO; 12 | import com.ibm.team.filesystem.rcp.core.internal.changelog.BaseChangeLogEntryVisitor; 13 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 14 | 15 | public class HistoryEntryVisitor extends BaseChangeLogEntryVisitor { 16 | 17 | private final RtcTagList tags; 18 | private String component; 19 | private final Map lastChangeSets; 20 | private boolean lastChangeSetReached; 21 | 22 | public HistoryEntryVisitor(RtcTagList tagList, Map lastChangeSets, IChangeLogOutput out) { 23 | this.tags = tagList; 24 | setOutput(out); 25 | this.lastChangeSets = lastChangeSets; 26 | this.lastChangeSetReached = false; 27 | } 28 | 29 | public void acceptInto(ChangeLogEntryDTO root) { 30 | if (!enter(root)) { 31 | return; 32 | } 33 | for (Iterator iterator = root.getChildEntries().iterator(); iterator.hasNext();) { 34 | ChangeLogEntryDTO child = (ChangeLogEntryDTO) iterator.next(); 35 | visitChild(root, child); 36 | acceptInto(child); 37 | } 38 | 39 | exit(root); 40 | } 41 | 42 | @Override 43 | protected void visitChangeSet(ChangeLogEntryDTO parent, ChangeLogChangeSetEntryDTO changeSetDto) { 44 | if (lastChangeSetReached) { 45 | return; 46 | } 47 | String changeSetUuid = changeSetDto.getItemId(); 48 | RtcChangeSet changeSet = new RtcChangeSet(changeSetUuid).setText(changeSetDto.getEntryName()) 49 | .setCreatorName(changeSetDto.getCreator().getFullName()) 50 | .setCreatorEMail(changeSetDto.getCreator().getEmailAddress()) 51 | .setCreationDate(changeSetDto.getCreationDate()).setComponent(component); 52 | @SuppressWarnings("unchecked") 53 | List workItems = changeSetDto.getWorkItems(); 54 | if (workItems != null && !workItems.isEmpty()) { 55 | for (ChangeLogWorkItemEntryDTO workItem : workItems) { 56 | changeSet.addWorkItem(workItem.getWorkItemNumber(), workItem.getEntryName()); 57 | } 58 | } 59 | RtcTag actualTag = getActualTag(parent); 60 | actualTag.add(changeSet); 61 | if (lastChangeSets.get(component).equals(changeSetUuid)) { 62 | lastChangeSetReached = true; 63 | actualTag.setContainLastChangeset(true); 64 | } 65 | } 66 | 67 | private RtcTag getActualTag(ChangeLogEntryDTO parent) { 68 | if (parent instanceof ChangeLogBaselineEntryDTO) { 69 | final ChangeLogBaselineEntryDTO dto = (ChangeLogBaselineEntryDTO) parent; 70 | return tags.getTag(dto.getItemId(), dto.getEntryName(), dto.getCreationDate()); 71 | } else { 72 | return tags.getHeadTag(); 73 | } 74 | } 75 | 76 | @Override 77 | protected void visitComponent(ChangeLogEntryDTO parent, ChangeLogComponentEntryDTO dto) { 78 | component = dto.getEntryName(); 79 | lastChangeSetReached = false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/LoggingPrintStream.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.io.OutputStream; 4 | import java.io.PrintStream; 5 | import java.util.Date; 6 | 7 | public class LoggingPrintStream extends PrintStream { 8 | private static final byte NEWLINE = (byte) '\n'; 9 | 10 | private boolean afterNewLine; 11 | 12 | LoggingPrintStream(OutputStream stream) { 13 | super(stream); 14 | afterNewLine = true; 15 | } 16 | 17 | @Override 18 | public void write(byte[] bytes, int i, int j) { 19 | if (afterNewLine) { 20 | byte[] dateBytes = getDateTime(); 21 | super.write(dateBytes, 0, dateBytes.length); 22 | afterNewLine = false; 23 | } 24 | super.write(bytes, i, j); 25 | if (endsWithNewLine(bytes, i, j)) { 26 | afterNewLine = true; 27 | } 28 | } 29 | 30 | boolean endsWithNewLine(byte[] bytes, int offset, int length) { 31 | int position = bytes.length - 1; 32 | if (position > (offset + length)) { 33 | position = offset + length; 34 | } 35 | return NEWLINE == bytes[position]; 36 | } 37 | 38 | @Override 39 | public void println(String s) { 40 | super.println(s); 41 | afterNewLine = true; 42 | } 43 | 44 | @Override 45 | public void println() { 46 | super.println(); 47 | afterNewLine = true; 48 | } 49 | 50 | @Override 51 | public void println(char[] ac) { 52 | super.println(ac); 53 | afterNewLine = true; 54 | } 55 | 56 | private byte[] getDateTime() { 57 | return String.format("[%1$tY-%1$tm-%1$td %1$tT] ", new Date()).getBytes(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/MigrateTo.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.io.File; 4 | import java.lang.reflect.Field; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.regex.Pattern; 10 | 11 | import org.eclipse.core.runtime.IProgressMonitor; 12 | import org.eclipse.core.runtime.NullProgressMonitor; 13 | 14 | import com.ibm.team.filesystem.cli.client.AbstractSubcommand; 15 | import com.ibm.team.filesystem.cli.core.internal.ScmCommandLineArgument; 16 | import com.ibm.team.filesystem.cli.core.subcommands.CommonOptions; 17 | import com.ibm.team.filesystem.cli.core.util.RepoUtil; 18 | import com.ibm.team.filesystem.cli.core.util.RepoUtil.ItemType; 19 | import com.ibm.team.filesystem.cli.core.util.SubcommandUtil; 20 | import com.ibm.team.filesystem.client.FileSystemException; 21 | import com.ibm.team.filesystem.client.internal.PathLocation; 22 | import com.ibm.team.filesystem.client.internal.snapshot.FlowType; 23 | import com.ibm.team.filesystem.client.internal.snapshot.SnapshotId; 24 | import com.ibm.team.filesystem.client.internal.snapshot.SnapshotSyncReport; 25 | import com.ibm.team.filesystem.client.rest.IFilesystemRestClient; 26 | import com.ibm.team.filesystem.client.rest.parameters.ParmsGetBaselines; 27 | import com.ibm.team.filesystem.common.changemodel.IPathResolver; 28 | import com.ibm.team.filesystem.common.internal.rest.client.changelog.ChangeLogEntryDTO; 29 | import com.ibm.team.filesystem.common.internal.rest.client.core.BaselineDTO; 30 | import com.ibm.team.filesystem.common.internal.rest.client.sync.BaselineHistoryEntryDTO; 31 | import com.ibm.team.filesystem.common.internal.rest.client.sync.GetBaselinesDTO; 32 | import com.ibm.team.filesystem.rcp.core.internal.changelog.ChangeLogCustomizer; 33 | import com.ibm.team.filesystem.rcp.core.internal.changelog.ChangeLogStreamOutput; 34 | import com.ibm.team.filesystem.rcp.core.internal.changelog.GenerateChangeLogOperation; 35 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 36 | import com.ibm.team.filesystem.rcp.core.internal.changes.model.CopyFileAreaPathResolver; 37 | import com.ibm.team.filesystem.rcp.core.internal.changes.model.FallbackPathResolver; 38 | import com.ibm.team.filesystem.rcp.core.internal.changes.model.SnapshotPathResolver; 39 | import com.ibm.team.repository.client.IItemManager; 40 | import com.ibm.team.repository.client.ITeamRepository; 41 | import com.ibm.team.repository.common.TeamRepositoryException; 42 | import com.ibm.team.rtc.cli.infrastructure.internal.core.CLIClientException; 43 | import com.ibm.team.rtc.cli.infrastructure.internal.core.ISubcommand; 44 | import com.ibm.team.rtc.cli.infrastructure.internal.core.LocalContext; 45 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.ICommandLine; 46 | import com.ibm.team.scm.client.IWorkspaceConnection; 47 | import com.ibm.team.scm.client.IWorkspaceManager; 48 | import com.ibm.team.scm.client.SCMPlatform; 49 | import com.ibm.team.scm.client.internal.ClientChangeSetEntry; 50 | import com.ibm.team.scm.common.IChangeSetHandle; 51 | import com.ibm.team.scm.common.IComponent; 52 | import com.ibm.team.scm.common.IComponentHandle; 53 | import com.ibm.team.scm.common.IWorkspace; 54 | import com.ibm.team.scm.common.IWorkspaceHandle; 55 | 56 | @SuppressWarnings("restriction") 57 | public abstract class MigrateTo extends AbstractSubcommand implements ISubcommand { 58 | 59 | private StreamOutput output; 60 | private boolean listTagsOnly = false; 61 | 62 | private IProgressMonitor getMonitor() { 63 | return new LogTaskMonitor(new StreamOutput(config.getContext().stdout())); 64 | } 65 | 66 | public abstract Migrator getMigrator(); 67 | 68 | public abstract Pattern getBaselineIncludePattern(); 69 | 70 | @Override 71 | public void run() throws FileSystemException { 72 | boolean isUpdateMigration = false; 73 | long start = System.currentTimeMillis(); 74 | setStdOut(); 75 | output = new StreamOutput(config.getContext().stdout()); 76 | 77 | try { 78 | // Consume the command-line 79 | ICommandLine subargs = config.getSubcommandCommandLine(); 80 | 81 | int timeout = 900; 82 | if (subargs.hasOption(MigrateToOptions.OPT_RTC_CONNECTION_TIMEOUT)) { 83 | String timeoutOptionValue = subargs.getOptionValue(MigrateToOptions.OPT_RTC_CONNECTION_TIMEOUT) 84 | .getValue(); 85 | timeout = Integer.parseInt(timeoutOptionValue); 86 | } 87 | 88 | if (subargs.hasOption(MigrateToOptions.OPT_RTC_LIST_TAGS_ONLY)) { 89 | listTagsOnly = true; 90 | output.writeLine("***** LIST ONLY THE TAGS *****"); 91 | } 92 | 93 | if (subargs.hasOption(MigrateToOptions.OPT_RTC_IS_UPDATE_MIGRATION)) { 94 | isUpdateMigration = true; 95 | output.writeLine("***** IS UPDATE MIGRATION *****"); 96 | } 97 | 98 | final ScmCommandLineArgument sourceWsOption = ScmCommandLineArgument.create( 99 | subargs.getOptionValue(MigrateToOptions.OPT_SRC_WS), config); 100 | SubcommandUtil.validateArgument(sourceWsOption, ItemType.WORKSPACE); 101 | final ScmCommandLineArgument destinationWsOption = ScmCommandLineArgument.create( 102 | subargs.getOptionValue(MigrateToOptions.OPT_DEST_WS), config); 103 | SubcommandUtil.validateArgument(destinationWsOption, ItemType.WORKSPACE); 104 | 105 | // Initialize connection to RTC 106 | output.writeLine("Initialize RTC connection with connection timeout of " + timeout + "s"); 107 | IFilesystemRestClient client = SubcommandUtil.setupDaemon(config); 108 | ITeamRepository repo = RepoUtil.loginUrlArgAncestor(config, client, destinationWsOption); 109 | repo.setConnectionTimeout(timeout); 110 | 111 | IWorkspace sourceWs = RepoUtil.getWorkspace(sourceWsOption.getItemSelector(), true, false, repo, config); 112 | IWorkspace destinationWs = RepoUtil.getWorkspace(destinationWsOption.getItemSelector(), true, false, repo, 113 | config); 114 | 115 | output.writeLine("Get full history information from RTC. This could take a large amount of time."); 116 | output.writeLine("Create the list of baselines"); 117 | RtcTagList tagList = createTagListFromBaselines(client, repo, sourceWs); 118 | 119 | output.writeLine("Get changeset information for all baselines"); 120 | addChangeSetInfo(tagList, repo, sourceWs, destinationWs); 121 | 122 | tagList.printTagList(listTagsOnly); 123 | 124 | output.writeLine("Filter included baselines..."); 125 | 126 | // Sorting is required berore pruning if migration from multiple components should be done. Otherwise tags 127 | // of some code could be wrong. 128 | tagList.sortByCreationDate(); 129 | tagList.pruneInactiveTags(); 130 | tagList.pruneExcludedTags(getBaselineIncludePattern()); 131 | 132 | tagList.printTagList(true); 133 | 134 | if (listTagsOnly) { 135 | // Stop here before migration of any data 136 | return; 137 | } 138 | 139 | final File sandboxDirectory; 140 | output.writeLine("Start migration of tags."); 141 | if (subargs.hasOption(CommonOptions.OPT_DIRECTORY)) { 142 | sandboxDirectory = new File(subargs.getOption(CommonOptions.OPT_DIRECTORY)); 143 | } else { 144 | sandboxDirectory = new File(System.getProperty("user.dir")); 145 | } 146 | Migrator migrator = getMigrator(); 147 | migrator.init(sandboxDirectory); 148 | 149 | Map destinationWsComponents = RepoUtil.getComponentsInSandbox( 150 | destinationWs.getItemId().getUuidValue(), new PathLocation(sandboxDirectory.getAbsolutePath()), 151 | client, config); 152 | 153 | RtcMigrator rtcMigrator = new RtcMigrator(output, config, destinationWsOption.getStringValue(), migrator, 154 | sandboxDirectory, destinationWsComponents.values(), isUpdateMigration); 155 | boolean isFirstTag = true; 156 | int numberOfTags = tagList.size(); 157 | int tagCounter = 0; 158 | for (RtcTag tag : tagList) { 159 | if (isUpdateMigration && isFirstTag && tag.isEmpty()) { 160 | output.writeLine("Ignore migration of tag [" + tag.toString() + "] because it is empty."); 161 | tagCounter++; 162 | continue; 163 | } 164 | isFirstTag = false; 165 | final long startTag = System.currentTimeMillis(); 166 | output.writeLine("Start migration of Tag [" + tag.getName() + "] [" + (tagCounter + 1) + "/" 167 | + numberOfTags + "]"); 168 | try { 169 | rtcMigrator.migrateTag(tag); 170 | tagCounter++; 171 | } catch (CLIClientException e) { 172 | e.printStackTrace(output.getOutputStream()); 173 | throw new RuntimeException(e); 174 | } 175 | output.writeLine("Migration of tag [" + tag.getName() + "] [" + (tagCounter) + "/" + numberOfTags 176 | + "] took [" + (System.currentTimeMillis() - startTag) / 1000 + "] s"); 177 | } 178 | } catch (Throwable t) { 179 | t.printStackTrace(output.getOutputStream()); 180 | throw new RuntimeException(t); 181 | } finally { 182 | output.writeLine("Migration took [" + (System.currentTimeMillis() - start) / 1000 + "] s"); 183 | } 184 | } 185 | 186 | private void setStdOut() { 187 | Class c = LocalContext.class; 188 | Field subargs; 189 | try { 190 | subargs = c.getDeclaredField("stdout"); 191 | subargs.setAccessible(true); 192 | subargs.set(config.getContext(), new LoggingPrintStream(config.getContext().stdout())); 193 | } catch (Exception e) { 194 | throw new RuntimeException(e); 195 | } 196 | } 197 | 198 | private Map getLastChangeSetUuids(ITeamRepository repo, IWorkspace sourceWs) { 199 | IWorkspaceConnection sourceWsConnection; 200 | IWorkspaceManager workspaceManager = SCMPlatform.getWorkspaceManager(repo); 201 | IItemManager itemManager = repo.itemManager(); 202 | Map lastChangeSets = new HashMap(); 203 | try { 204 | IProgressMonitor monitor = getMonitor(); 205 | sourceWsConnection = workspaceManager.getWorkspaceConnection(sourceWs, monitor); 206 | @SuppressWarnings("unchecked") 207 | List componentHandles = sourceWsConnection.getComponents(); 208 | @SuppressWarnings("unchecked") 209 | List components = itemManager.fetchCompleteItems(componentHandles, componentHandles.size(), 210 | monitor); 211 | for (IComponent component : components) { 212 | @SuppressWarnings("unchecked") 213 | List changeSets = sourceWsConnection.changeHistory(component).recent(monitor); 214 | // select first change set if there are any 215 | if (!changeSets.isEmpty()) { 216 | IChangeSetHandle changeSetHandle = changeSets.get(changeSets.size() - 1).changeSet(); 217 | lastChangeSets.put(component.getName(), changeSetHandle.getItemId().getUuidValue()); 218 | } 219 | } 220 | } catch (TeamRepositoryException e) { 221 | e.printStackTrace(output.getOutputStream()); 222 | } 223 | return lastChangeSets; 224 | } 225 | 226 | private RtcTagList createTagListFromBaselines(IFilesystemRestClient client, ITeamRepository repo, 227 | IWorkspace sourceWs) { 228 | RtcTagList tagList = new RtcTagList(output); 229 | try { 230 | IWorkspaceConnection sourceWsConnection = SCMPlatform.getWorkspaceManager(repo).getWorkspaceConnection( 231 | sourceWs, getMonitor()); 232 | 233 | IWorkspaceHandle sourceStreamHandle = (IWorkspaceHandle) (sourceWsConnection.getFlowTable() 234 | .getCurrentAcceptFlow().getFlowNode()); 235 | 236 | @SuppressWarnings("unchecked") 237 | List componentHandles = sourceWsConnection.getComponents(); 238 | 239 | ParmsGetBaselines parms = new ParmsGetBaselines(); 240 | parms.workspaceItemId = sourceStreamHandle.getItemId().getUuidValue(); 241 | parms.repositoryUrl = repo.getRepositoryURI(); 242 | parms.max = 1000000; 243 | 244 | GetBaselinesDTO result = null; 245 | for (IComponentHandle component : componentHandles) { 246 | parms.componentItemId = component.getItemId().getUuidValue(); 247 | result = client.getBaselines(parms, getMonitor()); 248 | for (Object obj : result.getBaselineHistoryEntriesInWorkspace()) { 249 | BaselineHistoryEntryDTO baselineEntry = (BaselineHistoryEntryDTO) obj; 250 | BaselineDTO baseline = baselineEntry.getBaseline(); 251 | long creationDate = baseline.getCreationDate(); 252 | RtcTag tag = new RtcTag(baseline.getItemId()).setCreationDate(creationDate).setOriginalName( 253 | baseline.getName()); 254 | tag = tagList.add(tag); 255 | } 256 | } 257 | // add default tag 258 | tagList.getHeadTag(); 259 | } catch (TeamRepositoryException e) { 260 | e.printStackTrace(output.getOutputStream()); 261 | } 262 | return tagList; 263 | } 264 | 265 | private void addChangeSetInfo(RtcTagList tagList, ITeamRepository repo, IWorkspace sourceWs, 266 | IWorkspace destinationWs) { 267 | 268 | SnapshotSyncReport syncReport; 269 | try { 270 | IWorkspaceConnection sourceWsConnection = SCMPlatform.getWorkspaceManager(repo).getWorkspaceConnection( 271 | sourceWs, getMonitor()); 272 | 273 | IWorkspaceHandle sourceStreamHandle = (IWorkspaceHandle) (sourceWsConnection.getFlowTable() 274 | .getCurrentAcceptFlow().getFlowNode()); 275 | SnapshotId sourceSnapshotId = SnapshotId.getSnapshotId(sourceStreamHandle); 276 | SnapshotId destinationSnapshotId = SnapshotId.getSnapshotId(destinationWs.getItemHandle()); 277 | 278 | @SuppressWarnings("unchecked") 279 | List componentHandles = sourceWsConnection.getComponents(); 280 | syncReport = SnapshotSyncReport.compare(destinationSnapshotId.getSnapshot(null), 281 | sourceSnapshotId.getSnapshot(null), componentHandles, getMonitor()); 282 | GenerateChangeLogOperation clOp = new GenerateChangeLogOperation(); 283 | ChangeLogCustomizer customizer = new ChangeLogCustomizer(); 284 | 285 | customizer.setFlowsToInclude(FlowType.Incoming); 286 | customizer.setIncludeComponents(true); 287 | customizer.setIncludeBaselines(true); 288 | customizer.setIncludeChangeSets(true); 289 | customizer.setIncludeWorkItems(true); 290 | customizer.setPruneEmptyDirections(false); 291 | customizer.setPruneUnchangedComponents(false); 292 | 293 | List pathResolvers = new ArrayList(); 294 | pathResolvers.add(CopyFileAreaPathResolver.create()); 295 | pathResolvers.add(SnapshotPathResolver.create(destinationSnapshotId)); 296 | pathResolvers.add(SnapshotPathResolver.create(sourceSnapshotId)); 297 | IPathResolver pathResolver = new FallbackPathResolver(pathResolvers, true); 298 | clOp.setChangeLogRequest(repo, syncReport, pathResolver, customizer); 299 | output.writeLine("Get list of baselines and changesets form RTC."); 300 | long startTime = System.currentTimeMillis(); 301 | ChangeLogEntryDTO changelog = clOp.run(getMonitor()); 302 | output.writeLine("Get list of baselines and changesets form RTC took [" 303 | + (System.currentTimeMillis() - startTime) / 1000 + "]s."); 304 | output.writeLine("Parse the list of baselines and changesets."); 305 | HistoryEntryVisitor visitor = new HistoryEntryVisitor(tagList, getLastChangeSetUuids(repo, sourceWs), 306 | new ChangeLogStreamOutput(config.getContext().stdout())); 307 | 308 | startTime = System.currentTimeMillis(); 309 | visitor.acceptInto(changelog); 310 | output.writeLine("Parse the list of baselines and changesets took [" 311 | + (System.currentTimeMillis() - startTime) / 1000 + "]s."); 312 | 313 | } catch (TeamRepositoryException e) { 314 | e.printStackTrace(output.getOutputStream()); 315 | } 316 | } 317 | 318 | static class LogTaskMonitor extends NullProgressMonitor { 319 | private String taskName; 320 | private int total = -1; 321 | private int done = 0; 322 | private final IChangeLogOutput output; 323 | 324 | LogTaskMonitor(IChangeLogOutput output) { 325 | this.output = output; 326 | } 327 | 328 | @Override 329 | public void beginTask(String task, int totalWork) { 330 | if (task != null && !task.isEmpty()) { 331 | taskName = task; 332 | output.writeLine(taskName + " start"); 333 | } 334 | total = totalWork; 335 | } 336 | 337 | @Override 338 | public void subTask(String subTask) { 339 | output.setIndent(2); 340 | output.writeLine(subTask + " [" + getPercent() + "%]"); 341 | } 342 | 343 | private int getPercent() { 344 | if (total <= 0) { 345 | return -1; 346 | } 347 | return done * 100 / total; 348 | } 349 | 350 | @Override 351 | public void worked(int workDone) { 352 | done += workDone; 353 | } 354 | 355 | @Override 356 | public void done() { 357 | taskName = null; 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/MigrateToOptions.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import com.ibm.team.filesystem.cli.core.subcommands.CommonOptions; 4 | import com.ibm.team.filesystem.cli.core.util.SubcommandUtil; 5 | import com.ibm.team.rtc.cli.infrastructure.internal.core.IOptionSource; 6 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.IOptionKey; 7 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.NamedOptionDefinition; 8 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.OptionKey; 9 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.Options; 10 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.PositionalOptionDefinition; 11 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions.ConflictingOptionException; 12 | 13 | public class MigrateToOptions implements IOptionSource { 14 | public static final IOptionKey OPT_SRC_WS = new OptionKey("source-workspace-name"); //$NON-NLS-1$ 15 | public static final IOptionKey OPT_DEST_WS = new OptionKey("destination-workspace-name"); //$NON-NLS-1$ 16 | 17 | public static final IOptionKey OPT_RTC_CONNECTION_TIMEOUT = new OptionKey("timeout"); 18 | public static final IOptionKey OPT_RTC_LIST_TAGS_ONLY = new OptionKey("listTagsOnly"); 19 | public static final IOptionKey OPT_RTC_IS_UPDATE_MIGRATION = new OptionKey("updateMigration"); 20 | 21 | @Override 22 | public Options getOptions() throws ConflictingOptionException { 23 | Options options = new Options(false); 24 | 25 | SubcommandUtil.addRepoLocationToOptions(options); 26 | options.addOption(new PositionalOptionDefinition(OPT_SRC_WS, "source-workspace-name", 1, 1), //$NON-NLS-1$ 27 | "name of the pre configured source RTC workspace that could follow the stream to migrate."); 28 | options.addOption( 29 | new PositionalOptionDefinition(OPT_DEST_WS, "destination-workspace-name", 1, 1), //$NON-NLS-1$ 30 | "name of the pre configured RTC workspace that holds the current state of the migration and that follows the source-workspace-name."); 31 | 32 | options.addOption(CommonOptions.OPT_DIRECTORY, CommonOptions.OPT_DIRECTORY_HELP); 33 | options.addOption(new NamedOptionDefinition(OPT_RTC_CONNECTION_TIMEOUT, "t", "timeout", 1), 34 | "Timeout in seconds, default is 900"); 35 | options.addOption(new NamedOptionDefinition(OPT_RTC_LIST_TAGS_ONLY, "L", "list-tags-only", 0), 36 | "List only all tags that would be migrated but do not migrate them."); 37 | options.addOption(new NamedOptionDefinition(OPT_RTC_IS_UPDATE_MIGRATION, "U", "update", 0), 38 | "Update the content of an already migrated workspace."); 39 | return options; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/Migrator.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @author florian.buehlmann 7 | * @author patrick.reinhart 8 | */ 9 | public interface Migrator { 10 | 11 | /** 12 | * Initializes the migration implementation with the given sandboxRootDirectory. 13 | * 14 | * @param sandboxRootDirectory 15 | * the sand box root directory 16 | */ 17 | void init(File sandboxRootDirectory); 18 | 19 | /** 20 | * Releases all resources 21 | */ 22 | void close(); 23 | 24 | void createTag(Tag tag); 25 | 26 | void commitChanges(ChangeSet changeSet); 27 | 28 | void intermediateCleanup(); 29 | 30 | boolean needsIntermediateCleanup(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/RtcChangeSet.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author florian.buehlmann 8 | */ 9 | final class RtcChangeSet implements ChangeSet { 10 | private final String uuid; 11 | private final List workItems; 12 | 13 | private long creationDate; 14 | private String entryName; 15 | private String creatorName; 16 | private String emailAddress; 17 | private String component; 18 | 19 | RtcChangeSet(String changeSetUuid) { 20 | uuid = changeSetUuid; 21 | workItems = new ArrayList(); 22 | } 23 | 24 | RtcChangeSet addWorkItem(long workItem, String workItemText) { 25 | workItems.add(new RtcWorkItem(workItem, workItemText)); 26 | return this; 27 | } 28 | 29 | RtcChangeSet setText(String entryName) { 30 | this.entryName = entryName; 31 | return this; 32 | } 33 | 34 | RtcChangeSet setCreatorName(String creatorName) { 35 | this.creatorName = creatorName; 36 | return this; 37 | } 38 | 39 | RtcChangeSet setCreatorEMail(String emailAddress) { 40 | this.emailAddress = emailAddress; 41 | return this; 42 | } 43 | 44 | RtcChangeSet setCreationDate(long creationDate) { 45 | this.creationDate = creationDate; 46 | return this; 47 | } 48 | 49 | RtcChangeSet setComponent(String component) { 50 | this.component = component; 51 | return this; 52 | } 53 | 54 | String getUuid() { 55 | return uuid; 56 | } 57 | 58 | String getComponent() { 59 | return component; 60 | } 61 | 62 | @Override 63 | public String getComment() { 64 | return entryName; 65 | } 66 | 67 | @Override 68 | public String getCreatorName() { 69 | return creatorName; 70 | } 71 | 72 | @Override 73 | public String getEmailAddress() { 74 | return emailAddress; 75 | } 76 | 77 | @Override 78 | public long getCreationDate() { 79 | return creationDate; 80 | } 81 | 82 | @Override 83 | public List getWorkItems() { 84 | return workItems; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/RtcMigrator.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.io.File; 4 | import java.util.Collection; 5 | import java.util.Date; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | import to.rtc.cli.migrate.command.AcceptCommandDelegate; 12 | import to.rtc.cli.migrate.command.LoadCommandDelegate; 13 | import to.rtc.cli.migrate.util.Files; 14 | 15 | import com.ibm.team.filesystem.cli.core.Constants; 16 | import com.ibm.team.filesystem.cli.core.subcommands.IScmClientConfiguration; 17 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 18 | import com.ibm.team.rtc.cli.infrastructure.internal.core.CLIClientException; 19 | 20 | public class RtcMigrator { 21 | 22 | /** 23 | * 24 | */ 25 | private static final int ACCEPTS_BEFORE_LOCAL_HISTORY_CLEAN = 1000; 26 | protected final IChangeLogOutput output; 27 | private final IScmClientConfiguration config; 28 | private final String workspace; 29 | private final Migrator migrator; 30 | private final Set initiallyLoadedComponents; 31 | private File sandboxDirectory; 32 | 33 | public RtcMigrator(IChangeLogOutput output, IScmClientConfiguration config, String workspace, Migrator migrator, 34 | File sandboxDirectory, Collection initiallyLoadedComponents, boolean isUpdateMigration) { 35 | this.output = output; 36 | this.config = config; 37 | this.workspace = workspace; 38 | this.migrator = migrator; 39 | this.sandboxDirectory = sandboxDirectory; 40 | this.initiallyLoadedComponents = new HashSet(initiallyLoadedComponents); 41 | } 42 | 43 | public void migrateTag(RtcTag tag) throws CLIClientException { 44 | List changeSets = tag.getOrderedChangeSets(); 45 | int changeSetCounter = 0; 46 | int numberOfChangesets = changeSets.size(); 47 | String tagName = tag.getName(); 48 | for (RtcChangeSet changeSet : changeSets) { 49 | try { 50 | long acceptDuration = accept(changeSet); 51 | long commitDuration = commit(changeSet); 52 | changeSetCounter++; 53 | output.writeLine("Migrated [" + tagName + "] [" + changeSetCounter + "]/[" + numberOfChangesets 54 | + "] changesets. Accept took " + acceptDuration + "ms commit took " + commitDuration + "ms"); 55 | if (migrator.needsIntermediateCleanup()) { 56 | intermediateCleanup(); 57 | } 58 | if (changeSetCounter % ACCEPTS_BEFORE_LOCAL_HISTORY_CLEAN == 0) { 59 | cleanLocalHistory(); 60 | } 61 | } catch (CLIClientException clie) { 62 | output.writeLine("Changeset details:"); 63 | output.writeLine(" Tag original name : " + tag.getOriginalName()); 64 | output.writeLine(" Tag creation date : " + new Date(tag.getCreationDate())); 65 | output.writeLine(" Changeset comment : " + changeSet.getComment()); 66 | output.writeLine(" Changeset creator : " + changeSet.getCreatorName()); 67 | output.writeLine(" Changeset creation date : " + new Date(changeSet.getCreationDate())); 68 | output.writeLine(" Changeset component : " + changeSet.getComponent()); 69 | output.writeLine(" Changeset UUID : " + changeSet.getUuid()); 70 | throw clie; 71 | } 72 | } 73 | cleanLocalHistory(); 74 | if (tag.doCreateTag()) { 75 | migrator.createTag(tag); 76 | } 77 | } 78 | 79 | void intermediateCleanup() { 80 | long startCleanup = System.currentTimeMillis(); 81 | migrator.intermediateCleanup(); 82 | output.writeLine("Intermediate cleanup had [" 83 | + (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startCleanup)) + "]sec"); 84 | } 85 | 86 | long commit(RtcChangeSet changeSet) { 87 | long startCommit = System.currentTimeMillis(); 88 | migrator.commitChanges(changeSet); 89 | long commitDuration = System.currentTimeMillis() - startCommit; 90 | return commitDuration; 91 | } 92 | 93 | long accept(RtcChangeSet changeSet) throws CLIClientException { 94 | long startAccept = System.currentTimeMillis(); 95 | acceptAndLoadChangeSet(changeSet); 96 | handleInitialLoad(changeSet); 97 | long acceptDuration = System.currentTimeMillis() - startAccept; 98 | return acceptDuration; 99 | } 100 | 101 | private void cleanLocalHistory() { 102 | File localHistoryDirectory = new File(sandboxDirectory, 103 | ".metadata/.plugins/org.eclipse.core.resources/.history"); 104 | if (localHistoryDirectory.exists() && localHistoryDirectory.isDirectory()) { 105 | long start = System.currentTimeMillis(); 106 | Files.delete(localHistoryDirectory); 107 | output.writeLine("Cleanup of local history had [" 108 | + (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start)) + "]sec"); 109 | } 110 | } 111 | 112 | private void acceptAndLoadChangeSet(RtcChangeSet changeSet) throws CLIClientException { 113 | output.setIndent(2); 114 | int result = new AcceptCommandDelegate(config, output, workspace, changeSet.getUuid(), false, false).run(); 115 | switch (result) { 116 | case Constants.STATUS_OUT_OF_SYNC: 117 | output.writeLine("Try loading of workspace again with force option"); 118 | result = new LoadCommandDelegate(config, output, workspace, null, true).run(); 119 | break; 120 | case Constants.STATUS_GAP: 121 | output.writeLine("Retry accepting with --accept-missing-changesets"); 122 | result = new AcceptCommandDelegate(config, output, workspace, changeSet.getUuid(), false, true).run(); 123 | if (Constants.STATUS_GAP == result || Constants.STATUS_OUT_OF_SYNC == result) { 124 | throw new CLIClientException("There was a PROBLEM in accepting that we cannot solve."); 125 | } 126 | break; 127 | default: 128 | break; 129 | } 130 | } 131 | 132 | private void handleInitialLoad(RtcChangeSet changeSet) { 133 | if (!initiallyLoadedComponents.contains(changeSet.getComponent())) { 134 | try { 135 | new LoadCommandDelegate(config, output, workspace, changeSet.getComponent(), false).run(); 136 | initiallyLoadedComponents.add(changeSet.getComponent()); 137 | } catch (CLIClientException e) { 138 | throw new RuntimeException("Not a valid sandbox. Please run [scm load " + workspace 139 | + "] before [scm migrate-to-git] command"); 140 | } 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/RtcTag.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | final class RtcTag implements Tag { 14 | 15 | /** 16 | * 17 | */ 18 | private static final long TIME_DIFFERENCE_PLUS_MINUS_MILLISECONDS = TimeUnit.SECONDS.toMillis(90); 19 | private static final RtcChangeSet EARLYEST_CHANGESET = new RtcChangeSet("").setCreationDate(Long.MAX_VALUE); 20 | private String uuid; 21 | private String originalName; 22 | private boolean makeNameUnique; 23 | private long creationDate; 24 | private final Map> components; 25 | private long totalChangeSetCount; 26 | private boolean doCreateTag; 27 | private boolean containLastChangeset; 28 | 29 | RtcTag(String uuid) { 30 | this.uuid = uuid; 31 | components = new HashMap>(); 32 | totalChangeSetCount = 0; 33 | makeNameUnique = false; 34 | doCreateTag = true; 35 | containLastChangeset = false; 36 | } 37 | 38 | RtcTag setCreationDate(long creationDate) { 39 | this.creationDate = creationDate; 40 | return this; 41 | } 42 | 43 | RtcTag setOriginalName(String originalName) { 44 | this.originalName = originalName; 45 | return this; 46 | } 47 | 48 | String getUuid() { 49 | return uuid; 50 | } 51 | 52 | RtcTag setUuid(String uuid) { 53 | this.uuid = uuid; 54 | return this; 55 | } 56 | 57 | void add(RtcChangeSet changeSet) { 58 | List changesets = null; 59 | String component = changeSet.getComponent(); 60 | if (components.containsKey(component)) { 61 | changesets = components.get(component); 62 | } else { 63 | changesets = new ArrayList(); 64 | components.put(component, changesets); 65 | } 66 | changesets.add(changeSet); 67 | totalChangeSetCount++; 68 | } 69 | 70 | Map> getComponentsChangeSets() { 71 | return components; 72 | } 73 | 74 | List getOrderedChangeSets() { 75 | List changeSets = new ArrayList(); 76 | Map changeSetOrderIndex = new HashMap(); 77 | 78 | for (String component : components.keySet()) { 79 | changeSetOrderIndex.put(component, new AtomicInteger(0)); 80 | } 81 | 82 | while (changeSets.size() < totalChangeSetCount) { 83 | changeSets.add(getLatestChangeSet(changeSetOrderIndex)); 84 | } 85 | return changeSets; 86 | } 87 | 88 | private RtcChangeSet getLatestChangeSet(Map changeSetOrderIndex) { 89 | RtcChangeSet earlyestChangeSet = EARLYEST_CHANGESET; 90 | for (Entry> entry : components.entrySet()) { 91 | AtomicInteger index = changeSetOrderIndex.get(entry.getKey()); 92 | List changeSets = entry.getValue(); 93 | int changeSetIndex = index.get(); 94 | if (changeSetIndex < changeSets.size()) { 95 | RtcChangeSet changeSet = changeSets.get(changeSetIndex); 96 | if (earlyestChangeSet.getCreationDate() > changeSet.getCreationDate()) { 97 | earlyestChangeSet = changeSet; 98 | } 99 | } 100 | } 101 | changeSetOrderIndex.get(earlyestChangeSet.getComponent()).incrementAndGet(); 102 | return earlyestChangeSet; 103 | } 104 | 105 | @Override 106 | public String getName() { 107 | if (makeNameUnique) { 108 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss"); 109 | return originalName + "_" + dateFormat.format(new Date(creationDate)); 110 | } else { 111 | return originalName; 112 | } 113 | } 114 | 115 | @Override 116 | public long getCreationDate() { 117 | return creationDate; 118 | } 119 | 120 | public boolean isEmpty() { 121 | return totalChangeSetCount <= 0; 122 | } 123 | 124 | RtcTag setMakeNameUnique(boolean makeNameUnique) { 125 | this.makeNameUnique = makeNameUnique; 126 | return this; 127 | } 128 | 129 | boolean isMakeNameUnique() { 130 | return makeNameUnique; 131 | } 132 | 133 | boolean isContainingLastChangeset() { 134 | return containLastChangeset; 135 | } 136 | 137 | @Override 138 | public int hashCode() { 139 | final int prime = 31; 140 | int result = 1; 141 | result = prime * result + ((components == null) ? 0 : components.hashCode()); 142 | result = prime * result + (int) (creationDate ^ (creationDate >>> 32)); 143 | result = prime * result + (makeNameUnique ? 1231 : 1237); 144 | result = prime * result + ((originalName == null) ? 0 : originalName.hashCode()); 145 | result = prime * result + (int) (totalChangeSetCount ^ (totalChangeSetCount >>> 32)); 146 | result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); 147 | return result; 148 | } 149 | 150 | @Override 151 | public boolean equals(Object obj) { 152 | if (obj == this) { 153 | return true; 154 | } 155 | if (obj == null) { 156 | return false; 157 | } 158 | if (obj.getClass() == getClass()) { 159 | RtcTag tag = (RtcTag) obj; 160 | long objCreationDate = tag.getCreationDate(); 161 | if (getOriginalName().equals(tag.getOriginalName())) { 162 | if ((objCreationDate == this.creationDate) 163 | || ((objCreationDate <= this.creationDate + TIME_DIFFERENCE_PLUS_MINUS_MILLISECONDS) && (objCreationDate >= this.creationDate 164 | - TIME_DIFFERENCE_PLUS_MINUS_MILLISECONDS))) { 165 | return true; 166 | } 167 | } 168 | } 169 | return false; 170 | } 171 | 172 | @Override 173 | public String toString() { 174 | return (new StringBuilder(getName())).append('@').append(new Date(creationDate)).toString(); 175 | } 176 | 177 | String getOriginalName() { 178 | return originalName; 179 | } 180 | 181 | public void addAll(Map> componentsChangeSets) { 182 | for (Entry> changesetList : componentsChangeSets.entrySet()) { 183 | for (RtcChangeSet changeset : changesetList.getValue()) { 184 | add(changeset); 185 | } 186 | } 187 | } 188 | 189 | RtcTag setDoCreateTag(boolean doCreateTag) { 190 | this.doCreateTag = doCreateTag; 191 | return this; 192 | } 193 | 194 | boolean doCreateTag() { 195 | return doCreateTag; 196 | } 197 | 198 | RtcTag setContainLastChangeset(boolean containLastChangeset) { 199 | this.containLastChangeset = containLastChangeset; 200 | return this; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/RtcTagList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package to.rtc.cli.migrate; 5 | 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.Date; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | import java.util.Map.Entry; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | public class RtcTagList implements Iterable { 17 | 18 | private final StreamOutput output; 19 | private List rtcTags; 20 | 21 | public RtcTagList(StreamOutput output) { 22 | this.output = output; 23 | rtcTags = new ArrayList(); 24 | } 25 | 26 | public RtcTag add(RtcTag tag) { 27 | long creationDate = tag.getCreationDate(); 28 | int tagIndex = rtcTags.indexOf(tag); 29 | if (tagIndex < 0) { 30 | for (RtcTag tagToCheck : rtcTags) { 31 | if (tagToCheck.getOriginalName().equals(tag.getOriginalName())) { 32 | tag.setMakeNameUnique(true); 33 | break; 34 | } 35 | } 36 | rtcTags.add(tag); 37 | } else { 38 | tag = rtcTags.get(tagIndex); 39 | tag.setCreationDate(creationDate / 2 + tag.getCreationDate() / 2); 40 | } 41 | return tag; 42 | } 43 | 44 | public void printTagList(boolean printChangesetDetails) { 45 | output.writeLine("********** BASELINE INFOS **********"); 46 | int totalChangeSets = 0; 47 | for (RtcTag tag : rtcTags) { 48 | List orderedChangeSets = tag.getOrderedChangeSets(); 49 | int totalChangeSetsByBaseline = orderedChangeSets.size(); 50 | totalChangeSets += totalChangeSetsByBaseline; 51 | output.writeLine(" Baseline [" + tag.getName() + "] with original name [" + tag.getOriginalName() 52 | + "] created at [" + (new Date(tag.getCreationDate())) + "] total number of changesets [" 53 | + totalChangeSetsByBaseline + "] will be tagged [" + tag.doCreateTag() + "]"); 54 | for (Entry> entry : tag.getComponentsChangeSets().entrySet()) { 55 | output.writeLine(" number of changesets for component [" + entry.getKey() + "] is [" 56 | + entry.getValue().size() + "]"); 57 | } 58 | if (printChangesetDetails) { 59 | for (RtcChangeSet changeSet : orderedChangeSets) { 60 | output.writeLine(" -- " + new Date(changeSet.getCreationDate()) + " : [" 61 | + changeSet.getCreatorName() + "] " + changeSet.getComment()); 62 | } 63 | } 64 | } 65 | output.writeLine("TOTAL NUMBER OF CHANGESETS [" + totalChangeSets + "]"); 66 | output.writeLine("********** BASELINE INFOS **********"); 67 | } 68 | 69 | public void pruneInactiveTags() { 70 | RtcTag lastTagThatRequiresTagging = null; 71 | for (RtcTag tag : rtcTags) { 72 | if (tag.isContainingLastChangeset()) { 73 | lastTagThatRequiresTagging = tag; 74 | } 75 | 76 | } 77 | boolean lastTagReached = false; 78 | for (RtcTag tag : rtcTags) { 79 | tag.setDoCreateTag(!lastTagReached && tag.doCreateTag()); 80 | if (tag.equals(lastTagThatRequiresTagging)) { 81 | lastTagReached = true; 82 | } 83 | } 84 | } 85 | 86 | public void pruneExcludedTags(Pattern includePattern) { 87 | List prunedList = new ArrayList(); 88 | RtcTag tmpTag = null; 89 | 90 | for (RtcTag currentTag : rtcTags) { 91 | if (tmpTag == null) { 92 | tmpTag = currentTag; 93 | } else { 94 | tmpTag.setUuid(currentTag.getUuid()).setOriginalName(currentTag.getOriginalName()) 95 | .setCreationDate(currentTag.getCreationDate()).setMakeNameUnique(currentTag.isMakeNameUnique()) 96 | .setDoCreateTag(currentTag.doCreateTag()); 97 | tmpTag.addAll(currentTag.getComponentsChangeSets()); 98 | } 99 | 100 | Matcher matcher = includePattern.matcher(tmpTag.getOriginalName()); 101 | if (matcher.matches()) { 102 | prunedList.add(tmpTag); 103 | tmpTag = null; 104 | } 105 | } 106 | 107 | if (tmpTag != null) { 108 | prunedList.add(tmpTag); 109 | } 110 | rtcTags = prunedList; 111 | } 112 | 113 | public void sortByCreationDate() { 114 | Collections.sort(rtcTags, new TagCreationDateComparator()); 115 | } 116 | 117 | public int size() { 118 | return rtcTags.size(); 119 | } 120 | 121 | @Override 122 | public Iterator iterator() { 123 | return rtcTags.iterator(); 124 | } 125 | 126 | public RtcTag getTag(String itemId, String tagName, long creationDate) { 127 | RtcTag tag = new RtcTag(itemId).setOriginalName(tagName).setCreationDate(creationDate); 128 | int tagIndex = rtcTags.indexOf(tag); 129 | if (tagIndex < 0) { 130 | output.writeLine("Error: Tag could not be found in Stream"); 131 | output.writeLine("Searching for Tag: [" + tagName + "] [" 132 | + (new SimpleDateFormat("yyyyMMdd_HHmmss")).format(new Date(creationDate)) + "]"); 133 | sortByCreationDate(); 134 | printTagList(false); 135 | throw new RuntimeException("Tag not found"); 136 | } else { 137 | tag = rtcTags.get(tagIndex); 138 | } 139 | return tag; 140 | } 141 | 142 | public RtcTag getHeadTag() { 143 | RtcTag tag = new RtcTag(null).setDoCreateTag(false).setOriginalName("HEAD").setCreationDate(Long.MAX_VALUE); 144 | int tagIndex = rtcTags.indexOf(tag); 145 | if (tagIndex < 0) { 146 | add(tag); 147 | } else { 148 | tag = rtcTags.get(tagIndex); 149 | } 150 | return tag; 151 | } 152 | 153 | public Boolean contains(RtcTag tag) { 154 | return Boolean.valueOf(rtcTags.contains(tag)); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/RtcWorkItem.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import to.rtc.cli.migrate.ChangeSet.WorkItem; 4 | 5 | /** 6 | * @author patrick.reinhart 7 | */ 8 | final class RtcWorkItem implements WorkItem { 9 | private long number; 10 | private String text; 11 | 12 | RtcWorkItem(long number, String text) { 13 | this.number = number; 14 | this.text = text; 15 | } 16 | 17 | @Override 18 | public long getNumber() { 19 | return number; 20 | } 21 | 22 | @Override 23 | public String getText() { 24 | return text; 25 | } 26 | } -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/StreamOutput.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | import java.io.PrintStream; 4 | 5 | import com.ibm.team.filesystem.rcp.core.internal.changelog.ChangeLogStreamOutput; 6 | 7 | public class StreamOutput extends ChangeLogStreamOutput { 8 | 9 | private PrintStream stream; 10 | 11 | StreamOutput(PrintStream out) { 12 | super(out); 13 | stream = out; 14 | } 15 | 16 | PrintStream getOutputStream() { 17 | return stream; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/Tag.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate; 2 | 3 | /** 4 | * Represents a tag. 5 | * 6 | * @author florian.buehlmann 7 | * @author patrick.reinhart 8 | */ 9 | public interface Tag { 10 | /** 11 | * Returns the actual tag name. 12 | * 13 | * @return the name of the tag 14 | */ 15 | public String getName(); 16 | 17 | /** 18 | * Returns the tag set creation time stamp. 19 | * 20 | * @return the creation date time stamp 21 | */ 22 | public long getCreationDate(); 23 | } -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/TagCreationDateComparator.java: -------------------------------------------------------------------------------- 1 | 2 | package to.rtc.cli.migrate; 3 | 4 | import java.util.Comparator; 5 | 6 | public class TagCreationDateComparator implements Comparator { 7 | 8 | @Override 9 | public int compare(RtcTag o1, RtcTag o2) { 10 | if (o1.getCreationDate() > o2.getCreationDate()) { 11 | return 1; 12 | } 13 | if (o1.getCreationDate() < o2.getCreationDate()) { 14 | return -1; 15 | } 16 | return 0; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/command/AcceptCommandDelegate.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.command; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.core.runtime.IStatus; 7 | 8 | import com.ibm.team.filesystem.cli.client.internal.subcommands.AcceptCmd; 9 | import com.ibm.team.filesystem.cli.client.internal.subcommands.AcceptCmdOptions; 10 | import com.ibm.team.filesystem.cli.core.AbstractSubcommand; 11 | import com.ibm.team.filesystem.cli.core.Constants; 12 | import com.ibm.team.filesystem.cli.core.subcommands.CommonOptions; 13 | import com.ibm.team.filesystem.cli.core.subcommands.IScmClientConfiguration; 14 | import com.ibm.team.filesystem.client.FileSystemException; 15 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 16 | import com.ibm.team.rtc.cli.infrastructure.internal.core.CLIClientException; 17 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.ICommandLine; 18 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.Options; 19 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions.ConflictingOptionException; 20 | 21 | @SuppressWarnings("restriction") 22 | public class AcceptCommandDelegate extends RtcCommandDelegate { 23 | 24 | public AcceptCommandDelegate(IScmClientConfiguration config, IChangeLogOutput output, String targetWorkspace, 25 | String changeSetUuid, boolean baseline, boolean acceptMissingChangesets) { 26 | super(config, output, "accept " + targetWorkspace + " " + changeSetUuid + " baseline[" + baseline + "]"); 27 | setSubCommandLine(targetWorkspace, changeSetUuid, baseline, acceptMissingChangesets); 28 | } 29 | 30 | @Override 31 | public int run() throws CLIClientException { 32 | try { 33 | return super.run(); 34 | } catch (CLIClientException e) { 35 | IStatus status = e.getStatus(); 36 | if (status != null) { 37 | switch (status.getCode()) { 38 | case Constants.STATUS_FAILURE: 39 | printExceptionMessage("FAILURE", status); 40 | return Constants.STATUS_FAILURE; 41 | case Constants.STATUS_INTERNAL_ERROR: 42 | printExceptionMessage("INTERNAL_ERROR", status); 43 | return Constants.STATUS_INTERNAL_ERROR; 44 | case Constants.STATUS_GAP: 45 | printExceptionMessage("GAP", status); 46 | return Constants.STATUS_GAP; 47 | case Constants.STATUS_CONFLICT: 48 | printExceptionMessage("CONFLICT", status); 49 | return Constants.STATUS_CONFLICT; 50 | case Constants.STATUS_NWAY_CONFLICT: 51 | printExceptionMessage("NWAY_CONFLICT", status); 52 | return Constants.STATUS_NWAY_CONFLICT; 53 | case Constants.STATUS_WORKSPACE_UNCHANGED: 54 | printExceptionMessage("WORKSPACE_UNCHANGED", status); 55 | return Constants.STATUS_WORKSPACE_UNCHANGED; 56 | case Constants.STATUS_OUT_OF_SYNC: 57 | printExceptionMessage("WORKSPACE_OUT_OF_SYNC", status); 58 | return Constants.STATUS_OUT_OF_SYNC; 59 | default: 60 | output.writeLine("There was an unexpected exception with state [" + status.getCode() + "](" 61 | + status.getMessage() + ")"); 62 | break; 63 | } 64 | } 65 | throw e; 66 | } 67 | } 68 | 69 | void printExceptionMessage(String codeText, IStatus status) { 70 | output.writeLine("There was a [" + codeText + "](" + status.getMessage() 71 | + "). We ignore that, because the following accepts should fix that"); 72 | } 73 | 74 | @Override 75 | AbstractSubcommand getCommand() { 76 | return new AcceptCmd(); 77 | } 78 | 79 | @Override 80 | Options getOptions() throws ConflictingOptionException { 81 | return new AcceptCmdOptions().getOptions(); 82 | } 83 | 84 | void setSubCommandLine(String targetWorkspace, String changeSetUuid, boolean isBaseline, 85 | boolean acceptMissingChangesets) { 86 | String uri = getSubCommandOption(config, CommonOptions.OPT_URI); 87 | String username = getSubCommandOption(config, CommonOptions.OPT_USERNAME); 88 | String password; 89 | if (config.getSubcommandCommandLine().hasOption(CommonOptions.OPT_PASSWORD)) { 90 | password = getSubCommandOption(config, CommonOptions.OPT_PASSWORD); 91 | } else { 92 | try { 93 | password = config.getConnectionInfo().getPassword(); 94 | } catch (FileSystemException e) { 95 | throw new RuntimeException("Unable to get password", e); 96 | } 97 | } 98 | setSubCommandLine( 99 | config, 100 | generateCommandLine(uri, username, password, targetWorkspace, changeSetUuid, isBaseline, 101 | acceptMissingChangesets)); 102 | } 103 | 104 | private ICommandLine generateCommandLine(String uri, String username, String password, String rtcWorkspace, 105 | String changeSetUuid, boolean isBaseline, boolean acceptMissingChangesets) { 106 | List args = new ArrayList(); 107 | args.add("-o"); 108 | args.add("--no-merge"); 109 | if (acceptMissingChangesets) { 110 | args.add("--accept-missing-changesets"); 111 | } 112 | args.add("--no-local-refresh"); 113 | args.add("-r"); 114 | args.add(uri); 115 | args.add("-t"); 116 | args.add(rtcWorkspace); 117 | args.add("-u"); 118 | args.add(username); 119 | args.add("-P"); 120 | args.add(password); 121 | 122 | if (isBaseline) { 123 | args.add("--baseline"); 124 | } else { 125 | args.add("--changes"); 126 | } 127 | args.add(changeSetUuid); 128 | return generateCommandLine(args); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/command/LoadCommandDelegate.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.command; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.ibm.team.filesystem.cli.client.internal.subcommands.LoadCmdLauncher; 7 | import com.ibm.team.filesystem.cli.client.internal.subcommands.LoadCmdOptions; 8 | import com.ibm.team.filesystem.cli.core.AbstractSubcommand; 9 | import com.ibm.team.filesystem.cli.core.subcommands.CommonOptions; 10 | import com.ibm.team.filesystem.cli.core.subcommands.IScmClientConfiguration; 11 | import com.ibm.team.filesystem.client.FileSystemException; 12 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 13 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.ICommandLine; 14 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.Options; 15 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions.ConflictingOptionException; 16 | 17 | @SuppressWarnings("restriction") 18 | public class LoadCommandDelegate extends RtcCommandDelegate { 19 | 20 | public LoadCommandDelegate(IScmClientConfiguration config, IChangeLogOutput output, String workspace, 21 | String component, boolean force) { 22 | super(config, output, "load " + workspace + " force[" + force + "]"); 23 | setSubCommandLineByReflection(config, workspace, component, force); 24 | } 25 | 26 | @Override 27 | AbstractSubcommand getCommand() { 28 | return new LoadCmdLauncher(); 29 | } 30 | 31 | @Override 32 | Options getOptions() throws ConflictingOptionException { 33 | return new LoadCmdOptions().getOptions(); 34 | } 35 | 36 | private void setSubCommandLineByReflection(IScmClientConfiguration config, String workspace, String component, 37 | boolean force) { 38 | String uri = getSubCommandOption(config, CommonOptions.OPT_URI); 39 | String username = getSubCommandOption(config, CommonOptions.OPT_USERNAME); 40 | String password; 41 | if (config.getSubcommandCommandLine().hasOption(CommonOptions.OPT_PASSWORD)) { 42 | password = getSubCommandOption(config, CommonOptions.OPT_PASSWORD); 43 | } else { 44 | try { 45 | password = config.getConnectionInfo().getPassword(); 46 | } catch (FileSystemException e) { 47 | throw new RuntimeException("Unable to get password", e); 48 | } 49 | } 50 | setSubCommandLine(config, generateCommandLine(uri, username, password, workspace, component, force)); 51 | } 52 | 53 | private ICommandLine generateCommandLine(String uri, String username, String password, String workspace, 54 | String component, boolean force) { 55 | List args = new ArrayList(); 56 | args.add("-r"); 57 | args.add(uri); 58 | args.add("-u"); 59 | args.add(username); 60 | args.add("-P"); 61 | args.add(password); 62 | 63 | if (force) { 64 | args.add("--force"); 65 | } 66 | 67 | args.add(workspace); 68 | if (component != null) { 69 | args.add(component); 70 | } 71 | 72 | return generateCommandLine(args); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/command/RtcCommandDelegate.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.command; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.List; 5 | 6 | import com.ibm.team.filesystem.cli.core.AbstractSubcommand; 7 | import com.ibm.team.filesystem.cli.core.subcommands.IScmClientConfiguration; 8 | import com.ibm.team.filesystem.rcp.core.internal.changelog.IChangeLogOutput; 9 | import com.ibm.team.rtc.cli.infrastructure.internal.core.CLIClientException; 10 | import com.ibm.team.rtc.cli.infrastructure.internal.core.ClientConfiguration; 11 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.CLIParser; 12 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.ICommandLine; 13 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.IOptionKey; 14 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.Options; 15 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions.ConflictingOptionException; 16 | 17 | public abstract class RtcCommandDelegate { 18 | 19 | protected final IScmClientConfiguration config; 20 | 21 | private final String commandLine; 22 | 23 | protected final IChangeLogOutput output; 24 | 25 | protected RtcCommandDelegate(IScmClientConfiguration config, IChangeLogOutput output, String commandLine) { 26 | this.config = config; 27 | this.output = output; 28 | this.commandLine = commandLine; 29 | } 30 | 31 | public int run() throws CLIClientException { 32 | long start = System.currentTimeMillis(); 33 | AbstractSubcommand command = getCommand(); 34 | try { 35 | return command.run(config); 36 | } finally { 37 | output.writeLine( 38 | "DelegateCommand [" + this + "] finished in [" + (System.currentTimeMillis() - start) + "]ms"); 39 | } 40 | } 41 | 42 | abstract AbstractSubcommand getCommand(); 43 | 44 | abstract Options getOptions() throws ConflictingOptionException; 45 | 46 | protected ICommandLine generateCommandLine(List args) { 47 | try { 48 | CLIParser parser = new CLIParser(getOptions(), args); 49 | return parser.parse(); 50 | } catch (Exception e) { 51 | throw new RuntimeException(e); 52 | } 53 | } 54 | 55 | protected static String getSubCommandOption(IScmClientConfiguration config, IOptionKey key) { 56 | return config.getSubcommandCommandLine().getOption(key); 57 | } 58 | 59 | protected void setSubCommandLine(IScmClientConfiguration config, ICommandLine commandLine) { 60 | Class c = ClientConfiguration.class; 61 | Field subargs; 62 | try { 63 | subargs = c.getDeclaredField("subargs"); 64 | subargs.setAccessible(true); 65 | subargs.set(config, commandLine); 66 | } catch (Exception e) { 67 | throw new RuntimeException(e); 68 | } 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | if (commandLine == null) { 74 | return super.toString(); 75 | } 76 | return commandLine; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/git/GitMigrator.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.git; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.Formatter; 10 | import java.util.HashSet; 11 | import java.util.Iterator; 12 | import java.util.LinkedHashSet; 13 | import java.util.List; 14 | import java.util.Map.Entry; 15 | import java.util.Properties; 16 | import java.util.Set; 17 | import java.util.SortedSet; 18 | import java.util.TreeSet; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | import org.eclipse.jgit.api.AddCommand; 23 | import org.eclipse.jgit.api.CheckoutCommand; 24 | import org.eclipse.jgit.api.Git; 25 | import org.eclipse.jgit.api.RmCommand; 26 | import org.eclipse.jgit.api.Status; 27 | import org.eclipse.jgit.api.errors.GitAPIException; 28 | import org.eclipse.jgit.lib.Config; 29 | import org.eclipse.jgit.lib.PersonIdent; 30 | import org.eclipse.jgit.lib.StoredConfig; 31 | import org.eclipse.jgit.storage.file.WindowCacheConfig; 32 | 33 | import to.rtc.cli.migrate.ChangeSet; 34 | import to.rtc.cli.migrate.ChangeSet.WorkItem; 35 | import to.rtc.cli.migrate.Migrator; 36 | import to.rtc.cli.migrate.Tag; 37 | import to.rtc.cli.migrate.util.CommitCommentTranslator; 38 | import to.rtc.cli.migrate.util.Files; 39 | import to.rtc.cli.migrate.util.JazzignoreTranslator; 40 | 41 | /** 42 | * Git implementation of a {@link Migrator}. 43 | * 44 | * @author otmar.humbel 45 | * @author patrick.reinhart 46 | */ 47 | public final class GitMigrator implements Migrator { 48 | private static final String GIT_CONFIG_PREFIX = "git.config."; 49 | static final List ROOT_IGNORED_ENTRIES = Arrays.asList("/.jazz5", "/.jazzShed", "/.metadata"); 50 | static final Pattern GITIGNORE_PATTERN = Pattern.compile("(^.*(/|))\\.gitignore$"); 51 | static final Pattern JAZZIGNORE_PATTERN = Pattern.compile("(^.*(/|))\\.jazzignore$"); 52 | static final Pattern VALUE_PATTERN = Pattern.compile("^([0-9]+) *(m|mb|k|kb|)$", Pattern.CASE_INSENSITIVE); 53 | 54 | private final Charset defaultCharset; 55 | private final Set ignoredFileExtensions; 56 | private final WindowCacheConfig WindowCacheConfig; 57 | 58 | private int commitsAfterClean; 59 | private Git git; 60 | private Properties properties; 61 | private PersonIdent defaultIdent; 62 | private File rootDir; 63 | private CommitCommentTranslator commentTranslator; 64 | 65 | public GitMigrator(Properties properties) { 66 | defaultCharset = Charset.forName("UTF-8"); 67 | ignoredFileExtensions = new HashSet(); 68 | WindowCacheConfig = new WindowCacheConfig(); 69 | commitsAfterClean = 0; 70 | initialize(properties); 71 | } 72 | 73 | private Charset getCharset() { 74 | return defaultCharset; 75 | } 76 | 77 | private void initRootGitignore(File sandboxRootDirectory) throws IOException { 78 | Set ignoreEntries = new LinkedHashSet(ROOT_IGNORED_ENTRIES); 79 | parseElements(properties.getProperty("global.gitignore.entries", ""), ignoreEntries); 80 | initRootFile(new File(sandboxRootDirectory, ".gitignore"), ignoreEntries); 81 | } 82 | 83 | private void initRootGitattributes(File sandboxRootDirectory) throws IOException { 84 | initRootFile(new File(sandboxRootDirectory, ".gitattributes"), getGitattributeLines()); 85 | } 86 | 87 | private void initRootFile(File rootFile, Collection linesToAdd) throws IOException { 88 | Charset charset = getCharset(); 89 | List existingLines = Files.readLines(rootFile, charset); 90 | addMissing(existingLines, linesToAdd); 91 | if (!existingLines.isEmpty()) { 92 | Files.writeLines(rootFile, existingLines, charset, false); 93 | } 94 | } 95 | 96 | private void parseElements(String elementString, Collection consumer) { 97 | if (elementString == null || elementString.isEmpty()) { 98 | return; 99 | } 100 | String[] splitted = elementString.split(";"); 101 | int splittedLength = splitted.length; 102 | for (int i = 0; i < splittedLength; i++) { 103 | consumer.add(splitted[i].trim()); 104 | } 105 | } 106 | 107 | void addMissing(Collection existing, Collection adding) { 108 | for (String entry : adding) { 109 | if (!existing.contains(entry)) { 110 | existing.add(entry); 111 | } 112 | } 113 | } 114 | 115 | String getCommitMessage(String workItemNumbers, String comment, String workItemTexts) { 116 | return String.format(properties.getProperty("commit.message.format", "%1s %2s"), workItemNumbers, 117 | commentTranslator.translate(comment), workItemTexts).trim(); 118 | } 119 | 120 | List getGitattributeLines() { 121 | List lines = new ArrayList(); 122 | parseElements(properties.getProperty("gitattributes", ""), lines); 123 | return lines; 124 | } 125 | 126 | Set getIgnoredFileExtensions() { 127 | return ignoredFileExtensions; 128 | } 129 | 130 | WindowCacheConfig getWindowCacheConfig() { 131 | return WindowCacheConfig; 132 | } 133 | 134 | String getCommentText(ChangeSet changeSet) { 135 | String comment = changeSet.getComment(); 136 | String workItemText = changeSet.getWorkItems().isEmpty() ? "" : changeSet.getWorkItems().get(0).getText(); 137 | final boolean substituteWorkItemText = Boolean 138 | .valueOf(properties.getProperty("rtc.changeset.comment.substitute", Boolean.FALSE.toString())); 139 | if (comment.isEmpty() && substituteWorkItemText) 140 | return workItemText; 141 | final String format = properties.getProperty("rtc.changeset.comment.format", "%1s"); 142 | return String.format(format, comment, workItemText); 143 | } 144 | 145 | String getWorkItemNumbers(List workItems) { 146 | if (workItems.isEmpty()) { 147 | return ""; 148 | } 149 | final String format = properties.getProperty("rtc.workitem.number.format", "%1s"); 150 | final String delimiter = properties.getProperty("rtc.workitem.number.delimiter", " "); 151 | final StringBuilder sb = new StringBuilder(); 152 | boolean isFirst = true; 153 | Formatter formatter = new Formatter(sb); 154 | try { 155 | for (WorkItem workItem : workItems) { 156 | if (isFirst) { 157 | isFirst = false; 158 | } else { 159 | sb.append(delimiter); 160 | } 161 | formatter.format(format, String.valueOf(workItem.getNumber())); 162 | } 163 | 164 | } finally { 165 | formatter.close(); 166 | } 167 | return sb.toString(); 168 | } 169 | 170 | String getWorkItemTexts(List workItems) { 171 | if (workItems.isEmpty()) { 172 | return ""; 173 | } 174 | final String format = properties.getProperty("rtc.workitem.text.format", "%1s %2s"); 175 | final String delimiter = properties.getProperty("rtc.workitem.text.delimiter", 176 | System.getProperty("line.separator")); 177 | final StringBuilder sb = new StringBuilder(); 178 | boolean isFirst = true; 179 | Formatter formatter = new Formatter(sb); 180 | try { 181 | for (WorkItem workItem : workItems) { 182 | if (isFirst) { 183 | isFirst = false; 184 | } else { 185 | sb.append(delimiter); 186 | } 187 | formatter.format(format, String.valueOf(workItem.getNumber()), workItem.getText()); 188 | } 189 | 190 | } finally { 191 | formatter.close(); 192 | } 193 | return sb.toString(); 194 | } 195 | 196 | SortedSet getExistingIgnoredFiles() { 197 | try { 198 | TreeSet exstingIgnoredFiles = new TreeSet(); 199 | for (String ignoredFile : Files.readLines(new File(rootDir, ".gitignore"), getCharset())) { 200 | if (ignoredFile.startsWith("/")) { 201 | File ignored = new File(rootDir, ignoredFile.substring(1)); 202 | if (ignored.exists() && ignored.isFile()) { 203 | exstingIgnoredFiles.add(ignoredFile); 204 | } 205 | } 206 | } 207 | return exstingIgnoredFiles; 208 | } catch (IOException e) { 209 | throw new RuntimeException("To process .gitignore", e); 210 | } 211 | } 212 | 213 | private void gitCommit(PersonIdent ident, String comment) { 214 | try { 215 | // add all untracked files 216 | Status status = git.status().call(); 217 | 218 | Set toAdd = handleAdded(status); 219 | Set toRestore = new HashSet(); 220 | Set toRemove = handleRemoved(status, toRestore); 221 | 222 | // execute the git index commands if needed 223 | if (!toAdd.isEmpty()) { 224 | AddCommand add = git.add(); 225 | for (String filepattern : toAdd) { 226 | add.addFilepattern(filepattern); 227 | } 228 | add.call(); 229 | } 230 | if (!toRemove.isEmpty()) { 231 | RmCommand rm = git.rm(); 232 | for (String filepattern : toRemove) { 233 | rm.addFilepattern(filepattern); 234 | } 235 | rm.call(); 236 | } 237 | if (!toRestore.isEmpty()) { 238 | CheckoutCommand checkout = git.checkout(); 239 | for (String filepattern : toRestore) { 240 | checkout.addPath(filepattern); 241 | } 242 | checkout.call(); 243 | } 244 | 245 | // execute commit if something has changed 246 | if (!toAdd.isEmpty() || !toRemove.isEmpty()) { 247 | git.commit().setMessage(comment).setAuthor(ident).setCommitter(ident).call(); 248 | } 249 | 250 | ++commitsAfterClean; 251 | } catch (RuntimeException e) { 252 | throw e; 253 | } catch (Exception e) { 254 | throw new RuntimeException("Unable to commit changes", e); 255 | } 256 | } 257 | 258 | @Override 259 | public boolean needsIntermediateCleanup() { 260 | return commitsAfterClean >= 1000; 261 | } 262 | 263 | @Override 264 | public void intermediateCleanup() { 265 | runGitGc(); 266 | commitsAfterClean = 0; 267 | } 268 | 269 | private Set handleRemoved(Status status, Set toRestore) { 270 | Set toRemove = new HashSet(); 271 | // go over all deleted files 272 | for (String removed : status.getMissing()) { 273 | Matcher matcher = GITIGNORE_PATTERN.matcher(removed); 274 | if (matcher.matches()) { 275 | File jazzignore = new File(rootDir, matcher.group(1).concat(".jazzignore")); 276 | if (jazzignore.exists()) { 277 | // restore .gitignore files that where deleted if corresponding .jazzignore exists 278 | toRestore.add(removed); 279 | continue; 280 | } 281 | } 282 | // adds removed entry to the index 283 | toRemove.add(removed); 284 | } 285 | handleJazzignores(toRemove); 286 | return toRemove; 287 | } 288 | 289 | private Set handleAdded(Status status) { 290 | Set toAdd = new HashSet(); 291 | // go over untracked files 292 | for (String untracked : status.getUntracked()) { 293 | // add it to the index 294 | toAdd.add(untracked); 295 | } 296 | // go over modified files 297 | for (String modified : status.getModified()) { 298 | // adds a modified entry to the index 299 | toAdd.add(modified); 300 | } 301 | handleGlobalFileExtensions(toAdd); 302 | handleJazzignores(toAdd); 303 | return toAdd; 304 | } 305 | 306 | private void handleJazzignores(Set relativeFileNames) { 307 | try { 308 | Set additionalNames = new HashSet(); 309 | for (String relativeFileName : relativeFileNames) { 310 | Matcher matcher = JAZZIGNORE_PATTERN.matcher(relativeFileName); 311 | if (matcher.matches()) { 312 | File jazzIgnore = new File(rootDir, relativeFileName); 313 | String gitignoreFile = matcher.group(1).concat(".gitignore"); 314 | if (jazzIgnore.exists()) { 315 | // change/add case 316 | List ignoreContent = JazzignoreTranslator.toGitignore(jazzIgnore); 317 | Files.writeLines(new File(rootDir, gitignoreFile), ignoreContent, getCharset(), false); 318 | } else { 319 | // delete case 320 | new File(rootDir, gitignoreFile).delete(); 321 | } 322 | additionalNames.add(gitignoreFile); 323 | } 324 | } 325 | // add additional modified name 326 | relativeFileNames.addAll(additionalNames); 327 | } catch (IOException e) { 328 | throw new RuntimeException("Unable to handle .jazzignore", e); 329 | } 330 | } 331 | 332 | private void handleGlobalFileExtensions(Set addToGitIndex) { 333 | Set gitignoreEntries = new LinkedHashSet(); 334 | for (String extension : getIgnoredFileExtensions()) { 335 | for (Iterator candidateIt = addToGitIndex.iterator(); candidateIt.hasNext();) { 336 | String addCandidate = candidateIt.next(); 337 | if (addCandidate.endsWith(extension)) { 338 | gitignoreEntries.add("/".concat(addCandidate)); 339 | candidateIt.remove(); 340 | } 341 | } 342 | } 343 | if (!gitignoreEntries.isEmpty()) { 344 | try { 345 | Files.writeLines(new File(rootDir, ".gitignore"), gitignoreEntries, getCharset(), true); 346 | addToGitIndex.add(".gitignore"); 347 | } catch (IOException e) { 348 | throw new RuntimeException("Unable to handle .gitignore", e); 349 | } 350 | } 351 | } 352 | 353 | private void initConfig() throws IOException { 354 | StoredConfig config = git.getRepository().getConfig(); 355 | config.setBoolean("core", null, "ignoreCase", false); 356 | config.setString("core", null, "autocrlf", File.separatorChar == '/' ? "input" : "true"); 357 | config.setBoolean("http", null, "sslverify", false); 358 | config.setString("push", null, "default", "simple"); 359 | fillConfigFromProperties(config); 360 | config.save(); 361 | } 362 | 363 | private int getFactor(String sign) { 364 | if (!sign.isEmpty()) { 365 | switch (sign.charAt(0)) { 366 | case 'k': 367 | case 'K': 368 | return org.eclipse.jgit.storage.file.WindowCacheConfig.KB; 369 | case 'm': 370 | case 'M': 371 | return org.eclipse.jgit.storage.file.WindowCacheConfig.MB; 372 | } 373 | } 374 | return 1; 375 | } 376 | 377 | long parseConfigValue(String value, long defaultValue) { 378 | if (value != null) { 379 | Matcher matcher = VALUE_PATTERN.matcher(value.trim()); 380 | if (matcher.matches()) { 381 | return getFactor(matcher.group(2)) * Long.parseLong(matcher.group(1)); 382 | } 383 | } 384 | return defaultValue; 385 | } 386 | 387 | void initialize(Properties props) { 388 | properties = props; 389 | commentTranslator = new CommitCommentTranslator(props); 390 | defaultIdent = new PersonIdent(props.getProperty("user.name", "RTC 2 git"), 391 | props.getProperty("user.email", "rtc2git@rtc.to")); 392 | parseElements(props.getProperty("ignore.file.extensions", ""), ignoredFileExtensions); 393 | // update window cache config 394 | WindowCacheConfig cfg = getWindowCacheConfig(); 395 | cfg.setPackedGitOpenFiles( 396 | (int) parseConfigValue(props.getProperty("packedgitopenfiles"), cfg.getPackedGitOpenFiles())); 397 | cfg.setPackedGitLimit(parseConfigValue(props.getProperty("packedgitlimit"), cfg.getPackedGitLimit())); 398 | cfg.setPackedGitWindowSize( 399 | (int) parseConfigValue(props.getProperty("packedgitwindowsize"), cfg.getPackedGitWindowSize())); 400 | cfg.setPackedGitMMAP(Boolean.parseBoolean(props.getProperty("packedgitmmap"))); 401 | cfg.setDeltaBaseCacheLimit( 402 | (int) parseConfigValue(props.getProperty("deltabasecachelimit"), cfg.getDeltaBaseCacheLimit())); 403 | long sft = parseConfigValue(props.getProperty("streamfilethreshold"), cfg.getStreamFileThreshold()); 404 | cfg.setStreamFileThreshold(getMaxFileThresholdValue(sft, Runtime.getRuntime().maxMemory())); 405 | } 406 | 407 | int getMaxFileThresholdValue(long configThreshold, final long maxMem) { 408 | // don't use more than 1/4 of the heap 409 | configThreshold = Math.min(configThreshold, maxMem / 4); 410 | // cannot exceed array length 411 | configThreshold = Math.min(configThreshold, Integer.MAX_VALUE); 412 | return (int) configThreshold; 413 | } 414 | 415 | String createTagName(String tagName) { 416 | return tagName.replace(' ', '_').replace('[', '_').replace(']', '_'); 417 | } 418 | 419 | @Override 420 | public void init(File sandboxRootDirectory) { 421 | rootDir = sandboxRootDirectory; 422 | try { 423 | File bareGitDirectory = new File(sandboxRootDirectory, ".git"); 424 | if (bareGitDirectory.exists()) { 425 | git = Git.open(sandboxRootDirectory); 426 | } else if (sandboxRootDirectory.exists()) { 427 | git = Git.init().setDirectory(sandboxRootDirectory).call(); 428 | } else { 429 | throw new RuntimeException(bareGitDirectory + " does not exist"); 430 | } 431 | getWindowCacheConfig().install(); 432 | initRootGitignore(sandboxRootDirectory); 433 | initRootGitattributes(sandboxRootDirectory); 434 | initConfig(); 435 | gitCommit(new PersonIdent(defaultIdent, System.currentTimeMillis(), 0), "Initial commit"); 436 | } catch (IOException e) { 437 | throw new RuntimeException("Unable to initialize GIT repository", e); 438 | } catch (GitAPIException e) { 439 | throw new RuntimeException("Unable to initialize GIT repository", e); 440 | } 441 | } 442 | 443 | @Override 444 | public void close() { 445 | if (git != null) { 446 | runGitGc(); 447 | } 448 | SortedSet existingIgnoredFiles = getExistingIgnoredFiles(); 449 | if (!existingIgnoredFiles.isEmpty()) { 450 | System.err.println("Some ignored files still exist in the sandbox:"); 451 | for (String existingIgnoredEntry : existingIgnoredFiles) { 452 | System.err.println(existingIgnoredEntry); 453 | } 454 | } 455 | } 456 | 457 | private void runGitGc() { 458 | try { 459 | git.gc().call(); 460 | } catch (GitAPIException e) { 461 | e.printStackTrace(); 462 | } finally { 463 | git.close(); 464 | } 465 | } 466 | 467 | @Override 468 | public void commitChanges(ChangeSet changeset) { 469 | gitCommit( 470 | new PersonIdent(changeset.getCreatorName(), changeset.getEmailAddress(), changeset.getCreationDate(), 471 | 0), 472 | getCommitMessage(getWorkItemNumbers(changeset.getWorkItems()), getCommentText(changeset), 473 | getWorkItemTexts(changeset.getWorkItems()))); 474 | } 475 | 476 | @Override 477 | public void createTag(Tag tag) { 478 | String tagName = tag.getName(); 479 | if (tagName != null && !tagName.isEmpty()) { 480 | try { 481 | git.tag().setTagger(defaultIdent).setName(createTagName(tagName)).call(); 482 | } catch (RuntimeException e) { 483 | throw e; 484 | } catch (Exception e) { 485 | throw new RuntimeException("Unable to tag", e); 486 | } 487 | } 488 | } 489 | 490 | private void fillConfigFromProperties(Config config) { 491 | for (Entry entry : properties.entrySet()) { 492 | if (entry.getKey() instanceof String && (((String) entry.getKey()).startsWith(GIT_CONFIG_PREFIX))) { 493 | 494 | String key = ((String) entry.getKey()).substring(GIT_CONFIG_PREFIX.length()); 495 | int dot = key.indexOf('.'); 496 | int dot1 = key.lastIndexOf('.'); 497 | // so far supporting section/key entries, no subsections 498 | if (dot < 1 || dot == key.length() - 1 || dot1 != dot) { 499 | // invalid config key entry 500 | continue; 501 | } 502 | String section = key.substring(0, dot); 503 | String name = key.substring(dot + 1); 504 | config.setString(section, null, name, entry.getValue().toString()); 505 | } 506 | 507 | } 508 | } 509 | } 510 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/git/MigrateToGit.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.git; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.util.Properties; 6 | import java.util.Set; 7 | import java.util.regex.Pattern; 8 | 9 | import to.rtc.cli.migrate.MigrateTo; 10 | import to.rtc.cli.migrate.Migrator; 11 | 12 | import com.ibm.team.filesystem.client.FileSystemException; 13 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.ICommandLine; 14 | 15 | public class MigrateToGit extends MigrateTo { 16 | private Migrator migratorImplementation; 17 | private Pattern baselineIncludeRegexPattern; 18 | 19 | @Override 20 | public void run() throws FileSystemException { 21 | Properties migrationProperties = readProperties(config.getSubcommandCommandLine()); 22 | baselineIncludeRegexPattern = Pattern.compile(migrationProperties.getProperty("rtc.baseline.include", "")); 23 | migratorImplementation = new GitMigrator(migrationProperties); 24 | try { 25 | super.run(); 26 | } finally { 27 | migratorImplementation.close(); 28 | } 29 | } 30 | 31 | @Override 32 | public Migrator getMigrator() { 33 | return migratorImplementation; 34 | } 35 | 36 | @Override 37 | public Pattern getBaselineIncludePattern() { 38 | return baselineIncludeRegexPattern; 39 | } 40 | 41 | private Properties readProperties(ICommandLine subargs) { 42 | final Properties props = new Properties(); 43 | if (subargs.hasOption(MigrateToGitOptions.OPT_MIGRATION_PROPERTIES)) { 44 | try { 45 | FileInputStream in = new FileInputStream( 46 | subargs.getOption(MigrateToGitOptions.OPT_MIGRATION_PROPERTIES)); 47 | try { 48 | props.load(in); 49 | } finally { 50 | in.close(); 51 | } 52 | } catch (IOException e) { 53 | throw new RuntimeException("Unable to read migration properties", e); 54 | } 55 | } 56 | return trimProperties(props); 57 | } 58 | 59 | protected static Properties trimProperties(Properties props) { 60 | Set keyset = props.keySet(); 61 | for (Object keyObject : keyset) { 62 | String key = (String) keyObject; 63 | props.setProperty(key, props.getProperty(key).trim()); 64 | } 65 | return props; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/git/MigrateToGitOptions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package to.rtc.cli.migrate.git; 5 | 6 | import to.rtc.cli.migrate.MigrateToOptions; 7 | 8 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.IOptionKey; 9 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.NamedOptionDefinition; 10 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.OptionKey; 11 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.Options; 12 | import com.ibm.team.rtc.cli.infrastructure.internal.parser.exceptions.ConflictingOptionException; 13 | 14 | /** 15 | * @author florian.buehlmann 16 | * 17 | */ 18 | public class MigrateToGitOptions extends MigrateToOptions { 19 | 20 | public static final IOptionKey OPT_MIGRATION_PROPERTIES = new OptionKey("migrationProperties"); //$NON-NLS-1$ 21 | 22 | @Override 23 | public Options getOptions() throws ConflictingOptionException { 24 | Options options = super.getOptions(); 25 | 26 | // rtc2git migration properties 27 | options.addOption(new NamedOptionDefinition(OPT_MIGRATION_PROPERTIES, "m", "migrationProperties", 1), 28 | "File with migration properties."); 29 | return options; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/util/CommitCommentTranslator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * File Name: CommitCommentTranslator.java 3 | * 4 | * Copyright (c) 2016 BISON Schweiz AG, All Rights Reserved. 5 | */ 6 | 7 | package to.rtc.cli.migrate.util; 8 | 9 | import java.util.Map.Entry; 10 | import java.util.Properties; 11 | import java.util.SortedMap; 12 | import java.util.TreeMap; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | /** 20 | * Translates a commit comment based on a optional set of commit.message.regex.x/ 21 | * commit.message.replacement.x definition applied in their x numerical order. 22 | * 23 | * @author Patrick Reinhart 24 | */ 25 | public class CommitCommentTranslator { 26 | private static final Logger LOGGER = LoggerFactory.getLogger(CommitCommentTranslator.class); 27 | private static final String REPLACEMENT_FORMAT = "commit.message.replacement.%s"; 28 | private static final Pattern SEARCH_PATTERN = Pattern.compile("^commit\\.message\\.regex\\.([0-9]+)$"); 29 | 30 | private final SortedMap searches = new TreeMap(); 31 | 32 | /** 33 | * @param props 34 | */ 35 | public CommitCommentTranslator(Properties props) { 36 | for (Entry entry : props.entrySet()) { 37 | String key = entry.getKey().toString(); 38 | Matcher matcher = SEARCH_PATTERN.matcher(key); 39 | if (matcher.matches()) { 40 | String order = matcher.group(1); 41 | String replacement = props.getProperty(String.format(REPLACEMENT_FORMAT, order)); 42 | if (replacement == null) { 43 | LOGGER.warn("Search definition {} without any replacement definition.", key); 44 | } else { 45 | String pattern = entry.getValue().toString(); 46 | try { 47 | Pattern searchPattern = Pattern.compile(pattern); 48 | if (searches.put(Integer.valueOf(order), new SearchEntry(searchPattern, replacement)) != null) { 49 | LOGGER.warn("Search definition {} already processed.", key); 50 | } 51 | } catch (NumberFormatException e) { 52 | LOGGER.error("Unable to parse order '{}' pattern '{}'", order, pattern); 53 | } catch (Exception e) { 54 | LOGGER.error("Unable to compile '{}' pattern '{}'", key, pattern); 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * Translates the given input and returns the resulting string. 63 | * 64 | * @param input 65 | * the comment to be translated based on the defined Regex/replacement pairs 66 | * @return the resulting string with all replacements applied. 67 | */ 68 | public String translate(String input) { 69 | String result = input; 70 | for (SearchEntry entry : searches.values()) { 71 | result = entry.apply(result); 72 | } 73 | return result; 74 | } 75 | 76 | static final class SearchEntry { 77 | private Pattern pattern; 78 | private String replacement; 79 | 80 | SearchEntry(Pattern pattern, String replacement) { 81 | this.pattern = pattern; 82 | this.replacement = replacement; 83 | } 84 | 85 | String apply(String input) { 86 | return pattern.matcher(input).replaceAll(replacement); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/util/Files.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.io.OutputStreamWriter; 10 | import java.io.PrintWriter; 11 | import java.nio.charset.Charset; 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.List; 15 | 16 | /** 17 | * Reads/writes all lines of a file using the default platform line separator. 18 | * 19 | * @author patrick.reinhart 20 | */ 21 | public class Files { 22 | 23 | /** 24 | * Reads all lines of the given file using the given character set cs and returns them as 25 | * a list without any of the line separators. 26 | * 27 | * @param file 28 | * the file being read 29 | * @param cs 30 | * the character used for reading 31 | * @return a list of all read lines (empty lines as empty string) 32 | * @throws IOException 33 | * if the read operation fails 34 | */ 35 | public static List readLines(File file, Charset cs) throws IOException { 36 | if (file.exists()) { 37 | FileInputStream in = new FileInputStream(file); 38 | try { 39 | BufferedReader br = new BufferedReader(new InputStreamReader(in, cs)); 40 | List lines = new ArrayList(); 41 | String line = null; 42 | while ((line = br.readLine()) != null) { 43 | lines.add(line); 44 | } 45 | return lines; 46 | } finally { 47 | in.close(); 48 | } 49 | } else { 50 | return new ArrayList(); 51 | } 52 | } 53 | 54 | /** 55 | * Writes all lines given to the file using the given character set cs and 56 | * optionally appends them to an existing file, if append is set to true. The default 57 | * platform line separator will be used. 58 | * 59 | * @param file 60 | * the file being written/appended 61 | * @param toGlobalIgnore 62 | * the lines to be written without any line separators 63 | * @param cs 64 | * the character set used for writing 65 | * @param append 66 | * true if a existing file should be appended, false otherwise 67 | * @throws IOException 68 | * if the write operation fails 69 | */ 70 | public static void writeLines(File file, Collection toGlobalIgnore, Charset cs, boolean append) 71 | throws IOException { 72 | FileOutputStream out = new FileOutputStream(file, append); 73 | try { 74 | PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, cs)); 75 | try { 76 | for (String line : toGlobalIgnore) { 77 | pw.append(line).println(); 78 | } 79 | } finally { 80 | pw.close(); 81 | } 82 | } finally { 83 | out.close(); 84 | } 85 | } 86 | 87 | /** 88 | * @param file 89 | */ 90 | public static void delete(File file) { 91 | if (file.isDirectory()) { 92 | if (file.list().length == 0) { 93 | file.delete(); 94 | } else { 95 | String files[] = file.list(); 96 | for (String temp : files) { 97 | File fileDelete = new File(file, temp); 98 | delete(fileDelete); 99 | } 100 | if (file.list().length == 0) { 101 | file.delete(); 102 | } 103 | } 104 | } else { 105 | file.delete(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src/to/rtc/cli/migrate/util/JazzignoreTranslator.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.lang.reflect.Method; 6 | import java.nio.charset.Charset; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | import org.eclipse.jgit.ignore.internal.Strings; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | /** 17 | * @author christoph.erni 18 | */ 19 | public class JazzignoreTranslator { 20 | private static final Logger LOGGER = LoggerFactory.getLogger(JazzignoreTranslator.class); 21 | private static final Pattern EXCLUSION = Pattern.compile("\\{(.*?)\\}"); 22 | private static final Method CONVERT_GLOB_METHOD = initConvertGlobMethod(); 23 | 24 | /** 25 | * Translates a .jazzignore file to .gitignore 26 | * 27 | * @param jazzignore 28 | * the input .jazzignore file 29 | * 30 | * @return the translation, as a list of lines 31 | */ 32 | public static List toGitignore(File jazzignore) { 33 | List gitignoreLines = new ArrayList(); 34 | try { 35 | // default charset should be ok here 36 | List jazzignoreLines = Files.readLines(jazzignore, Charset.defaultCharset()); 37 | String lineForRegex = ""; 38 | boolean needToTransform = false; 39 | for (String line : jazzignoreLines) { 40 | line = line.trim(); 41 | if (!line.startsWith("#")) { 42 | needToTransform = true; 43 | lineForRegex += line; 44 | if (!line.endsWith("\\")) { 45 | addGroupsToList(lineForRegex, gitignoreLines); 46 | lineForRegex = ""; 47 | needToTransform = false; 48 | } 49 | } 50 | } 51 | if (needToTransform) { 52 | gitignoreLines = addGroupsToList(lineForRegex, gitignoreLines); 53 | } 54 | } catch (IOException ioe) { 55 | throw new RuntimeException("unable to read .jazzignore file " + jazzignore.getAbsolutePath(), ioe); 56 | } 57 | return gitignoreLines; 58 | } 59 | 60 | private static Method initConvertGlobMethod() { 61 | try { 62 | Method method = Strings.class.getDeclaredMethod("convertGlob", String.class); 63 | method.setAccessible(true); 64 | return method; 65 | } catch (Exception e) { 66 | LOGGER.error("Unable to access needed method", e); 67 | return null; 68 | } 69 | } 70 | 71 | private static List addGroupsToList(String lineToMatch, List ignoreLines) { 72 | boolean recursive = lineToMatch.startsWith("core.ignore.recursive"); 73 | Matcher matcher = EXCLUSION.matcher(lineToMatch); 74 | while (matcher.find()) { 75 | String pattern = (!recursive ? "/" : "").concat(matcher.group(1)); 76 | if (checkPattern(pattern)) { 77 | ignoreLines.add(pattern); 78 | } 79 | } 80 | return ignoreLines; 81 | } 82 | 83 | private static boolean checkPattern(String pattern) { 84 | if (CONVERT_GLOB_METHOD != null) { 85 | try { 86 | CONVERT_GLOB_METHOD.invoke(null, pattern); 87 | } catch (Exception e) { 88 | LOGGER.warn("Ignoring uncompilable pattern: {}", pattern); 89 | return false; 90 | } 91 | } 92 | return true; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/RtcTagListTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * File Name: CommitCommentTranslatorTest.java 3 | * 4 | * Copyright (c) 2016 BISON Schweiz AG, All Rights Reserved. 5 | */ 6 | 7 | package to.rtc.cli.migrate; 8 | 9 | import static org.hamcrest.CoreMatchers.equalTo; 10 | import static org.hamcrest.CoreMatchers.is; 11 | import static org.hamcrest.CoreMatchers.not; 12 | import static org.hamcrest.CoreMatchers.startsWith; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | 15 | import java.util.Date; 16 | import java.util.Iterator; 17 | import java.util.regex.Pattern; 18 | 19 | import org.junit.Before; 20 | import org.junit.Rule; 21 | import org.junit.Test; 22 | import org.junit.rules.ExpectedException; 23 | 24 | /** 25 | * Tests the {@link RtcTagList} implementation. 26 | * 27 | * @author Florian Bühlmann 28 | */ 29 | public class RtcTagListTest { 30 | 31 | private RtcTagList tagList; 32 | 33 | @Rule 34 | public ExpectedException thrown = ExpectedException.none(); 35 | 36 | @Before 37 | public void setup() { 38 | tagList = new RtcTagList(new StreamOutput(System.out)); 39 | } 40 | 41 | private long TODAY = (new Date()).getTime(); 42 | private long YESTERDAY = TODAY - 86400000; 43 | private long TOMORROW = TODAY + 86400000; 44 | 45 | @Test 46 | public void testAddAndGetUniqueTag() { 47 | RtcTag rtcTag = new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(Long.MAX_VALUE); 48 | tagList.add(rtcTag); 49 | 50 | assertThat("get returns the added tag", tagList.getTag("uuit", "TagNameUnique", Long.MAX_VALUE), 51 | equalTo(rtcTag)); 52 | } 53 | 54 | @Test 55 | public void testAddMakeTagsUniqueIfCreatedateDifferToMuch() { 56 | tagList.add(new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(YESTERDAY)); 57 | tagList.add(new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(TODAY)); 58 | 59 | assertThat("We have two tags in the list", tagList.size(), equalTo(2)); 60 | 61 | Iterator tagListIterator = tagList.iterator(); 62 | RtcTag tag1 = tagListIterator.next(); 63 | RtcTag tag2 = tagListIterator.next(); 64 | 65 | assertThat("We have two tags with unique name", tag1.getName(), not(equalTo(tag2.getName()))); 66 | assertThat("We have two tags with the same original name", tag1.getOriginalName(), 67 | equalTo(tag2.getOriginalName())); 68 | assertThat("The secondly added tag has a unique name", tag2.getName(), startsWith("TagNameUnique_20")); 69 | } 70 | 71 | @Test 72 | public void testTagsKeepUniqueAfterPrune() { 73 | tagList.add(new RtcTag("uuid").setOriginalName("v20110202").setCreationDate(YESTERDAY)); 74 | tagList.add(new RtcTag("uuid").setOriginalName("rc11-01").setCreationDate(TODAY)); 75 | tagList.add(new RtcTag("uuid").setOriginalName("v20100202").setCreationDate(TOMORROW)); 76 | tagList.add(new RtcTag("uuid").setOriginalName("rc11-01").setCreationDate(TOMORROW)); 77 | assertThat("We have two tags in the list", tagList.size(), equalTo(4)); 78 | 79 | tagList.pruneExcludedTags(Pattern.compile("^rc.*$")); 80 | 81 | Iterator tagListIterator = tagList.iterator(); 82 | RtcTag tag1 = tagListIterator.next(); 83 | RtcTag tag2 = tagListIterator.next(); 84 | 85 | assertThat("We have two tags with unique name", tag1.getName(), not(equalTo(tag2.getName()))); 86 | assertThat("We have two tags with the same original name", tag1.getOriginalName(), 87 | equalTo(tag2.getOriginalName())); 88 | assertThat("The secondly added tag has a unique name", tag2.getName(), startsWith("rc11-01_20")); 89 | } 90 | 91 | @Test 92 | public void testAddMakeTagsUniqueIfCreatedateDifferInDefinedRange() { 93 | tagList.add(new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(TODAY - 10000)); 94 | tagList.add(new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(TODAY - 29999)); 95 | tagList.add(new RtcTag("uuid").setOriginalName("TagNameUnique").setCreationDate(TODAY - 10000)); 96 | 97 | assertThat("We have only one tag in the list", tagList.size(), equalTo(1)); 98 | 99 | } 100 | 101 | @Test 102 | public void testKeepOnlyActiveTags() { 103 | RtcTag tag1 = new RtcTag("uuid").setOriginalName("TagName_1").setCreationDate(TODAY - 7000); 104 | RtcTag tag2 = new RtcTag("uuid").setOriginalName("TagName_2").setCreationDate(TODAY - 6000); 105 | RtcTag tag3 = new RtcTag("uuid").setOriginalName("TagName_3").setCreationDate(TODAY - 5000) 106 | .setContainLastChangeset(true); 107 | RtcTag tag4 = new RtcTag("uuid").setOriginalName("TagName_4").setCreationDate(TODAY - 4000); 108 | RtcTag tag5 = new RtcTag("uuid").setOriginalName("TagName_5").setCreationDate(TODAY - 3000) 109 | .setContainLastChangeset(true); 110 | RtcTag tag6 = new RtcTag("uuid").setOriginalName("TagName_6").setCreationDate(TODAY - 2000); 111 | RtcTag tag7 = new RtcTag("uuid").setOriginalName("TagName_7").setCreationDate(TODAY - 1000); 112 | tagList.add(tag1); 113 | tagList.add(tag2); 114 | tagList.add(tag3); 115 | tagList.add(tag4); 116 | tagList.add(tag5); 117 | tagList.add(tag6); 118 | tagList.add(tag7); 119 | 120 | tagList.sortByCreationDate(); 121 | tagList.pruneInactiveTags(); 122 | 123 | assertThat("We tag only active tags in the list", tagList.size(), equalTo(7)); 124 | assertThat("Tag 1 will be tagged", 125 | tagList.getTag(tag1.getName(), tag1.getOriginalName(), tag1.getCreationDate()).doCreateTag(), is(true)); 126 | assertThat("Tag 2 will be tagged", 127 | tagList.getTag(tag2.getName(), tag2.getOriginalName(), tag2.getCreationDate()).doCreateTag(), is(true)); 128 | assertThat("Tag 3 will be tagged", 129 | tagList.getTag(tag3.getName(), tag3.getOriginalName(), tag3.getCreationDate()).doCreateTag(), is(true)); 130 | assertThat("Tag 4 will be tagged", 131 | tagList.getTag(tag4.getName(), tag4.getOriginalName(), tag4.getCreationDate()).doCreateTag(), is(true)); 132 | assertThat("Tag 5 will be tagged", 133 | tagList.getTag(tag5.getName(), tag5.getOriginalName(), tag5.getCreationDate()).doCreateTag(), is(true)); 134 | assertThat("Tag 6 will NOT be tagged", 135 | tagList.getTag(tag6.getName(), tag6.getOriginalName(), tag6.getCreationDate()).doCreateTag(), is(false)); 136 | assertThat("Tag 7 will NOT be tagged", 137 | tagList.getTag(tag7.getName(), tag7.getOriginalName(), tag7.getCreationDate()).doCreateTag(), is(false)); 138 | 139 | } 140 | 141 | @Test 142 | public void testPruneExcludedTags() { 143 | tagList.add(new RtcTag("uuid").setOriginalName("includedTag").setCreationDate(Long.MAX_VALUE - 10000)); 144 | tagList.add(new RtcTag("uuid").setOriginalName("includedSecondTag").setCreationDate(Long.MAX_VALUE - 10000)); 145 | tagList.add(new RtcTag("uuid").setOriginalName("excludedTag").setCreationDate(Long.MAX_VALUE - 10000)); 146 | tagList.add(new RtcTag("uuid").setOriginalName("notIncludedTag").setCreationDate(Long.MAX_VALUE - 10000)); 147 | tagList.getHeadTag(); 148 | 149 | assertThat("All added tags are in the list", tagList.size(), equalTo(5)); 150 | 151 | tagList.pruneExcludedTags(Pattern.compile("^(included.*|HEAD)$")); 152 | 153 | assertThat( 154 | "Expect tag with name 'includedTag' is in the list", 155 | tagList.contains(new RtcTag("uuid").setOriginalName("includedTag").setCreationDate( 156 | Long.MAX_VALUE - 10000)), equalTo(true)); 157 | assertThat( 158 | "Expect tag with name 'includedSecondTag' is in the list", 159 | tagList.contains(new RtcTag("uuid").setOriginalName("includedSecondTag").setCreationDate( 160 | Long.MAX_VALUE - 10000)), equalTo(true)); 161 | assertThat("Expect tag with name 'HEAD' is in the list", 162 | tagList.contains(new RtcTag("uuid").setOriginalName("HEAD").setCreationDate(Long.MAX_VALUE)), 163 | equalTo(true)); 164 | assertThat( 165 | "Expect tag with name 'excludedTag' is not in the list", 166 | tagList.contains(new RtcTag("uuid").setOriginalName("excludedTag").setCreationDate( 167 | Long.MAX_VALUE - 10000)), equalTo(false)); 168 | } 169 | 170 | @Test 171 | public void testRuntimeExceptionIfTagNotFound() { 172 | thrown.expect(RuntimeException.class); 173 | tagList.getTag("itemId", "tagName", 0); 174 | } 175 | 176 | @Test 177 | public void testHeadTagWillNotBeTagged() { 178 | RtcTag headTag = tagList.getHeadTag(); 179 | tagList.pruneInactiveTags(); 180 | 181 | assertThat("HEAD tag will never be tagged", headTag.doCreateTag(), equalTo(false)); 182 | 183 | assertThat("HEAD tag will never be tagged", tagList.getHeadTag().doCreateTag(), equalTo(false)); 184 | } 185 | 186 | @Test 187 | public void testHeadTagOnlyExistOnce() { 188 | tagList.getHeadTag(); 189 | 190 | assertThat("Only one tag is in the list", tagList.size(), equalTo(1)); 191 | 192 | tagList.getHeadTag(); 193 | 194 | assertThat("Only one tag is in the list", tagList.size(), equalTo(1)); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/git/GitMigratorTest.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.git; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | import static org.hamcrest.MatcherAssert.assertThat; 5 | import static org.junit.Assert.*; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.nio.charset.Charset; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.HashSet; 14 | import java.util.Iterator; 15 | import java.util.List; 16 | import java.util.Properties; 17 | import java.util.Set; 18 | import java.util.SortedSet; 19 | import java.util.TreeSet; 20 | 21 | import org.eclipse.jgit.api.Git; 22 | import org.eclipse.jgit.api.Status; 23 | import org.eclipse.jgit.lib.Ref; 24 | import org.eclipse.jgit.lib.StoredConfig; 25 | import org.eclipse.jgit.revwalk.RevCommit; 26 | import org.eclipse.jgit.storage.file.WindowCacheConfig; 27 | import org.junit.After; 28 | import org.junit.Before; 29 | import org.junit.Rule; 30 | import org.junit.Test; 31 | import org.junit.rules.TemporaryFolder; 32 | 33 | import to.rtc.cli.migrate.ChangeSet; 34 | import to.rtc.cli.migrate.ChangeSet.WorkItem; 35 | import to.rtc.cli.migrate.Tag; 36 | import to.rtc.cli.migrate.util.Files; 37 | 38 | /** 39 | * Tests the {@link GitMigrator} implementation. 40 | * 41 | * @author patrick.reinhart 42 | */ 43 | public class GitMigratorTest { 44 | @Rule 45 | public TemporaryFolder tempFolder = new TemporaryFolder(); 46 | 47 | private Charset cs; 48 | private GitMigrator migrator; 49 | private Git git; 50 | private Properties props; 51 | private File basedir; 52 | 53 | @Before 54 | public void setUo() { 55 | cs = Charset.forName("UTF-8"); 56 | props = new Properties(); 57 | migrator = new GitMigrator(props); 58 | basedir = tempFolder.getRoot(); 59 | } 60 | 61 | @After 62 | public void tearDown() { 63 | migrator.close(); 64 | if (git != null) { 65 | git.close(); 66 | } 67 | } 68 | 69 | @Test 70 | public void testClose() { 71 | migrator.close(); 72 | } 73 | 74 | @Test 75 | public void testInit_noGitRepoAvailableNoGitIgnore() throws Exception { 76 | props.setProperty("user.email", "john.doe@somewhere.com"); 77 | props.setProperty("user.name", "John Doe"); 78 | 79 | assertFalse(new File(basedir, ".gitattributes").exists()); 80 | 81 | migrator.initialize(props); 82 | migrator.init(basedir); 83 | 84 | checkGit("John Doe", "john.doe@somewhere.com", "Initial commit"); 85 | checkExactLines(new File(basedir, ".gitignore"), GitMigrator.ROOT_IGNORED_ENTRIES); 86 | assertFalse(new File(basedir, ".gitattributes").exists()); 87 | } 88 | 89 | @Test 90 | public void testInit_noGitRepoAvailableWithGitIgnore() throws Exception { 91 | Files.writeLines(new File(basedir, ".gitignore"), Arrays.asList("/.jazz5", "/bin/", "/.jazzShed"), cs, false); 92 | props.setProperty("global.gitignore.entries", "/projectX/WebContent/node_modules; *.ignored"); 93 | 94 | migrator.init(basedir); 95 | 96 | checkGit("RTC 2 git", "rtc2git@rtc.to", "Initial commit"); 97 | checkExactLines(new File(basedir, ".gitignore"), Arrays.asList("/.jazz5", "/bin/", "/.jazzShed", "/.metadata", 98 | "/projectX/WebContent/node_modules", "*.ignored")); 99 | } 100 | 101 | @Test 102 | public void testInit_Gitattributes() throws IOException { 103 | props.setProperty("gitattributes", "* text=auto"); 104 | 105 | migrator.init(basedir); 106 | 107 | File gitattributes = new File(basedir, ".gitattributes"); 108 | assertTrue(gitattributes.exists() && gitattributes.isFile()); 109 | List expectedLines = new ArrayList(); 110 | expectedLines.add("* text=auto"); 111 | assertEquals(expectedLines, Files.readLines(gitattributes, cs)); 112 | } 113 | 114 | @Test 115 | public void testInit_GitRepoAvailable() throws Exception { 116 | git = Git.init().setDirectory(basedir).call(); 117 | 118 | migrator.init(basedir); 119 | 120 | checkGit("RTC 2 git", "rtc2git@rtc.to", "Initial commit"); 121 | assertEquals(GitMigrator.ROOT_IGNORED_ENTRIES, Files.readLines(new File(basedir, ".gitignore"), cs)); 122 | } 123 | 124 | @Test 125 | public void testInit_GitConfig() throws Exception { 126 | git = Git.init().setDirectory(basedir).call(); 127 | StoredConfig config = git.getRepository().getConfig(); 128 | 129 | migrator.init(basedir); 130 | 131 | config.load(); 132 | assertFalse(config.getBoolean("core", null, "ignorecase", true)); 133 | assertEquals(File.separatorChar == '/' ? "input" : "true", config.getString("core", null, "autocrlf")); 134 | assertEquals("simple", config.getString("push", null, "default")); 135 | assertFalse(config.getBoolean("http", null, "sslverify", true)); 136 | } 137 | 138 | @Test 139 | public void testGetCommitMessage() { 140 | props.setProperty("commit.message.regex.1", "^B([0-9]+): (.+)$"); 141 | props.setProperty("commit.message.replacement.1", "BUG-$1 $2"); 142 | migrator.initialize(props); 143 | 144 | assertEquals("gugus BUG-1234 gaga", migrator.getCommitMessage("gugus", "B1234: gaga", "")); 145 | } 146 | 147 | @Test 148 | public void testGetCommitMessage_withCustomFormat() { 149 | props.setProperty("commit.message.format", "%1s%n%n%2s"); 150 | migrator.init(basedir); 151 | String lf = System.getProperty("line.separator"); 152 | 153 | assertEquals("gug%us" + lf + lf + "ga%ga", migrator.getCommitMessage("gug%us", "ga%ga", "")); 154 | } 155 | 156 | @Test 157 | public void testGetCommitMessage_withCustomFormat1() { 158 | props.setProperty("commit.message.format", "%1s%n%n%2s%n%n%3s"); 159 | migrator.init(basedir); 160 | String lf = System.getProperty("line.separator"); 161 | 162 | assertEquals("gug%us" + lf + lf + "ga%ga" + lf + lf + "gi%gl", 163 | migrator.getCommitMessage("gug%us", "ga%ga", "gi%gl")); 164 | } 165 | 166 | @Test 167 | public void testGetWorkItemNumbers_noWorkItems() { 168 | assertEquals("", migrator.getWorkItemNumbers(Collections. emptyList())); 169 | } 170 | 171 | @Test 172 | public void testGetWorkItemNumbers_singleWorkItem() { 173 | migrator.init(basedir); 174 | List items = new ArrayList(); 175 | items.add(TestWorkItem.INSTANCE1); 176 | assertEquals("4711", migrator.getWorkItemNumbers(items)); 177 | } 178 | 179 | @Test 180 | public void testGetWorkItemNumbers_singleWorkItem_customFormat() { 181 | props.setProperty("rtc.workitem.number.format", "RTC-%s"); 182 | migrator.init(basedir); 183 | 184 | List items = new ArrayList(); 185 | items.add(TestWorkItem.INSTANCE1); 186 | assertEquals("RTC-4711", migrator.getWorkItemNumbers(items)); 187 | } 188 | 189 | @Test 190 | public void testGetWorkItemNumbers_multipleWorkItems() { 191 | props.setProperty("rtc.workitem.number.format", "RTC-%s"); 192 | migrator.init(basedir); 193 | 194 | List items = new ArrayList(); 195 | items.add(TestWorkItem.INSTANCE1); 196 | items.add(TestWorkItem.INSTANCE2); 197 | assertEquals("RTC-4711 RTC-4712", migrator.getWorkItemNumbers(items)); 198 | } 199 | 200 | @Test 201 | public void testCommitChanges() throws Exception { 202 | migrator.init(basedir); 203 | 204 | File testFile = new File(basedir, "somefile"); 205 | Files.writeLines(testFile, Collections.singletonList("somevalue"), cs, false); 206 | 207 | migrator.commitChanges(TestChangeSet.INSTANCE); 208 | 209 | checkGit("Heiri Mueller", "heiri.mueller@irgendwo.ch", "4711 the checkin comment"); 210 | checkExactLines(testFile, Collections.singletonList("somevalue")); 211 | } 212 | 213 | @Test 214 | public void testCommitChanges_noWorkItem() throws Exception { 215 | migrator.init(basedir); 216 | 217 | File testFile = new File(basedir, "somefile"); 218 | Files.writeLines(testFile, Collections.singletonList("somevalue"), cs, false); 219 | 220 | migrator.commitChanges(TestChangeSet.NO_WORKITEM_INSTANCE); 221 | 222 | checkGit("Heiri Mueller", "heiri.mueller@irgendwo.ch", "the checkin comment"); 223 | checkExactLines(testFile, Collections.singletonList("somevalue")); 224 | } 225 | 226 | @Test 227 | public void testGetGitattributeLines() throws Exception { 228 | props.setProperty("gitattributes", " # handle text files; * text=auto; *.sql text"); 229 | migrator.initialize(props); 230 | 231 | List lines = migrator.getGitattributeLines(); 232 | assertNotNull(lines); 233 | assertEquals(3, lines.size()); 234 | assertEquals("# handle text files", lines.get(0)); 235 | assertEquals("* text=auto", lines.get(1)); 236 | assertEquals("*.sql text", lines.get(2)); 237 | } 238 | 239 | @Test 240 | public void testGetIgnoredFileExtensions() throws Exception { 241 | props.setProperty("ignore.file.extensions", ".zip; .jar; .exe; .dll"); 242 | migrator.initialize(props); 243 | 244 | Set ignoredExtensions = migrator.getIgnoredFileExtensions(); 245 | HashSet expected = new HashSet(Arrays.asList(".zip", ".jar", ".exe", ".dll")); 246 | 247 | assertEquals(expected, ignoredExtensions); 248 | } 249 | 250 | @Test 251 | public void testAddMissing() { 252 | List existing = new ArrayList(); 253 | existing.add("0"); 254 | existing.add("3"); 255 | List adding = new ArrayList(); 256 | adding.add("0"); 257 | adding.add("1"); 258 | adding.add("2"); 259 | adding.add("4"); 260 | List expectedLines = new ArrayList(); 261 | expectedLines.add("0"); 262 | expectedLines.add("3"); 263 | expectedLines.add("1"); 264 | expectedLines.add("2"); 265 | expectedLines.add("4"); 266 | migrator.addMissing(existing, adding); 267 | assertEquals(expectedLines, existing); 268 | } 269 | 270 | @Test 271 | public void testAddUpdateGitignoreIfJazzignoreAddedOrChanged() throws Exception { 272 | migrator.init(basedir); 273 | File jazzignore = new File(basedir, ".jazzignore"); 274 | 275 | Files.writeLines(jazzignore, Arrays.asList("core.ignore = {*.suo}", "core.ignore.recursive = {*.class}"), cs, 276 | false); 277 | 278 | migrator.commitChanges(TestChangeSet.INSTANCE); 279 | 280 | checkGit("Heiri Mueller", "heiri.mueller@irgendwo.ch", "4711 the checkin comment"); 281 | checkExactLines(new File(basedir, ".gitignore"), Arrays.asList("/*.suo", "*.class")); 282 | } 283 | 284 | @Test 285 | public void testAddUpdateGitignoreIfJazzignoreAddedOrChangedInSubdirectory() throws Exception { 286 | migrator.init(basedir); 287 | File subdir = tempFolder.newFolder("subdir"); 288 | File jazzignore = new File(subdir, ".jazzignore"); 289 | 290 | Files.writeLines(jazzignore, Arrays.asList("core.ignore = {*.suo}", "core.ignore.recursive = {*.class}"), cs, 291 | false); 292 | 293 | migrator.commitChanges(TestChangeSet.INSTANCE); 294 | 295 | checkGit("Heiri Mueller", "heiri.mueller@irgendwo.ch", "4711 the checkin comment"); 296 | checkExactLines(new File(subdir, ".gitignore"), Arrays.asList("/*.suo", "*.class")); 297 | } 298 | 299 | @Test 300 | public void testRemovedGitignoreIfJazzignoreRemoved() throws Exception { 301 | migrator.init(basedir); 302 | File jazzignore = new File(basedir, ".jazzignore"); 303 | File gitignore = new File(basedir, ".gitignore"); 304 | 305 | Files.writeLines(jazzignore, Arrays.asList("core.ignore = {*.suo}", "core.ignore.recursive = {*.class}"), cs, 306 | false); 307 | migrator.commitChanges(TestChangeSet.INSTANCE); 308 | 309 | assertTrue(jazzignore.delete()); 310 | 311 | migrator.commitChanges(TestChangeSet.INSTANCE); 312 | 313 | assertFalse(gitignore.exists()); 314 | } 315 | 316 | @Test 317 | public void testRestoreGitignoreIfJazzignoreNotRemoved() throws Exception { 318 | migrator.init(basedir); 319 | File jazzignore = new File(basedir, ".jazzignore"); 320 | File gitignore = new File(basedir, ".gitignore"); 321 | 322 | Files.writeLines(jazzignore, Arrays.asList("core.ignore = {*.suo}", "core.ignore.recursive = {*.class}"), cs, 323 | false); 324 | migrator.commitChanges(TestChangeSet.INSTANCE); 325 | 326 | assertTrue(gitignore.delete()); 327 | 328 | migrator.commitChanges(TestChangeSet.INSTANCE); 329 | 330 | assertTrue(gitignore.exists()); 331 | } 332 | 333 | @Test 334 | public void testRestoreGitignoreIfJazzignoreNotRemovedInSubdirectory() throws Exception { 335 | migrator.init(basedir); 336 | File subdir = tempFolder.newFolder("subdir"); 337 | File jazzignore = new File(subdir, ".jazzignore"); 338 | File gitignore = new File(subdir, ".gitignore"); 339 | 340 | Files.writeLines(jazzignore, Arrays.asList("core.ignore = {*.suo}", "core.ignore.recursive = {*.class}"), cs, 341 | false); 342 | migrator.commitChanges(TestChangeSet.INSTANCE); 343 | 344 | assertTrue(gitignore.delete()); 345 | 346 | migrator.commitChanges(TestChangeSet.INSTANCE); 347 | 348 | assertTrue(gitignore.exists()); 349 | } 350 | 351 | @Test 352 | public void testGlobalIgnoredFilesAddedToRootGitIgnore() throws Exception { 353 | props.setProperty("ignore.file.extensions", ".zip; .jar; .exe; .dLL"); 354 | migrator.initialize(props); 355 | migrator.init(basedir); 356 | 357 | create(new File(basedir, "some.zip")); 358 | create(new File(basedir, "subdir/some.jar")); 359 | create(new File(basedir, "subdir/subsub/some.dLL")); 360 | 361 | migrator.commitChanges(TestChangeSet.INSTANCE); 362 | 363 | checkGit("Heiri Mueller", "heiri.mueller@irgendwo.ch", "4711 the checkin comment"); 364 | checkAllLines(new File(basedir, ".gitignore"), Arrays.asList("/.jazz5", "/.jazzShed", "/.metadata", 365 | "/subdir/subsub/some.dLL", "/some.zip", "/subdir/some.jar")); 366 | } 367 | 368 | @Test 369 | public void testCreateTagNameReplacesWhiteSpacesWithUnderscore() { 370 | String tagname = migrator.createTagName("tag with whitespaces"); 371 | 372 | assertThat(tagname, is("tag_with_whitespaces")); 373 | } 374 | 375 | @Test 376 | public void testCreateTag() throws Exception { 377 | migrator.init(basedir); 378 | 379 | migrator.createTag(TestTag.INSTANCE); 380 | 381 | git = Git.open(basedir); 382 | List tags = git.tagList().call(); 383 | assertEquals(1, tags.size()); 384 | Ref ref = tags.get(0); 385 | assertEquals("refs/tags/myTag", ref.getName()); 386 | } 387 | 388 | @Test 389 | public void testGetExistingIgnoredFiles() throws Exception { 390 | migrator.init(basedir); 391 | Files.writeLines(new File(basedir, ".gitignore"), Arrays.asList("/.jazz5", "/some.zip", "/someother.zip", 392 | "/subdir/some.jar", "/subdir/subsub/some.dll", "/subdir/subsub/someother.dll"), cs, false); 393 | 394 | new File(basedir, ".jazz5").mkdir(); 395 | create(new File(basedir, "some.zip")); 396 | create(new File(basedir, "subdir/some.jar")); 397 | create(new File(basedir, "subdir/subsub/some.dll")); 398 | 399 | SortedSet expected = new TreeSet( 400 | Arrays.asList("/some.zip", "/subdir/some.jar", "/subdir/subsub/some.dll")); 401 | 402 | SortedSet stillExistingFiles = migrator.getExistingIgnoredFiles(); 403 | 404 | assertEquals(expected, stillExistingFiles); 405 | } 406 | 407 | @Test 408 | public void testParseConfigValue() { 409 | assertEquals(1, migrator.parseConfigValue(null, 1)); 410 | assertEquals(1, migrator.parseConfigValue("", 1)); 411 | assertEquals(1, migrator.parseConfigValue(" ", 1)); 412 | assertEquals(2, migrator.parseConfigValue("2", 1)); 413 | assertEquals(1024, migrator.parseConfigValue("1k", 1)); 414 | assertEquals(1024, migrator.parseConfigValue("1K", 1)); 415 | assertEquals(1024, migrator.parseConfigValue("1 kB", 1)); 416 | assertEquals(1024, migrator.parseConfigValue("1 KB", 1)); 417 | assertEquals(2097152, migrator.parseConfigValue("2 m", 1)); 418 | assertEquals(2097152, migrator.parseConfigValue("2 M", 1)); 419 | assertEquals(2097152, migrator.parseConfigValue("2mb", 1)); 420 | assertEquals(2097152, migrator.parseConfigValue("2MB", 1)); 421 | } 422 | 423 | @Test 424 | public void testGetGitCacheConfig_defaults() throws Exception { 425 | // check values 426 | WindowCacheConfig cfg = migrator.getWindowCacheConfig(); 427 | assertEquals(128, cfg.getPackedGitOpenFiles()); 428 | assertEquals(10 * WindowCacheConfig.MB, cfg.getPackedGitLimit()); 429 | assertEquals(8 * WindowCacheConfig.KB, cfg.getPackedGitWindowSize()); 430 | assertFalse(cfg.isPackedGitMMAP()); 431 | assertEquals(10 * WindowCacheConfig.MB, cfg.getDeltaBaseCacheLimit()); 432 | assertEquals(50 * WindowCacheConfig.MB, cfg.getStreamFileThreshold()); 433 | } 434 | 435 | @Test 436 | public void testGetGitCacheConfig() throws Exception { 437 | props.setProperty("packedgitopenfiles", "129"); 438 | props.setProperty("packedgitlimit", "11m"); 439 | props.setProperty("packedgitwindowsize", "9k"); 440 | props.setProperty("packedgitmmap", "true"); 441 | props.setProperty("deltabasecachelimit", "11m"); 442 | props.setProperty("streamfilethreshold", "51m"); 443 | migrator.initialize(props); 444 | // check values 445 | WindowCacheConfig cfg = migrator.getWindowCacheConfig(); 446 | assertEquals(129, cfg.getPackedGitOpenFiles()); 447 | assertEquals(11 * WindowCacheConfig.MB, cfg.getPackedGitLimit()); 448 | assertEquals(9 * WindowCacheConfig.KB, cfg.getPackedGitWindowSize()); 449 | assertTrue(cfg.isPackedGitMMAP()); 450 | assertEquals(11 * WindowCacheConfig.MB, cfg.getDeltaBaseCacheLimit()); 451 | assertEquals(51 * WindowCacheConfig.MB, cfg.getStreamFileThreshold()); 452 | } 453 | 454 | @Test 455 | public void testGetMaxFileThresholdValue_maxOneFirthOfHeap() { 456 | assertEquals(10000, migrator.getMaxFileThresholdValue(12000, 40000)); 457 | } 458 | 459 | @Test 460 | public void testGetMaxFileThresholdValue_lessOrEqulalMaxArraySize() { 461 | assertEquals(Integer.MAX_VALUE, migrator.getMaxFileThresholdValue(Integer.MAX_VALUE, Long.MAX_VALUE)); 462 | } 463 | 464 | // 465 | // helper stuff 466 | // 467 | 468 | private void create(File file) throws Exception { 469 | file.getParentFile().mkdirs(); 470 | file.createNewFile(); 471 | } 472 | 473 | private void checkExactLines(File fileName, List expected) throws Exception { 474 | assertEquals(expected, Files.readLines(fileName, cs)); 475 | } 476 | 477 | private void checkAllLines(File fileName, List expected) throws Exception { 478 | List readLines = Files.readLines(fileName, cs); 479 | assertEquals(expected.size(), readLines.size()); 480 | for (String line : expected) { 481 | assertTrue(readLines.contains(line)); 482 | } 483 | } 484 | 485 | private void checkGit(String userName, String userEmail, String comment) throws Exception { 486 | git = Git.open(basedir); 487 | Status status = git.status().call(); 488 | assertTrue(status.isClean()); 489 | Iterator log = git.log().call().iterator(); 490 | RevCommit revCommit = log.next(); 491 | assertEquals(userEmail, revCommit.getAuthorIdent().getEmailAddress()); 492 | assertEquals(userName, revCommit.getAuthorIdent().getName()); 493 | assertEquals(comment, revCommit.getFullMessage()); 494 | } 495 | 496 | private enum TestChangeSet implements ChangeSet { 497 | INSTANCE, NO_WORKITEM_INSTANCE { 498 | @Override 499 | public List getWorkItems() { 500 | return Collections.emptyList(); 501 | } 502 | }; 503 | 504 | @Override 505 | public String getComment() { 506 | return "the checkin comment"; 507 | } 508 | 509 | @Override 510 | public String getCreatorName() { 511 | return "Heiri Mueller"; 512 | } 513 | 514 | @Override 515 | public String getEmailAddress() { 516 | return "heiri.mueller@irgendwo.ch"; 517 | } 518 | 519 | @Override 520 | public long getCreationDate() { 521 | return 0; 522 | } 523 | 524 | @Override 525 | public List getWorkItems() { 526 | List items = new ArrayList(); 527 | items.add(TestWorkItem.INSTANCE1); 528 | return items; 529 | } 530 | } 531 | 532 | private enum TestWorkItem implements WorkItem { 533 | INSTANCE1 { 534 | @Override 535 | public long getNumber() { 536 | return 4711; 537 | } 538 | 539 | @Override 540 | public String getText() { 541 | return "The one and only"; 542 | } 543 | }, 544 | INSTANCE2 { 545 | @Override 546 | public long getNumber() { 547 | return 4712; 548 | } 549 | 550 | @Override 551 | public String getText() { 552 | return "The even more and only"; 553 | } 554 | }; 555 | } 556 | 557 | private enum TestTag implements Tag { 558 | INSTANCE; 559 | 560 | @Override 561 | public String getName() { 562 | return "myTag"; 563 | } 564 | 565 | @Override 566 | public long getCreationDate() { 567 | return 0; 568 | } 569 | } 570 | } 571 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/git/GitPlainTest.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.git; 2 | 3 | import java.io.File; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.regex.Pattern; 8 | 9 | import org.eclipse.jgit.api.AddCommand; 10 | import org.eclipse.jgit.api.CheckoutCommand; 11 | import org.eclipse.jgit.api.Git; 12 | import org.eclipse.jgit.api.RmCommand; 13 | import org.eclipse.jgit.api.Status; 14 | import org.eclipse.jgit.lib.PersonIdent; 15 | import org.eclipse.jgit.lib.StoredConfig; 16 | import org.junit.Rule; 17 | import org.junit.Test; 18 | import org.junit.rules.TemporaryFolder; 19 | 20 | /** 21 | * @author patrick.reinhart 22 | * @see https://github.com/ centic9/jgit-cookbook 23 | */ 24 | public class GitPlainTest { 25 | @Rule 26 | public TemporaryFolder tempFolder = new TemporaryFolder(); 27 | 28 | static final Pattern gitIgnorePattern = Pattern.compile("^.*(/|)\\.gitignore$"); 29 | static final Pattern jazzIgnorePattern = Pattern.compile("^.*(/|)\\.jazzignore$"); 30 | 31 | @Test 32 | public void plainJGit() throws Exception { 33 | File gitDir = tempFolder.getRoot(); 34 | Git git = init(gitDir); 35 | try { 36 | // sample add of a boolean configuration entry 37 | StoredConfig config = git.getRepository().getConfig(); 38 | config.setBoolean("core", null, "ignoreCase", false); 39 | config.save(); 40 | 41 | // add all untracked files 42 | Status status = git.status().call(); 43 | Set toAdd = new HashSet(); 44 | Set toRemove = new HashSet(); 45 | Set toRestore = new HashSet(); 46 | 47 | // go over untracked files 48 | for (String untracked : status.getUntracked()) { 49 | // add it to the index 50 | toAdd.add(untracked); 51 | } 52 | // go over modified files 53 | for (String modified : status.getModified()) { 54 | // adds a modified entry to the index 55 | toAdd.add(modified); 56 | } 57 | 58 | // go over all deleted files 59 | for (String removed : status.getMissing()) { 60 | System.out.println("-: " + removed); 61 | // adds a modified entry to the index 62 | if (gitIgnorePattern.matcher(removed).matches()) { 63 | // restore .gitignore files that where deleted 64 | toRestore.add(removed); 65 | } else { 66 | toRemove.add(removed); 67 | } 68 | } 69 | 70 | // execute the git index commands if needed 71 | if (!toAdd.isEmpty()) { 72 | AddCommand add = git.add(); 73 | for (String filepattern : toAdd) { 74 | add.addFilepattern(filepattern); 75 | } 76 | add.call(); 77 | } 78 | if (!toRemove.isEmpty()) { 79 | RmCommand rm = git.rm(); 80 | for (String filepattern : toRemove) { 81 | rm.addFilepattern(filepattern); 82 | } 83 | rm.call(); 84 | } 85 | if (!toRestore.isEmpty()) { 86 | CheckoutCommand checkout = git.checkout(); 87 | for (String filepattern : toRestore) { 88 | checkout.addPath(filepattern); 89 | } 90 | checkout.call(); 91 | } 92 | 93 | // execute commit if something has changed 94 | if (!toAdd.isEmpty() || !toRemove.isEmpty()) { 95 | PersonIdent ident = new PersonIdent("Robocop", "john.doe@somewhere.com", System.currentTimeMillis(), 96 | (int) TimeUnit.HOURS.toMillis(1)); 97 | git.commit().setMessage("auto commit").setAuthor(ident).setCommitter(ident).call(); 98 | } 99 | } finally { 100 | git.close(); 101 | } 102 | } 103 | 104 | private Git init(File gitDir) throws Exception { 105 | if (new File(gitDir, ".git").exists()) { 106 | return Git.open(gitDir); 107 | } else { 108 | return Git.init().setDirectory(gitDir).call(); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/git/MigrateToGitTest.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.git; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.nio.charset.Charset; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Properties; 12 | 13 | import org.junit.Rule; 14 | import org.junit.Test; 15 | import org.junit.rules.TemporaryFolder; 16 | 17 | import to.rtc.cli.migrate.util.Files; 18 | 19 | public class MigrateToGitTest { 20 | 21 | @Rule 22 | public TemporaryFolder tempFolder = new TemporaryFolder(); 23 | 24 | @Test 25 | public void testTrimProperties() throws Exception { 26 | List lines = new ArrayList(); 27 | lines.add("a.b.c = d "); 28 | lines.add("p2 = my value ; "); 29 | Properties untrimmed = prepareUntrimmedProperties(lines); 30 | Properties trimmed = MigrateToGit.trimProperties(untrimmed); 31 | assertNotNull(trimmed); 32 | assertEquals(2, trimmed.entrySet().size()); 33 | assertEquals("d", trimmed.getProperty("a.b.c")); 34 | assertEquals("my value ;", trimmed.getProperty("p2")); 35 | } 36 | 37 | private Charset getPropertyCharset() { 38 | return Charset.forName("ISO-8859-1"); 39 | } 40 | 41 | private Properties prepareUntrimmedProperties(List lines) throws Exception { 42 | File file = new File(tempFolder.getRoot(), "untrimmed.properties"); 43 | Files.writeLines(file, lines, getPropertyCharset(), false); 44 | Properties untrimmed = new Properties(); 45 | FileInputStream in = new FileInputStream(file); 46 | try { 47 | untrimmed.load(in); 48 | } finally { 49 | in.close(); 50 | } 51 | return untrimmed; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/util/CommitCommentTranslatorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * File Name: CommitCommentTranslatorTest.java 3 | * 4 | * Copyright (c) 2016 BISON Schweiz AG, All Rights Reserved. 5 | */ 6 | 7 | package to.rtc.cli.migrate.util; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | import java.util.Properties; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | /** 17 | * Tests the {@link CommitCommentTranslator} implementation. 18 | * 19 | * @author Patrick Reinhart 20 | */ 21 | public class CommitCommentTranslatorTest { 22 | private Properties props; 23 | private CommitCommentTranslator translator; 24 | 25 | @Before 26 | public void setUp() { 27 | props = new Properties(); 28 | props.setProperty("commit.message.regex.1", "Revision [0-9]+: (.+)"); 29 | props.setProperty("commit.message.replacement.1", "$1"); 30 | 31 | props.setProperty("commit.message.regex.2", "^(b|B|#)0*([1-9][0-9]+) *[:-]? +(.*)"); 32 | props.setProperty("commit.message.replacement.2", "BUG-$2 $3"); 33 | 34 | props.setProperty("commit.message.regex.3", "^(b|B|#)0* *[:-]? +(.*)"); 35 | props.setProperty("commit.message.replacement.3", "$2"); 36 | 37 | props.setProperty("commit.message.regex.4", "^(US?|D)0*([1-9][0-9]+) *[:-]? +(.*)"); 38 | props.setProperty("commit.message.replacement.4", "RTC-$2 $3"); 39 | 40 | translator = new CommitCommentTranslator(props); 41 | } 42 | 43 | @Test 44 | public void testTranslate() throws Exception { 45 | assertEquals("BUG-33589 Added JUnit for renamed RecordListener implementation", 46 | translator.translate("Revision 49988: B33589 - Added JUnit for renamed RecordListener implementation")); 47 | } 48 | 49 | @Test 50 | public void testTranslate_removeTailingDashAndColumn() throws Exception { 51 | assertEquals("BUG-33589 Added JUnit for renamed RecordListener implementation", 52 | translator.translate("Revision 49988: B33589- Added JUnit for renamed RecordListener implementation")); 53 | assertEquals("BUG-33589 Added JUnit for renamed RecordListener implementation", 54 | translator.translate("Revision 49988: B33589: Added JUnit for renamed RecordListener implementation")); 55 | } 56 | 57 | @Test 58 | public void testTranslateLeadingZerosRemoved() throws Exception { 59 | assertEquals("BUG-33589 Added JUnit for renamed RecordListener implementation", translator 60 | .translate("Revision 49988: B0033589 - Added JUnit for renamed RecordListener implementation")); 61 | } 62 | 63 | @Test 64 | public void testTranslateLeadingDummyValuesRemoved() throws Exception { 65 | assertEquals("Some changes", translator.translate("B00000 - Some changes")); 66 | assertEquals("Some changes", translator.translate("#0: Some changes")); 67 | assertEquals("Some changes", translator.translate("#00000: Some changes")); 68 | } 69 | 70 | @Test 71 | public void testTranslateRtcSpecificComments() throws Exception { 72 | assertEquals("RTC-1234 Some changes", translator.translate("D01234 - Some changes")); 73 | assertEquals("RTC-1234 Some changes", translator.translate("U01234: Some changes")); 74 | assertEquals("RTC-1234 Some changes", translator.translate("US01234: Some changes")); 75 | assertEquals("RTC-1234 Some changes", translator.translate("US01234: Some changes")); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /rtc2git.cli.extension/src_test/to/rtc/cli/migrate/util/JazzignoreTranslatorTest.java: -------------------------------------------------------------------------------- 1 | package to.rtc.cli.migrate.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.charset.Charset; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.junit.rules.TemporaryFolder; 14 | 15 | public class JazzignoreTranslatorTest { 16 | 17 | @Rule 18 | public TemporaryFolder tempFolder = new TemporaryFolder(); 19 | 20 | @Test 21 | public void testToGitignore() throws IOException { 22 | File jazzignore = new File(tempFolder.getRoot(), ".jazzignore"); 23 | Files.writeLines(jazzignore, getJazzignoreLines(), Charset.defaultCharset(), false); 24 | List gitignoreLines = JazzignoreTranslator.toGitignore(jazzignore); 25 | assertEquals(getExpectedGitignoreLines(), gitignoreLines); 26 | } 27 | 28 | private List getJazzignoreLines() { 29 | List lines = new ArrayList(); 30 | // leading white space is intentional 31 | lines.add("### Jazz Ignore 0"); 32 | lines.add(" # The pattern list may be split across lines"); 33 | lines.add(" # e.g: core.ignore.recursive = {*.sh} {\\.*}"); 34 | lines.add(" # some text"); 35 | lines.add("# some text"); 36 | lines.add(""); 37 | lines.add(" core.ignore.recursive = {*.class} {*.so} \\"); 38 | lines.add(" {*.pyc}"); 39 | lines.add(""); 40 | lines.add(" core.ignore = {*.suo} {.classpath} \\"); 41 | lines.add(" {.idea} \\"); 42 | lines.add(" {.project} \\"); 43 | lines.add(" {.settings} \\"); 44 | lines.add(" {${buildDirectory\\}} \\"); // this line must be ignored 45 | lines.add(" {bin} \\"); 46 | lines.add(" {dist} \\"); 47 | lines.add(" {a?c} \\"); // no next line after line continuation 48 | return lines; 49 | } 50 | 51 | private List getExpectedGitignoreLines() { 52 | List lines = new ArrayList(); 53 | lines.add("*.class"); 54 | lines.add("*.so"); 55 | lines.add("*.pyc"); 56 | lines.add("/*.suo"); 57 | lines.add("/.classpath"); 58 | lines.add("/.idea"); 59 | lines.add("/.project"); 60 | lines.add("/.settings"); 61 | lines.add("/bin"); 62 | lines.add("/dist"); 63 | lines.add("/a?c"); 64 | return lines; 65 | } 66 | } 67 | --------------------------------------------------------------------------------