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)
示例#7
0
    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)
示例#8
0
    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)
示例#10
0
 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)
示例#12
0
    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)
示例#13
0
 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)
示例#15
0
    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)
示例#18
0
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)
示例#24
0
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."
            )
示例#25
0
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'))