# Projects Migrator
Migrates one or more ZenHub workspaces to a Github Project
Install
```
pip install projectsmigrator
```
Usage:
```
projectsmigrator https://github.com/orgs/myorg/myproj/1 -w="Workspace 1" --w="Workspace 2" -f="Estimate:Size"
```
# Details
```
Projects Migrator: Sync Zenhub workspaces into a single Github Project
Usage:
projectsmigrator PROJECT_URL [--workspace=NAME]... [--exclude=FIELD:PATTERN]... [--field=SRC:DST]... [options]
projectsmigrator (-h | --help)
Options:
-w=NAME, --workspace=NAME Name of a Zenhub workspace to import or none means include all.
-f=SRC:DST:CNV, --field=SRC:DST:CNV Transfer SRC field to DST field. "Text" as DST will add a checklist
for Epic and Blocking issues, and values into the text for other fields.
CNV "Scale" (match by rank), Exact or Closest (default).
One SRC can have many DST fields.
[Default: Estimate:Size:Scale, Priority:Priority, Pipeline:Status,
Linked Issues:Text, Epic:Text, Blocking:Text, Sprint:Iteration]
"SRC:" Will not transfer this field
-x=FIELD:PAT, --exclude=FIELD:PAT Don't include issues with field values that match the pattern
e.g. "Workspace:Private*", "Pipeline:Done".
--disable-remove Project items not found in any of the workspace won't be removed.
--github-token=<token> or use env var GITHUB_TOKEN.
--zenhub-token=<token> or use env var ZENHUB_TOKEN.
-h, --help Show this screen.
For zenhub the following fields are available.
- Estimate, Priority, Pipeline, Linked Issues, Epic, Blocking, Sprint, Position, Workspace
For Projects the fields are customisable. However the following are special
- Status: the column on the board
- Position: Id of the item to place after
- Text: turns the value into a checklist/list in the body
- Linked Pull Requests: changes to the body of each PR to link back to the Issue
```
or [Latest Usage](https://raw.githubusercontent.com/pretagov/projectsmigrator/main/projectsmigrator.py) or run
```
projectsmigrator --help
```
Note if you want to install a github checkout of the latest code:
```
python3 -m pip install -e .
```
## Project
The project must be a organisation ProjectV2 that already exists.
You should add the status and other field options you want manually first.
## Columns/Status
The default setting is ```-f="Pipeline:Status"```
The columns/status value won't be added automatically if it doesn't exist but instead
the issues will be placed in the closest existing column that matches.
The position with in that column is set using the default ```-f="Position:Position"```.
You can drop pipelines via ```--exclude=Pipeline:MyIgnoredPipelines*```
You can change the closest option match behaviour to an exact match via ```-f="Pipeline:Status:Exact"```
## Epics
The default setting is ```-f="Epic:Text"```
This will recreate Epics as checklists in the form
``` markdown
# Dependencies
## Epic
- [ ] #23
- [ ] otherorg/otherepo#42
```
While Projects doesn't have native support for Epics, this does seem to be what GitHub is leaning towards for the recommended way to
relate tickets togeather. When you view an issue that is a checklist elsewhere you will see this highlighted below the header and it
will include the headings "Dependencies Epic" so you can see why they are related.
One thing you lose is the ability to filter a board by Epic. If you want you can instead convert Epics as a field on the sub issue.
```-f="Epic:MyEpicField"```. This will set the value to the name of the epic.
Or you can both at the same time.
```-f="Epic:Text" -f="Epic:MyEpicField"```
GitHub doesn't currently support multivalued fields so there isn't another way to set links on the Epic issue itself via a field.
## Blocking/Blocked
The default setting is ```-f="Blocking:Text"```
An issue that is blocked will have a dependencies section added to it that lists the blocking issues
e.g.
``` markdown
# Dependencies
## Blocked by
- [ ] #23
- [ ] otherorg/otherepo#42
```
Issues that are blocking will remain unchaged.
## Linked Issues
The default setting is ```-f="Linked Issues:Text"```
Since zenhub has its own way to linking pull requests to issues this information is transfered by
modifying the PR to add text which then will use githubs automatic PR linking
e.g.
```
- [ ] fixes otherorg/otherepo#42
```
it won't do this for PR's in repos outside the org your project is in.
NOTE: Github linked PR's will automatically close the linked ticket once the PR is merged
to the main branch. This is different to zenhub. While you can't change this behavior, github
also doesn't move an item in your project automatically when it closes so this shouldn't change
your workflow too much.
## Workspace
You can specify which workspaces to merge using
```
--workspace="Workspace 1" --workspace="Workspace 2"
```
or merge all workspaces excluding some
```
--exclude="Workspace:Workspace 1*"
```
They are merged in the priorty listed. ie if fields/pipeline data differs, the first workspace data will be used
If no workspaces are specified then all workspaces will be merged in most recently used order
You can optionally add the workspace name the issue came from into a new custom field, but ff not enabled this information is not transfered. This can be enabled with ```-f="Workspace:MyWorkspaceField"```
## Priority
The default setting is ```-f="Priority:Priority"```
By default Projects has a custom field called Priority with more options than ZenHub's "High Priority" flag.
If this field exists we will migrate High Priority issues to the cloest word match.
## Estimate
The default setting is ```-f="Estimate:Size:Scale"```
The default Projects equivilent is "Size" which has a different scale to the default Zenhub story points.
This is mapped by rank (The ```:Scale``` suffix) rather than my word match. The 1st estimate option becomes the 1st size option. The last estimate option becomes the last
size option, and the rest are mapped proportionally. Currently there doesn't seem to be an api to read the options for Estimate from zenhub so it assumes the default storypoints.
if the value doesn't match one of those then it will pick the closest story point.
If you would like to match by closest then use ```-f="Estimate:Size:Closest"```. Closest is based on letters, not numerically.
## Sprints
You can enable transfer of sprint information with ```-f="Sprint:MySprintField"```.
If the field is a singleselect field it will pick the closest matching option.
## Authentication
You will need access to both the Zenhub graphql api and Github graphql api.
Once you have got auth tokens for both you can either
- put them environment variables ```ZENHUB_TOKEN``` and ```GITHUB_TOKEN```
- use ```--zenhub-token=<token>``` and ```--github-token=<token>``` command line options
For Github currently only Classic tokens appear to work. For this you will need ```repo```, ```admin:org``` and ```project``` permissions.
Fine grain personal access tokens don't currently appear to work.
# TODO
- [ ] Dry run mode
- [ ] verbose or less verbose mode. esp to help see pipline mapping more clearly
- [ ] CSV import
- [ ] Migrate projects -> project
- [ ] filtering issues by src field value
- [ ] blacklist certain field values
- [ ] include labels as a field target e.g. put workspace name as new label
- [ ] handle sync data from closed issues
- [ ] Handle zenhub only epics and issues
- [ ] zenhub Milestones - depricated and not possible to get from the graphql
- [ ] zenhub Release Reports?
- [ ] Handle different estimate scales
- [ ] Fix inability to add more options to the workspace field or removing adding fields.
- [ ] set a global default value. e.g. normal priority
# Contributing
PR's or tickets welcome
# Credits
Sponsored by PretaGov UK/AU https://pretagov.com
Inspired by [this manual process for migrating zenhub to projects](https://medium.com/collaborne-engineering/migrate-from-zenhub-to-github-projects-948d69adc17d)
but we were motiviated by
- the need for longer transition so needed some way to sync so we needed something more automated
- the need to merge many workspaces into a single project
- the idea that epics represented by checklists rather than fields would work better
- the suprise that no one had written a tool for this already and that others might find it useful.
Raw data
{
"_id": null,
"home_page": null,
"name": "projectsmigrator",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "github,project management,zenhub,migration,sync",
"author": null,
"author_email": "Dylan Jay <software@pretagov.com>",
"download_url": "https://files.pythonhosted.org/packages/67/e8/2f9ec838089cd9e65b9f6012540300b0bd4afb2746f8fc089d72ab237414/projectsmigrator-0.0.2.tar.gz",
"platform": null,
"description": "# Projects Migrator\n\nMigrates one or more ZenHub workspaces to a Github Project\n\nInstall\n\n```\npip install projectsmigrator\n```\n\nUsage:\n\n```\nprojectsmigrator https://github.com/orgs/myorg/myproj/1 -w=\"Workspace 1\" --w=\"Workspace 2\" -f=\"Estimate:Size\" \n```\n\n\n# Details\n\n```\nProjects Migrator: Sync Zenhub workspaces into a single Github Project\n\nUsage:\n projectsmigrator PROJECT_URL [--workspace=NAME]... [--exclude=FIELD:PATTERN]... [--field=SRC:DST]... [options]\n projectsmigrator (-h | --help)\n\nOptions:\n -w=NAME, --workspace=NAME Name of a Zenhub workspace to import or none means include all.\n -f=SRC:DST:CNV, --field=SRC:DST:CNV Transfer SRC field to DST field. \"Text\" as DST will add a checklist\n for Epic and Blocking issues, and values into the text for other fields.\n CNV \"Scale\" (match by rank), Exact or Closest (default).\n One SRC can have many DST fields.\n [Default: Estimate:Size:Scale, Priority:Priority, Pipeline:Status,\n Linked Issues:Text, Epic:Text, Blocking:Text, Sprint:Iteration]\n \"SRC:\" Will not transfer this field\n -x=FIELD:PAT, --exclude=FIELD:PAT Don't include issues with field values that match the pattern\n e.g. \"Workspace:Private*\", \"Pipeline:Done\".\n --disable-remove Project items not found in any of the workspace won't be removed.\n --github-token=<token> or use env var GITHUB_TOKEN.\n --zenhub-token=<token> or use env var ZENHUB_TOKEN.\n -h, --help Show this screen.\n\nFor zenhub the following fields are available.\n- Estimate, Priority, Pipeline, Linked Issues, Epic, Blocking, Sprint, Position, Workspace\n\nFor Projects the fields are customisable. However the following are special\n- Status: the column on the board\n- Position: Id of the item to place after\n- Text: turns the value into a checklist/list in the body\n- Linked Pull Requests: changes to the body of each PR to link back to the Issue \n```\nor [Latest Usage](https://raw.githubusercontent.com/pretagov/projectsmigrator/main/projectsmigrator.py) or run \n\n```\nprojectsmigrator --help\n```\n\n\nNote if you want to install a github checkout of the latest code:\n```\npython3 -m pip install -e .\n```\n\n## Project\n\nThe project must be a organisation ProjectV2 that already exists.\n\nYou should add the status and other field options you want manually first.\n\n\n## Columns/Status\nThe default setting is ```-f=\"Pipeline:Status\"```\n\nThe columns/status value won't be added automatically if it doesn't exist but instead\nthe issues will be placed in the closest existing column that matches.\n\nThe position with in that column is set using the default ```-f=\"Position:Position\"```.\n\nYou can drop pipelines via ```--exclude=Pipeline:MyIgnoredPipelines*```\n\nYou can change the closest option match behaviour to an exact match via ```-f=\"Pipeline:Status:Exact\"```\n\n## Epics\n\nThe default setting is ```-f=\"Epic:Text\"```\n\nThis will recreate Epics as checklists in the form\n\n``` markdown\n# Dependencies\n\n## Epic\n- [ ] #23\n- [ ] otherorg/otherepo#42\n```\n\nWhile Projects doesn't have native support for Epics, this does seem to be what GitHub is leaning towards for the recommended way to\nrelate tickets togeather. When you view an issue that is a checklist elsewhere you will see this highlighted below the header and it\nwill include the headings \"Dependencies Epic\" so you can see why they are related.\n\nOne thing you lose is the ability to filter a board by Epic. If you want you can instead convert Epics as a field on the sub issue.\n\n```-f=\"Epic:MyEpicField\"```. This will set the value to the name of the epic.\n\nOr you can both at the same time.\n\n```-f=\"Epic:Text\" -f=\"Epic:MyEpicField\"```\n\nGitHub doesn't currently support multivalued fields so there isn't another way to set links on the Epic issue itself via a field.\n\n## Blocking/Blocked\n\nThe default setting is ```-f=\"Blocking:Text\"```\n\nAn issue that is blocked will have a dependencies section added to it that lists the blocking issues\n\ne.g.\n``` markdown\n# Dependencies\n\n## Blocked by\n- [ ] #23\n- [ ] otherorg/otherepo#42\n```\n\nIssues that are blocking will remain unchaged.\n\n## Linked Issues\n\nThe default setting is ```-f=\"Linked Issues:Text\"```\n\nSince zenhub has its own way to linking pull requests to issues this information is transfered by\nmodifying the PR to add text which then will use githubs automatic PR linking\n\ne.g.\n```\n- [ ] fixes otherorg/otherepo#42\n```\n\nit won't do this for PR's in repos outside the org your project is in.\n\nNOTE: Github linked PR's will automatically close the linked ticket once the PR is merged\nto the main branch. This is different to zenhub. While you can't change this behavior, github\nalso doesn't move an item in your project automatically when it closes so this shouldn't change\nyour workflow too much.\n\n## Workspace\n\nYou can specify which workspaces to merge using \n```\n--workspace=\"Workspace 1\" --workspace=\"Workspace 2\"\n```\n\nor merge all workspaces excluding some\n```\n--exclude=\"Workspace:Workspace 1*\"\n```\n\nThey are merged in the priorty listed. ie if fields/pipeline data differs, the first workspace data will be used\n\nIf no workspaces are specified then all workspaces will be merged in most recently used order\n\nYou can optionally add the workspace name the issue came from into a new custom field, but ff not enabled this information is not transfered. This can be enabled with ```-f=\"Workspace:MyWorkspaceField\"```\n\n\n## Priority\n\nThe default setting is ```-f=\"Priority:Priority\"```\n\nBy default Projects has a custom field called Priority with more options than ZenHub's \"High Priority\" flag.\nIf this field exists we will migrate High Priority issues to the cloest word match.\n\n## Estimate\n\nThe default setting is ```-f=\"Estimate:Size:Scale\"```\n\nThe default Projects equivilent is \"Size\" which has a different scale to the default Zenhub story points.\n\nThis is mapped by rank (The ```:Scale``` suffix) rather than my word match. The 1st estimate option becomes the 1st size option. The last estimate option becomes the last\nsize option, and the rest are mapped proportionally. Currently there doesn't seem to be an api to read the options for Estimate from zenhub so it assumes the default storypoints.\nif the value doesn't match one of those then it will pick the closest story point.\n\nIf you would like to match by closest then use ```-f=\"Estimate:Size:Closest\"```. Closest is based on letters, not numerically.\n## Sprints\n\nYou can enable transfer of sprint information with ```-f=\"Sprint:MySprintField\"```.\n\nIf the field is a singleselect field it will pick the closest matching option.\n\n## Authentication\n\nYou will need access to both the Zenhub graphql api and Github graphql api.\n\nOnce you have got auth tokens for both you can either \n- put them environment variables ```ZENHUB_TOKEN``` and ```GITHUB_TOKEN```\n- use ```--zenhub-token=<token>``` and ```--github-token=<token>``` command line options\n\nFor Github currently only Classic tokens appear to work. For this you will need ```repo```, ```admin:org``` and ```project``` permissions.\nFine grain personal access tokens don't currently appear to work.\n \n# TODO\n\n- [ ] Dry run mode\n- [ ] verbose or less verbose mode. esp to help see pipline mapping more clearly\n- [ ] CSV import\n- [ ] Migrate projects -> project\n- [ ] filtering issues by src field value\n- [ ] blacklist certain field values\n- [ ] include labels as a field target e.g. put workspace name as new label\n- [ ] handle sync data from closed issues\n- [ ] Handle zenhub only epics and issues\n- [ ] zenhub Milestones - depricated and not possible to get from the graphql\n- [ ] zenhub Release Reports?\n- [ ] Handle different estimate scales\n- [ ] Fix inability to add more options to the workspace field or removing adding fields.\n- [ ] set a global default value. e.g. normal priority\n\n# Contributing\n\nPR's or tickets welcome\n\n# Credits\n\nSponsored by PretaGov UK/AU https://pretagov.com\n\nInspired by [this manual process for migrating zenhub to projects](https://medium.com/collaborne-engineering/migrate-from-zenhub-to-github-projects-948d69adc17d)\nbut we were motiviated by\n- the need for longer transition so needed some way to sync so we needed something more automated\n- the need to merge many workspaces into a single project\n- the idea that epics represented by checklists rather than fields would work better\n- the suprise that no one had written a tool for this already and that others might find it useful.\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Migrates one or more ZenHub workspaces to a Github Project",
"version": "0.0.2",
"project_urls": {
"Bug Tracker": "https://github.com/pretagov/projectsmigrator/issues",
"Homepage": "https://github.com/pretagov/projectsmigrator",
"changelog": "https://github.com/pretagov/projectsmigrator/blob/master/CHANGELOG.md"
},
"split_keywords": [
"github",
"project management",
"zenhub",
"migration",
"sync"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "33b94b166f07e5c97501fd8c29c4165261a956f6924f9546bdf81114b80f5aec",
"md5": "0a2826c6911e99d6f5c236bdfc0bb613",
"sha256": "564919b3e497347cb7bc0720350df0d448012b73829d6c7bce9e309b8aa76a21"
},
"downloads": -1,
"filename": "projectsmigrator-0.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0a2826c6911e99d6f5c236bdfc0bb613",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 16171,
"upload_time": "2023-11-13T15:42:34",
"upload_time_iso_8601": "2023-11-13T15:42:34.705959Z",
"url": "https://files.pythonhosted.org/packages/33/b9/4b166f07e5c97501fd8c29c4165261a956f6924f9546bdf81114b80f5aec/projectsmigrator-0.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "67e82f9ec838089cd9e65b9f6012540300b0bd4afb2746f8fc089d72ab237414",
"md5": "583432aa1ad0a77b979b24c62a679eb7",
"sha256": "ad69e373954955d1e6b2717e2d77b2b3a50ef6531b1130b5cbc3c91bdfdb2e91"
},
"downloads": -1,
"filename": "projectsmigrator-0.0.2.tar.gz",
"has_sig": false,
"md5_digest": "583432aa1ad0a77b979b24c62a679eb7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 19726,
"upload_time": "2023-11-13T15:42:38",
"upload_time_iso_8601": "2023-11-13T15:42:38.482570Z",
"url": "https://files.pythonhosted.org/packages/67/e8/2f9ec838089cd9e65b9f6012540300b0bd4afb2746f8fc089d72ab237414/projectsmigrator-0.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-11-13 15:42:38",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pretagov",
"github_project": "projectsmigrator",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "projectsmigrator"
}