hipmost 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +49 -0
- data/HOWTO.md +55 -0
- data/KNOWN-BUGS.md +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/hipmost +48 -0
- data/hipmost.gemspec +31 -0
- data/lib/hipmost.rb +21 -0
- data/lib/hipmost/cmds.rb +6 -0
- data/lib/hipmost/cmds/private.rb +55 -0
- data/lib/hipmost/cmds/room.rb +126 -0
- data/lib/hipmost/hipchat.rb +68 -0
- data/lib/hipmost/hipchat/conversion.rb +26 -0
- data/lib/hipmost/hipchat/post.rb +36 -0
- data/lib/hipmost/hipchat/post_repository.rb +43 -0
- data/lib/hipmost/hipchat/room.rb +57 -0
- data/lib/hipmost/hipchat/room_repository.rb +46 -0
- data/lib/hipmost/hipchat/user_repository.rb +74 -0
- data/lib/hipmost/mattermost.rb +7 -0
- data/lib/hipmost/mattermost/channel.rb +26 -0
- data/lib/hipmost/mattermost/team.rb +22 -0
- data/lib/hipmost/room.rb +4 -0
- data/lib/hipmost/version.rb +3 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dad37853ecd2f590343ce5366c2f9c6560aa287ea6bd878c2eac1f51ce46d143
|
4
|
+
data.tar.gz: 47bd0029d1bf0a4ab79c1e57d098f0a394e1a2de5ddcf48727647764b03bf8d4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e00a51e7a1a45b5bf446c193bf86e36bef54f29562a796cec9e4981199c58839f2910fc26c2497ef142271522f0937c8a5270d227d6f13c54bc85037c637523
|
7
|
+
data.tar.gz: 8d57d5844c80d8bddabf359d2b617a6fc828f3bd370e98973299b3f13945dd5ed21f6eadcf3c1ff8beda8fcfd5a0f08348ef0aa0ff86081addecf2e7a7e9c7b6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# The Ruby Community Conduct Guideline
|
2
|
+
|
3
|
+
This document provides community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to the Ruby community. It applies to all "collaborative space," which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.).
|
4
|
+
|
5
|
+
- Participants will be tolerant of opposing views.
|
6
|
+
- Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
7
|
+
- When interpreting the words and actions of others, participants should always assume good intentions.
|
8
|
+
- Behaviour which can be reasonably considered harassment will not be tolerated.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
hipmost (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
coderay (1.1.2)
|
10
|
+
diff-lcs (1.3)
|
11
|
+
method_source (0.8.2)
|
12
|
+
pry (0.10.4)
|
13
|
+
coderay (~> 1.1.0)
|
14
|
+
method_source (~> 0.8.1)
|
15
|
+
slop (~> 3.4)
|
16
|
+
pry-doc (0.12.0)
|
17
|
+
pry (~> 0.9)
|
18
|
+
yard (~> 0.9)
|
19
|
+
rake (10.5.0)
|
20
|
+
rspec (3.7.0)
|
21
|
+
rspec-core (~> 3.7.0)
|
22
|
+
rspec-expectations (~> 3.7.0)
|
23
|
+
rspec-mocks (~> 3.7.0)
|
24
|
+
rspec-core (3.7.1)
|
25
|
+
rspec-support (~> 3.7.0)
|
26
|
+
rspec-expectations (3.7.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.7.0)
|
29
|
+
rspec-mocks (3.7.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.7.0)
|
32
|
+
rspec-support (3.7.1)
|
33
|
+
slop (3.6.0)
|
34
|
+
yard (0.9.15)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
bundler (~> 1.16)
|
41
|
+
hipmost!
|
42
|
+
method_source (>= 0.8.2)
|
43
|
+
pry (~> 0.10.3)
|
44
|
+
pry-doc (>= 0.8.0)
|
45
|
+
rake (~> 10.0)
|
46
|
+
rspec (~> 3.0)
|
47
|
+
|
48
|
+
BUNDLED WITH
|
49
|
+
1.16.2
|
data/HOWTO.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# How to migrate from Hipchat to Mattermost with Hipmost
|
2
|
+
|
3
|
+
Migrating from Hipchat to Mattermost is a bit of a process, but if you know what to do then it's fairly straightforward. We'll describe some steps of what to do in this document, taking from [Mattermost's own guidelines.](https://mattermost.com/atlassian/#hipchat-migration) *Credit goes to Mattermost for the content which they wrote.*
|
4
|
+
|
5
|
+
## Step 1: Set up your Mattermost Instance
|
6
|
+
|
7
|
+
1. Download the [latest version of Mattermost](https://about.mattermost.com/download/).
|
8
|
+
2. [Deploy Mattermost](https://docs.mattermost.com/guides/administrator.html#installing-mattermost) in your environment using the configuration that meets your organization’s needs for performance and scalability.
|
9
|
+
3. [Request a Trial](https://mattermost.com/trial) of Mattermost Enterprise for [advanced features](https://mattermost.com/pricing).
|
10
|
+
|
11
|
+
Feel free to [submit an issue](https://github.com/orbitalimpact/hipmost/issues/new) or visit Mattermost's [troubleshooting forum](https://forum.mattermost.org/t/how-to-use-the-troubleshooting-forum/150) for help.
|
12
|
+
|
13
|
+
## Step 2: Export your data from HipChat
|
14
|
+
|
15
|
+
### Situation 1:
|
16
|
+
|
17
|
+
If your Hipchat instance is hosted on hipchat.com (i.e., **not** self-hosted) then you need to request your data from Atlassian. Go to [this page,](https://support.atlassian.com/hipchat/) log in with your Hipchat account information, submit a ticket via the `Contact Support` button, and explain that you wish to obtain a copy of your team's data. After some days, they should give you an AES-encrypted tarball containing your data (the file will have the extension `.tar.gz.aes`). [Here is another document](https://confluence.atlassian.com/hipchatkb/unable-to-decrypt-file-while-importing-into-hipchat-server-756777042.html) explaining how to manually decrypt your tarball at the command line.
|
18
|
+
|
19
|
+
### Situation 2:
|
20
|
+
|
21
|
+
These are the steps to follow if you're using Hipchat Server or Hipchat Data Center, as given by Mattermost.
|
22
|
+
|
23
|
+
(i.e., what to do if you **are** self-hosted)
|
24
|
+
|
25
|
+
If you’re able to upgrade HipChat Server or HipChat Data Center to the latest version, we recommend using Group Export Dashboard to export your data. If you’re unable to upgrade, see Command Line Interface procedure below.
|
26
|
+
|
27
|
+
*Using the Group Export Dashboard*:
|
28
|
+
|
29
|
+
1. Log in to your Hipchat Server or HipChat Server instance (e.g., hipchat.yourcompany.com)
|
30
|
+
2. Click on **Server Admin > Export**.
|
31
|
+
3. Select the data to export.
|
32
|
+
4. In the Password and Confirm Password fields, create a password to protect your archive files. (Store this password as it is not saved anywhere else.)
|
33
|
+
5. Click Export. Once the export is done, you will receive an email with a link to download the file.
|
34
|
+
|
35
|
+
*If you’re unable to use the Group Export Dashboard, use the Command Line Interface to export:*
|
36
|
+
|
37
|
+
1. Go to CLI.
|
38
|
+
2. Enter `hipchat export --export -p your_password`
|
39
|
+
3. Once the export is done, you will receive an email with a link to download the file.
|
40
|
+
|
41
|
+
*More detailed instructions can be found at https://confluence.atlassian.com/hipchatdc3/export-data-from-hipchat-data-center-913476832.html.*
|
42
|
+
|
43
|
+
## Step 3: Use Hipmost to convert your data
|
44
|
+
|
45
|
+
After you've received your data, decrypted it, and extracted it to a folder, you may then use `hipmost` to convert your data for importation into Mattermost. If you name your folder `data`, then you can simply use `hipmost rooms import "Example Room" "Mattermost Team":"Mattermost Channel"`. Of course, substitute whatever the actual name of your room, channel, and team is in their respective fields. Furthermore, you may use the `-p` option to set a different path to your data. More usage options [in the `Usage` section of README.md.](./README.md#usage)
|
46
|
+
|
47
|
+
After you execute the `hipmost` command, you should have a file entitled `Room Name.jsonl` in the current directory which is ready to be imported into Mattermost.
|
48
|
+
|
49
|
+
## Step 4: Import your data into Mattermost
|
50
|
+
|
51
|
+
1. Follow the [Mattermost Bulk Load Tool](https://docs.mattermost.com/deployment/bulk-loading.html) guide to import your data into Mattermost.
|
52
|
+
a. Note: Efforts are underway to source scripts from the Mattermost community to further automate this step. If you’re interested in contributing, please contact Mattermost at [info@mattermost.com](info@mattermost.com), Twitter or Mattermost forums at https://forum.mattermost.org
|
53
|
+
2. Alternatively, [contact Mattermost](https://mattermost.com/contact-us) for partner recommendations for your region to assist in your import.
|
54
|
+
|
55
|
+
If you encounter any troubles along the way, please feel free to [submit an issue](https://github.com/orbitalimpact/hipmost/issues/new) and let us know what problem you're having.
|
data/KNOWN-BUGS.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Known Bugs
|
2
|
+
Unfortunately, there are a number of problems which exist that we are presently aware of. We have worked on this project in our spare time, in between work on actual projects. Since we worked on it for free and with our specific data in mind, we have accrued the following bugs and have been unable to devote the time and effort necessary to properly fix all of them (although, some of these bugs have workarounds). We would like to remedy this, yet we could certainly use help in the way of patches or donations. If this project has been helpful to your team or you'd like to improve it to help your team migrate, then please consider submitting patches or donating money so that we can devote more time to this project.
|
3
|
+
|
4
|
+
Of course, please do not assume that this list encompasses *all* of the bugs which you may encounter.
|
5
|
+
|
6
|
+
Items which are fairly easy to tackle and for which we would like help are marked with "**(help wanted)**"
|
7
|
+
|
8
|
+
Without further ado:
|
9
|
+
|
10
|
+
## General improvements
|
11
|
+
|
12
|
+
- Verbose mode could be better (i.e., more verbose but not too verbose). **(help wanted)**
|
13
|
+
- The CLI could perhaps become easier and more intuitive. **(help wanted)**
|
14
|
+
- More thorough documentation is always a good thing. **(help wanted)**
|
15
|
+
|
16
|
+
## What gets converted
|
17
|
+
|
18
|
+
- Messages which are of the type `TopicRoomMessage`, `ArchiveRoomMessage`, `GuestAccessMessage` or `NotificationMessage` are skipped; only `UserMessage`'s and `PrivateUserMessage`'s are processed.
|
19
|
+
- Certain Hipchat [slash commands](https://confluence.atlassian.com/hipchat/keyboard-shortcuts-and-slash-commands-749385232.html#Keyboardshortcutsandslashcommands-Slashcommands) are not translated into Mattermost messages because they do not have Mattermost equivalents. This includes: `/clear`, `/me`, `s/`, `#color-hex`. However, we do attempt to translate some slash commands since they have Mattermost equivalents; namely, the formatting slash commands: `/code` and `/quote`.
|
20
|
+
- We do not currently handle any kind of conversion or importation of files uploaded to Hipchat. E.g., images, documents, media, etc. The reason being that our team relies on external file-hosting services to upload such files to. We found Hipchat's file-hosting to be flaky and not robust. **(help wanted)**
|
21
|
+
- Some posts may contain old usernames, i.e., a username which someone used in Hipchat that is different than the new username they've chosen for Mattermost. Unfortunately, this cannot be caught by the validator. **(help wanted)**
|
22
|
+
- A workaround is to use `sed` or a text editor to find & replace the occurrences of the old username with the new one.
|
23
|
+
|
24
|
+
## Potential errors
|
25
|
+
|
26
|
+
- Sometimes [user objects](https://docs.mattermost.com/deployment/bulk-loading.html#user-object) don't get generated. We're not exactly sure why this happens; unfortunately, it causes the validator to get upset and say something like: `Error importing post. User with username "john_doe" could not be found., SqlUserStore.GetByUsername: We couldn't find an existing account matching your username for this team.` **(help wanted)**
|
27
|
+
- The current workaround is to manually [create the missing user(s)](https://docs.mattermost.com/administration/command-line-tools.html#mattermost-user-create) in the system by hand.
|
28
|
+
- If a user object *is* generated, but a user's username is now different than what it used to be in Hipchat, Mattermost may complain about them having an insufficient password. E.g.: `User.IsValid: model.user.is_valid.pwd_lowercase_uppercase_number_symbol.app_error` **(help wanted)**
|
29
|
+
- A workaround is to remove that user object or to modify the user object to have the right username.
|
30
|
+
|
31
|
+
## Questionable behavior
|
32
|
+
|
33
|
+
- If a file is generated whose name conflicts with an already existing file, then the already existing file will be overwritten.
|
34
|
+
- This may be considered a feature, depending on your opinion and use case.
|
35
|
+
|
36
|
+
If you feel like tackling any of these problems, please feel free to submit a pull request or file an issue for discussion. We welcome contributions and are happy to help.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Gabriel Rios
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Hipmost
|
2
|
+
|
3
|
+
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AYNCCNVFYPKXW)
|
4
|
+
|
5
|
+
Hipmost is a tool to migrate your Hipchat history to Mattermost. It parses your Hipchat export and generates a file to be imported on a Mattermost server. After generating this file, please see [the Mattermost documentation](https://docs.mattermost.com/deployment/bulk-loading.html) for how to import it on your server.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
$ gem install hipmost
|
10
|
+
|
11
|
+
## Getting started
|
12
|
+
|
13
|
+
See [HOWTO.md](./HOWTO.md) for a step-by-step guide for the entire process. It covers everything from how to get your data from Hipchat, and finally, how to get that data into Mattermost.
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Usage: hipmost [options] [command]
|
18
|
+
|
19
|
+
Commands:
|
20
|
+
|
21
|
+
public (AKA: `room' or `rooms')
|
22
|
+
Form: public [import|list] [room names] - Import or list public Hipchat rooms
|
23
|
+
|
24
|
+
[room names] must be at least one pair composed by "Hipchat room name" and "Mattermost team":"Mattermost channel".
|
25
|
+
The Mattermost team or channel can be the part visible in the URL path, such as "town-square", or it can be the plain-English name, such as "General"
|
26
|
+
|
27
|
+
--------
|
28
|
+
|
29
|
+
private (AKA: `direct')
|
30
|
+
Form: private [import|list] - Import or list private chats
|
31
|
+
|
32
|
+
--------
|
33
|
+
|
34
|
+
Examples:
|
35
|
+
$ hipmost room import "Orbital Impact" "Orbital Impact":"General"
|
36
|
+
$ hipmost public import "Orbital Impact" "Orbital Impact":"General" -p data_folder
|
37
|
+
$ hipmost private list
|
38
|
+
$ hipmost -v rooms import "Orbital Impact" "Orbital Impact":"General"
|
39
|
+
|
40
|
+
-p, --path [PATH] Path to Hipchat data folder (Default: "./data")
|
41
|
+
-v, --[no-]verbose Run verbosely
|
42
|
+
|
43
|
+
## Known Bugs
|
44
|
+
See the [KNOWN-BUGS.md](./KNOWN-BUGS.md) file for discussion of known problems, workarounds, and potential improvements. This is also a good place to start if you're interested in contributing.
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
Bug reports and pull requests are welcome. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Ruby code of conduct.](https://www.ruby-lang.org/en/conduct/)
|
49
|
+
|
50
|
+
Also, [here is a great reference for Hipchat's data format](https://confluence.atlassian.com/hipchatkb/exporting-from-hipchat-server-or-data-center-for-data-portability-950821555.html) and [here is a great reference for how Mattermost's data format.](https://docs.mattermost.com/deployment/bulk-loading.html#data-format) These are highly useful for aspiring contributors.
|
51
|
+
|
52
|
+
## License
|
53
|
+
|
54
|
+
The gem is available as open source under the terms of the [MIT License.](https://opensource.org/licenses/MIT)
|
55
|
+
|
56
|
+
## Code of Conduct
|
57
|
+
|
58
|
+
Everyone interacting in the Hipmost project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct.](./CODE_OF_CONDUCT.md)
|
59
|
+
|
60
|
+
## Donation
|
61
|
+
If this project has helped you or your team, a donation would be appreciated and will help keep the project alive :)
|
62
|
+
|
63
|
+
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AYNCCNVFYPKXW)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "hipmost"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/hipmost
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
3
|
+
require "rubygems" if RUBY_VERSION < "1.9"
|
4
|
+
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require "hipmost"
|
8
|
+
|
9
|
+
options = { path: "./data" }
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.banner = <<-BANNER
|
12
|
+
Usage: hipmost [options] [command]
|
13
|
+
|
14
|
+
Commands:
|
15
|
+
|
16
|
+
public (AKA, room or rooms)
|
17
|
+
Form: public [import|list] [rooms] - Import or list public Hipchat rooms
|
18
|
+
|
19
|
+
[rooms] must be at least one pair composed by "Hipchat channel name" and "Mattermost team":"Mattermost channel"
|
20
|
+
The Mattermost team or channel can be the URL endpoint, such as "town-square", or the channel name, such as "General"
|
21
|
+
|
22
|
+
--------
|
23
|
+
|
24
|
+
private (AKA, direct)
|
25
|
+
Form: private [import|list] - Import or list private chats
|
26
|
+
|
27
|
+
--------
|
28
|
+
|
29
|
+
Examples:
|
30
|
+
$ hipmost room import "Orbital Impact" "Orbital Impact":"General"
|
31
|
+
$ hipmost public import "Orbital Impact" "Orbital Impact":"General" -p data_folder
|
32
|
+
$ hipmost private list
|
33
|
+
$ hipmost -v rooms import "Orbital Impact" "Orbital Impact":"General"
|
34
|
+
|
35
|
+
BANNER
|
36
|
+
|
37
|
+
opts.on("-p", "--path [PATH]", 'Path to Hipchat data folder (Default: "./data")') do |p|
|
38
|
+
options[:path] = p
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
42
|
+
options[:verbose] = true
|
43
|
+
end
|
44
|
+
end.parse!
|
45
|
+
|
46
|
+
command = ARGV.shift
|
47
|
+
|
48
|
+
exit Hipmost::CLI.run(command, ARGV, options)
|
data/hipmost.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "hipmost/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hipmost"
|
8
|
+
spec.version = Hipmost::VERSION
|
9
|
+
spec.authors = ["Gabriel Rios"]
|
10
|
+
spec.email = ["gabrielfalcaorios@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Migrate your hipchat history to Mattermost}
|
13
|
+
spec.description = %q{Migrate your hipchat history to Mattermost}
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
spec.add_development_dependency "pry", "~> 0.10.3"
|
29
|
+
spec.add_development_dependency "pry-doc", ">= 0.8.0"
|
30
|
+
spec.add_development_dependency "method_source", ">= 0.8.2"
|
31
|
+
end
|
data/lib/hipmost.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require "hipmost/version"
|
3
|
+
require "hipmost/hipchat"
|
4
|
+
require "hipmost/mattermost"
|
5
|
+
require "hipmost/cmds"
|
6
|
+
|
7
|
+
module Hipmost
|
8
|
+
class CLI
|
9
|
+
def self.run(command, args, options)
|
10
|
+
case command.to_sym
|
11
|
+
when :public, :room, :rooms
|
12
|
+
Hipmost::Cmds::Room.new(**options).run(args)
|
13
|
+
when :private, :direct
|
14
|
+
Hipmost::Cmds::Private.new(**options).run(args)
|
15
|
+
else
|
16
|
+
puts "Invalid command"
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/hipmost/cmds.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Hipmost
|
2
|
+
module Cmds
|
3
|
+
class Private
|
4
|
+
def initialize(path:, verbose: false)
|
5
|
+
$path = Pathname.new(path).expand_path
|
6
|
+
@outpath = $path.join("..", "Private Chats.jsonl").expand_path
|
7
|
+
@verbose = verbose
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(args)
|
11
|
+
subcommand = args.shift
|
12
|
+
|
13
|
+
if ["list", "import"].include?(subcommand)
|
14
|
+
else
|
15
|
+
puts "Command invalid for `private`, must be `import` or `list`"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
send(subcommand, args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def list(_args)
|
23
|
+
puts "Listing Private chats" if @verbose
|
24
|
+
Hipchat.direct_channels.each do |members|
|
25
|
+
puts members.inspect
|
26
|
+
end
|
27
|
+
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def import(args)
|
32
|
+
File.open(@outpath, "w") do |jsonl|
|
33
|
+
puts "Writing version header..." if @verbose
|
34
|
+
jsonl.puts %[{ "type": "version", "version": 1 }]
|
35
|
+
|
36
|
+
puts "Writing room members..." if @verbose
|
37
|
+
Hipchat.users.each do |_,user|
|
38
|
+
jsonl.puts(user.to_jsonl)
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Writing 1-on-1 room members..." if @verbose
|
42
|
+
Hipchat.direct_channels.each do |members|
|
43
|
+
puts members.inspect if @verbose
|
44
|
+
jsonl.puts(%[{ "type": "direct_channel", "direct_channel": { "members": #{members.inspect} }}])
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Writing 1-on-1 room posts (oldest to newest)..." if @verbose
|
48
|
+
Hipchat.direct_posts(jsonl, @verbose)
|
49
|
+
end
|
50
|
+
|
51
|
+
true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Hipmost
|
2
|
+
module Cmds
|
3
|
+
class Room
|
4
|
+
def initialize(path:, verbose: false)
|
5
|
+
$path = Pathname.new(path).expand_path
|
6
|
+
@verbose = verbose
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(args)
|
10
|
+
subcommand = args.shift
|
11
|
+
@outpath = $path.join("..", "#{args[0]}.jsonl").expand_path
|
12
|
+
|
13
|
+
if ["list", "import"].include?(subcommand)
|
14
|
+
else
|
15
|
+
puts "Command invalid for `public`; must be `import` or `list`"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
send(subcommand, args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def list(_args)
|
23
|
+
puts "Listing rooms..." if @verbose
|
24
|
+
Hipchat.rooms.each do |_,room|
|
25
|
+
puts room.display_name
|
26
|
+
end
|
27
|
+
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def import(args)
|
32
|
+
rooms = args
|
33
|
+
rooms_size = rooms.size
|
34
|
+
|
35
|
+
if rooms_size.zero? || (rooms_size % 2).nonzero?
|
36
|
+
puts "Need a pair of rooms to migrate"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
@data = rooms
|
41
|
+
|
42
|
+
parse_rooms_arg
|
43
|
+
save
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def save
|
48
|
+
puts "Opening #{@outpath} for writing..." if @verbose
|
49
|
+
|
50
|
+
File.open(@outpath, "w") do |jsonl|
|
51
|
+
puts "Writing version header..." if @verbose
|
52
|
+
jsonl.puts %[{ "type": "version", "version": 1 }]
|
53
|
+
|
54
|
+
puts "Writing team info..." if @verbose
|
55
|
+
@teams.each {|t| jsonl.puts(t.to_jsonl) }
|
56
|
+
puts "Writing channel info..." if @verbose
|
57
|
+
@channels.each {|r| jsonl.puts(r.to_jsonl) }
|
58
|
+
|
59
|
+
puts "Writing room members..." if @verbose
|
60
|
+
@rooms.each do |room|
|
61
|
+
room.users.each do |user|
|
62
|
+
jsonl.puts(user.to_jsonl)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
puts "Writing room posts (newest to oldest)..." if @verbose
|
67
|
+
i = 1 if @verbose
|
68
|
+
j = 1 if @verbose
|
69
|
+
|
70
|
+
@rooms.each do |room|
|
71
|
+
if @verbose
|
72
|
+
puts "On room #{i}"
|
73
|
+
i += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
Hipchat::PostRepository.new(room).tap(&:load).each do |post|
|
77
|
+
if @verbose
|
78
|
+
print "On post #{j}\r"
|
79
|
+
j += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
jsonl.puts(post.to_jsonl)
|
83
|
+
end
|
84
|
+
|
85
|
+
if @verbose
|
86
|
+
print "\n"
|
87
|
+
puts "Successfully wrote public room data\n\n"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_rooms_arg
|
94
|
+
@rooms = []
|
95
|
+
@channels = []
|
96
|
+
@teams = []
|
97
|
+
|
98
|
+
@data.each_slice(2).each do |hipchat_room, mattermost_room|
|
99
|
+
if @verbose
|
100
|
+
puts "Parsing rooms for Hipchat and Mattermost..."
|
101
|
+
puts "Hipchat room is: #{hipchat_room}"
|
102
|
+
puts "Mattermost team & channel are: #{mattermost_room}"
|
103
|
+
end
|
104
|
+
|
105
|
+
team, channel_name = mattermost_room.split(":")
|
106
|
+
team = Mattermost::Team.new(team)
|
107
|
+
room = Hipchat.rooms.find_by_name(hipchat_room)
|
108
|
+
channel = Mattermost::Channel.from_hipchat(room, name: channel_name, team: team)
|
109
|
+
|
110
|
+
room.team = team
|
111
|
+
room.channel = channel
|
112
|
+
|
113
|
+
@rooms << room
|
114
|
+
@teams << team
|
115
|
+
@channels << channel
|
116
|
+
|
117
|
+
puts "Successfully parsed rooms\n\n" if @verbose
|
118
|
+
end
|
119
|
+
|
120
|
+
@teams.uniq!
|
121
|
+
@rooms.uniq!
|
122
|
+
@channels.uniq!
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
require_relative "hipchat/user_repository"
|
5
|
+
require_relative "hipchat/room_repository"
|
6
|
+
require_relative "hipchat/post_repository"
|
7
|
+
require_relative "hipchat/conversion"
|
8
|
+
|
9
|
+
module Hipmost
|
10
|
+
module Hipchat
|
11
|
+
class << self
|
12
|
+
def users
|
13
|
+
@users ||= UserRepository.load_from($path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def rooms
|
17
|
+
@rooms ||= RoomRepository.new($path).tap(&:load)
|
18
|
+
end
|
19
|
+
|
20
|
+
def direct_channels
|
21
|
+
Dir[$path.join("users", "**", "*.json")].flat_map do |file_path|
|
22
|
+
json = JSON.parse(File.read(file_path))
|
23
|
+
json.map do |message|
|
24
|
+
msg = message["PrivateUserMessage"]
|
25
|
+
sender = users[msg["sender"]["id"]]
|
26
|
+
receiver = users[msg["receiver"]["id"]]
|
27
|
+
[sender.username, receiver.username].sort
|
28
|
+
end
|
29
|
+
end.uniq
|
30
|
+
end
|
31
|
+
|
32
|
+
def direct_posts(file, verbose)
|
33
|
+
i = 1 if verbose
|
34
|
+
|
35
|
+
Dir[$path.join("users", "**", "*.json")].each do |file_path|
|
36
|
+
puts "Opening 1-on-1 room at #{file_path}..." if verbose
|
37
|
+
json = JSON.parse(File.read(file_path))
|
38
|
+
puts "Successfully parsed file at #{file_path}" if verbose
|
39
|
+
|
40
|
+
puts "Examining messages in this file..." if verbose
|
41
|
+
|
42
|
+
json.each do |message|
|
43
|
+
if verbose
|
44
|
+
print "On post #{i}\r"
|
45
|
+
i += 1
|
46
|
+
end
|
47
|
+
|
48
|
+
msg = message["PrivateUserMessage"]
|
49
|
+
sender = users[msg["sender"]["id"]]
|
50
|
+
receiver = users[msg["receiver"]["id"]]
|
51
|
+
message = msg["message"]
|
52
|
+
create_at = DateTime.strptime(msg["timestamp"]).to_time.to_i*1000
|
53
|
+
|
54
|
+
members = [ sender.username, receiver.username ] .sort
|
55
|
+
|
56
|
+
Conversion.convert_formatting_to_markdown(message)
|
57
|
+
file.puts(%[{ "type": "direct_post", "direct_post": { "channel_members": #{members.inspect}, "user": "#{sender.username}", "message": "#{message}", "create_at": #{create_at} } }])
|
58
|
+
end
|
59
|
+
|
60
|
+
if verbose
|
61
|
+
print "\n"
|
62
|
+
puts "Successfully wrote data for that 1-on-1 room\n\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Misc utilties to do data conversion from Hipchat to Mattermost
|
2
|
+
|
3
|
+
module Hipmost
|
4
|
+
module Conversion
|
5
|
+
def self.convert_formatting_to_markdown(message)
|
6
|
+
# According to Hipchat's docs, the only formatting commands which are
|
7
|
+
# translatable to Mattermost are /code and /quote.
|
8
|
+
# Relevant docs: https://confluence.atlassian.com/hipchat/keyboard-shortcuts-and-slash-commands-749385232.html#Keyboardshortcutsandslashcommands-Slashcommands
|
9
|
+
|
10
|
+
if message
|
11
|
+
if message.start_with?("/code") && message.lines.count > 1
|
12
|
+
message.sub!("/code", "```\n")
|
13
|
+
message << "\n```"
|
14
|
+
elsif message.start_with?("/code") && message.lines.count == 1
|
15
|
+
message.sub!("/code", "`")
|
16
|
+
message << "`"
|
17
|
+
end
|
18
|
+
|
19
|
+
if message.start_with?("/quote")
|
20
|
+
message.sub!("/quote", ">")
|
21
|
+
message.gsub!(/\n\n(.)/, "\n\n> \\1")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
require_relative "conversion"
|
4
|
+
|
5
|
+
module Hipmost
|
6
|
+
module Hipchat
|
7
|
+
class Post
|
8
|
+
def initialize(attrs, room, is_private_room)
|
9
|
+
@private = is_private_room
|
10
|
+
@attrs = attrs
|
11
|
+
@sender = Hipchat.users[attrs["sender"]["id"]]
|
12
|
+
@message = attrs["message"]
|
13
|
+
@created_at = DateTime.strptime(attrs["timestamp"])
|
14
|
+
@team = room.team
|
15
|
+
@channel = room.channel
|
16
|
+
if is_private_room
|
17
|
+
@receiver = Hipchat.users[attrs["sender"]["id"]]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
attr_reader :team, :channel, :sender
|
21
|
+
|
22
|
+
def to_jsonl
|
23
|
+
# First, convert Hipchat formatting to markdown...
|
24
|
+
Conversion.convert_formatting_to_markdown(@message)
|
25
|
+
|
26
|
+
# Then, generate the actual object based on whether the room is private or not.
|
27
|
+
if @private
|
28
|
+
members = [@sender.username, @receiver.username].sort
|
29
|
+
%[{ "type": "direct_post", "direct_post": { "channel_members": #{members.inspect}, "user": "#{@sender.username}", "message": "#{JSON.dump(@message)}", "create_at": #{@created_at.to_time.to_i*1000} } }]
|
30
|
+
else
|
31
|
+
%[{ "type": "post", "post": { "team": "#{team.name}", "channel": "#{channel.name}", "user": "#{sender.username}", "message": #{JSON.dump(@message)}, "create_at": #{@created_at.to_time.to_i*1000} } }]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'forwardable'
|
3
|
+
require_relative 'post'
|
4
|
+
|
5
|
+
module Hipmost
|
6
|
+
module Hipchat
|
7
|
+
class PostRepository
|
8
|
+
attr_accessor :posts, :name_index
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegators :@posts, :size, :[], :select, :each
|
12
|
+
|
13
|
+
def self.for_room(room)
|
14
|
+
new(room).tap(&:load)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(room)
|
18
|
+
@room = room
|
19
|
+
@path = $path.join("rooms", room.id.to_s, "history.json")
|
20
|
+
@posts = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def load(data = file_data)
|
24
|
+
return if !File.exists?(@path)
|
25
|
+
json = JSON.load(data)
|
26
|
+
|
27
|
+
json.each do |post_obj|
|
28
|
+
next if post_obj.key?("NotificationMessage")
|
29
|
+
next if post_obj.key?("GuestAccessMessage")
|
30
|
+
next if post_obj.key?("ArchiveRoomMessage")
|
31
|
+
next if post_obj.key?("TopicRoomMessage")
|
32
|
+
post = post_obj["UserMessage"]
|
33
|
+
@posts << Post.new(post, @room)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def file_data
|
38
|
+
return if !File.exists?(@path)
|
39
|
+
File.read(@path)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
=begin
|
3
|
+
{
|
4
|
+
"Room": {
|
5
|
+
"created": "2013-05-27T13:29:02+00:00",
|
6
|
+
"guest_access_url": null,
|
7
|
+
"id": 206455,
|
8
|
+
"is_archived": false,
|
9
|
+
"members": [
|
10
|
+
752160,
|
11
|
+
1002528,
|
12
|
+
844771,
|
13
|
+
340070,
|
14
|
+
1017103,
|
15
|
+
340825
|
16
|
+
],
|
17
|
+
"name": "Orbital Impact",
|
18
|
+
"owner": 340070,
|
19
|
+
"participants": [],
|
20
|
+
"privacy": "private",
|
21
|
+
"topic": "Welcome! Send this link to coworkers who need accounts: https://www.hipchat.com/invite/50371/3c380f069e21ba92e3441c57952e4ed0"
|
22
|
+
}
|
23
|
+
},
|
24
|
+
=end
|
25
|
+
|
26
|
+
module Hipmost
|
27
|
+
module Hipchat
|
28
|
+
class Room
|
29
|
+
def initialize(attrs)
|
30
|
+
@id = attrs["id"]
|
31
|
+
@name = attrs["name"].gsub(/\s/, "-").downcase
|
32
|
+
@display_name = attrs["name"]
|
33
|
+
@topic = attrs["topic"]
|
34
|
+
@attrs = attrs
|
35
|
+
end
|
36
|
+
attr_reader :id, :attrs, :name, :display_name, :topic
|
37
|
+
attr_accessor :team, :channel
|
38
|
+
|
39
|
+
def private?
|
40
|
+
privacy == "private"
|
41
|
+
end
|
42
|
+
|
43
|
+
def users
|
44
|
+
@users ||= attrs["members"].map{|uid| Hipchat.users[uid] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def posts
|
48
|
+
@posts ||= PostRepository.for_room(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
def method_missing(method)
|
52
|
+
attrs[method.to_s]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'forwardable'
|
3
|
+
require_relative "room"
|
4
|
+
|
5
|
+
module Hipmost
|
6
|
+
module Hipchat
|
7
|
+
class RoomRepository
|
8
|
+
attr_accessor :rooms, :name_index
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegators :@rooms, :size, :[], :select, :each
|
12
|
+
|
13
|
+
def self.load_from(path)
|
14
|
+
new(path).tap(&:load)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(path)
|
18
|
+
@path = Pathname.new(path).join("rooms.json")
|
19
|
+
@rooms = {}
|
20
|
+
@name_index = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def load(data = file_data)
|
24
|
+
json = JSON.load(data)
|
25
|
+
|
26
|
+
json.each do |room_obj|
|
27
|
+
room = room_obj["Room"]
|
28
|
+
@rooms[room["id"]] = Room.new(room)
|
29
|
+
@name_index[room["name"]] = room["id"]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_by_name(name)
|
34
|
+
self[name_index[name]]
|
35
|
+
end
|
36
|
+
|
37
|
+
def file_data
|
38
|
+
if File.exists? @path
|
39
|
+
File.read(@path)
|
40
|
+
else
|
41
|
+
abort "./data does not exist; did you forget to specify a path to the data?"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Hipmost
|
5
|
+
module Hipchat
|
6
|
+
class UserRepository
|
7
|
+
attr_accessor :users
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def_delegators :@users, :size, :[], :select, :each
|
11
|
+
|
12
|
+
def self.load_from(path)
|
13
|
+
new(path).tap(&:load)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(path)
|
17
|
+
@path = Pathname.new(path).join("users.json")
|
18
|
+
@users = {}
|
19
|
+
@name_index = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def load(data = file_data)
|
23
|
+
json = JSON.load(data)
|
24
|
+
|
25
|
+
json.each do |user_obj|
|
26
|
+
user = user_obj["User"]
|
27
|
+
user_obj = User.new(user)
|
28
|
+
@users[user["id"]] = user_obj
|
29
|
+
@name_index[user_obj.username] = user["id"]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def file_data
|
34
|
+
File.read(@path)
|
35
|
+
end
|
36
|
+
|
37
|
+
class User
|
38
|
+
def initialize(attrs)
|
39
|
+
@id = attrs["id"]
|
40
|
+
@attrs = attrs
|
41
|
+
end
|
42
|
+
attr_reader :id, :attrs
|
43
|
+
|
44
|
+
def guest?
|
45
|
+
attrs["account_type"] == "guest"
|
46
|
+
end
|
47
|
+
|
48
|
+
def inactive?
|
49
|
+
attrs["is_deleted"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(method)
|
53
|
+
attrs[method.to_s]
|
54
|
+
end
|
55
|
+
|
56
|
+
def username
|
57
|
+
attrs["mention_name"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def email
|
61
|
+
attrs["email"] || "#{username}@orbitalimpact.com"
|
62
|
+
end
|
63
|
+
|
64
|
+
def teams
|
65
|
+
[]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_jsonl
|
69
|
+
%[{ "type": "user", "user": { "username": "#{username}", "email": "#{email}", "teams": #{teams.inspect} } }]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Hipmost
|
2
|
+
module Mattermost
|
3
|
+
class Channel
|
4
|
+
def self.from_hipchat(room, name:, team: )
|
5
|
+
new(name: name,
|
6
|
+
type: room.private? ? "P" : "O",
|
7
|
+
display_name: room.display_name,
|
8
|
+
header: room.topic,
|
9
|
+
team: team)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(name:, team:, display_name:, type:, header:)
|
13
|
+
@name = name.downcase.gsub(/\s/, "-")
|
14
|
+
@team = team
|
15
|
+
@display_name = display_name
|
16
|
+
@type = type
|
17
|
+
@header = header
|
18
|
+
end
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
def to_jsonl
|
22
|
+
%[{ "type": "channel", "channel": { "team": "#{@team.name}", "name": "#@name", "display_name": "#@display_name", "type": "#@type", "header": "#@header" } }]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Hipmost
|
2
|
+
module Mattermost
|
3
|
+
class Team
|
4
|
+
def initialize(display_name)
|
5
|
+
@display_name = display_name
|
6
|
+
end
|
7
|
+
attr_reader :display_name
|
8
|
+
|
9
|
+
def to_jsonl
|
10
|
+
%[{ "type": "team", "team": { "display_name": "#@display_name", "name": "#{name}", "type": "I", "description": "#@display_name", "allow_open_invite": false } }]
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
if display_name == "Orbital Impact"
|
15
|
+
"oi"
|
16
|
+
else
|
17
|
+
@display_name.gsub(/\s/, "-").downcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hipmost/room.rb
ADDED
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hipmost
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabriel Rios
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.10.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.10.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-doc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.8.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.8.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: method_source
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.8.2
|
97
|
+
description: Migrate your hipchat history to Mattermost
|
98
|
+
email:
|
99
|
+
- gabrielfalcaorios@gmail.com
|
100
|
+
executables:
|
101
|
+
- hipmost
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".travis.yml"
|
108
|
+
- CODE_OF_CONDUCT.md
|
109
|
+
- Gemfile
|
110
|
+
- Gemfile.lock
|
111
|
+
- HOWTO.md
|
112
|
+
- KNOWN-BUGS.md
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- bin/console
|
117
|
+
- bin/setup
|
118
|
+
- exe/hipmost
|
119
|
+
- hipmost.gemspec
|
120
|
+
- lib/hipmost.rb
|
121
|
+
- lib/hipmost/cmds.rb
|
122
|
+
- lib/hipmost/cmds/private.rb
|
123
|
+
- lib/hipmost/cmds/room.rb
|
124
|
+
- lib/hipmost/hipchat.rb
|
125
|
+
- lib/hipmost/hipchat/conversion.rb
|
126
|
+
- lib/hipmost/hipchat/post.rb
|
127
|
+
- lib/hipmost/hipchat/post_repository.rb
|
128
|
+
- lib/hipmost/hipchat/room.rb
|
129
|
+
- lib/hipmost/hipchat/room_repository.rb
|
130
|
+
- lib/hipmost/hipchat/user_repository.rb
|
131
|
+
- lib/hipmost/mattermost.rb
|
132
|
+
- lib/hipmost/mattermost/channel.rb
|
133
|
+
- lib/hipmost/mattermost/team.rb
|
134
|
+
- lib/hipmost/room.rb
|
135
|
+
- lib/hipmost/version.rb
|
136
|
+
homepage:
|
137
|
+
licenses:
|
138
|
+
- MIT
|
139
|
+
metadata: {}
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 2.7.7
|
157
|
+
signing_key:
|
158
|
+
specification_version: 4
|
159
|
+
summary: Migrate your hipchat history to Mattermost
|
160
|
+
test_files: []
|