Functions

Mathematical Functions

You can use the operators MIN(param[,param,param...]), MAX(param[,param,param...]), ABS(param), and AVR(param[,param,param...]) if you need to determine the minimum, maximum, absolute or average value in a set of parameters.

For more advanced calculations, the following functions are also available:

  • EXP(<Computation> value) to calculate the exponential of a value

  • LN(<Computation> value) to calculate the natural logarithm of a value

  • LOG(<Computation> value, <Computation> base) to calculate the logarithm of a value

  • POW(<Computation> value, <Computation> power) to calculate a power

  • SQRT(<Computation> value) to calculate a square root

  • ROUND(<Computation> value) to round a number to the nearest integer

  • FLOOR(<Computation> value) to round down a number to the nearest integer

  • CEIL(<Computation> value) to round up a number to the nearest integer

  • CENTROID(<Computation> value [| <computation> weight], ...) to calculate the centroid of comma-separated pairs of value|weight. If no weight is specified, it is set to 1.

  • FCENTROID(<Computation> min, <Computation> max, <Computation> value [| <computation> weight], ...) to calculate the filtered centroid of comma-separated pairs of value|weight. When using the FCENTROID() function, only the values within min and max are used to calculate a CENTROID(). To specify infinity as a bound, leave the value of min or max empty. If no values match the filter, the default value is returned.

  • FMIN(<Computation> min, <Computation> max, <Computation> value [, <Computation> value, <Computation> value...]) to calculate the filtered minimum of comma-separated values. When using the FMIN() function, only the values within min and max are used to calculate a MIN(). To specify infinity as a bound, leave the value of min or max empty. If no values match the filter, the default value is returned.

  • FMAX(<Computation> min, <Computation> max, <Computation> value [, <Computation> value, <Computation> value...]) to calculate the filtered maximum of comma-separated values. When using the FMAX() function, only the values within min and max are used to calculate a MAX(). To specify infinity as a bound, leave the value of min or max empty. If no values match the filter, the default value is returned.

  • FSUM(<Computation> min, <Computation> max, <Computation> value [, <Computation> value, <Computation> value...]) to calculate the filtered sum of comma-separated values. When using the FSUM() function, only the values within min and max are used to calculate a SUM(). To specify infinity as a bound, leave the value of min or max empty. If no values match the filter, the default value is returned.

Examples

Using a measure if it is above a threshold, else use the threshold:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="MAX(10,VG)" />
</Measure>

Using the higher of two measures:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="MAX(LC,SLOC)" />
</Measure>

Using lower of three indicators:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="MIN(I.TESTABILITY, I.CHANGEABILITY, I.ANALISABILITY)" />
</Measure>

Example preventing division by 0:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="LC / MAX(STAT, 1)" />
</Measure>

Example retrieving the variation of a measure:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="ABS(DELTA_VALUE(LC))" />
</Measure>

Example using nested MIN and MAX functions:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="MIN(MAX(SLOC+(BLANK/2),1000),MAX(LC,1000))+2" />
</Measure>

Calculating the average of three indicators:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="AVR(I.TESTABILITY, I.CHANGEABILITY, I.ANALISABILITY)" />
</Measure>

Calculating the centroid of 3 with weight 3 and 2 with weight 100 (=2.03):

Note: this translates to (3x3 + 2x100) / (100+3)

<Measure measureId="MATH_CENTROID_3_3_2_100" defaultValue="0">
<Computation targetArtefactTypes="APPLICATION" result="CENTROID(3|3,2|100)"/>
</Measure>

Calculating the filtered centroid of TESTABILITY/STABILITY/MAINTAINABILITY:

Given the scale:

  • level: UNKNOWN, rank: -1

  • level: LEVELA, rank: 0

  • level: LEVELB, rank: 1

  • level: LEVELC, rank: 2

and given that I.TESTABILITY is UNKNOWN, I.STABILITY is LEVELB, I.MAINTAINABILITY is LEVELC

<Measure measureId="MATH_FCENTROID" defaultValue="0">
<Computation targetArtefactTypes="APPLICATION" result="FCENTROID(0,,I.TESTABILITY|3,I.STABILITY|2,I.MAINTAINABILITY)"/>
</Measure>

I.TESTABILITY is filtered out as it is not between the specified minimum and maximum.

The value is then computed as CENTROID(I.STABILITY|2,I.MAINTAINABILITY), which is (1x2 + 2) / (2+1).

Understanding filtered min, max and sum:

FMIN(,,-2,4,11) 
is equivalent to: FMIN(-Infinity,+Infinity,-2,4,11)
is equivalent to: MIN(-2,4,11)
FMIN(0,10,-2,4,11)
is equivalent to: MIN(4,11)
FMIN(0,1,-2,4,11)
is equivalent to: MIN(), which evaluates to null 
and leads to using the default value of the measure and marking 
it in the indicator tree with the status ERROR.
FMIN(2,,1,I.LC)
is equivalent to: FMIN(2,+Infinity,1,I.lC)
is equivalent to: MIN(I.LC)
resolves to: I.LC if LC >= 2, else default value
FSUM(,,1,2.5,2>1,3)
is evaluated as: 1 + 2.5 + 1 + 3
FSUM(2,4,1,2.5,2>1,3)
is evaluated as: 2.5 + 3
FSUM(6,,-1,I.LC,LC)
resolves to: I.LC if >= 6 or LC if >= 6

Conditional and Level-Related Functions

More advanced decisions can be made when using the following conditional and level-related functions:

  • You can use the IF(cond,val_yes,val_no) function to assign different values based on the result of a condition. Note that nested IF constructions are allowed, and an IF block can contain OR or AND operators.

    Tip

    A condition is simply a computation that returns 1 if true and 0 if false. For example,

    result="SLOC>50"

    returns 1 or 0 depending on the value of SLOC for the current artefact.

  • Use the CASE(measureId,case1:value1,case2:value2[,...][,DEFAULT:value]) function to assign different values to a measure based on the value of another measure. A fallback can be specified by using the DEFAULT case.

  • The NOT(computation) function returns 0 if the result of the computation is greater than or equal to 1, or 1 otherwise.

  • The RANK(scale_id,level_id) function provides a way to retrieve rank values from your model.

  • The FIND_RANK(scale_id,measure_id) function provides a way to retrieve a rank from your model by passing a measure and a scale.

  • The APP(measure_id) function provides a way to retrieve the value of a measure at application level from any artefact:

  • The PARENT(measure_id, [type]) and ANCESTOR(measure_id, [type]), functions provide a way to get a measure value for an artefact's parent or ancestor containing this measure. The concept is similar to that of the APP() function, but PARENT() only checks the artefact's direct parent and ANCESTOR() goes up the tree until finding an artefact (of the optionally specified type) that has the requested measure ID.

    Both functions have an equivalent filtered function to limit the scope of the values included in the search, using the syntax FPARENT(min,max,measure_id, [type]) and FANCESTOR(min,max,measure_id, [type]). Note that if min or max are omitted, they are automatically replaced by -Infinity and +Infinity respectively.

  • The IS_DP_OK(data_provider_name) function provides a way to find out if a Data Provider was executed successfully or not during the analysis. If the data provider was not executed or failed, the function returns 0. If the Data Provider was executed successfully, then the function returns 1.

  • The DP_STATUS(data_provider_name) function provides finer information about the execution status of a Data Provider than IS_DP_OK().

    • returns -1 if the DP was not run

    • returns 0 if the DP was successful

    • returns 1 if the DP returned some warnings

    • returns 2 if the DP reported errors

    • returns 3 if the DP stopped with a fatal error

  • The IS_META_PROJECT() function allows determining if the project is a meta-project, i.e. an aggregation of results from other Squore projects, and allows you to compute results differently if needed. The function returns 0 for regular projects and 1 for meta-projects. For more information about meta-projects, consult the section called “Understanding Wizards”.

  • The IS_APPROVED_TEMPLATE() function returns 1 when the project uses an approved ruleset template, or 0 when it does not. Approved ruleset templates can be created by model managers using the Analysis Model Editor. Refer to the Getting Started Guide for more information about ruleset edition.

  • The IS_ARTEFACT_TYPE(artefact_type) function provides a way to find out if an artefact is of the type specified. If the artefact is of the type specified, the function returns 1, else it returns 0.

  • IS_NEW_ARTEFACT() tests whether the artefact is new for the current version of the project. It returns 1 if true, 0 if false.

  • The IS_RELAXED_ARTEFACT() function provides a way to find out if an artefact's relaxation status. It returns 1 if an artefact is relaxed and 0 if it is not.

  • IS_NEW_FINDING() allows determining if a finding is new in the latest analysis or not. It returns 1 if true, 0 if false.

  • The LINKS(<linkTypeId> [, OUT|IN|IN_OUT] [, CONDITION]) function returns the number of links for an artefact. It requires defining the type of link to consider (linkTypeId) and optionally allows to specify an extra parameter to refine which link directions to consider:

    • OUT considers only outbound links (links from this artefact to other artefacts)

    • IN considers only inbound links (links from other artefacts to this artefact)

    • IN_OUT considers all links for this artefact and is the default value if none is specified

    The function also allows defining a condition to filter out unwanted links when counting. The condition is verified against the target artefacts according to the specified link direction. In order for the condition to be taken into account, the link type and its supported IN and OUT artefacts must be declared in the analysis model, see the section called “Artefact Links” for more details.

  • The LINKS_AGGREGATE(<aggregationType>, <computation>, <linkTypeId> [, OUT|IN|IN_OUT] [, CONDITION] [, default computation]) function (new in 16.3) allows aggregating metrics from linked artefacts. Its parameters are:

    • aggregationType (mandatory) defines how the values for the metrics are aggregated. The supported values are:

      • MIN

      • MAX

      • OCC

      • AVG

      • DEV

      • SUM

      • MED

      • MOD

    • computation (mandatory) is the computation to perform when encountering the desired type of link.

    • linkTypeId (mandatory) is desired type of link to aggregate data from. The link type and its supported IN and OUT artefacts must be declared in the analysis model, see the section called “Artefact Links” for more details.

    • The link direction, which is one of:

      • OUT considers only outbound links (links from this artefact to other artefacts)

      • IN considers only inbound links (links from other artefacts to this artefact)

      • IN_OUT considers all links for this artefact and is the default value if none is specified

    • A computation used as a condition to filter out unwanted artefacts

    • A default computation that is used to return a value in case no link exists

Examples

Set a measure to 6 if SLOC is above a threshold, else set it to 4:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="2+IF(SLOC>50,4,2)" />
</Measure>

Set a measure to 6 if SLOC is above a value and below another one, else set it to 4:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="2+IF(SLOC>50 AND SLOC<100,4,2)" />
</Measure>

A nested IF construction:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="2+IF(I.LC>IF(SLOC>300,SLOC,MAX(250,300)),98,8)" />
</Measure>

Example using NOT:

<Measure measureId="OLD_LARGE_FILE" defaultValue="0">
<Computation targetArtefactTypes="FILE"
result="NOT(IS_NEW_ARTEFACT() AND SLOC<500)" />
</Measure>

An example of CASE() statement (on the metric :

<Measure measureId="EASE_OF_USE" defaultValue="0">
	<Computation targetArtefactTypes="APPLICATION"
				 result="CASE(FEEDBACK,BAD:0,GOOD:50,EXCELLENT:80,DEFAULT:-1)" />
</Measure>

Retrieving rank values using RANK(), given the following scale:

<Scale scaleId="SCALE_LINE">
<ScaleLevel levelId="LEVELA" bounds="];10]"  rank="0" />
<ScaleLevel levelId="LEVELB" bounds="]10;30]" rank="1" />
<ScaleLevel levelId="LEVELC" bounds="]30;60]" rank="2" />
<ScaleLevel levelId="LEVELD" bounds="]60;100]" rank="4" />
<ScaleLevel levelId="LEVELE" bounds="]100;[" rank="8" />
</Scale>

You can use the RANK function as follows to find the rank of LEVELD. The example below returns 4:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="RANK(SCALE_LINE,LEVELD)" />
</Measure>

For more information about scales, refer to the section called “Scales”.

Using RANK is useful when combined with conditions. The examples below are equivalent:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="IF(I.LC>4,1,0)" />
</Measure>
<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="IF(I.LC>RANK(SCALE_LINE,LEVELD),1,0)" />
</Measure>
<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="IF(I.LC>LEVELD,1,0)" />
</Measure>

In the last example, we use the short syntax for the RANK function: >LEVELD is only valid when used after an indicator. The rank retrieved is the rank of level LEVELD for the scale of the current artefact type for the indicator LC.

The FIND_RANK() function is mostly useful when using dynamic scales (see the section called “Dynamic Scales”). The example below assigns to TEST_COVERAGE_RANK the value of the rank for the value of COVERAGE on the scale DYN_SCALE_OK_KO:

<Measure measureId="OBJECTIVE" targetArtefactTypes="APPLICATION;FODLER;FILE;CLASS" defaultValue="0" />
<Measure measureId="COVERAGE" targetArtefactTypes="APPLICATION;FODLER;FILE;CLASS" defaultValue="0" />

<Scale scaleId="DYN_SCALE_OK_KO">
    <ScaleLevel levelId="DYN_OK" bounds="[;APP(OBJECTIVE)]"  rank="0" />
    <ScaleLevel levelId="DYN_KO" bounds="[APP(OBJECTIVE);]" rank="1" />
</Scale>

<Scale scaleId="SCALE_OK_KO">
    <ScaleLevel levelId="OK" bounds="[1;1]"  rank="0" />
    <ScaleLevel levelId="KO" bounds="[0;0]" rank="1" />
</Scale>

<Measure measureId="TEST_COVERAGE_RANK">
	<Computation targetArtefactTypes="APPLICATION"
				 result="FIND_RANK(DYN_SCALE_OK_KO,COVERAGE)" />
</Measure>

<Indicator 
    indicatorId="TEST_COVERAGE" 
    measureId="TEST_COVERAGE_RANK"
    scaleId="SCALE_OK_KO" />

Compute the percentage of lines of code present in the current artefact using the entire application as the reference, with APP():

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="(LC*100)/APP(LC)" />
</Measure>

Mark a method as risky if the parent class has changed, using PARENT():

<Measure measureId="RISKY" defaultValue="0">
<Computation targetArtefactTypes="FUNCTION"
result="PARENT(CHANGED,CLASS)" />
</Measure>

Set an artefact as critical if one of its containing folder is critical:

<Measure measureId="IS_CRITICAL" defaultValue="0">
<Computation targetArtefactTypes="FOLDER;CLASS;FUNCTION"
result="ANCESTOR(IS_CRITICAL,FOLDER)" />
</Measure>

Filtering with FPARENT():

IF(FPARENT(RANK(SCALE_LINE,LEVELG), RANK(SCALE_LINE,LEVELG), I.LC),1,2)
=> resolves as: IF(PARENT(I.LC)=RANK(SCALE_LINE,LEVELG),1,2)
=> return 1 if PARENT(I.LC) = LEVELG, otherwise 2

Filtering with FANCESTOR():

FANCESTOR(500,, LC, FOLDER)
=> returns LC for the first folder ancestor where LC >= 500

Find out if the Checkstyle Data Provider was executed successfully with IS_DP_OK:

<Measure measureId="RAN_CHECKSTYLE" defaultValue="0">
<Computation targetArtefactTypes="APPLICATION;FOLDER;FILE;FUNCTION"
result="IS_DP_OK(Checkstyle)" />
</Measure>

Do something if the artefact is a CHANGE_REQUEST, with IS_ARTEFACT_TYPE:

<ArtefactType id="ISSUE" heirs="BUG;CHANGE_REQUEST;HOTLINE;REGRESSION" />
<Measure measureId="IS_CR" defaultValue="0">
<Computation targetArtefactTypes="ISSUE"
result="IS_ARTEFACT_TYPE("CHANGE_REQUEST")" />
</Measure>

Defining a measure whose value is set to 1 when the artefact is new, else 0:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="IS_NEW_ARTEFACT()" />
</Measure>

Using IS_NEW_ARTEFACT as a condition operator:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="IF(IS_NEW_ARTEFACT(),3,4)" />
</Measure>

Note: IF(IS_NEW_ARTEFACT(),val_yes,val_no) is equivalent to IF(IS_NEW_ARTEFACT()>0,val_yes,val_no)

Counting the number of new findings in this analysis:

<Measure measureId="COUNT_NEW_FINDINGS" defaultValue="-1">
<Computation targetArtefactTypes="APPLICATION;FILE;FUNCTION" 
  result="COUNT RULE.OCCURRENCES FROM TREE WHERE IS_NEW_FINDING()" />
</Measure>

Find the number of failing tests (link type: BLOCKS) for each requirement and requirement folder

<Measure measureId="NUM_FAILING_TESTS" defaultValue="-1">
	<Computation targetArtefactTypes="REQUIREMENT" result="LINKS(BLOCKS,IN)" />
	<Computation targetArtefactTypes="REQUIREMENT_FOLDER" result="SUM REQUIREMENT.NUM_FAILING_TESTS FROM TREE" />
</Measure>

Find the number of failing tests for each requirement, excluding failing tests on relaxed code

<Link id="BLOCKS" inArtefactTypes="CODE" outArtefactTypes="REQUIREMENT" />
	<Measure measureId="NUM_FAILING_TESTS_COND" defaultValue="-1">
	<Computation targetArtefactTypes="REQUIREMENT" result="LINKS(BLOCKS,IN, NOT(IS_RELAXED_ARTEFACT())" />
</Measure>

Find out the average code coverage for code implementing requirements where tests are failing. Only consider code artefacts where there is test coverage. If there are no failing tests, set the metric to 0

<Link id="BLOCKS" inArtefactTypes="CODE" outArtefactTypes="REQUIREMENT" />
	<Measure measureId="TCOV_FAILING_TESTS" defaultValue="-1" type="PERCENT">
	<Computation targetArtefactTypes="REQUIREMENT" result="LINKS_AGGREGATE(AVG, TCOV, BLOCKS,IN, TCOV != -1, 0)" />
</Measure>

Temporal Functions

Temporal functions allow to retrieve and use values computed in the previous baseline. The available operators are:

  • PREVIOUS_VALUE(measureId) to get the previous value of a measure or indicator (measureId). This function returns 0 when no previous value can be found.

  • DELTA_VALUE(measureId) to use the computed difference between the current value of a measure or indicator (measureId) and its previous value. This function returns 0 if no delta can be calculated.

  • PREVIOUS_INFO(infoId) allows retrieving the value of some artefact information (infoId) in the previous version so it can be compared with the current artefact information (This is useful when combined with the EQUALS() or MATCHES() functions, as described in the section called “String Matching Functions”).

  • FIRST_VALUE(measureId [, <computation> min] [, <computation> max]) returns the first value ever assigned to a metric (measureId) in the current project, optionally within specific bounds (min, max).

  • AGGREGATE(aggregationType, measureId, [, <computation> minNb] [, <computation> maxNb] [, <computation> min] [, <computation> max]) returns the aggregated value of the previous values of a metric (measureId). You can optionally configure the minimun and maximum (minNb, maxNb) number of valid data points to be aggregated, and specify bounds (min, max) for the values to consider for aggregation. The aggregation type (aggregationType) is a mandatory parameter, and must be one of MIN, MAX, OCC, AVG, DEV, SUM, MED or MOD.

  • LEAST_SQUARE_FIT(<computation> degree, measureId, <computation> date, [, <computation> minNb] [, <computation> maxNb] [, <computation> min] [, <computation> max]) returns the interpolated or extrapolated value from the previous values of a metric (measureId) at a specific date (date). You can optionally configure the minimun and maximum (minNb, maxNb) number of valid data points to be taken into account, and specify bounds (min, max) for the values to consider for extrapolation. The date (date) and degree (degree) of the polynomial extrapolation are mandatory parameters.

Examples

Using the value of LC from the previous analysis:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="PREVIOUS_VALUE(LC)" />
</Measure>

Obtaining the difference in ranking between two analyses for an artefact:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="DELTA_VALUE(RANK)" />
</Measure>

Compute a delta of opened/closed bugs since the previous analysis:

<Measure measureId="SPRINT_PROGRESS" defaultValue="-1">
<Computation targetArtefactTypes="SPRINT"
result="DELTA_VALUE(NB_OPEN_CR)" />
</Measure>

Compute a delta of opened/closed bugs since the beginning of a sprint:

<Measure measureId="SPRINT_PROGRESS" defaultValue="-1">
<Computation targetArtefactTypes="SPRINT"
result="FIRST_VALUE(NB_OPEN_CR)-NB_OPEN_CR" />
</Measure>

Count the number of new issues reported based on the number of new issues opened daily:

<Measure measureId="NEW_ISSUES_TALLY" defaultValue="-1">
<Computation targetArtefactTypes="SPRINT"
result="AGGREGATE(SUM, NEW_CR)" />
</Measure>

Compute the average number of issues opened daily:

<Measure measureId="ISSUE_DISCOVERY_RATE" defaultValue="-1">
<Computation targetArtefactTypes="SPRINT"
result="AGGREGATE(AVG, NEW_CR)" />
</Measure>

Date Functions

You can use the following operators to work with dates in your model:

  • DATE(<year_param>, <month_param>, <day_param>) to convert year/month/day numbers to a date

  • DAYS(<param>) to pass a number as a number of days

  • TO_DAYS(<date_difference>) to evaluate the number of dates between two dates

  • TODAY() to retrieve today's date at midnight

  • NOW() to retrieve today's exact date and time at the time of the analysis

  • VERSION_DATE() to retrieve the version's date. By default, this is the same value as the time of the analysis (NOW()), but users are allowed to specify a different date different from the current one.

  • TRUNCATE_DATE(<date>, <unit>) returns a date truncated to the specified precision unit and is useful when calculating date differences (see below for examples). The supported units are:

    • YEAR

    • MONTH

    • SEMI_MONTH

    • WEEK_SUNDAY (use when the first day of the week is Sunday)

    • WEEK_MONDAY (use when the first day of the week is Monday)

    • DAY

    • AM_PM

    • HOUR

    • MINUTE

    • SECOND

Note

Note: Dates are computed and stored internally as the number of milliseconds since January 1st 1970. However, calculations involving dates are designed to work with a number of days, not hours or minutes.

Examples

Converting to the date 28th July 1979:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="DATE(1979,07,28)" />
</Measure>

Converting to a date using measure IDs:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="DATE(YEAR_START+2,MONTH_START+MONTHS_SPENT,TARGET_DAY)" />
</Measure>

Find the number of days since the start of the project (the project attribute PROJECT_START_DATE) until today

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="TO_DAYS(TODAY()-PROJECT_START_DATE)" />
</Measure>

Add 4 days to May 19th 2012 to obtain May 23rd 2012:

<Measure measureId="EXAMPLE" defaultValue="0">
<Computation targetArtefactTypes="FILE;FUNCTION;CLASS"
result="DATE(2012,05,19)+DAYS(4)" />
</Measure>

Calculate whether an issue expires within a week of the analysis:

<Measure measureId="EXPIRES_THIS_WEEK" defaultValue="0">
<Computation targetArtefactTypes="BUG;CR"
result="IF(EXPIRY_DATE - DAYS(7) < VERSION_DATE(),1,0)" />
</Measure>

Truncate a date down to year precision:

<!-- Sat, 28 Jul 1979 11:14:04 GMT -->
<Constant id="EXACT_DATE" value="302008444000" />

<!-- Returns 283996800000 (aka: Mon, 01 Jan 1979 00:00:00 GMT) -->
<Measure measureId="TRUNCATE_TO_YEAR" defaultValue="-1">
<Computation targetArtefactTypes="ISSUE"
result="TRUNCATE_DATE(EXACT_DATE, YEAR)" />
</Measure>

Find out how much time it took to solve an issue. This example highlights how using TRUNCATE_DAYS() can bring more precision depending on how you want to handle periods under 24 hours as one day or two days.

<!-- Date opened: Sat, 28 Jul 1979 07:47:47 GMT -->
<Constant id="TIME_OPENED" value="301996067000" />

<!-- Date closed 1: Sat, 28 Jul 1979 12:02:25 GMT -->
<Constant id="TIME_CLOSED_1" value="302011345000" />

<!-- Date closed 2: Sun, 29 Jul 1979 04:56:04 GMT -->
<Constant id="TIME_CLOSED_2" value="302072164000" />


<Measure measureId="TRUNCATE_TO_RETURN_ZERO" defaultValue="-1">
<Computation targetArtefactTypes="ISSUE"
result="TRUNCATE_DATE(TIME_CLOSED_1, DAY) - TRUNCATE_DATE(TIME_OPENED, DAY)" />
</Measure>

<Measure measureId="TRUNCATE_TO_RETURN_ONE" defaultValue="-1">
<Computation targetArtefactTypes="ISSUE"
result="TRUNCATE_DATE(TIME_CLOSED_2, DAY) - TRUNCATE_DATE(TIME_OPENED, DAY)" />
</Measure>

<Measure measureId="TO_DAYS_RETURNS_ONE" defaultValue="-1">
<Computation targetArtefactTypes="ISSUE"
result="DAYS(TIME_CLOSED_1 - TIME_OPENED)" />
</Measure>

<Measure measureId="TO_DAYS_RETURNS_ONE_ALSO" defaultValue="-1">
<Computation targetArtefactTypes="ISSUE"
result="DAYS(TIME_CLOSED_2 - TIME_OPENED)" />
</Measure>

Milestone Functions

This section lists the functions you can use when you want to retrieve information related to milestones.

Tip

You can use keywords instead of using a milestone ID. You can retrieve information about the next, previous, first or last milestones in the project by using:

  • NEXT

  • NEXT+STEP where STEP is a number indicating how many milestones to jump ahead

  • PREVIOUS

  • PREVIOUS-STEP where STEP is a number indicating how many milestones to jump backward

  • FIRST

  • LAST

Note

In all milestone functions, if no milestone ID and no keyword is specified, then NEXT is used by default.

All milestone functions accept a date parameter. The date is used to execute the function in that date context. If no date is specified, then the context used to execute the function is the analysis date.

  • HAS_MILESTONE([milestoneId or keyword] [, date]) checks if a milestone with the specified milestoneId exists in the project.

    The function returns 0 if no milestone is found, 1 if a milestone is found.

  • DATE_MILESTONE([milestoneId or keyword] [, date]) returns the date associated to a milestone.

  • GOAL(measureId [, milestoneId or keyword] [, date]) returns the goal for a metric at a milestone.

Examples

  1. Find if we are at the last milestone of the project:

    IS_LAST_MILESTONE=IF(HAS_MILESTONE(),0,1)
  2. Find if the date for the milestone BETA_RELEASE has been modified between June 2015 and now:

    DATE_HAS_SLIPPED=(DATE_MILESTONE(BETA_RELEASE)-DATE_MILESTONE(BETA_RELEASE, DATE(2015,06,01))) != 0
  3. Find the goal for requirement stability set for the milestone PROTOTYPE as of June 2016:

    REQ_STABILITY_GOAL=GOAL(REQ_STABILITY, PROTOTYPE, DATE(2016,06,01))
  4. Find the delta between the goal for TEST between the previous and next milestones:

    DELTA=GOAL(TEST) - GOAL(TEST, PREVIOUS)
  5. Find the delta between the goal for TEST for the next milestone set for the previous analysis and now:

    DELTA=GOAL(TEST) - GOAL(TEST, NEXT, VERSION_DATE(PREVIOUS))
  6. Find the delta between the current value of TEST and the goal for TEST at the next milestone:

    DELTA=GOAL(TEST) - TEST
  7. Compute the date difference between the previous and next milestones:

    MILESTONE_DURATION=DATE_MILESTONE(NEXT) - DATE_MILESTONE(PREVIOUS)
  8. Find the date slip for the next milestone between now and the previous anlaysis:

    DATE_SLIP=DATE_MILESTONE(NEXT) - DATE_MILESTONE(NEXT, VERSION_DATE(PREVIOUS))
  9. Find the amount of time left until the next milestone:

    DEADLINE=DATE_MILESTONE(NEXT) - VERSION_DATE()

String Matching Functions

In order to extract the specific information that is added to artefacts by various Data Providers, you can use the INFO(info_tag) and ARTEFACT_NAME() functions. Both functions return a string containing the information requested. You can then use these string matching functions in your computations:

  • EQUALS('string','string'[, forceIgnoreCase])

  • CONTAINS('string','string'[, forceIgnoreCase])

  • STARTS_WITH('string','string'[, forceIgnoreCase])

  • ENDS_WITH('string','string'[, forceIgnoreCase])

  • MATCHES('string','regexp'[, forceIgnoreCase])

forceIgnoreCase is an optional boolean set to 1 by default. If you want to perform a case-sensitive search, use 0, instead.

Tip

You can also retrieve the previous value of some artefact information using the PREVIOUS_INFO() function, as described in the section called “Temporal Functions”

Examples

Note

The examples for these functions are based on an artefact with the following data:

<I n="LANGUAGES" v="Java, C#, C++, C"/>
<I n="AUTHOR" v="gabriel"/>
<I n="URL" v="http://www.my_url.com"/> [^]
<I n="ONE_LANGUAGE" v="JaVa"/>

EQUALS()

EQUALS(INFO(AUTHOR), 'gabriel')
=> 1
EQUALS(INFO(LANGUAGES), 'Java, C#, C++, C', 0)
=> 1

STARTS_WITH()

STARTS_WITH(INFO(URL), 'HTTP')
=> 1
STARTS_WITH(INFO(URL), 'HTTPS')
=> 0

ENDS_WITH()

ENDS_WITH(INFO(URL), '.COM')
=> 1
ENDS_WITH(INFO(URL), '.COM', 0)
=> 0 (note the case-sensitive flag)

CONTAINS()

CONTAINS(INFO(LANGUAGES), 'C++')
=> 1
CONTAINS(INFO(LANGUAGES), 'Cobol')
=> 0
CONTAINS(INFO(LANGUAGES), INFO(ONE_LANGUAGE), 1)
=> 1

MATCHES()

MATCHES(INFO(LANGUAGES), 'J.*', 0)
=> 1
MATCHES(INFO(LANGUAGES), '.*(, C\+\+).*', 0)
=> 1
MATCHES(INFO(LANGUAGES), '.*(, C\+\+\+).*', 0)
=> 0