From 4b74a8814dd69b1959bf384b8ddd29fe7df548f3 Mon Sep 17 00:00:00 2001 From: Martin Olsen Date: Thu, 20 May 2021 13:18:44 +0200 Subject: [PATCH 1/4] replciate how-to steps using dockerr --- Dockerfile | 44 +++++++++ README.md | 260 +++++++++++++++++++++++++++++------------------------ 2 files changed, 186 insertions(+), 118 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c7f33ec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +# This dockerfile replicates the "how to" steps in this guide: +# https://github.com/JPustkuchen/active-collab-to-jira-migrator#how + +FROM php:7.3.28-buster + +# ---------- Install requirements ---------- # +RUN apt-get update && apt-get install -y wget git && \ + # cleanup to reduce image size + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Install composer +RUN wget -O composer-setup.php https://getcomposer.org/installer && \ + php composer-setup.php --install-dir=/usr/local/bin --filename=composer && \ + composer self-update + + +# ---------- Set up non-root user ---------- # +ENV USER=migrator +RUN useradd --create-home ${USER} -s /bin/bash && echo "alias ll='ls -alF'" >> /home/${USER}/.bashrc + + +# ---------- Set up application ---------- # +ARG SECRET=mysecret +ARG ACTIVE_COLLAB_URL=https://app.activecollab.com/123456/ +ARG MEMORY_LIMIT=4096M + +# copy repo files in to docker +COPY . /home/${USER}/active-collab-to-jira-migrator +RUN chown -R ${USER}:${USER} /home/${USER} + +# switch to non-root user +WORKDIR /home/${USER}/active-collab-to-jira-migrator +USER ${USER} + +# set up config +RUN mv config/EXAMPLE.config.php config/config.php && \ + mv config/EXAMPLE.modifications.php config/modifications.php && \ + sed -i "s#\$acUrl = 'https://ac.mycompany.com/';#\$acUrl = '${ACTIVE_COLLAB_URL}';#g" config/config.php && \ + sed -i "s#// \$secret = urlencode('');#\$secret = urlencode('${SECRET}');#g" config/config.php && \ + sed -i "s#ini_set('memory_limit', '4GB');#ini_set('memory_limit', '${MEMORY_LIMIT}');#g" config/config.php && \ + composer install + + +ENTRYPOINT ["php", "-S", "0.0.0.0:8080", "-t", "app/"] diff --git a/README.md b/README.md index 76d1661..557a554 100755 --- a/README.md +++ b/README.md @@ -1,118 +1,142 @@ -![PHP Composer](https://github.com/JPustkuchen/active-collab-to-jira-migrator/workflows/PHP%20Composer/badge.svg?branch=master) - -# ActiveCollab to Jira® Migrator - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.* - -## Important notes -If you're happy with this project, please help to improve it by solving issues, -writing pull-requests and other improvements. -Always keep in mind, what you get for free here and give back. - -We do NOT suggest anyone to move away from the wonderful [ActiveCollab](https://activecollab.com/) which we loved for nealy a decade -and still love. Anyway structures changed for us and ActiveCollab wasn't the right tool for us anymore. -But it might be different for you and [ActiveCollab](https://activecollab.com/) is still a very very good choice & wonderful software with a wonderful team. -THANK YOU VERY MUCH @ActiveCollab Team for all your great work! - -If you need to move from ActiveCollab to Jira®, this tool may help you to do that and keep most of your assets. - -## Dependencies? -- PHP >=7.3 -- Composer -- Jira® Server >= 8.x (tested with 8.10.0) -- ActiveCollab >= 5. (tested with ActiveCollab 6.2.135) - -## What? -ActiveCollabToJiraMigrator provides an export tool with UI, based on PHP and the [ActiveCollab Feather SDK](https://github.com/activecollab/activecollab-feather-sdk) using the [ActiveCollab SDK](https://developers.activecollab.com/api-documentation/) to create imports for Jira® based on the (JSON import functionality)[https://confluence.atlassian.com/adminjiraserver089/importing-data-from-json-1005346888.html]. - -### Exported / importable entities: -Most of these are only partially supported, because the systems structure is different: -- User => Users -- Project => Project -- Task => Task -- Subtask => Sub-task -- Comment => Comment -- Task attachment => Task attachmant -- Tracked time => Worklog - -#### Not supported for example: -- Companies -- Task Lists / Milestones (migrated as label) -- Comment files / attachments -- Reactions -- Notes -- Discussions -- Receipts -- ... - -## How? -0. Read this project documentation and code to understand what it does and how - it works. -1. Copy to your webserver and set `/app` as DocumentRoot for your VirtualHost. - like `thisactivecollabtojiramigrator.example.com` (Example) -2. Run `composer install` on the base directory via bash. -3. Copy `config/EXAMPLE.config.php` to `config/config.php` -4. Set all values in `config/config.php`, especially the _secret_ - *Keep your secret safe and secure!* -5. Open https://thisactivecollabtojiramigrator.example.com/index.php?secret=_secret_ - (Your secret from config.php) in your browser. You should see a form. -6. Enter your ActiveCollab Admin Credentials, set your offsets and limits (to allow splitting the export) -7. Export and check the results carefully - -## Tips & Tricks -- Enable debug mode in config.php to see details and check for errors - -## Important notes & limitations: -!! Due to limitations in Jira Import some ActiveCollab entities are not migrated at all. See below. !! -If you wish to add these functionalities, you may help to develop Export/JiraRestExporter which uses the Jira® API instead of the import. -Anyway some structural differences will never be 1:1 migratable like expenses, project expenses, non-task time records and others. -Here you'll need other workarounds or JiraApps which allow API-based creation. - -!! Futhermore there are properties / settings which are not supported by Jira® Import which may also lead to unwanted access elevation. See below !! - -## !! Important !! -1. The Jira® importer doesn't provide a sandbox environment. Data may be inconsistent if import fails. -So **TAKE BACKUPS** to be able to restore the clean state before the import! -2. Jira® has an issue with "External issue ID", which occurs if you split your import, see https://jira.atlassian.com/browse/JRASERVER-64477 - so you should try the workaround mentioned in this comment: https://jira.atlassian.com/browse/JRASERVER-64477?focusedCommentId=2274882&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-2274882 by Joe Harmon: -"There is another workaround that I found. The external issue ID is created per project that you import. The first time that I import it, I changed it to a global fields for any project. After that, after I import it doesn't duplicate the field anymore." and set the custom field global after the first import. -Due to this issue it might also be a good idea to create only one large import file. - -### No processing implemented for: -- Project expenses -- Project time records -- Project task lists -- Project notes -- Project files -- Task expenses -- Comment attachments -These entities are not migrated at all. - -Furthermore the following properties / settings are not supported: -- Project roles -- Attachments hidden from client - -# References: - -## ActiveCollab API and SDK: -- https://developers.activecollab.com/api-documentation/ -- https://github.com/activecollab/activecollab-feather-sdk - -## Jira JSON Import: -- https://confluence.atlassian.com/adminjiraserver089/importing-data-from-json-1005346888.html - -## Additional resources -- The Jira JSON import documentation doesn't seem to list all available fields. So if you need further fields, you should follow this documentation (https://confluence.atlassian.com/jirakb/how-to-enable-json-export-in-jira-server-723158427.html) to -enable JSON export in tasks and export some tasks to see the exported format, which seems to match the import format. - -# Copyrights / Trademarks -All product names, logos, and brands are property of their respective owners. -All company, product and service names used are for identification purposes only. -Use of these names, logos, and brands does not imply endorsement. -- [ActiveCollab](https://activecollab.com/) -- [Atlassian®, Jira® and Confluence® are registered trademarks of Atlassian](https://www.atlassian.com/legal/trademark) +![PHP Composer](https://github.com/JPustkuchen/active-collab-to-jira-migrator/workflows/PHP%20Composer/badge.svg?branch=master) + +# ActiveCollab to Jira® Migrator + +*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.* + +## Important notes +If you're happy with this project, please help to improve it by solving issues, +writing pull-requests and other improvements. +Always keep in mind, what you get for free here and give back. + +We do NOT suggest anyone to move away from the wonderful [ActiveCollab](https://activecollab.com/) which we loved for nealy a decade +and still love. Anyway structures changed for us and ActiveCollab wasn't the right tool for us anymore. +But it might be different for you and [ActiveCollab](https://activecollab.com/) is still a very very good choice & wonderful software with a wonderful team. +THANK YOU VERY MUCH @ActiveCollab Team for all your great work! + +If you need to move from ActiveCollab to Jira®, this tool may help you to do that and keep most of your assets. + +## Dependencies? +- PHP >=7.3 +- Composer +- Jira® Server >= 8.x (tested with 8.10.0) +- ActiveCollab >= 5. (tested with ActiveCollab 6.2.135 and cloud) + +## What? +ActiveCollabToJiraMigrator provides an export tool with UI, based on PHP and the [ActiveCollab Feather SDK](https://github.com/activecollab/activecollab-feather-sdk) using the [ActiveCollab SDK](https://developers.activecollab.com/api-documentation/) to create imports for Jira® based on the (JSON import functionality)[https://confluence.atlassian.com/adminjiraserver089/importing-data-from-json-1005346888.html]. + +### Exported / importable entities: +Most of these are only partially supported, because the systems structure is different: +- User => Users +- Project => Project +- Task => Task +- Subtask => Sub-task +- Comment => Comment +- Task attachment => Task attachmant +- Tracked time => Worklog + +#### Not supported for example: +- Companies +- Task Lists / Milestones (migrated as label) +- Comment files / attachments +- Reactions +- Notes +- Discussions +- Receipts +- ... + +## How? +0. Read this project documentation and code to understand what it does and how + it works. +1. Copy to your webserver and set `/app` as DocumentRoot for your VirtualHost. + like `thisactivecollabtojiramigrator.example.com` (Example) +2. Run `composer install` on the base directory via bash. +3. Copy `config/EXAMPLE.config.php` to `config/config.php` +4. Set all values in `config/config.php`, especially the _secret_ + *Keep your secret safe and secure!* +5. Open https://thisactivecollabtojiramigrator.example.com/index.php?secret=_secret_ + (Your secret from config.php) in your browser. You should see a form. +6. Enter your ActiveCollab Admin Credentials, set your offsets and limits (to allow splitting the export) +7. Export and check the results carefully + +###*Alternative (Docker):* +*Tested locally running linux. Docker is required, see https://docs.docker.com/get-docker/* + +Read the *how*-steps above and then take a look at the provided `Dockerfile` to understand if this option suits you. +This option replaces step 1-5 above. + +Build docker image: + ```bash + docker build . --rm --tag=active-collab-to-jira-migrator:latest \ + --build-arg SECRET=mysuperduperstrongsecret \ + --build-arg ACTIVE_COLLAB_URL=https://app.activecollab.com/123456/ \ + --build-arg MEMORY_LIMIT=8192M + ``` +Start php service: + ```bash + docker run -it --rm -p 8080:8080 --name=migrateservice active-collab-to-jira-migrator:latest + ``` + +* To open a bash shell inside the docker: `docker exec -it migrateservice /bin/bash` +* to stop the running php server: `docker kill migrateservice` + +Open your browser and go to http://localhost:8080/?secret=mysuperduperstrongsecret + + +## Tips & Tricks +- Enable debug mode in config.php to see details and check for errors + +## Important notes & limitations: +!! Due to limitations in Jira Import some ActiveCollab entities are not migrated at all. See below. !! +If you wish to add these functionalities, you may help to develop Export/JiraRestExporter which uses the Jira® API instead of the import. +Anyway some structural differences will never be 1:1 migratable like expenses, project expenses, non-task time records and others. +Here you'll need other workarounds or JiraApps which allow API-based creation. + +!! Futhermore there are properties / settings which are not supported by Jira® Import which may also lead to unwanted access elevation. See below !! + +## !! Important !! +1. The Jira® importer doesn't provide a sandbox environment. Data may be inconsistent if import fails. +So **TAKE BACKUPS** to be able to restore the clean state before the import! +2. Jira® has an issue with "External issue ID", which occurs if you split your import, see https://jira.atlassian.com/browse/JRASERVER-64477 - so you should try the workaround mentioned in this comment: https://jira.atlassian.com/browse/JRASERVER-64477?focusedCommentId=2274882&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-2274882 by Joe Harmon: +"There is another workaround that I found. The external issue ID is created per project that you import. The first time that I import it, I changed it to a global fields for any project. After that, after I import it doesn't duplicate the field anymore." and set the custom field global after the first import. +Due to this issue it might also be a good idea to create only one large import file. + +### No processing implemented for: +- Project expenses +- Project time records +- Project task lists +- Project notes +- Project files +- Task expenses +- Comment attachments +These entities are not migrated at all. + +Furthermore the following properties / settings are not supported: +- Project roles +- Attachments hidden from client + +# References: + +## ActiveCollab API and SDK: +- https://developers.activecollab.com/api-documentation/ +- https://github.com/activecollab/activecollab-feather-sdk + +## Jira JSON Import: +- https://confluence.atlassian.com/adminjiraserver089/importing-data-from-json-1005346888.html + +## Additional resources +- The Jira JSON import documentation doesn't seem to list all available fields. So if you need further fields, you should follow this documentation (https://confluence.atlassian.com/jirakb/how-to-enable-json-export-in-jira-server-723158427.html) to +enable JSON export in tasks and export some tasks to see the exported format, which seems to match the import format. + +# Copyrights / Trademarks +All product names, logos, and brands are property of their respective owners. +All company, product and service names used are for identification purposes only. +Use of these names, logos, and brands does not imply endorsement. +- [ActiveCollab](https://activecollab.com/) +- [Atlassian®, Jira® and Confluence® are registered trademarks of Atlassian](https://www.atlassian.com/legal/trademark) From 264c0601453fee4afc953c48ebcb76f08222bf6c Mon Sep 17 00:00:00 2001 From: Martin Olsen Date: Thu, 20 May 2021 13:19:11 +0200 Subject: [PATCH 2/4] added cloud support --- app/form.html | 7 +++++++ app/index.php | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/app/form.html b/app/form.html index 359b951..95b1052 100644 --- a/app/form.html +++ b/app/form.html @@ -31,6 +31,13 @@

ActiveCollab to Jira Migration

Advanced options +

+ Self hosted or cloud version of ActiveCollab? + +
+ +
+
Project import
diff --git a/app/index.php b/app/index.php index ccb83ac..57c7d7a 100755 --- a/app/index.php +++ b/app/index.php @@ -6,6 +6,7 @@ use ActiveCollab\SDK\Client; use ActiveCollab\SDK\TokenInterface; +use ActiveCollab\SDK\Authenticator\Cloud; use ActiveCollab\SDK\Authenticator\SelfHosted; use ActiveCollab\SDK\Exceptions\Authentication; use ActiveCollabToJiraMigrator\Export\JiraJsonExporter; @@ -36,16 +37,34 @@ } try { - // Construct a self-hosted authenticator. Last parameter is URL - // where your Active Collab. - $authenticator = new SelfHosted('ActiveCollab to Jira Migration Export', - 'ActiveCollab to Jira Migration Export', - $_username, - $_password, - $acUrl); - - // Issue a token. - $token = $authenticator->issueToken(); + $_acTypeRadio = filter_input(INPUT_POST, 'acType', FILTER_SANITIZE_STRING); + if($_acTypeRadio == 'cloud'){ + // Construct a cloud authenticator. + $authenticator = new Cloud('ActiveCollab to Jira Migration Export', + 'ActiveCollab to Jira Migration Export', + $_username, + $_password); + + // Get user ID + $accounts = $authenticator->getAccounts(); + // TODO: support multiple ActiveCollab accounts, reset will get first element in array of accounts + $account = reset($accounts)['id']; + + // Issue a token. + $token = $authenticator->issueToken($account); + } elseif($_acTypeRadio == 'selfhosted'){ + // Construct a self-hosted authenticator. Last parameter is URL where your Active Collab. + $authenticator = new SelfHosted('ActiveCollab to Jira Migration Export', + 'ActiveCollab to Jira Migration Export', + $_username, + $_password, + $acUrl); + + // Issue a token. + $token = $authenticator->issueToken(); + } else { + throw new \Exception('Unknown ActiveCollab type, you should select cloud or self hosted'); + } if ($token instanceof TokenInterface) { // Login successful! $acUrl = $token->getUrl(); From 0e84bf325e9cb68cf440b1d114542a8ae1fd0bbe Mon Sep 17 00:00:00 2001 From: Martin Olsen Date: Thu, 20 May 2021 13:31:25 +0200 Subject: [PATCH 3/4] Removed unused package --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c7f33ec..59246f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM php:7.3.28-buster # ---------- Install requirements ---------- # -RUN apt-get update && apt-get install -y wget git && \ +RUN apt-get update && apt-get install -y wget && \ # cleanup to reduce image size apt-get clean && rm -rf /var/lib/apt/lists/* From b60352b6bd3f164bc71b7fea8cd814dcff98a52c Mon Sep 17 00:00:00 2001 From: Martin Olsen Date: Thu, 20 May 2021 13:47:36 +0200 Subject: [PATCH 4/4] re-added git, it was in use --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 59246f4..c7f33ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM php:7.3.28-buster # ---------- Install requirements ---------- # -RUN apt-get update && apt-get install -y wget && \ +RUN apt-get update && apt-get install -y wget git && \ # cleanup to reduce image size apt-get clean && rm -rf /var/lib/apt/lists/*