-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(clean-install): add clean install feature #70
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -249,6 +249,11 @@ def get_parser(): | |||
help="markdown files or directories to upload to Confluence. Empty for stdin", | ||||
nargs="*", | ||||
) | ||||
parser.add_argument( | ||||
"--clean-install", | ||||
action="store_true", | ||||
help="Deletes all pages in confluence with the specified parent that is not the file or in the folder specified. If no parent then parent will be set to the space homepage", | ||||
) | ||||
|
||||
return parser | ||||
|
||||
|
@@ -308,6 +313,11 @@ def main(): | |||
) | ||||
sys.exit(1) | ||||
|
||||
if args.parent_title is not None and args.parent_id is not None: | ||||
error_console.log( | ||||
":x: Parent Title and Parent page ID cannot both be specified on the command line " | ||||
) | ||||
|
||||
pages_to_upload = collect_pages_to_upload(args) | ||||
|
||||
page_title_counts = Counter([page.title for page in pages_to_upload]) | ||||
|
@@ -347,6 +357,10 @@ def main(): | |||
) | ||||
sys.exit(1) | ||||
|
||||
if args.clean_install: | ||||
# This runs even though that there are no files found, i.e. len(pages_to_upload) == 0 | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should it? I'm curious if this was more of an explicit choice or a TODO. It's funny though: I never considered the edge case where nothing would be found at all. I should add a test for that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was actually an explicit choice from the initial thoughts of having it being a "complete clean slate flag" that removed everything before re-uploading the documentation. Considering that it was changed to be the diff between AS/IS and TO/BE step, a much less intrusive way of making this work, would be moving this post uploading the files and then making this part of a "clean-up step" which could be presented in the |
||||
perform_clean_install(confluence, pages_to_upload, args) | ||||
|
||||
preface_markup = "" | ||||
if args.preface_markdown: | ||||
preface_markup = md2cf.document.parse_page([args.preface_markdown]).body | ||||
|
@@ -722,6 +736,29 @@ def collect_pages_to_upload(args): | |||
|
||||
return pages_to_upload | ||||
|
||||
def perform_clean_install(confluence, pages_to_upload, args): | ||||
page_descendants = get_page_descendants(confluence, args) | ||||
|
||||
pages_to_purge = [page for page in page_descendants if page['title'] not in [p.title for p in pages_to_upload]] | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually pretty implicit, so it's not surprising you got tripped up, but the title for a page can change all the way up to this function call later on, unfortunately: Line 389 in e842bfd
That would be another reason for the cleanup to potentially be done after uploading everything (and for me to add a comment mentioning the footgun). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree - the functionality should be moved! |
||||
|
||||
if not args.dry_run: | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick/suggestion: it would be cleaner to only pass the arguments needed by the function. In this case, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree 🙂 On a side note_ I also wanted to give If you'd like, I might work on that on another branch, when this feature gets ready for a merge / merged 🙂. |
||||
console.log("Number of pages set to be purged before deployment: ", len(pages_to_purge)) | ||||
for page_to_purge in pages_to_purge: | ||||
confluence.purge_page(page_to_purge) | ||||
console.log("-", page_to_purge.title, "- has been purged") | ||||
else: | ||||
console.log("Number of pages set to be purged before deployment: ", len(pages_to_purge)) | ||||
console.log("Pages to be purged: ", ", ".join([page['title'] for page in pages_to_purge])) | ||||
|
||||
def get_page_descendants(confluence, args): | ||||
if args.parent_title is not None: | ||||
return confluence.get_content_descendant( | ||||
title=args.parent_title, space_key=args.space) | ||||
elif args.parent_id is not None: | ||||
return confluence.get_content_descendant( | ||||
page_id=args.parent_id, space_key=args.space) | ||||
else: | ||||
return confluence.get_content_descendant(space_key=args.space) | ||||
|
||||
if __name__ == "__main__": | ||||
main() |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -75,6 +75,9 @@ def _post(self, path, **kwargs): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def _put(self, path, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self._request("PUT", path, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def _delete(self, path, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self.api.request("DELETE", urljoin(self.host, path), **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I think you copied the wrong function here. This should be
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah.. 🙈 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_page( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -184,6 +187,7 @@ def update_page( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
update_message=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
labels=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
minor_edit=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status=None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
update_structure = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"version": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -208,6 +212,13 @@ def update_page( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"labels": [{"name": label, "prefix": "global"} for label in labels] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if status is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ['current', 'trashed', 'deleted', 'historical', 'draft'].count(status) > 0: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Pythonic way to do this is actually
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I live to learn, and today was some python! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
update_structure["status"] = status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raise ValueError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Status has to be either current, trashed, deleted, historical or draft") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self._put(f"content/{page.id}", json=update_structure) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_attachment(self, confluence_page, name): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -256,3 +267,86 @@ def get_space(self, space, additional_expansions=None): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if additional_expansions is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params = {"expand": ",".join(additional_expansions)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self._get(f"space/{space}", params=params) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_content_descendant( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
space_key=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page_id=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content_type="page", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
additional_expansions=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Gets content descendant | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title (str): the title for the page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
space_key (str): the Confluence space for the page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content_type (str): Content type. Default value: page. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Valid values: page, blogpost. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page_id (str or int): the ID of the page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
additional_expansions (list of str): Additional expansions that should be | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
made when calling the api | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The response from the API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if additional_expansions is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params = {"expand": ",".join(additional_expansions)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if page_id is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response = self._get( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
f"content/{page_id}/descendant/{content_type}", params=params) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
results = response.results | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while (hasattr(response, '_links') and hasattr(response._links, 'next')): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response = self._get(response._links.next.replace( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'/rest/api/', ''), params=params) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
results.extend(response.results) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return results | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif title is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params = {"title": title, "type": content_type} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if space_key is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params["spaceKey"] = space_key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response = self._get("content", params=params) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# A search by title/space doesn't return full page objects, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# and since we don't support expansion in this implementation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# just yet, we just retrieve the "full" page data using the page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# ID for the first search result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self.get_content_descendant( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page_id=response.results[0].id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
additional_expansions=additional_expansions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except IndexError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif space_key is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
space_homepage_id = self._get( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
f"space/{space_key}")._expandable.homepage.replace('/rest/api/content/', '') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self.get_content_descendant(page_id=space_homepage_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raise ValueError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"At least one of title or page_id or space_key must not be None") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def purge_page( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page=None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Delete page in a space | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page (page): the page to be purged | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The response from the API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if page is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
params = {"status": "trashed"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page_from_get = self.get_page(page_id=page.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.update_page(page=page_from_get, body="", status="trashed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return self._delete(f"content/{page.id}", params=params) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raise ValueError("Page cannot be None") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+332
to
+352
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the parameter is not optional, I would just remove the
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Less code is better indeed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually already ensured by those arguments being part of a mutually exclusive group :)
md2cf/md2cf/__main__.py
Lines 84 to 105 in e842bfd