Beispiel #1
0
def _get_launchpad_client():
    cred_location = os.path.expanduser('~/.lp_creds')
    credential_store = UnencryptedFileCredentialStore(cred_location)
    return Launchpad.login_with('cpc',
                                'production',
                                version='devel',
                                credential_store=credential_store)
def connect_launchpad():
    """Use the launchpad module connect to launchpad.

    Will connect you to the Launchpad website the first time you run
    this to authorize your system to connect.
    """
    cred_location = os.path.expanduser('~/.lp_creds')
    credential_store = UnencryptedFileCredentialStore(cred_location)
    return Launchpad.login_with('ustriage', 'production', version='devel',
                                credential_store=credential_store)
def get_launchpad(launchpadlib_dir=None, lp_credentials_store=None):
    """ return a launchpad API class. In case launchpadlib_dir is
    specified used that directory to store launchpadlib cache instead of
    the default """
    if not lp_credentials_store:
        creds_prefix = os.environ.get('SNAP_USER_COMMON',
                                      os.path.expanduser('~'))
        store = UnencryptedFileCredentialStore(
            os.path.join(creds_prefix, '.launchpad.credentials'))
    else:
        store = UnencryptedFileCredentialStore(lp_credentials_store)
    lp_app = 'review-gator'
    lp_env = 'production'
    lp_version = 'devel'

    authorization_engine = AuthorizeRequestTokenWithConsole(lp_env, lp_app)
    return Launchpad.login_with(lp_app,
                                lp_env,
                                credential_store=store,
                                authorization_engine=authorization_engine,
                                launchpadlib_dir=launchpadlib_dir,
                                version=lp_version)
def get_launchpad(launchpadlib_dir=None):
    """ return a launchpad API class. In case launchpadlib_dir is
    specified used that directory to store launchpadlib cache instead of
    the default """
    store = UnencryptedFileCredentialStore(
        os.path.join(os.path.expanduser('~'), '.launchpad.credentials'))
    lp_app = 'landscape-review-aggregator'
    lp_env = 'production'
    lp_version = 'devel'

    authorization_engine = AuthorizeRequestTokenWithConsole(lp_env, lp_app)
    return Launchpad.login_with(lp_app,
                                lp_env,
                                credential_store=store,
                                authorization_engine=authorization_engine,
                                launchpadlib_dir=launchpadlib_dir,
                                version=lp_version)
Beispiel #5
0
class TestUnencryptedFileCredentialStore(CredentialStoreTestCase):
    """Tests for the UnencryptedFileCredentialStore class."""

    def setUp(self):
        ignore, self.filename = tempfile.mkstemp()
        self.store = UnencryptedFileCredentialStore(self.filename)

    def tearDown(self):
        if os.path.exists(self.filename):
            os.remove(self.filename)

    def test_save_and_load(self):
        # Make sure you can save and load credentials to a file.
        credential = self.make_credential("consumer key")
        self.store.save(credential, "unique key")
        credential2 = self.store.load("unique key")
        self.assertEquals(credential.consumer.key, credential2.consumer.key)

    def test_unique_id_doesnt_matter(self):
        # If a file contains a credential, that credential will be
        # accessed no matter what unique ID you specify.
        credential = self.make_credential("consumer key")
        self.store.save(credential, "some key")
        credential2 = self.store.load("some other key")
        self.assertEquals(credential.consumer.key, credential2.consumer.key)

    def test_file_only_contains_one_credential(self):
        # A credential file may contain only one credential. If you
        # write two credentials with different unique IDs to the same
        # file, the first credential will be overwritten with the
        # second.
        credential1 = self.make_credential("consumer key")
        credential2 = self.make_credential("consumer key2")
        self.store.save(credential1, "unique key 1")
        self.store.save(credential1, "unique key 2")
        loaded = self.store.load("unique key 1")
        self.assertEquals(loaded.consumer.key, credential2.consumer.key)
    def _launchpad_connect(self, anon=False):
        """Use the launchpad module connect to launchpad.

        Will connect you to the Launchpad website the first time you
        run this to authorize your system to connect unless anonymous
        login is specified.
        """
        if anon:
            self._log.debug('logging into Launchpad anonymously')
            return Launchpad.login_anonymously('ubuntu-bug-triage',
                                               'production',
                                               version='devel')

        self._log.debug('logging into Launchpad')
        credential_store = UnencryptedFileCredentialStore(
            os.path.expanduser('~/.lp_creds'))
        return Launchpad.login_with('ubuntu-bug-triage',
                                    'production',
                                    version='devel',
                                    credential_store=credential_store)
Beispiel #7
0
 def credential_store_factory(cls, credential_save_failed):
     return UnencryptedFileCredentialStore(tempfile.mkstemp()[1],
                                           credential_save_failed)
Beispiel #8
0
if __name__ == "__main__":
    check_notices = os.path.isfile(CHECK_NOTICES_PATH) and os.access(
        CHECK_NOTICES_PATH, os.X_OK) and CHECK_NOTICES_PATH

    if not check_notices:
        logger.info("`review-tools` not found, skipping USN checks…")
        sys.exit(0)

    try:
        lp = Launchpad.login_with(
            APPLICATION,
            LAUNCHPAD,
            version="devel",
            authorization_engine=RequestTokenAuthorizationEngine(
                LAUNCHPAD, APPLICATION),
            credential_store=UnencryptedFileCredentialStore(
                os.path.expanduser(sys.argv[1])),
        )
    except NotImplementedError:
        raise RuntimeError("Invalid credentials.")

    ubuntu = lp.distributions["ubuntu"]
    logger.debug("Got ubuntu: %s", ubuntu)

    team = lp.people[TEAM]
    logger.debug("Got team: %s", team)

    errors = []

    for snap, channels in SNAPS.items():
        for channel, snap_map in channels.items():
            logger.info("Processing channel %s for snap %s…", channel, snap)
def main(args=None):
    global jira_server

    opt_parser = argparse.ArgumentParser(
            description="Report the status of all active LaunchPad bug "
                        "imported into a JIRA project with lp-to-jira",
            formatter_class=argparse.RawTextHelpFormatter,
            epilog=textwrap.dedent('''\
            Examples:
                lp-to-jira-report FR
                lp-to-jira-report --csv  results.csv  FR
                lp-to-jira-report --json results.json FR
                lp-to-jira-report --html results.html FR
            ''')
        )
    opt_parser.add_argument(
        'project', type=str,
        help="The JIRA project string key")

    opt_parser.add_argument(
        '--csv',
        dest='csv',
        help='export the results of the report into FILE in csv format',
    )
    opt_parser.add_argument(
        '--html',
        dest='html',
        help='export the results of the report into FILE in html format',
    )
    opt_parser.add_argument(
        '--json',
        dest='json',
        help='export the results of the report into FILE in json format',
    )
    opt_parser.add_argument(
        '--sync',
        dest='sync', action='store_true',
        help='Sync JIRA items with corresponding bugs in LP',
    )

    opts = opt_parser.parse_args(args)

    jira_project = opts.project

    # 1. Initialize JIRA API
    api = jira_api()
    jira_server = api.server
    jira = JIRA(api.server, basic_auth=(api.login, api.token))

    # TODO: catch exception if the Launchpad API isn't open
    # 2. Initialize Launchpad API
    # Connect to Launchpad API
    # TODO: catch exception if the Launchpad API isn't open
    snap_home = os.getenv("SNAP_USER_COMMON")
    if snap_home:
        credential_store = UnencryptedFileCredentialStore(
            "{}/.lp_creds".format(snap_home))
    else:
        credential_store = UnencryptedFileCredentialStore(
            os.path.expanduser("~/.lp_creds"))
    lp = Launchpad.login_with(
        'foundations',
        'production',
        version='devel',
        credential_store=credential_store)

    print(
        "Searching for JIRA issues in project %s imported with lp-to-jira..."
        % opts.project,
        flush=True
        )

    # Create a Database of all JIRA issues imported by lp-to-jira
    jira_lp_db = find_issues_in_project(jira, jira_project)
    print("Found %s issues" % len(jira_lp_db))

    # For each issue retrieve latest lp data and sync if required
    merge_lp_data_with_jira_issues(jira, lp, jira_lp_db, opts.sync)

    # Create a table version of the database
    jira_lp_db_table = []
    if jira_lp_db:
        jira_lp_db_table.append(list(jira_lp_db[0].keys()))
        jira_lp_db_table += [list(x.values()) for x in jira_lp_db]
    else:
        return 1

    # Display the content of jira_lp_db based on the output option
    if opts.json:
        with open(opts.json, 'w') as fp:
            json.dump(jira_lp_db, fp, indent=2)
        print("JSON report saved as %s" % opts.json)

    if opts.html:
        print_html_report(jira_lp_db, opts.html)
        print("HTML report saved as %s" % opts.html)

    if opts.csv:
        print_table(jira_lp_db_table, sep=";", limit=1024,
                    align=False, draw_title=False, file=opts.csv)
        print("CSV report saved as %s" % opts.csv)

    if not opts.csv and not opts.html and not opts.json:
        print_table(jira_lp_db_table, sep=" | ", limit=60,
                    align=True, draw_title=True, file="/dev/stdout")

    return 0
Beispiel #10
0
 def setUp(self):
     ignore, self.filename = tempfile.mkstemp()
     self.store = UnencryptedFileCredentialStore(self.filename)
 def setUp(self):
     ignore, self.filename = tempfile.mkstemp()
     self.store = UnencryptedFileCredentialStore(self.filename)
Beispiel #12
0
        except subprocess.CalledProcessError as e:
            logger.error("Failed to check notices:\n%s", e.output)
        else:
            notices = json.loads(notices)
            return notices


if __name__ == '__main__':
    try:
        lp = Launchpad.login_with(
            APPLICATION,
            LAUNCHPAD,
            version="devel",
            authorization_engine=RequestTokenAuthorizationEngine(
                LAUNCHPAD, APPLICATION),
            credential_store=UnencryptedFileCredentialStore(
                os.path.expanduser("~/.launchpadlib/credentials")))
    except NotImplementedError:
        raise RuntimeError("Invalid credentials.")

    check_notices = (os.path.isfile(CHECK_NOTICES_PATH)
                     and os.access(CHECK_NOTICES_PATH, os.X_OK)
                     and CHECK_NOTICES_PATH)
    if not check_notices:
        logger.info("`review-tools` not found, skipping USN checks…")

    ubuntu = lp.distributions["ubuntu"]
    logger.debug("Got ubuntu: %s", ubuntu)

    series = ubuntu.getSeries(name_or_version=RELEASE)
    logger.debug("Got series: %s", series)
Beispiel #13
0
    def login_with(cls,
                   application_name=None,
                   service_root=uris.STAGING_SERVICE_ROOT,
                   launchpadlib_dir=None,
                   timeout=None,
                   proxy_info=None,
                   authorization_engine=None,
                   allow_access_levels=None,
                   max_failed_attempts=None,
                   credentials_file=None,
                   version=DEFAULT_VERSION,
                   consumer_name=None,
                   credential_save_failed=None,
                   credential_store=None):
        """Log in to Launchpad, possibly acquiring and storing credentials.

        Use this method to get a `Launchpad` object. If the end-user
        has no cached Launchpad credential, their browser will open
        and they'll be asked to log in and authorize a desktop
        integration. The authorized Launchpad credential will be
        stored securely: in the GNOME keyring, the KDE Wallet, or in
        an encrypted file on disk.

        The next time your program (or any other program run by that
        user on the same computer) invokes this method, the end-user
        will be prompted to unlock their keyring (or equivalent), and
        the credential will be retrieved from local storage and
        reused.

        You can customize this behavior in three ways:

        1. Pass in a filename to `credentials_file`. The end-user's
           credential will be written to that file, and on subsequent
           runs read from that file.

        2. Subclass `CredentialStore` and pass in an instance of the
           subclass as `credential_store`. This lets you change how
           the end-user's credential is stored and retrieved locally.

        3. Subclass `RequestTokenAuthorizationEngine` and pass in an
           instance of the subclass as `authorization_engine`. This
           lets you change change what happens when the end-user needs
           to authorize the Launchpad credential.

        :param application_name: The application name. This is *not*
            the OAuth consumer name. Unless a consumer_name is also
            provided, the OAuth consumer will be a system-wide
            consumer representing the end-user's computer as a whole.
        :type application_name: string

        :param service_root: The URL to the root of the web service.
        :type service_root: string.  Can either be the full URL to a service
            or one of the short service names.

        :param launchpadlib_dir: The directory used to store cached
           data obtained from Launchpad. The cache is shared by all
           consumers, and each Launchpad service root has its own
           cache.
        :type launchpadlib_dir: string

        :param authorization_engine: A strategy for getting the
            end-user to authorize an OAuth request token, for
            exchanging the request token for an access token, and for
            storing the access token locally so that it can be
            reused. By default, launchpadlib will open the end-user's
            web browser to have them authorize the request token.
        :type authorization_engine: `RequestTokenAuthorizationEngine`

        :param allow_access_levels: The acceptable access levels for
            this application.

            This argument is used to construct the default
            `authorization_engine`, so if you pass in your own
            `authorization_engine` any value for this argument will be
            ignored. This argument will also be ignored unless you
            also specify `consumer_name`.

        :type allow_access_levels: list of strings

        :param max_failed_attempts: Ignored; only present for
            backwards compatibility.

        :param credentials_file: The path to a file in which to store
            this user's OAuth access token.

        :param version: The version of the Launchpad web service to use.

        :param consumer_name: The consumer name, as appropriate for
            the `Consumer` constructor. You probably don't want to
            provide this, since providing it will prevent you from
            taking advantage of desktop-wide integration.
        :type consumer_name: string

        :param credential_save_failed: a callback that is called upon
           a failure to save the credentials locally. This argument is
           used to construct the default `credential_store`, so if
           you pass in your own `credential_store` any value for
           this argument will be ignored.
        :type credential_save_failed: A callable

        :param credential_store: A strategy for storing an OAuth
            access token locally. By default, tokens are stored in the
            GNOME keyring (or equivalent). If `credentials_file` is
            provided, then tokens are stored unencrypted in that file.
        :type credential_store: `CredentialStore`

        :return: A web service root authorized as the end-user.
        :rtype: `Launchpad`

        """
        (service_root, launchpadlib_dir, cache_path,
         service_root_dir) = cls._get_paths(service_root, launchpadlib_dir)

        if (application_name is None and consumer_name is None
                and authorization_engine is None):
            raise ValueError(
                "At least one of application_name, consumer_name, or "
                "authorization_engine must be provided.")

        if credentials_file is not None and credential_store is not None:
            raise ValueError(
                "At most one of credentials_file and credential_store "
                "must be provided.")

        if credential_store is None:
            if credentials_file is not None:
                # The end-user wants credentials stored in an
                # unencrypted file.
                credential_store = UnencryptedFileCredentialStore(
                    credentials_file, credential_save_failed)
            else:
                credential_store = cls.credential_store_factory(
                    credential_save_failed)
        else:
            # A credential store was passed in, so we won't be using
            # any provided value for credential_save_failed. But at
            # least make sure we weren't given a conflicting value,
            # since that makes the calling code look confusing.
            cls._assert_login_argument_consistency(
                'credential_save_failed', credential_save_failed,
                credential_store.credential_save_failed, "credential_store")
            credential_store = credential_store

        if authorization_engine is None:
            authorization_engine = cls.authorization_engine_factory(
                service_root, application_name, consumer_name,
                allow_access_levels)
        else:
            # An authorization engine was passed in, so we won't be
            # using any provided values for application_name,
            # consumer_name, or allow_access_levels. But at least make
            # sure we weren't given conflicting values, since that
            # makes the calling code look confusing.
            cls._assert_login_argument_consistency(
                "application_name", application_name,
                authorization_engine.application_name)

            cls._assert_login_argument_consistency(
                "consumer_name", consumer_name,
                authorization_engine.consumer.key)

            cls._assert_login_argument_consistency(
                "allow_access_levels", allow_access_levels,
                authorization_engine.allow_access_levels)

        return cls._authorize_token_and_login(
            authorization_engine.consumer, service_root, cache_path, timeout,
            proxy_info, authorization_engine, allow_access_levels,
            credential_store, credential_save_failed, version)
Beispiel #14
0
def main():
    usage = """\
usage: lp-to-jira [options] bug-id project-id

Create JIRA entry for a given Launchpad bug ID

options:
    -e, --exists"
                Look if the Launchpad Bug has alreaady been imported
                print the JIRA issue ID if found
    -l, --label LABEL
                Add LABEL to the JIRA issue after creation
    -s SYNC_PROJECT_BUGS, --sync_project_bugs=SYNC_PROJECT_BUGS
                The name of the LP Project. This will bring in every
                bug from your project if you do not also specify days
    -d DAYS, --days=DAYS
                Only look for LP Bugs in the past n days
    --no-lp-tag

Examples:
    lp-to-jira 3215487 FR
    lp-to-jira -e 3215487 FR
    lp-to-jira -l ubuntu-meeting 3215487 PR
    lp-to-jira -s ubuntu -d 3 IQA
        """

    opt_parser = OptionParser(usage)
    opt_parser.add_option(
        '-l',
        '--label',
        dest='label',
    )
    opt_parser.add_option('-e', '--exists', dest='exists', action='store_true')

    opt_parser.add_option(
        '-s',
        '--sync_project_bugs',
        dest='sync_project_bugs',
        action='store',
        type=str,
        help='Adds all bugs from a specified LP Project to specified Jira board'
        ' if they are not already on the Jira board.'
        ' Use --days to narrow down bugs')

    opt_parser.add_option('-d',
                          '--days',
                          dest='days',
                          action='store',
                          type=int,
                          help='Only look for LP Bugs in the past n days')

    opt_parser.add_option('--no-lp-tag',
                          dest='no_lp_tag',
                          action='store_true',
                          help='Do not add tag to LP Bug')

    opts, args = opt_parser.parse_args()

    # Connect to Launchpad API
    # TODO: catch exception if the Launchpad API isn't open
    credential_store = UnencryptedFileCredentialStore(
        os.path.expanduser("~/.lp_creds"))
    lp = Launchpad.login_with('foundations',
                              'production',
                              version='devel',
                              credential_store=credential_store)

    # Connect to the JIRA API
    api = jira_api()
    jira = JIRA(api.server, basic_auth=(api.login, api.token))

    if opts.sync_project_bugs:
        bugs_list = get_all_lp_project_bugs(lp, opts.sync_project_bugs,
                                            opts.days)

        for bug in bugs_list:
            bug_number = bug.bug_link.split('/')[-1]
            bug = get_lp_bug(lp, bug_number)
            lp_to_jira_bug(lp, jira, bug, args[0], opts)
        return 0

    # Make sure there's 2 arguments
    if len(args) < 2:
        opt_parser.print_usage()
        return 1

    bug_number = args[0]
    project_id = args[1]
    bug = get_lp_bug(lp, bug_number)

    if opts.exists:
        # We are simply testing if the bug was already in JIRA
        if is_bug_in_jira(jira, bug, project_id):
            return 0
        print("Launchpad Issue {} is not in JIRA project {}".format(
            bug.id, project_id))
        return 1

    # Create the Jira Issue
    lp_to_jira_bug(lp, jira, bug, project_id, opts)

    return 0
Beispiel #15
0
def main(args=None):
    opt_parser = argparse.ArgumentParser(
        description="A script create JIRA issue from Launchpad bugs",
        formatter_class=argparse.RawTextHelpFormatter,
        epilog=textwrap.dedent('''\
        Examples:
            lp-to-jira 3215487 FR
            lp-to-jira -e 3215487 FR
            lp-to-jira -l ubuntu-meeting 3215487 PR
            lp-to-jira -s ubuntu -d 3 IQA
        ''')
    )
    opt_parser.add_argument(
        'bug', type=int,
        # Somewhat hacky way to allow -s option to not require bug id
        # -s (sync) is an optional parameter that doesn't require bug id
        default=0,
        nargs='?',
        help="The Launchpad numeric bug ID")
    opt_parser.add_argument(
        'project', type=str,
        help="The JIRA project string key")
    opt_parser.add_argument(
        '-l',
        '--label',
        dest='label',
        help='Add LABEL to the JIRA issue after creation')
    opt_parser.add_argument(
        '-c',
        '--component',
        dest='component',
        help='Specify COMPONENT to assign the issue to')
    opt_parser.add_argument(
        '-E',
        '--epic',
        dest='epic',
        help='Specify EPIC to link this new issue to')
    opt_parser.add_argument(
        '-e', '--exists',
        dest='exists',
        action='store_true',
        help=textwrap.dedent('''
            Look if the Launchpad Bug has already been imported
            print the JIRA issue ID if found
        ''')
    )
    opt_parser.add_argument(
        '-s', '--sync_project_bugs',
        dest='sync_project_bugs',
        action='store',
        type=str,
        help=textwrap.dedent('''
            Adds all bugs from a specified LP Project to specified Jira board
            if they are not already on the Jira board.
            Use --days to narrow down bugs
            ''')
    )
    opt_parser.add_argument(
        '-d', '--days',
        dest='days',
        action='store',
        type=int,
        help='Only look for LP Bugs in the past n days'
    )
    opt_parser.add_argument(
        '--no-lp-tag',
        dest='no_lp_tag',
        action='store_true',
        help='Do not add tag to LP Bug'
    )

    opts = opt_parser.parse_args(args)

    if (opts.bug == 0 and not opts.sync_project_bugs):
        opt_parser.print_usage()
        print('lp-to-jira: error: the follow argument is required: bug')
        return 1

    # Connect to Launchpad API
    # TODO: catch exception if the Launchpad API isn't open
    snap_home = os.getenv("SNAP_USER_COMMON")
    if snap_home:
        credential_store = UnencryptedFileCredentialStore(
            "{}/.lp_creds".format(snap_home))
    else:
        credential_store = UnencryptedFileCredentialStore(
            os.path.expanduser("~/.lp_creds"))
    lp = Launchpad.login_with(
        'foundations',
        'production',
        version='devel', credential_store=credential_store)

    # Connect to the JIRA API
    try:
        api = jira_api()
    except ValueError:
        return "ERROR: Cannot initialize JIRA API."

    jira = JIRA(api.server, basic_auth=(api.login, api.token))

    if opts.sync_project_bugs:
        tasks_list = get_all_lp_project_bug_tasks(
            lp, opts.sync_project_bugs, opts.days)
        if tasks_list is None:
            return 1

        for bug_task in tasks_list:
            bug = bug_task.bug
            lp_to_jira_bug(lp, jira, bug, opts.project, opts)
        return 0

    bug_number = opts.bug
    project_id = opts.project

    bug = get_lp_bug(lp, bug_number)
    if bug is None:
        return 1

    if opts.exists:
        # We are simply testing if the bug was already in JIRA
        if is_bug_in_jira(jira, bug, project_id):
            return 0
        print("Launchpad Issue {} is not in JIRA project {}".format(
            bug.id, project_id))
        return 1

    # Create the Jira Issue
    lp_to_jira_bug(lp, jira, bug, project_id, opts)

    return 0