def strings(self, no_space=False): """ checks if a configuration is a collection of strings After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a collection of strings. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`) or is an empty collection, this method will have no effect. Args: no_space (optional): whether or not all string values cannot contain any spaces (default: False) Returns: the validator instance """ value = self._value() if value is not None: if not (isinstance(value, (list, set, tuple)) and all(isinstance(entry, basestring) for entry in value)): raise ConfluenceConfigurationError( '%s is not a collection of strings' % self.key) if no_space: for entry in value: if ' ' in entry: raise ConfluenceConfigurationError( '%s has an entry containing a space' % self.key) return self
def docnames(self): """ checks if a configuration is a collection of valid docnames After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a collection of valid docnames. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`) or is an empty collection, this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if not (isinstance(value, (list, set, tuple)) or not all(isinstance(label, basestring) for label in value)): raise ConfluenceConfigurationError( '%s is not a collection of filenames' % self.key) for docname in value: if not any( os.path.isfile( os.path.join(self.env.srcdir, docname + suffix)) for suffix in self.config.source_suffix): raise ConfluenceConfigurationError( '%s is missing document %s' % (self.key, docname)) return self
def string_or_strings(self): """ checks if a configuration is a string or collection of strings After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a string or collection of strings. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`) or is an empty collection, this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if isinstance(value, (list, set, tuple)): if not all(isinstance(entry, basestring) for entry in value): raise ConfluenceConfigurationError( '%s is not a collection of strings' % self.key) elif not isinstance(value, basestring): raise ConfluenceConfigurationError( '%s is not a string or collection of strings' % self.key) return self
def int_(self, positive=False): """ checks if a configuration is an integer After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is an integer. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Args: positive (optional): whether or not the integer value must be a positive value (default: False) Returns: the validator instance """ value = self._value() if value is not None: if positive: if not isinstance(value, int) or value <= 0: raise ConfluenceConfigurationError( '%s is not a positive integer' % self.key) elif not isinstance(value, int) or value < 0: raise ConfluenceConfigurationError( '%s is not a non-negative integer' % self.key) return self
def getBasePageId(self): base_page_id = None if not self.parent_name: return base_page_id rsp = self.rest_client.get('content', { 'type': 'page', 'spaceKey': self.space_name, 'title': self.parent_name, 'status': 'current' }) if rsp['size'] == 0: raise ConfluenceConfigurationError("""Configured parent """ """page name do not exist.""") page = rsp['results'][0] if self.parent_id and page['id'] != str(self.parent_id): raise ConfluenceConfigurationError("""Configured parent """ """page ID and name do not match.""") base_page_id = page['id'] self._name_cache[base_page_id] = self.parent_name if not base_page_id and self.parent_id: raise ConfluenceConfigurationError("""Unable to find the """ """parent page matching the ID or name provided.""") return base_page_id
def bool(self): """ checks if a configuration is a boolean After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a boolean. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if isinstance(value, basestring): try: str2bool(value) except ValueError: raise ConfluenceConfigurationError( '%s is not a boolean string' % self.key) elif not isinstance(value, bool) and not isinstance(value, int): raise ConfluenceConfigurationError('%s is not a boolean type' % self.key) return self
def docnames_from_file(self): """ checks if a configuration is a collection of valid docnames from a file After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a collection of valid docnames found within the contents of a valid file. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if not isinstance(value, basestring) or not os.path.isfile( os.path.join(self.env.srcdir, value)): raise ConfluenceConfigurationError('%s is not a file' % self.key) docnames = extract_strings_from_file(value) for docname in docnames: if not any( os.path.isfile( os.path.join(self.env.srcdir, docname + suffix)) for suffix in self.config.source_suffix): raise ConfluenceConfigurationError( '%s is missing document %s' % (self.key, docname)) return self
def matching(self, *expected): """ checks if a configuration matches any of the expected arguments After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key matches one of the provided expected arguments. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Args: *expected: valid entries for a configuration to check against Returns: the validator instance """ value = self._value() if value is not None and value not in expected: raise ConfluenceConfigurationError( '%s does not match expected values' % self.key) return self
def string(self, permit_empty=False): """ checks if a configuration is a string After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a string. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Args: permit_empty (optional): whether or not all an empty string of this value is considered to be a set value Returns: the validator instance """ value = self._value(permit_empty=True) if value is not None and not isinstance(value, basestring): raise ConfluenceConfigurationError( '%s is not a string' % self.key) return self
def dict_str_str(self): """ checks if a configuration is a dictionary (str, str) After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a dictionary type with string keys and values. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`) or is an empty dictionary, this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if not isinstance(value, dict) or not all( isinstance(k, basestring) and isinstance(v, basestring) for k, v in value.items()): raise ConfluenceConfigurationError( '%s is not a dictionary of strings' % self.key) return self
def get_base_page_id(self): base_page_id = None if not self.parent_ref: return base_page_id if isinstance(self.parent_ref, int): base_page_id, page = self.get_page_by_id(self.parent_ref) if not page: raise ConfluenceConfigurationError( '''Configured parent page identifier does not exist.''') return base_page_id rsp = self.rest_client.get( 'content', { 'type': 'page', 'spaceKey': self.space_key, 'title': self.parent_ref, 'status': 'current' }) if rsp['size'] == 0: raise ConfluenceConfigurationError( '''Configured parent page name does not exist.''') page = rsp['results'][0] if self.parent_id and page['id'] != str(self.parent_id): raise ConfluenceConfigurationError( """Configured parent """ """page ID and name do not match.""") base_page_id = page['id'] self._name_cache[base_page_id] = self.parent_ref if not base_page_id and self.parent_id: raise ConfluenceConfigurationError( """Unable to find the """ """parent page matching the ID or name provided.""") return base_page_id
def process_ask_configs(config): """ process any ask-based configurations for a user A series of asking configurations can be set in a configuration, such as asking for a password on a command line. This call will help process through the available questions and populate a final configuration state for the builder/publisher to use. Args: config: the configuration to check/update """ if config.confluence_ask_user: print('(request to accept username from interactive session)') print(' Instance: ' + config.confluence_server_url) default_user = config.confluence_server_user u_str = '' if default_user: u_str = ' [{}]'.format(default_user) input_ = compat.compat_input target_user = input_(' User{}: '.format(u_str)) or default_user if not target_user: raise ConfluenceConfigurationError('no user provided') config.confluence_server_user = target_user if config.confluence_ask_password: print('(request to accept password from interactive session)') if not config.confluence_ask_user: print(' Instance: ' + config.confluence_server_url) print(' User: '******' Password: '******'') if not config.confluence_server_pass: raise ConfluenceConfigurationError('no password provided')
def callable_(self): """ checks if a configuration is a callable After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a callable type. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None and not callable(value): raise ConfluenceConfigurationError('%s is not a callable' % self.key) return self
def file(self): """ checks if a configuration is a valid file After an instance has been set a configuration key (via `conf`), this method can be used to check if the value (if any) configured with this key is a valid file. If not, an `ConfluenceConfigurationError` exception will be thrown. In the event that the configuration is not set (e.g. a value of `None`), this method will have no effect. Returns: the validator instance """ value = self._value() if value is not None: if not isinstance(value, basestring) or not os.path.isfile( os.path.join(self.env.srcdir, value)): raise ConfluenceConfigurationError('%s is not a file' % self.key) return self
def validate_configuration(builder): """ validate a builder's configuration state This call will check if the provided builder's configuration has any issues with the existing configuration. For errors in the existing configuration, an `ConfluenceConfigurationError` exception will be thrown. In addition to errors, this call will also generate warning messages on other configuration issues such as deprecated configurations. Args: builder: the builder state to validate a configuration on """ config = builder.config env = builder.app.env validator = ConfigurationValidation(builder) # ################################################################## # confluence_add_secnumbers validator.conf('confluence_add_secnumbers') \ .bool() # ################################################################## # confluence_additional_mime_types validator.conf('confluence_additional_mime_types') \ .strings(no_space=True) # ################################################################## # confluence_adv_aggressive_search validator.conf('confluence_adv_aggressive_search') \ .bool() # ################################################################## # confluence_adv_permit_raw_html validator.conf('confluence_adv_permit_raw_html') \ .bool() # ################################################################## # confluence_adv_trace_data validator.conf('confluence_adv_trace_data') \ .bool() # ################################################################## # confluence_adv_writer_no_section_cap validator.conf('confluence_adv_writer_no_section_cap') \ .bool() # ################################################################## # confluence_append_labels validator.conf('confluence_append_labels') \ .bool() # ################################################################## # confluence_ask_password validator.conf('confluence_ask_password') \ .bool() # ################################################################## # confluence_ask_user validator.conf('confluence_ask_user') \ .bool() # ################################################################## # confluence_asset_force_standalone validator.conf('confluence_asset_force_standalone') \ .bool() # ################################################################## # confluence_asset_override validator.conf('confluence_asset_override') \ .bool() # ################################################################## validator.conf('confluence_ca_cert') \ .path() # ################################################################## if config.confluence_client_cert is not None: client_cert = config.confluence_client_cert if isinstance(client_cert, tuple): cert_files = client_cert else: cert_files = (client_cert, None) if len(cert_files) != 2: raise ConfluenceConfigurationError('''\ confluence_client_cert is not a 2-tuple The option 'confluence_client_cert' has been provided but there are too many values. The client certificate can either be a file/path which defines a certificate/key-pair, or a 2-tuple of the certificate and key. ''') for cert in cert_files: if cert and not os.path.isfile(os.path.join(env.srcdir, cert)): raise ConfluenceConfigurationError('''\ confluence_ca_cert missing certificate file The option 'confluence_client_cert' has been provided to find a client certificate file from a relative location, but the certificate could not be found. Ensure the following file exists: {file} '''.format(file=cert)) # ################################################################## # confluence_client_cert_pass validator.conf('confluence_client_cert_pass') \ .string() # ################################################################## # confluence_default_alignment try: validator.conf('confluence_default_alignment') \ .matching('left', 'center', 'right') except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The option 'confluence_default_alignment' has been provided to override the default alignment for tables, figures, etc. Accepted values include 'left', 'center' and 'right'. '''.format(msg=e)) # ################################################################## # confluence_disable_autogen_title validator.conf('confluence_disable_autogen_title') \ .bool() # ################################################################## # confluence_disable_notifications validator.conf('confluence_disable_notifications') \ .bool() # ################################################################## # confluence_disable_ssl_validation validator.conf('confluence_disable_ssl_validation') \ .bool() # ################################################################## # confluence_domain_indices try: validator.conf('confluence_domain_indices').bool() except ConfluenceConfigurationError: try: validator.conf('confluence_domain_indices').strings() except ConfluenceConfigurationError: raise ConfluenceConfigurationError('''\ confluence_domain_indices is not a boolean or collection of strings The option 'confluence_domain_indices' has been provided to indicate that domain indices should be generated. This value can either be set to `True` or set to a list of domains (strings) to be included. ''') # ################################################################## # confluence_file_suffix validator.conf('confluence_file_suffix') \ .string() # ################################################################## # confluence_file_transform validator.conf('confluence_file_transform') \ .callable_() # ################################################################## # confluence_footer_file try: validator.conf('confluence_footer_file') \ .string() \ .file() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The option 'confluence_footer_file' has been provided to find a footer template file from a path relative to the documentation source. Ensure the value is set to a proper file path. '''.format(msg=e)) # ################################################################## # confluence_global_labels try: validator.conf('confluence_global_labels') \ .strings(no_space=True) except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The option 'confluence_global_labels' can provide a collection to string values to use as labels for published documentation. Each label value must be a string that contains no spaces. '''.format(msg=e)) # ################################################################## # confluence_header_file try: validator.conf('confluence_header_file') \ .string() \ .file() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The option 'confluence_header_file' has been provided to find a header template file from a path relative to the documentation source. Ensure the value is set to a proper file path. '''.format(msg=e)) # ################################################################## # confluence_ignore_titlefix_on_index validator.conf('confluence_ignore_titlefix_on_index') \ .bool() # ################################################################## # confluence_include_search validator.conf('confluence_include_search') \ .bool() # ################################################################## # confluence_jira_servers if config.confluence_jira_servers is not None: issue = False jira_servers = config.confluence_jira_servers if not isinstance(jira_servers, dict): issue = True else: for name, info in jira_servers.items(): if not isinstance(name, basestring): issue = True break if not isinstance(info, dict): issue = True break jira_id = info.get('id') jira_name = info.get('name') if not (isinstance(jira_id, basestring) and isinstance(jira_name, basestring)): issue = True break if issue: raise ConfluenceConfigurationError('''\ confluence_jira_servers is not properly formed Jira server definitions should be a dictionary of string keys which contain dictionaries with keys 'id' and 'name' which identify the Jira instances. ''') # ################################################################## # confluence_lang_transform validator.conf('confluence_lang_transform') \ .callable_() # ################################################################## # confluence_latex_macro try: validator.conf('confluence_latex_macro').string() except ConfluenceConfigurationError: try: validator.conf('confluence_latex_macro').dict_str_str() except ConfluenceConfigurationError: raise ConfluenceConfigurationError('''\ confluence_latex_macro is not a string or dictionary of strings The option 'confluence_latex_macro' has been provided to indicate that a LaTeX content should be rendered with a LaTeX macro supported on a Confluence instance. This value can either be set to a string of the macro to be used or set to a dictionary of key-value strings for advanced options. ''') if config.confluence_latex_macro: conf_keys = config.confluence_latex_macro.keys() required_keys = [ 'block-macro', 'inline-macro', ] if not all(name in conf_keys for name in required_keys): raise ConfluenceConfigurationError('''\ missing keys in confluence_latex_macro The following keys are required: - {} '''.format('\n - '.join(required_keys))) # ################################################################## # confluence_link_suffix validator.conf('confluence_link_suffix') \ .string() # ################################################################## # confluence_link_transform validator.conf('confluence_link_transform') \ .callable_() # ################################################################## # confluence_mentions validator.conf('confluence_mentions') \ .dict_str_str() # ################################################################## # confluence_root_homepage validator.conf('confluence_root_homepage') \ .bool() # ################################################################## # confluence_max_doc_depth try: validator.conf('confluence_max_doc_depth') \ .int_() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} When limiting the document depth permitted for a building/publishing event, the defined maximum document depth must be defined as a non-negative integer value. If planning to use a depth of zero, it is recommended to use the 'singleconfluence' builder instead. '''.format(msg=e)) # ################################################################## # confluence_navdocs_transform validator.conf('confluence_navdocs_transform') \ .callable_() # ################################################################## try: validator.conf('confluence_parent_page').string() except ConfluenceConfigurationError: try: validator.conf('confluence_parent_page').int_(positive=True) except ConfluenceConfigurationError: raise ConfluenceConfigurationError('''\ confluence_parent_page is not a string or a positive integer''') # ################################################################## validator.conf('confluence_parent_page_id_check') \ .int_(positive=True) # ################################################################## # confluence_page_hierarchy validator.conf('confluence_page_hierarchy') \ .bool() # ################################################################## # confluence_page_generation_notice validator.conf('confluence_page_generation_notice') \ .bool() # ################################################################## # confluence_prev_next_buttons_location try: validator.conf('confluence_prev_next_buttons_location') \ .matching('bottom', 'both', 'top') except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The option 'confluence_prev_next_buttons_location' has been configured to enable navigational buttons onto generated pages. Accepted values include 'bottom', 'both' and 'top'. '''.format(msg=e)) # ################################################################## # confluence_proxy validator.conf('confluence_proxy') \ .string() # ################################################################## # confluence_publish_allowlist # confluence_publish_denylist publish_list_options = [ 'confluence_publish_allowlist', 'confluence_publish_denylist', ] for option in publish_list_options: value = getattr(config, option) if not value: continue # if provided via command line, treat as a list def conf_translate(value): if option in config['overrides'] and isinstance(value, basestring): value = value.split(',') return value value = conf_translate(value) try: validator.conf(option, conf_translate) \ .string_or_strings() if isinstance(value, basestring): validator.docnames_from_file() else: validator.docnames() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} The value type permitted for this publish list option can either be a list of document names or a string pointing to a file containing documents. Document names are relative to the documentation's source directory. '''.format(msg=e)) # ################################################################## validator.conf('confluence_publish_delay') \ .float_(positive=True) # ################################################################## # confluence_publish_dryrun validator.conf('confluence_publish_dryrun') \ .bool() # ################################################################## # confluence_publish_headers validator.conf('confluence_publish_headers') \ .dict_str_str() # ################################################################## # confluence_publish_onlynew validator.conf('confluence_publish_onlynew') \ .bool() # ################################################################## # confluence_publish_postfix validator.conf('confluence_publish_postfix') \ .string() # ################################################################## # confluence_publish_prefix validator.conf('confluence_publish_prefix') \ .string() # ################################################################## validator.conf('confluence_publish_root') \ .int_(positive=True) # ################################################################## # confluence_publish_token validator.conf('confluence_publish_token') \ .string() # ################################################################## # confluence_purge validator.conf('confluence_purge') \ .bool() # ################################################################## # confluence_purge_from_root validator.conf('confluence_purge_from_root') \ .bool() # ################################################################## # confluence_remove_title validator.conf('confluence_remove_title') \ .bool() # ################################################################## # confluence_request_session_override validator.conf('confluence_request_session_override') \ .callable_() # ################################################################## # confluence_secnumber_suffix validator.conf('confluence_secnumber_suffix') \ .string() # ################################################################## # confluence_server_auth if config.confluence_server_auth is not None: if not issubclass(type(config.confluence_server_auth), AuthBase): raise ConfluenceConfigurationError('''\ confluence_server_auth is not an implementation of requests.auth.AuthBase Providing a custom authentication for Requests requires an implementation that inherits 'requests.auth.AuthBase'. For more information, please consult the following: requests -- Authentication https://requests.readthedocs.io/en/latest/user/authentication/ ''') # ################################################################## # confluence_server_cookies validator.conf('confluence_server_cookies') \ .dict_str_str() # ################################################################## # confluence_server_pass validator.conf('confluence_server_pass') \ .string() # ################################################################## # confluence_server_url validator.conf('confluence_server_url') \ .string() # ################################################################## # confluence_server_user validator.conf('confluence_server_user') \ .string() # ################################################################## # confluence_sourcelink validator.conf('confluence_sourcelink') \ .dict_str_str() if config.confluence_sourcelink: sourcelink = config.confluence_sourcelink # check if a supported template type is provided supported_types = [ 'bitbucket', 'github', 'gitlab', ] if 'type' in sourcelink: if sourcelink['type'] not in supported_types: raise ConfluenceConfigurationError('''\ unsupported type provided in confluence_sourcelink The following types are supported: - {} '''.format('\n - '.join(supported_types))) # ensure requires options are set required = [ 'owner', 'repo', 'version', ] if not all(k in sourcelink for k in required): raise ConfluenceConfigurationError('''\ required option missing in confluence_sourcelink The following options are required for the provided template type: - {} '''.format('\n - '.join(required))) # if not using a template type, ensure url is set elif 'url' not in sourcelink or not sourcelink['url']: raise ConfluenceConfigurationError('''\ url option is not set in confluence_sourcelink If a template type is not being configured for a source link, the `url` field must be configured. ''') reserved = [ 'page', 'suffix', ] if any(k in sourcelink for k in reserved): raise ConfluenceConfigurationError('''\ reserved option set in confluence_sourcelink The following options are reserved with confluence_sourcelink and cannot be set: - {} '''.format('\n - '.join(reserved))) # ################################################################## # confluence_space_key validator.conf('confluence_space_key') \ .string() # ################################################################## # confluence_title_overrides validator.conf('confluence_title_overrides') \ .dict_str_str() # ################################################################## # confluence_timeout try: validator.conf('confluence_timeout') \ .int_() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError('''\ {msg} A configured timeout should be set to a duration, in seconds, before any network request to timeout after inactivity. This should be set to a positive integer value (e.g. 2). '''.format(msg=e)) # ################################################################## # confluence_use_index validator.conf('confluence_use_index') \ .bool() # ################################################################## # confluence_version_comment validator.conf('confluence_version_comment') \ .string() # ################################################################## # confluence_watch validator.conf('confluence_watch') \ .bool() # ################################################################## if config.confluence_publish: if not config.confluence_server_url: raise ConfluenceConfigurationError('''\ confluence server url not provided While publishing has been configured using 'confluence_publish', the Confluence server URL has not. Ensure 'confluence_server_url' has been set to target Confluence instance to be published to. ''') if not config.confluence_space_key and not config.confluence_space_name: raise ConfluenceConfigurationError('''\ confluence space key not provided While publishing has been configured using 'confluence_publish', the Confluence space key has not. Ensure 'confluence_space_key' has been set to space's key which content should be published under. ''') if (config.confluence_ask_password and not config.confluence_server_user and not config.confluence_ask_user): raise ConfluenceConfigurationError('''\ confluence username not provided A publishing password has been flagged with 'confluence_ask_password'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username or have 'confluence_ask_user' set to provide a username. ''') if config.confluence_server_pass: if not config.confluence_server_user: raise ConfluenceConfigurationError('''\ confluence username not provided A publishing password has been configured with 'confluence_server_pass'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username. ''') if config.confluence_parent_page_id_check: if not config.confluence_parent_page: raise ConfluenceConfigurationError('''\ parent page (holder) name not set When a parent page identifier check has been configured with the option 'confluence_parent_page_id_check', no parent page name has been provided with the 'confluence_parent_page' option. Ensure the name of the parent page name is provided as well. ''') if config.confluence_publish_root: if config.confluence_parent_page: raise ConfluenceConfigurationError('''\ conflicting publish point configurations When configuring for a publishing container, a user can configure for either 'confluence_parent_page' or 'confluence_publish_root'; however, both cannot be configured at the same time. ''') # ################################################################## # singleconfluence_toctree validator.conf('singleconfluence_toctree') \ .bool() # ################################################################## # inform users of additional configuration information deprecated(validator) warnings(validator)
def validate_configuration(builder): """ validate a builder's configuration state This call will check if the provided builder's configuration has any issues with the existing configuration. For errors in the existing configuration, an `ConfluenceConfigurationError` exception will be thrown. In addition to errors, this call will also generate warning messages on other configuration issues such as deprecated configurations. Args: builder: the builder state to validate a configuration on """ config = builder.config env = builder.app.env validator = ConfigurationValidation(builder) # ################################################################## # confluence_add_secnumbers validator.conf('confluence_add_secnumbers') \ .bool() # ################################################################## # confluence_additional_mime_types validator.conf('confluence_additional_mime_types') \ .strings(no_space=True) # ################################################################## # confluence_adv_aggressive_search validator.conf('confluence_adv_aggressive_search') \ .bool() # ################################################################## # confluence_adv_hierarchy_child_macro validator.conf('confluence_adv_hierarchy_child_macro') \ .bool() # ################################################################## # confluence_adv_trace_data validator.conf('confluence_adv_trace_data') \ .bool() # ################################################################## # confluence_adv_writer_no_section_cap validator.conf('confluence_adv_writer_no_section_cap') \ .bool() # ################################################################## # confluence_ask_password validator.conf('confluence_ask_password') \ .bool() # ################################################################## # confluence_ask_user validator.conf('confluence_ask_user') \ .bool() # ################################################################## # confluence_asset_force_standalone validator.conf('confluence_asset_force_standalone') \ .bool() # ################################################################## validator.conf('confluence_ca_cert') \ .file() # ################################################################## if config.confluence_client_cert is not None: client_cert = config.confluence_client_cert if isinstance(client_cert, tuple): cert_files = client_cert else: cert_files = (client_cert, None) if len(cert_files) != 2: raise ConfluenceConfigurationError( """confluence_client_cert is not a 2-tuple The option 'confluence_client_cert' has been provided but there are too many values. The client certificate can either be a file/path which defines a certificate/key-pair, or a 2-tuple of the certificate and key. """) for cert in cert_files: if cert and not os.path.isfile(os.path.join(env.srcdir, cert)): raise ConfluenceConfigurationError( """confluence_ca_cert missing certificate file The option 'confluence_client_cert' has been provided to find a client certificate file from a relative location, but the certificate could not be found. Ensure the following file exists: %s """ % cert) # ################################################################## # confluence_client_cert_pass validator.conf('confluence_client_cert_pass') \ .string() # ################################################################## # confluence_default_alignment try: validator.conf('confluence_default_alignment') \ .matching('left', 'center', 'right') except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The option 'confluence_default_alignment' has been provided to override the default alignment for tables, figures, etc. Accepted values include 'left', 'center' and 'right'. """ % str(e)) # ################################################################## # confluence_disable_autogen_title validator.conf('confluence_disable_autogen_title') \ .bool() # ################################################################## # confluence_disable_notifications validator.conf('confluence_disable_notifications') \ .bool() # ################################################################## # confluence_disable_ssl_validation validator.conf('confluence_disable_ssl_validation') \ .bool() # ################################################################## # confluence_file_suffix validator.conf('confluence_file_suffix') \ .string() # ################################################################## # confluence_file_transform validator.conf('confluence_file_transform') \ .callable_() # ################################################################## # confluence_footer_file try: validator.conf('confluence_footer_file') \ .string() \ .file() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The option 'confluence_footer_file' has been provided to find a footer template file from a path relative to the documentation source. Ensure the value is set to a proper file path. """ % str(e)) # ################################################################## # confluence_global_labels try: validator.conf('confluence_global_labels') \ .strings(no_space=True) except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The option 'confluence_global_labels' can provide a collection to string values to use as labels for published documentation. Each label value must be a string that contains no spaces. """ % str(e)) # ################################################################## # confluence_header_file try: validator.conf('confluence_header_file') \ .string() \ .file() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The option 'confluence_header_file' has been provided to find a header template file from a path relative to the documentation source. Ensure the value is set to a proper file path. """ % str(e)) # ################################################################## # confluence_ignore_titlefix_on_index validator.conf('confluence_ignore_titlefix_on_index') \ .bool() # ################################################################## # confluence_jira_servers if config.confluence_jira_servers is not None: issue = False jira_servers = config.confluence_jira_servers if not isinstance(jira_servers, dict): issue = True else: for name, info in jira_servers.items(): if not isinstance(name, basestring): issue = True break if not isinstance(info, dict): issue = True break jira_id = info.get('id') jira_name = info.get('name') if not (isinstance(jira_id, basestring) and isinstance(jira_name, basestring)): issue = True break if issue: raise ConfluenceConfigurationError( """confluence_jira_servers is not properly formed JIRA server definitions should be a dictionary of string keys which contain dictionaries with keys 'id' and 'name' which identify the JIRA instances. """) # ################################################################## # confluence_lang_transform validator.conf('confluence_lang_transform') \ .callable_() # ################################################################## # confluence_link_suffix validator.conf('confluence_link_suffix') \ .string() # ################################################################## # confluence_link_transform validator.conf('confluence_link_transform') \ .callable_() # ################################################################## # confluence_master_homepage validator.conf('confluence_master_homepage') \ .bool() # ################################################################## # confluence_max_doc_depth try: validator.conf('confluence_max_doc_depth') \ .int_() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s When limiting the document depth permitted for a building/publishing event, the defined maximum document depth must be defined as a non-negative integer value. If planning to use a depth of zero, it is recommended to use the 'singleconfluence' builder instead. """ % str(e)) # ################################################################## validator.conf('confluence_parent_page') \ .string() # ################################################################## validator.conf('confluence_parent_page_id_check') \ .int_(positive=True) # ################################################################## # confluence_page_hierarchy validator.conf('confluence_page_hierarchy') \ .bool() # ################################################################## # confluence_prev_next_buttons_location try: validator.conf('confluence_prev_next_buttons_location') \ .matching('bottom', 'both', 'top') except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The option 'confluence_prev_next_buttons_location' has been configured to enable navigational buttons onto generated pages. Accepted values include 'bottom', 'both' and 'top'. """ % str(e)) # ################################################################## # confluence_proxy validator.conf('confluence_proxy') \ .string() # ################################################################## # confluence_publish_allowlist # confluence_publish_denylist publish_list_options = [ 'confluence_publish_allowlist', 'confluence_publish_denylist', ] for option in publish_list_options: value = getattr(config, option) if not value: continue # if provided via command line, treat as a list def conf_translate(value): if option in config['overrides'] and isinstance(value, basestring): value = value.split(',') return value value = conf_translate(value) try: validator.conf(option, conf_translate) \ .string_or_strings() if isinstance(value, basestring): validator.docnames_from_file() else: validator.docnames() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s The value type permitted for this publish list option can either be a list of document names or a string pointing to a file containing documents. Document names are relative to the documentation's source directory. """ % str(e)) # ################################################################## # confluence_publish_dryrun validator.conf('confluence_publish_dryrun') \ .bool() # ################################################################## # confluence_publish_onlynew validator.conf('confluence_publish_onlynew') \ .bool() # ################################################################## # confluence_publish_postfix validator.conf('confluence_publish_postfix') \ .string() # ################################################################## # confluence_publish_prefix validator.conf('confluence_publish_prefix') \ .string() # ################################################################## # confluence_purge validator.conf('confluence_purge') \ .bool() # ################################################################## # confluence_purge_from_master validator.conf('confluence_purge_from_master') \ .bool() # ################################################################## # confluence_remove_title validator.conf('confluence_remove_title') \ .bool() # ################################################################## # confluence_secnumber_suffix validator.conf('confluence_secnumber_suffix') \ .string(permit_empty=True) # ################################################################## # confluence_server_auth if config.confluence_server_auth is not None: if not issubclass(type(config.confluence_server_auth), AuthBase): raise ConfluenceConfigurationError( """confluence_server_auth is not an implementation of requests.auth.AuthBase Providing a custom authentication for Requests requires an implementation that inherits 'requests.auth.AuthBase'. For more information, please consult the following: requests -- Authentication https://requests.readthedocs.io/en/latest/user/authentication/ """) # ################################################################## # confluence_server_cookies validator.conf('confluence_server_cookies') \ .dict_str_str() # ################################################################## # confluence_server_pass validator.conf('confluence_server_pass') \ .string() # ################################################################## # confluence_server_url validator.conf('confluence_server_url') \ .string() # ################################################################## # confluence_server_user validator.conf('confluence_server_user') \ .string() # ################################################################## # confluence_space_name validator.conf('confluence_space_name') \ .string() # ################################################################## # confluence_title_overrides validator.conf('confluence_title_overrides') \ .dict_str_str() # ################################################################## # confluence_timeout try: validator.conf('confluence_timeout') \ .int_() except ConfluenceConfigurationError as e: raise ConfluenceConfigurationError( """%s A configured timeout should be set to a value, in seconds, before any network request to timeout after inactivity. This should be set to a positive integer value (e.g. 2). """ % str(e)) # ################################################################## # confluence_watch validator.conf('confluence_watch') \ .bool() # ################################################################## if config.confluence_publish: if not config.confluence_server_url: raise ConfluenceConfigurationError( """confluence server url not provided While publishing has been configured using 'confluence_publish', the Confluence server URL has not. Ensure 'confluence_server_url' has been set to target Confluence instance to be published to. """) if not config.confluence_space_name: raise ConfluenceConfigurationError( """confluence space name not provided While publishing has been configured using 'confluence_publish', the Confluence space name has not. Ensure 'confluence_space_name' has been set to space's name which content should be published under. """) if (config.confluence_ask_password and not config.confluence_server_user and not config.confluence_ask_user): raise ConfluenceConfigurationError( """confluence username not provided A publishing password has been flagged with 'confluence_ask_password'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username or have 'confluence_ask_user' set to provide a username. """) if config.confluence_server_pass: if not config.confluence_server_user: raise ConfluenceConfigurationError( """confluence username not provided A publishing password has been configured with 'confluence_server_pass'; however, no username has been configured. Ensure 'confluence_server_user' is properly set with the publisher's Confluence username. """) if config.confluence_parent_page_id_check: if not config.confluence_parent_page: raise ConfluenceConfigurationError( """parent page (holder) name not set When a parent page identifier check has been configured with the option 'confluence_parent_page_id_check', no parent page name has been provided with the 'confluence_parent_page' option. Ensure the name of the parent page name is provided as well. """) # ################################################################## # inform users of aadditional configuration information deprecated(validator) warnings(validator)
def init(self, suppress_conf_check=False): if not ConfluenceConfig.validate(self, not suppress_conf_check): raise ConfluenceConfigurationError('configuration error') config = self.config if self.config.confluence_publish: if self.config.confluence_ask_user: print('(request to accept username from interactive session)') print(' Instance: ' + self.config.confluence_server_url) default_user = self.config.confluence_server_user u_str = '' if default_user: u_str = ' [{}]'.format(default_user) target_user = input(' User{}: '.format(u_str)) or default_user if not target_user: raise ConfluenceConfigurationError('no user provided') self.config.confluence_server_user = target_user if self.config.confluence_ask_password: print('(request to accept password from interactive session)') if not self.config.confluence_ask_user: print(' Instance: ' + self.config.confluence_server_url) print(' User: '******' Password: '******'') if not self.config.confluence_server_pass: raise ConfluenceConfigurationError('no password provided') self.assets = ConfluenceAssetManager(self.config.master_doc, self.env, self.outdir) self.writer = ConfluenceWriter(self) self.config.sphinx_verbosity = self.app.verbosity self.publisher.init(self.config) old_url = self.config.confluence_server_url new_url = ConfluenceUtil.normalizeBaseUrl(old_url) if old_url != new_url: ConfluenceLogger.warn('normalizing confluence url from ' '{} to {} '.format(old_url, new_url)) self.config.confluence_server_url = new_url # detect if Confluence Cloud if using the Atlassian domain if new_url: self.cloud = new_url.endswith('.atlassian.net/wiki/') if self.config.confluence_file_suffix is not None: self.file_suffix = self.config.confluence_file_suffix if self.config.confluence_link_suffix is not None: self.link_suffix = self.config.confluence_link_suffix elif self.link_suffix is None: self.link_suffix = self.file_suffix # Function to convert the docname to a reST file name. def file_transform(docname): return docname + self.file_suffix # Function to convert the docname to a relative URI. def link_transform(docname): return docname + self.link_suffix self.prev_next_loc = self.config.confluence_prev_next_buttons_location if self.config.confluence_file_transform is not None: self.file_transform = self.config.confluence_file_transform else: self.file_transform = file_transform if self.config.confluence_link_transform is not None: self.link_transform = self.config.confluence_link_transform else: self.link_transform = link_transform if self.config.confluence_lang_transform is not None: self.lang_transform = self.config.confluence_lang_transform else: self.lang_transform = None if self.config.confluence_publish: self.publish = True self.publisher.connect() else: self.publish = False if self.config.confluence_space_name is not None: self.space_name = self.config.confluence_space_name else: self.space_name = None def prepare_subset(option): value = getattr(config, option) if value is None: return None # if provided via command line, treat as a list if option in config['overrides']: value = value.split(',') if isinstance(value, basestring): files = extract_strings_from_file(value) else: files = value return set(files) if files else None self.publish_allowlist = prepare_subset('confluence_publish_allowlist') self.publish_denylist = prepare_subset('confluence_publish_denylist')