def main(): client = TrelloClient(api_key=config["TRELLO"]["API_KEY"], api_secret=config["TRELLO"]["API_SECRET"], token=config["TRELLO"]["TOKEN"]) try: inbox_list = client.get_list(config["TRELLO"]["GTD_LIST_INBOX_ID"]) inbox_cards = inbox_list.list_cards() information = get_info_all_cards(inbox_cards) print_to_file(information, config['TRELLO']['OUTPUT_FILE']) except FileNotFoundError: print('Inbox file not found') else: print('All was OK, archiving cards...') inbox_list.archive_all_cards()
class Trello: COMMENT_PREFIX = "external_id=" log = logging.getLogger(__name__) def __init__(self): self.config = load_config("config/trello-config.yaml") self.cards_with_external_ids = [] self.labels = {} app_key = self.config['app_key'] token = self.config['token'] board_id = self.config['board_id'] self.board = TrelloClient(api_key=app_key, token=token).get_board(board_id) self.classify_board() self.log.debug("Connecting to Trello board {0}".format(board_id)) def classify_board(self): cards = self.board.all_cards() self.log.debug("Classifying Trello board, contains {0} cards".format( len(cards))) for label in self.board.get_labels(): self.labels[label.name] = label for card in cards: if card.closed: self.log.debug("Ignoring closed card {0} ({1})".format( card.name, card.id)) else: self.log.debug("Looking for external id in {0}".format( card.name)) self.cards_with_external_ids.append( Trello.get_external_id(card)) @staticmethod def get_external_id(card): external_id = None card.fetch() comments = card.comments if comments: for comment in comments: text = comment['data']['text'] if Trello.COMMENT_PREFIX in text: external_id = re.sub(Trello.COMMENT_PREFIX, '', text) return external_id def clear_board(self): for card in self.board.all_cards(): self.log.debug("Deleting {0} {1}".format(card.name, card.id)) card.delete() def card_exists(self, identifier): return identifier in self.cards_with_external_ids def add_cards(self, cards): default_list = self.board.get_list(self.config['default_list']) self.log.debug("Adding {0} cards to lane {1} ({2})".format( len(cards), default_list.name, default_list.id)) for card in cards: name = card['name'] identifier = card['identifier'] card_type = card['type'] note = card['note'] card = default_list.add_card(name) if note is not None: card.set_description(note) card.comment("{0}{1}".format(Trello.COMMENT_PREFIX, identifier)) try: card.add_label(self.labels[card_type]) self.log.debug( "Creating card with details: name={0} id={1} type={2}". format(name, identifier, card_type)) except KeyError: self.log.debug( "Can't find card type {0} configured in Trello".format( card_type)) self.log.debug( "Creating card with details: name={0} id={1} type=default". format(name, identifier)) def find_completed_card_ids(self): completed_lists = self.config['completed_lists'] self.log.debug("Looking for cards in completed lanes: {0}".format( completed_lists)) cards = [] for list_id in completed_lists: completed_list = self.board.get_list(list_id) cards.extend([ Trello.get_external_id(card) for card in completed_list.list_cards() ]) # [cards.extend([card.external_card_id for card in self.trello.lane.get(lane).cards # if len(card.external_card_id) > 1]) for lane in lanes] self.log.debug("Found {0} completed cards on the board".format( len(cards))) self.log.debug("External ids: {0}".format(cards)) return cards
) board_id = "5e74996a963b6a6063936eed" # LISTs IDs board = client.get_board(board_id=board_id) newgroup_list_id = "5e7499aa34052a6172bd0e3f" planned_calls_list_id = "5e774f119849c8249f8f6541" dg_list_id = "5e74999f6801d386764d77f4" wg_list_id = "5e7499a2d7a1712de4fe2a84" projects_list_id = "5e749a07819e72462465bac2" past_calls_id = "5e98ee7ccafe1b1cd8061e76" inactive_list_id = "5e749a11b808322c392daf7d" archive_list_id = "5e749a16b2e2b0449d2f86f9" # LISTS (COLUMNS) IN TRELLO BOARD newgroup_list = client.get_list(newgroup_list_id) planned_calls_list = client.get_list(planned_calls_list_id) dg_list = client.get_list(dg_list_id) wg_list = client.get_list(wg_list_id) projects_list = client.get_list(projects_list_id) past_calls_list = client.get_list(past_calls_id) inactive_list = client.get_list(inactive_list_id) archive_list = client.get_list(archive_list_id) # LABELS IDs - accessed by bots upcoming_id = "5e74996a7669b225496b9f36" active_id = "5e74996a7669b225496b9f35" inactive_id = "5e74c0d2d9910d09dbd69398" info_id = "5e74c1241056462f867de53a" past_call_label_id = "5e7b985c53caf880abd11717" # Restriction ids
def main(): usage = '%prog (load|rebuild|commit|push|test|config|update)'\ ' [options] args... are you ready?' parser = OptionParser(usage) parser.add_option('-i', '--id', type='int', dest='id') parser.add_option('-u', '--user', dest='user') parser.add_option('-c', '--comment', dest='comment') parser.add_option('-g', '--gitpath', default=realpath(__file__), dest='gitpath') parser.add_option('-p', '--params', dest='params') parser.add_option('-t', '--title', dest='title') parser.add_option('-d', '--description', dest='description', default="") (options, args) = parser.parse_args() repo = Repo(options.gitpath) conf_path = join(expanduser("~"), '.gitr.json') if not len(args): handle_error(msg='Some action are required', handle=parser) if not isfile(conf_path): conf_src = join(dirname(realpath(__file__)), 'gitr.json') shutil.copy(conf_src, conf_path) with open(conf_path, 'r') as infile: json_data = json.load(infile) BOARD_ID = json_data['BOARD_ID'] CREATE_LIST_ID = json_data['CREATE_LIST_ID'] DONE_LIST_ID = json_data['DONE_LIST_ID'] MEMBERS = json_data['MEMBERS'] USER = MEMBERS[int(json_data['USER'])] client = TrelloClient(api_key=json_data['API_KEY'], token=json_data['TOKEN'], api_secret=json_data['API_SECRET']) if ('update' in args): create_list = client.get_list(CREATE_LIST_ID) card = get_current_card(repo, create_list) if options.description: card._set_remote_attribute('description', options.description) if options.title or options.params: def sub_match(match): match_args = [arg for arg in match.groups()] if options.title: match_args[4] = options.title if options.params: params = check_params(options.params) if (len(params) > 2): match_args[2] = params[2] elif (len(params) == 2): match_args[1] = params[1] match_args[3] = params[0] return '#%s. %sº (%s,%s) %s' % tuple(match_args) name = re.sub('#(\d+).(\d+)º \((\d+),(\d+)\) (.*)', sub_match, card.name) card._set_remote_attribute('name', name) elif ('members' in args): for idx, member_id in enumerate(MEMBERS): member = client.get_member(member_id) logging.info("*%s %d. %s (%s)" % ((USER == member_id) and '*' or '', idx, member.username, member.full_name)) elif ('config' in args): if options.params: params = options.params.split(',') for param in params: try: key, value = param.split(':') except ValueError: handle_error('(-p <key:value, key2:value2, ...>)'\ ' format is wrong.') json_data[key] = value if options.user: json_data['USER'] = options.user if not (options.params and options.user): members = client.get_board_members(BOARD_ID) json_data['MEMBERS'] = [member['id'] for member in members] json_data['USER'] = json_data['MEMBERS'].index(client.me()['id']) with open(conf_path, 'w') as outfile: json.dump(json_data, outfile) for key, value in json_data.items(): logging.info("* %s: %s" %(key, value)) elif ('load' in args): if not options.params: handle_error('(-p <t_estimated>)You must include '\ 'almost time estimated.') params = check_params(options.params) (t_estimated, priority, t_real) = (params + [1, 0])[:3] if options.id: short_id = options.id create_list = client.get_list(CREATE_LIST_ID) card = get_card_by_id(create_list, short_id) if not card: handle_error('Card not found') full_title = '%dº (%d,%d) %s' % (priority, t_estimated, t_real, card.name) card._set_remote_attribute('name', "#%d.%s" % (short_id, full_title)) checkout_by_id(repo, short_id) else: if not options.title: handle_error('(-t <title>) to load is required') full_title = '%dº (%d,%d) %s' % (priority, t_estimated, t_real, options.title) check_untracked(repo) create_list = client.get_list(CREATE_LIST_ID) card = create_list.add_card(full_title, options.description) if options.user: users = check_params(options.user) for member_pos in users: member_id = MEMBERS[member_pos] if (member_id <> USER): card.assign(member_id) card.assign(USER) card.fetch() short_id = int(card.short_id) card._set_remote_attribute('name', "#%d.%s" % (short_id, card.name)) checkout_by_id(repo, short_id) elif ('commit' in args): create_list = client.get_list(CREATE_LIST_ID) card = get_current_card(repo, create_list) if not options.comment: handle_error('(-c <comment>) to commit is required') card.comment(options.comment) git_add_commit(repo, options.comment) elif ('push' in args): create_list = client.get_list(CREATE_LIST_ID) card = get_current_card(repo, create_list) message = "CLOSED AT %s.\n%s" % (time.strftime('%Y-%m-%d %H:%M'), options.comment or "") git_add_commit(repo, message) card.comment(message) card.change_list(DONE_LIST_ID) try: repo.remotes.origin.pull() except CalledProcessError: pass active_branch = repo.active_branch.name repo.remotes.origin.push() repo.heads.devel.checkout() check_call(('git', 'merge', active_branch)) elif ('rebuild' in args): done_list = client.get_list(DONE_LIST_ID) card = get_current_card(repo, done_list) else: create_list = client.get_list(CREATE_LIST_ID) card = get_current_card(repo, create_list) message = "TESTED AT %s.\n%s" % (time.strftime('%Y-%m-%d %H:%M'), options.comment or "") git_add_commit(repo, message) repo.heads.devel.checkout() repo.remotes.origin.pull() checkout_by_id(repo, card.short_id, 'I') try: check_call(('git', 'merge', 'F-#%d' % card.short_id)) except CalledProcessError as error: handle_error('Conflict merge.') else: try: git_add_commit(repo, 'merge devel - I-#%d' % card.short_id) except CalledProcessError as error: handle_error(error)
with open(CONFIG_FILE_NAME, 'r') as conf_file: conf_data = json.load(conf_file) auth_data = conf_data[AUTH_DATA_KEY] # Logging in to Pocket pocket_consumer_key = conf_data[AUTH_DATA_KEY]['pocket_consumer_key'] pocket_client = Pocket( conf_data[AUTH_DATA_KEY]['pocket_consumer_key'], conf_data[AUTH_DATA_KEY]['pocket_user_credentials']['access_token']) logger.info('Logged in to Pocket') # Logging in to Trello trello_client = TrelloClient( api_key=conf_data[AUTH_DATA_KEY]['trello_api_key'], token=conf_data[AUTH_DATA_KEY]['trello_token']) trello_list = trello_client.get_list(conf_data['trello_list_id']) logger.info('Logged in to Trello') now_timestamp = int(datetime.now().timestamp()) since_timestamp = conf_data[ 'pocket_last_checked'] if 'pocket_last_checked' in conf_data else now_timestamp new_pocket_items, _ = pocket_client.get(since=since_timestamp) logger.info('Fetched new Pocket items') if len(new_pocket_items['list']) == 0: logger.info('No new items.') else: for pocket_item_id, pocket_item_data in new_pocket_items['list'].items(): # status - 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted
}, ... ] """ import sys from ratelimit import limits from trello import TrelloClient, Card import json # Load file and parse json new_apps = json.load(open(sys.argv[1])) new_apps = sorted(new_apps, key=lambda x: x["count"], reverse=True) # connect to Trello API client = TrelloClient(api_key=sys.argv[2], token=sys.argv[3]) # The ToDO list todo = client.get_list('5f7f8dd1238edd7ceea5f81d') # Method to create card (rate limited as to specification) @limits(calls=100, period=10) def sendCardCreationCall(trellist, name, appfilter): trellist.add_card(name=name, desc=appfilter, position="bottom") # loop over apps to add for app in new_apps: sendCardCreationCall( todo, app["name"], "ComponentInfo:\n{appfilter}\n\nPlay Store:\n{url}\n\nRequested {count} times" .format(**app))
class Trello: COMMENT_PREFIX = "external_id=" log = logging.getLogger(__name__) def __init__(self): self.config = load_config("config/trello-config.yaml") self.cards_with_external_ids = [] self.labels = {} app_key = self.config['app_key'] token = self.config['token'] board_id = self.config['board_id'] self.board = TrelloClient(api_key=app_key, token=token).get_board(board_id) self.classify_board() self.log.debug("Connecting to Trello board {0}".format(board_id)) def classify_board(self): cards = self.board.all_cards() self.log.debug("Classifying Trello board, contains {0} cards".format(len(cards))) for label in self.board.get_labels(): self.labels[label.name] = label for card in cards: if card.closed: self.log.info("Ignoring closed card {0} ({1})".format(card.name, card.id)) else: self.log.debug("Looking for external id in {0}".format(card.name)) self.cards_with_external_ids.append(Trello.get_external_id(card)) @staticmethod def get_external_id(card): external_id = None card.fetch() comments = card.comments if comments: for comment in comments: text = comment['data']['text'] if Trello.COMMENT_PREFIX in text: external_id = re.sub(Trello.COMMENT_PREFIX, '', text) return external_id def clear_board(self): for card in self.board.all_cards(): self.log.info("Deleting {0} {1}".format(card.name, card.id)) card.delete() def card_exists(self, identifier): return identifier in self.cards_with_external_ids def add_cards(self, cards): default_list = self.board.get_list(self.config['default_list']) self.log.info("Adding {0} cards to lane {1} ({2})".format(len(cards), default_list.name, default_list.id)) for card in cards: name = card['name'] identifier = card['identifier'] card_type = card['type'] note = card['note'] card = default_list.add_card(name) if note is not None: card.set_description(note) card.comment("{0}{1}".format(Trello.COMMENT_PREFIX, identifier)) try: card.add_label(self.labels[card_type]) self.log.info("Creating card with details: name={0} id={1} type={2}". format(name, identifier, card_type)) except KeyError: self.log.info("Can't find card type {0} configured in Trello".format(card_type)) self.log.info("Creating card with details: name={0} id={1} type=default". format(name, identifier)) def find_completed_card_ids(self): completed_lists = self.config['completed_lists'] self.log.info("Looking for cards in completed lanes: {0}".format(completed_lists)) cards = [] for list_id in completed_lists: completed_list = self.board.get_list(list_id) cards.extend([Trello.get_external_id(card) for card in completed_list.list_cards()]) # [cards.extend([card.external_card_id for card in self.trello.lane.get(lane).cards # if len(card.external_card_id) > 1]) for lane in lanes] self.log.info("Found {0} completed cards on the board".format(len(cards))) self.log.debug("External ids: {0}".format(cards)) return cards
class TrelloAPI(): """ docstring """ def __init__(self): """ docstring """ self._api_key = None self._token = None result = self._GetFile() self._SetAPIKeyToken(result) self._client = None self._TrelloClientAccess() self._board = [] self._doing_list = [] self._cards = [] def _TrelloClientAccess(self): """ docstring """ self._client = TrelloClient( api_key=self._api_key, api_secret=self._token, ) def _GetFile(self, path="../../mine/Token.txt"): """ docstring """ with open(path, encoding="utf-8") as target: result = target.readlines() result = list(map(lambda i: i.rstrip("\n"), result)) return result def _SetAPIKeyToken(self, files): """ docstring """ self._api_key, self._token = files def _GetBookList(self): path = self._GetFile("../../mine/list.txt") self._doing_list = self._client.get_list(path[0]) # print(self._doing_list.name) def _GetBoardList(self): path = self._GetFile("../../mine/Borad.txt") self._board = self._client.get_board(path[0]) def _GetCardslist(self): self._cards = self._board.get_cards() def _GetDoingBookList(self): self._GetBookList() self._GetBoardList() self._GetCardslist() result = {} for i in self._cards: if i.list_id == self._doing_list.id: result[i.name.replace("\u3000", " ")] = i return result def _AddDoingBookList(self, book_name): self._GetBookList() self._GetBoardList() result = self._doing_list.add_card(book_name) dt = datetime.date.today() result.comment("READ START " + dt.strftime("%Y-%m-%d")) # print(self._doing_list) return True if result is not None else False def _AddResult(self, result): """ everyday :daily doing today check list add book : move done book_name end read date """ if result["today"]: pass if result["time"]: pass if result["finish"]: pass pass def _AddEveryday(self): pass def _MoveBookIsDone(self): pass def _MoveCard(self, ): """ docstring """ raise NotImplementedError
class Trello: # cache shared across all instances of this class list_cache = {} def __init__(self, member, api_key, api_secret, token): self.trello = TrelloClient(api_key=api_key, api_secret=api_secret, token=token) self.member = member self.cards = [] print(f"Fetching cards for {self.member}") self.get_member_cards() def get_member_cards(self): member = self.trello.get_member(self.member) self.cards = member.fetch_cards() self.preprocess_cards() def get_list_name(self, list_id): """ cache trello List objects """ if list_id not in self.list_cache: list_data = self.trello.get_list(list_id) # ensure we stay under 100 hits per 10 sec period limit time.sleep(0.15) self.list_cache[list_id] = list_data return self.list_cache[list_id].name def date_str_to_datetime_obj(self, date_str): # trim off miscroseconds and Z char, and set to UTC trimmed = date_str[0:-5] + "+0000" return datetime.datetime.strptime(trimmed, "%Y-%m-%dT%H:%M:%S%z").astimezone() def preprocess_cards(self): for c in self.cards: # store actual list name c['listName'] = self.get_list_name(c['idList']) # localize dates c['dateLastActivity'] = self.date_str_to_datetime_obj( c['dateLastActivity']) if c['due']: c['due'] = self.date_str_to_datetime_obj(c['due']) def get_done(self): """ return the cards that are considered 'Done' """ done = [c for c in self.cards if c['dueComplete']] done = sorted(done, key=lambda c: c['dateLastActivity']) return done def get_to_complete(self): """ return the cards that are considered 'To Be Completed'. that means if it has a due date and it's not marked completed yet. """ to_complete = [ c for c in self.cards if not c['dueComplete'] and c['due'] is not None ] to_complete = sorted(to_complete, key=lambda c: c['due']) return to_complete def get_missing_due_date(self): # cards should never be missing a due date missing_due_date = [ c for c in self.cards if not c['dueComplete'] and c['due'] is None ] missing_due_date = sorted(missing_due_date, key=lambda c: c['dateLastActivity']) return missing_due_date def output_to_file(self): """ for debugging """ output = """ <html> <head> <style> h1 { } table th { text-align: left; } table td { text-align: left; } </style> </head> <body> """ output += "<h1>Done</h1>\n" output += "<table><thead><th>Est. Completion Date</th><th>Name</th></thead>\n" for card in self.get_done(): output += "<tr><td>%s</td><td><a href='%s'>%s</a></td></tr>\n" % ( card['dateLastActivity'].strftime("%c"), card['shortUrl'], card['name']) output += "</table>" output += "<h1>To Be Completed</h1>\n" output += "<table><thead><th>Due Date</th><th>Name</th></thead>\n" for card in self.get_to_complete(): output += "<tr><td>%s</td><td><a href='%s'>%s</a></td></tr>\n" % ( card['due'].strftime("%c"), card['shortUrl'], card['name']) output += "</table>" output += "<h1>Missing Due Date</h1>" output += "<table><thead><th>Last Updated</th><th>Name</th></thead>\n" for card in self.get_missing_due_date(): output += "<tr><td>%s</td><td><a href='%s'>%s</a></td></tr>\n" % ( card['dateLastActivity'].strftime("%c"), card['shortUrl'], card['name']) output += """ </body> </html> """ f = open("allcards.html", "w") f.write(output) f.close()
class doit: board_id = config.BOARD_ID def intialise_trello(self): self.trello_client = TrelloClient(api_key=TRELLO_API_KEY, api_secret=TRELLO_API_SECRET) def get_board(self): boards = self.trello_client.list_boards() for i in range(len(boards)): print(str(i) + ': ' + boards[i].name) done = False while not done: board_number = int(prompt.query('Board number: ')) puts(colored.yellow('Confirm board: ' + boards[board_number].name)) if prompt.query('Confirm: y/n: ') == 'y': self.board = boards[board_number] self.board_id = self.board.id puts(colored.green(self.board.name + ' confimed')) done = True def get_ticket_number(self): ticket_number = prompt.query('Ticket Number: ') puts(colored.yellow('Confirm ticket #' + str(ticket_number))) if prompt.query('Confirm: y/n: ') == 'y': self.ticket_number = int(ticket_number) puts(colored.green('#' + str(ticket_number) + ' confirmed!')) else: self.get_ticket_number() def get_trello_board(self): print('hi') def send_pr(self, pr_title): os.system("git pr") def get_card(self): for card in self.trello_client.get_list( config.BACKLOG_LIST_ID).list_cards(): if card.short_id == self.ticket_number: self.card = card self.card_title = card.name.split(") ", 1)[1] return puts( colored.red('Card not found in backlog with number: #' + str(self.ticket_number))) def process(self): for i in range(len(config.PROCESS_LIST_IDS[1:])): list = self.trello_client.get_list(config.PROCESS_LIST_IDS[i + 1]) input = prompt.query('Move to: ' + list.name + '? y/n') if input == 'y': self.card.change_list(list.id) self.card.set_pos('bottom') puts(colored.green('Moved!')) if list.id == config.PR_LIST_ID: puts(colored.yellow('Submitting PR')) self.pull_request() puts(colored.green('Submitted!')) def pull_request(self): os.system("git push") master_command = "hub pull-request -m \"" + self.card_title + "\" -h `git rev-parse --abbrev-ref HEAD` -b master -l \"master\"" staging_command = "hub pull-request -m \"" + self.card_title + "\" -h `git rev-parse --abbrev-ref HEAD` -b staging -l \"staging\"" master = subprocess.check_output(master_command, shell=True) staging = subprocess.check_output(staging_command, shell=True) self.master_pr = str(master)[2:].split("\\")[0] self.staging_pr = str(staging)[2:].split("\\")[0] puts(colored.green('Master link: ' + self.master_pr)) puts(colored.green('Staging link: ' + self.staging_pr)) def do(self): self.intialise_trello() self.get_ticket_number() self.get_card() self.process()
) trello_label = input('Enter the Card Label: ') trello_description = input('Description (optional): ') if len(trello_label) == 0: print("ERROR: Please provide a Label to create the card") sys.exit(-1) elif len(trello_description) == 0: trello_description = "" try: my_board = trello.get_board(BOARD_ID) board_lists = my_board.all_lists() #print(board_lists) for boardList in board_lists: boardList.fetch() # print(boardList.name + ": " + boardList.id) theListID = LIST_ID if len(LIST_ID) == 0: theListID = board_lists[0].id trello.get_list(theListID).add_card(trello_label, trello_description) except ResourceUnavailable as e: print('ERROR: %s' % e._msg) sys.exit(-1)
from trello import TrelloClient from github import GitHub from pprint import pprint from datetime import date, timedelta from time import strptime, mktime from os import getenv trello_client = TrelloClient( api_key=getenv("TRELLO_API_KEY"), api_secret=getenv("TRELLO_API_SECRET"), token=getenv("TRELLO_TOKEN") ) github_client = GitHub(access_token=getenv("GITHUB_ACCESS_TOKEN")) backlog = trello_client.get_list(list_id='5361b7091b0f3942310ab040') backlog.client = trello_client issues = github_client.repos('freedomofpress')('securedrop').issues.get(state='open') pprint(issues[0]) pprint(backlog) # a_month_ago = date.today() - timedelta(weeks=4) # # for issue in issues: # time_struct = strptime(issue['updated_at'], u"%Y-%m-%dT%H:%M:%SZ") # issue.date_time = mktime(time_struct) # # relevant_issues = [issue for issue in issues if date.fromtimestamp(issue.date_time) > a_month_ago] # # for issue in relevant_issues: # pprint(issue['updated_at'])
token=TOKEN ) def more_info(card): name = card.name labels = [label.name for label in card.labels] desc = card.description return "\n".join([name, "labels: " + ", ".join(labels), desc]) if __name__ == "__main__": r = Rofi() option = r.select(prompt="action: ", options=options).selection if option == "work": cards = client.get_list(ACTION_LIST).list_cards() random.shuffle(cards) selected_card = r.select(options=cards).selection if selected_card is not None: choice = r.select(options=('show', 'open', "select")).selection if choice is not None: if choice == "show": info = more_info(selected_card) r.show(info) choice, key = r.select(options=('open', "select")) if choice == "open": webbrowser.open(selected_card.url, new=1, autoraise=True) if choice == "select": selected_card.change_list(PROCESS_LIST) r.show("card has moved to PROCESS_LIST")