Idea ID: 1795411

ALM Octane - GET entities workflow transitions data

Status : Accepted
over 2 years ago
Hi,
 
To have API access or GUI, in order to shortlist/ distinguish defect or tests; which passed on specific entity’s workflow primary or secondary transition for specific phases eg; How many defect transit from "open to re-open", "rejected to closed” or “fixed to closed” etc.

Thanks,

Labels:

Business Rules
  • Hi,

    We are actually going to provide very soon a Business Rule with the functionality to increment a numeric value in case of an event. so you can use this to increment a value of certain udf each time a defect is rejected or reopened and then easily filter and find these defects.

    in addition and for a more complete reporting needs for all field changes use cases you want to track - you can use the audit API to extract the data for entity changes of fields (in your request - phases) , and using some code logic, extract the data that you need.

    based on this feedback we are going to provide some examples in Octane formal documentation (for the Audit part) for how to use the audit API to extract data like the requested above.

    For your specific request, R&D have created code samples in JS, to show how you can get the following:

    1. all defects that were reopened in a certain period of time

    2. all defects that were rejected 

    see the code sample below:

     

    //function definition
    async function getAudits(sharedspace, workspace, fromTimestamp, tillTimestamp, fromPhase, toPhase) {
       
        const MAX_LIMIT = 1000;
        let previousResults = {};
       
        do {
            //call GET audits resource and filter according to timestamp, entityType, action and field name
            let response = await fetch(`/api/shared_spaces/${sharedspace}/workspaces/${workspace}/audits?query="timestamp>=^${fromTimestamp}^;timestamp<=^${tillTimestamp}^;entity_type=^defect^;action=^update^;field_name=^phase^"&limit=${MAX_LIMIT}`);
           
            //verify response
            if (response.status !== 200){
                console.log('fail to call the audit resource');
                return;
            }
           
            //convert to json array
            audits = await response.json();
           
            //no relevant audits were found
            if (audits.data.length === 0 ){
                return;
            }
           
            //get the last audit result
            let lastAudit = audits.data[audits.data.length - 1];
           
            console.log('audits until timestamp=', lastAudit.timestamp);
           
            //if we got MAX_LIMIT results with the same timestamp, finish the function to avoid infinite loop
            if (audits.data.length === MAX_LIMIT && lastAudit.timestamp === tillTimestamp) {
                console.err('all the audits with the same timestamp');
                return;
            } else {
                //advance the index: tillTimestamp
                tillTimestamp = lastAudit.timestamp;
            }
           
            //actual filter according to the requested fromPhase and toPhase
            let filteredAudits = audits.data.filter(audit => audit.change_set.some(cs => cs.old_value === fromPhase && cs.value === toPhase));
           
            //check result wasn't printed in previous iteration
            filteredAudits = filteredAudits.filter(audit => !previousResults[audit.entity_id + '_' + audit.timestamp]);
           
            //init previousResults to next iteration
            previousResults = {};
           
            filteredAudits.forEach(filterAudit => {
                //save this audit for next iteration
                previousResults[filterAudit.entity_id + '_' + filterAudit.timestamp] = true;
               
                //actual output
                console.log(filterAudit.entity_id, filterAudit.timestamp, filterAudit);
               
            });
            //keep iterated until we got less results than the maximum
        } while (audits.data.length === MAX_LIMIT);
       
    }

    Now calling the function getAudits(sharedspaceId, workspaceId, fromTimestamp, tillTimestamp, fromPhase, toPhase);

     

    i.e. the following two examples we’ve discussed

    //function call I - fixed -> opened
    fromTimestamp = "1970-01-01T00:00:00Z";
    tillTimestamp = "2030-01-01T00:00:00Z";

    fromPhase = 'phase.defect.fixed';
    toPhase = 'phase.defect.opened';

    getAudits(<space_id>, <workspace_id>, fromTimestamp, tillTimestamp, fromPhase, toPhase);

     

    //function call II – rejected -> closed

    fromTimestamp = "1970-01-01T00:00:00Z";
    tillTimestamp = "2030-01-01T00:00:00Z";

    fromPhase = 'phase.defect.rejected';
    toPhase = 'phase.defect.closed';

    getAudits(<space_id>, <workspace_id>, fromTimestamp, tillTimestamp, fromPhase, toPhase);

     

    Regards,

    Sigal