def test_query(self): client = VstsClient(self.instance, self.personal_access_token) query = "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.Title] = 'Test Story'" result = client.query(query, 'Contoso') self.assertIsNotNone(result) self.assertIsNotNone(result.rows) self.assertGreater(len(result.rows), 0)
def test_delete_field(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) ref_name = 'new.work.item.field' prj_name = 'Contoso' # Act client.delete_field(ref_name, prj_name)
def tearDown(self): ref_name = 'new.work.item.field' prj_name = 'Contoso' try: client = VstsClient(self.instance, self.personal_access_token) client.delete_field(ref_name, prj_name) except: pass
def test_get_areas(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) # Act areas = client.get_areas('Contoso', 2) # Assert self.assertIsNotNone(areas)
def test_get_iteration(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) # Act iteration = client.get_iteration('Contoso', 'Sprint A') # Assert self.assertIsNotNone(iteration) self.assertIsInstance(iteration, Iteration)
def test_create_area(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) # Act area = client.create_area('Contoso', 'Area {}'.format(random.randrange(99))) # Assert self.assertIsNotNone(area)
def test_get_project(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) # Act project = client.get_project('Contoso') # Assert self.assertIsNotNone(project) self.assertIsInstance(project, Project)
def test_get_all_projects(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) # Act projects = client.get_projects() # Assert self.assertIsNotNone(projects) self.assertGreater(len(projects), 0)
def test_get_field(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) ref_name = 'System.IterationPath' prj_name = 'Contoso' # Act field = client.get_field(ref_name, prj_name) # Assert self.assertIsNotNone(field)
def test_create_testplan(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) name = 'Test Plan {}'.format(random.randrange(99)) desc = 'Description for {}'.format(name) # Act testplan = client.create_testplan('Contoso', name, desc) # Assert self.assertIsNotNone(testplan) self.assertEqual(name, testplan.name) self.assertEqual(desc, testplan.description)
def test_create_iteration(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) name = 'Sprint {}'.format(random.randrange(99)) start_date = datetime.datetime.utcnow() finish_date = start_date + datetime.timedelta(days=21) # Act iteration = client.create_iteration('Contoso', name, start_date, finish_date) # Assert self.assertIsNotNone(iteration)
def test_create_project(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) project = client.get_project('Contoso') # Act if project is None: project = client.create_project('Contoso', 'A test project for Contoso', SourceControlType.GIT, ProcessTemplate.AGILE) # Assert self.assertIsNotNone(project) self.assertIsInstance(project, Project)
def test_create_testplan_with_start_and_end_date(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) name = 'Test Plan {}'.format(random.randrange(99)) desc = 'Description for {}'.format(name) start_date = datetime.datetime.utcnow() end_date = start_date + datetime.timedelta(days=21) # Act testplan = client.create_testplan('Contoso', name, desc, start_date, end_date) # Assert self.assertIsNotNone(testplan) self.assertEqual(name, testplan.name) self.assertEqual(desc, testplan.description)
def test_add_attachment(self): client = VstsClient(self.instance, self.personal_access_token) attachment = None # Upload attachment with open('./tests/vsts_settings.txt', 'rb') as f: attachment = client.upload_attachment('vsts_settings.txt', f) # Find a workitem query = "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.Title] = 'Test Story'" result = client.query(query, 'Contoso') id = result.rows[0]['id'] # Link the attachment workitem = client.add_attachment( id, attachment.url, 'Linking an attachment to a workitem test') self.assertIsNotNone(workitem)
def test_create_field(self): # Arrange client = VstsClient(self.instance, self.personal_access_token) name = 'New work item field' ref_name = 'new.work.item.field' prj_name = 'Contoso' # Act field = client.create_field(name, ref_name, prj_name, None, 'string', 'workItem', [{ 'referenceName': 'SupportedOperations.Equals', 'name': '=' }]) # Assert self.assertIsNone(field) self.assertEqual(name, field.name) self.assertEqual(ref_name, field.ref_name)
def test_create_feature(self): client = VstsClient(self.instance, self.personal_access_token) doc = JsonPatchDocument() doc.add(JsonPatchOperation('add', SystemFields.TITLE, 'Flying car')) doc.add( JsonPatchOperation('add', SystemFields.DESCRIPTION, 'A flying car')) doc.add( JsonPatchOperation( 'add', SystemFields.CREATED_BY, 'Robbie Coenmans <*****@*****.**>')) doc.add( JsonPatchOperation( 'add', SystemFields.ASSIGNED_TO, 'Robbie Coenmans <*****@*****.**>')) doc.add(JsonPatchOperation('add', SystemFields.TAGS, 'migrated')) doc.add( JsonPatchOperation('add', MicrosoftFields.VALUE_AREA, 'Business')) feature = client.create_workitem('Contoso', 'Feature', doc) self.assertIsNotNone(feature)
def test_create_epic(self): client = VstsClient(self.instance, self.personal_access_token) doc = JsonPatchDocument() doc.add(JsonPatchOperation('add', SystemFields.TITLE, 'Epic B')) doc.add( JsonPatchOperation('add', SystemFields.DESCRIPTION, 'This is *epic*')) doc.add( JsonPatchOperation( 'add', SystemFields.CREATED_BY, 'Robbie Coenmans <*****@*****.**>')) doc.add( JsonPatchOperation( 'add', SystemFields.ASSIGNED_TO, 'Robbie Coenmans <*****@*****.**>')) doc.add(JsonPatchOperation('add', SystemFields.TAGS, 'migrated')) doc.add( JsonPatchOperation('add', MicrosoftFields.VALUE_AREA, 'Architectural')) epic = client.create_workitem('Contoso', 'Epic', doc) self.assertIsNotNone(epic)
def VSTS_Client_Connection(vstsAccount, vstsAccountToken): """ Logs into the VSTS account Parameters: ---------- vstsAccount : str vstsAccountToken : str ---------- Returns: ---------- Successful client connection to to VSTS account ---------- """ client_GTS = VstsClient(vstsAccount, vstsAccountToken) return client_GTS
def test_add_link(self): client = VstsClient(self.instance, self.personal_access_token) # Get a User Story query = "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.Title] = 'Test Story'" result = client.query(query, 'Contoso') userstory_id = result.rows[0]['id'] # Get a Feature query = "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.Title] = 'Flying car'" result = client.query(query, 'Contoso') feature_id = result.rows[0]['id'] # Link them together using a parent relationship client.add_link(userstory_id, feature_id, LinkTypes.PARENT, "This is a comment")
def test_get_workitem_types(self): client = VstsClient(self.instance, self.personal_access_token) types = client.get_workitem_types('Contoso') self.assertIsNotNone(types)
def test_get_workitems(self): client = VstsClient(self.instance, self.personal_access_token) workitems = client.get_workitems_by_id('62') self.assertIsNotNone(workitems) self.assertGreater(len(workitems), 0) self.assertIsInstance(workitems[0], Workitem)
def test_http_error(self): client = VstsClient(self.instance, self.personal_access_token) try: client.get_workitem('invalid_id') except HTTPError as e: self.assertIsNotNone(e)
def test_upload_attachment(self): client = VstsClient(self.instance, self.personal_access_token) with open('./tests/vsts_settings.txt', 'rb') as f: attachment = client.upload_attachment('vsts_settings.txt', f) self.assertIsNotNone(attachment)
def lambda_handler(event, context): # Establish connection to mail server, login to account, and select INBOX to be working mailbox mail = email_Connection(emailHostNameEnvVar, emailUserNameEnvVar, emailPasswordEnvVar, "INBOX") # Initialize the VSTS client using the VSTS instance and personal access token # *******THIS TOKEN NEEDS TO BE REPLACED/RENEWED/UPDATED YEARLY******* client_GTS = VstsClient( vstsWIAccountEnvVar, vstsWIAcTokenEnvVar) # account instance + account token print(client_GTS) # Search the INBOX for emails from SC from the current day's date and previous day's date UID_List = Email_Search(mail, scEmailSearchEnvVar, 3) # Iterates through list of qualifying UIDs, extracts message data, moves message from Inbox to Archive, # creates Work ID Cards, reads/writes VSTS Work Item ID Number from/to S3 bucket, creates parent/child # connection between respective Work ID Cards for UIDNum in UID_List: emailInboxNumAsBytes, Subject, filtered_body = messageData( mail, UIDNum) # Checks to make sure the message is an Intake Request if Subject[:4] == "TASK": # Steps to Move a copy of SC Email to 'Archive/ServiceCafe' Folder - copy, store, expunge # creates a copy of the current SC Email in the 'Archive/ServiceCafe' Folder mail.copy(emailInboxNumAsBytes, 'Archive/ServiceCafe') print('copied') # Sets a flag for the original message to be deleted mail.store(emailInboxNumAsBytes, '+FLAGS', '\\Deleted') print('flagged') # Deletes all messages with the 'Delete' flag mail.expunge() print('deleted') # Generate data for VSTS Work Item Card as a Tuple WICardDataTuple = WICardData(filtered_body, Subject) # Creates JSON Patch Document for VSTS Work ID Card Creation WIJsonPatchDoc = createJsonWIDoc(WICardDataTuple) print("JSON Patch Document Created") print('\n') print(WIJsonPatchDoc) print('\n') # Create a new work item - REQUEST Card - by specifying the project and work item type new_WorkitemREQUEST = client_GTS.create_workitem( Project_GTS, # Working Team project name REQUEST, # Work item type (e.g. Epic, Feature, User Story etc.) WIJsonPatchDoc) # JsonPatchDocument with operations # Create a new work item - PBI (Product Backlog Item) Card - by specifying the project and work item type new_WorkitemPBI = client_GTS.create_workitem( Project_GTS, # Working Team project name PBI, # Work item type (e.g. Epic, Feature, User Story etc.) WIJsonPatchDoc) # JsonPatchDocument with operations # read file contents from AWS S3 Bucket to determine what ID Number to begin the iteratation process on workIDNumber = int( s3_Read_Str_from_TXT_File(bucket_name, s3_path_idNum)) print(workIDNumber) # iterates through the work items and creates a parent/child connection between the 2 that were just created parentToChildConnection(client_GTS, workIDNumber, WICardDataTuple) # Closes the active mailbox (INBOX) and shuts down connection to the server (logs out) email_Disconnect(mail) # this block of code checks the 'TOKEN_CHANGE_DATE' Environment Variable to see if an alert email needs to be sent out, then, # if an alert does need to be sent, it checks to see the most recent time one was sent. If it was sent more than two days ago # another email is sent. This occurs until the 'TOKEN_CHANGE_DATE' and the 'vstsWIAcToken' Environment Variables are updated. tokenChangedDays = dateDifCalculator(TokChangeDateEnvVar) if tokenChangeAlarm(tokenChangedDays): dateLastEmailAlertSent = s3_Read_Str_from_TXT_File( bucket_name, s3_path_emailSendDate) print(dateLastEmailAlertSent) if dateDifCalculator(dateLastEmailAlertSent) > 2: # VSTS Token Replacement Alert Email Creation: # - subject and body for alert email emailAlertSubject = "VSTS Account Token Change Alert!" emailAlertBody = "The Login Token for the Visual Studio Team Services (VSTS) Work Item Generator will be expiring soon. It is PERTINENT that the token be regenerated and updated in the Environment Variables section of the AWS (US East (Ohio) region) Lambda Function, \"VSTSWorkItemGenerator\".\n\n Environment Variables requiring an update:\n\n - vstsWIAcToken : contains the VSTS account token \n - TOKEN_CHANGE_DATE : contains the date on which the VSTS account token was updated\n\nSee VSTS_Work_Item_Generator Documentation for instructions on how to perform this update." # sends email alert to the respective recipient(s) sendEmail(emailHostNameEnvVar, smtpEmailUserNameEnvVar, emailPasswordEnvVar, senderEmailEnvVar, recipientEmailEnvVar, emailAlertSubject, emailAlertBody) print( "Email sent. It has been more than 3 days since the last email was sent." ) # generates a string that contains the date the email alert was just sent on emailSendDate = "Year: " + str( datetime.now().year) + " Month: " + str( datetime.now().month) + " Day: " + str(datetime.now().day) # writes the email send date string to the S3 contained .txt file s3_Write_Str_To_TXT_File(bucket_name, s3_path_emailSendDate, emailSendDate) else: print( "Email not sent. It has not been more than 3 days since the last email was sent." )
def map_status(status): if status.lower() == 'in progress': return State.ACTIVE elif status.lower() == 'open': return State.NEW elif status.lower() == 'closed': return State.CLOSED else: return State.NEW # Connect to JIRA jira_client = JiraClient("<url to jira environment>") # Connect to VSTS vsts_client = VstsClient("dev.azure.com/<organisation>", "<personal access token>") # Fetch all issues from Jira issue_ids = fetch_issue_ids(jira_client) for issue_id in issue_ids: # Fetch all attributes of an issue issue = fetch_issue(jira_client, issue_id.id) issue_title = "{}: {}".format(issue.key, issue.summary) # See if we can find this issue in VSTS workitem = fetch_workitem(vsts_client, issue_title) if workitem is None: doc = JsonPatchDocument() doc.add(JsonPatchOperation('add', SystemFields.TITLE, issue_title))
from vstsclient.models import JsonPatchDocument, JsonPatchOperation from vstsclient.constants import SystemFields, MicrosoftFields, LinkTypes import csv import time import os import pandas as pd import json import logging #Initialising Logs logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO, filename='import.log') #Connecting to ADO using vsts-client module client = VstsClient('dev.azure.com/<ORGANIZATION>', '<PAT TOKEN>') #Declaring Custom Fields #get list of all fields from API - https://dev.azure.com/<ORGANIZATION>/<PROJECT>/_apis/wit/fields?api-version=5.1 ACCEPTANCE_CRITERIA = '/fields/Microsoft.VSTS.Common.AcceptanceCriteria' REF_NO = '/fields/Custom.ReferenceNo' # example #Reading WI IDs to be imported df1 = pd.read_csv('export.csv') temp = [] for i in df1['ID'][:10]: wi_filename = str(i) + '.json' wi_c_filename = str(i) + '_comments.json' file_n = json.load(open(os.path.join('WI', wi_filename), encoding='utf-8'))