### Frontend Build Steps for Example Plugin Source: https://docs.adaptavist.com/sr4js/8.x/integrations/vendors-api/vendors-api-example-plugin These commands are used to install frontend dependencies and build the frontend code for the example plugin. This is a prerequisite step before compiling the main plugin JAR, ensuring the latest frontend code is bundled. ```bash npm install npm run build ``` -------------------------------- ### Compiling the Example Plugin with Maven Source: https://docs.adaptavist.com/sr4js/8.x/integrations/vendors-api/vendors-api-example-plugin This command compiles the example plugin using Apache Maven. It requires the 'atlas-mvn' tool and generates a plugin JAR file in the 'backend/target' directory. Ensure you have the necessary Maven and ScriptRunner for Jira versions installed. ```bash atlas-mvn package ``` -------------------------------- ### GET /rest/api/2/project/{projectIdOrKey}/versions Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Lists all versions for a given project. Equivalent to VersionManager get versions. ```APIDOC ## GET /rest/api/2/project/{projectIdOrKey}/versions\n\n### Description\nRetrieves all version objects defined for a project.\n\n### Method\nGET\n\n### Endpoint\n/rest/api/2/project/{projectIdOrKey}/versions\n\n### Parameters\n#### Path Parameters\n- **projectIdOrKey** (string) - Required - Project ID or key.\n\n#### Query Parameters\n_None_\n\n#### Request Body\n_None_\n\n### Request Example\nGET /rest/api/2/project/TEST/versions\n\n### Response\n#### Success Response (200)\n- **values** (array) - List of version objects.\n\n### Response Example\n[\n {\n \"id\": \"10001\",\n \"name\": \"v1.0\",\n \"released\": false\n },\n {\n \"id\": \"10002\",\n \"name\": \"v1.1\",\n \"released\": true\n }\n] ``` -------------------------------- ### Example: Indexing Jira Project Key and Name (Groovy) Source: https://docs.adaptavist.com/sr4js/8.x/features/script-fields/built-in-script-fields/database-picker/database-picker-customizations An example of implementing the getIndexValue closure in Groovy to index both the project key and name from a Jira project table. This enhances JQL searches by including these fields. ```groovy import groovy.sql.GroovyRowResult getIndexValue = { GroovyRowResult row -> (row.PKEY as String) + ' ' + (row.PNAME as String) } ``` -------------------------------- ### POST /rest/scriptrunner/latest/custom/doSomething Source: https://docs.adaptavist.com/sr4js/8.x/features/rest-endpoints Example of a POST endpoint with request body handling and path parameter access. ```APIDOC ## POST /rest/scriptrunner/latest/custom/doSomething ### Description Example POST endpoint demonstrating request body handling and additional path segment access. ### Method POST ### Endpoint /rest/scriptrunner/latest/custom/doSomething[/extra/path] ### Parameters #### Path Parameters - **extraPath** (string) - Optional - Additional path segments after the endpoint name #### Request Body - **content** (string) - Required - The raw request body content ### Request Example { "example": "request data" } ### Response #### Success Response (200) - **processed** (boolean) - Indicates successful processing - **path** (string) - Contains any additional path segments #### Response Example { "processed": true, "path": "/extra/path" } ``` -------------------------------- ### GET /rest/api/2/project/search Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Searches for projects by key or name with pagination. Replaces ProjectManager project search functionality. ```APIDOC ## GET /rest/api/2/project/search\n\n### Description\nReturns a paginated list of projects matching a query string.\n\n### Method\nGET\n\n### Endpoint\n/rest/api/2/project/search\n\n### Parameters\n#### Query Parameters\n- **query** (string) - Optional - Project key or name to search for.\n- **startAt** (integer) - Optional - Index of the first project to return (default 0).\n- **maxResults** (integer) - Optional - Maximum number of projects to return (default 50).\n\n#### Path Parameters\n_None_\n\n#### Request Body\n_None_\n\n### Request Example\nGET /rest/api/2/project/search?query=TEST&startAt=0&maxResults=10\n\n### Response\n#### Success Response (200)\n- **values** (array) - List of project objects.\n- **startAt** (integer) - Starting index.\n- **maxResults** (integer) - Page size.\n- **total** (integer) - Total matching projects.\n\n### Response Example\n{\n \"startAt\": 0,\n \"maxResults\": 10,\n \"total\": 2,\n \"values\": [\n {\n \"id\": \"10000\",\n \"key\": \"TEST\",\n \"name\": \"Test Project\"\n },\n {\n \"id\": \"10001\",\n \"key\": \"DEMO\",\n \"name\": \"Demo Project\"\n }\n ]\n} ``` -------------------------------- ### Set and Get Basic Issue Property (Groovy) Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-issue-and-entity-properties A fundamental example of setting and retrieving a string property for a Jira issue. Requires an issue key and demonstrates direct property manipulation. ```groovy def issue = Issues.getByKey('ABC-1') // setting the property issue.entityProperties.setString('my first property', 'Hello World!') // retrieving the property value issue.entityProperties.getString('my first property') // returns 'Hello World!' ``` -------------------------------- ### POST /projects/create Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-projects Creates a new project with optional parameters. You can specify project lead, type, description, URL, avatar, and assignee settings. ```APIDOC ## POST /projects/create ### Description Creates a new project with optional configuration including project lead, project type, description, and other metadata. ### Method POST ### Endpoint /projects/create ### Parameters #### Request Body - **key** (string) - Required - The project key - **name** (string) - Required - The project name - **projectLead** (string) - Optional - The project lead username (defaults to current user) - **projectType** (string) - Optional - The project type (defaults to 'business') - **description** (string) - Optional - Project description - **url** (string) - Optional - Project URL - **avatarId** (number) - Optional - ID of the project avatar ### Request Example { "key": "TIS", "name": "Teams in Space", "projectLead": "admin", "projectType": "business", "description": "This is a new project!", "url": "https://google.com", "avatarId": 10001 } ### Response #### Success Response (200) - **id** (number) - Project ID - **key** (string) - Project key - **name** (string) - Project name #### Response Example { "id": 10000, "key": "TIS", "name": "Teams in Space" } ``` -------------------------------- ### GET /rest/scriptrunner/latest/custom/approve Source: https://docs.adaptavist.com/sr4js/8.x/features/fragments/web-item An example of a custom REST endpoint that approves an issue and returns a success flag. This endpoint can be integrated with UI elements like web items. ```APIDOC ## GET /rest/scriptrunner/latest/custom/approve ### Description This endpoint demonstrates how to create a custom REST endpoint using ScriptRunner. It simulates approving an issue and returns a JSON response containing a success flag, title, and body. ### Method GET ### Endpoint /rest/scriptrunner/latest/custom/approve ### Parameters #### Query Parameters - **issueId** (Long) - Required - The ID of the issue to be approved. ### Request Example ``` GET /rest/scriptrunner/latest/custom/approve?issueId=12345 HTTP/1.1 Host: ``` ### Response #### Success Response (200) - **type** (String) - The type of flag (e.g., 'success'). - **title** (String) - The title of the flag message. - **close** (String) - How the flag should be closed (e.g., 'auto'). - **body** (String) - The main content of the flag message. #### Response Example ```json { "type": "success", "title": "Issue approved", "close": "auto", "body": "This issue has been approved for release" } ``` ``` -------------------------------- ### Create Jira Project Using a Template Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-projects This example illustrates creating a Jira project from a specific project template. It requires the project key, name, and the `projectTemplateKey`. Available templates can be discovered via IDE completions. ```groovy Projects.create("TIS", "Teams in Space") { projectLead = 'admin' projectTemplateKey = "com.pyxis.greenhopper.jira:basic-software-development-template" } ``` -------------------------------- ### Get Incomplete Issues on Sprint Close Source: https://docs.adaptavist.com/sr4js/8.x/features/listeners/custom-listener This Groovy script listens for a SprintClosedEvent and retrieves a list of issues that were not completed within that sprint. It requires Jira Software to be installed and enabled. Dependencies include components for accessing sprint data and issue information. ```groovy import com.atlassian.greenhopper.service.rapid.view.RapidViewService import com.atlassian.greenhopper.service.sprint.Sprint import com.atlassian.greenhopper.web.rapid.chart.HistoricSprintDataFactory import com.atlassian.jira.component.ComponentAccessor import com.onresolve.scriptrunner.runner.customisers.ast.PluginModuleTransformer import com.onresolve.scriptrunner.runner.customisers.WithPlugin @WithPlugin("com.pyxis.greenhopper.jira") def historicSprintDataFactory = PluginModuleTransformer.getGreenHopperBean(HistoricSprintDataFactory) def rapidViewService = PluginModuleTransformer.getGreenHopperBean(RapidViewService) def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser() def sprint = event.sprint as Sprint if (sprint.state == Sprint.State.CLOSED) { def view = rapidViewService.getRapidView(user, sprint.rapidViewId).value def sprintContents = historicSprintDataFactory.getSprintOriginalContents(user, view, sprint) def sprintData = sprintContents.value if (sprintData) { def incompleteIssues = sprintData.contents.issuesNotCompletedInCurrentSprint*.issueId log.warn "incompelte issues id : ${incompleteIssues}" } } ``` -------------------------------- ### POST /projects/create/template Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-projects Creates a new project using a predefined template. Template keys are the same as those available in the Jira UI. ```APIDOC ## POST /projects/create/template ### Description Creates a new project using a predefined Jira project template. ### Method POST ### Endpoint /projects/create/template ### Parameters #### Request Body - **key** (string) - Required - The project key - **name** (string) - Required - The project name - **projectLead** (string) - Required - The project lead username - **projectTemplateKey** (string) - Required - The template key to use ### Request Example { "key": "TIS", "name": "Teams in Space", "projectLead": "admin", "projectTemplateKey": "com.pyxis.greenhopper.jira:basic-software-development-template" } ### Response #### Success Response (200) - **id** (number) - Project ID - **key** (string) - Project key - **name** (string) - Project name #### Response Example { "id": 10000, "key": "TIS", "name": "Teams in Space" } ``` -------------------------------- ### Creating a Confluence page and adding an attachment Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-linked-applications This example demonstrates creating a new Confluence page using its REST API and then adding an attachment to that newly created page. It involves two POST requests: one to create the page with specified content and another to upload the attachment. ```Groovy import static com.atlassian.sal.api.net.Request.MethodType.POST import com.atlassian.sal.api.net.RequestFilePart def confluenceLink = ApplicationLinks.primaryConfluenceLink def pageResponse = confluenceLink.executeRequest(POST, 'rest/api/content') { setHeader('Content-Type', 'application/json') setEntity([ type : 'page', title: 'new page', space: [ key: 'AAA' ], body : [ storage: [ value : "

This is
a new page

", representation: "storage" ] ] ]) } as Map def pageId = pageResponse.id def filePart = new RequestFilePart(new File('/path/to/screenshot.png'), 'file') confluenceLink.executeRequest(POST, "rest/api/content/${pageId}/child/attachment") { addHeader("X-Atlassian-Token", "no-check") setFiles([filePart]) } ``` -------------------------------- ### Get Active Records Filter (Groovy) Source: https://docs.adaptavist.com/sr4js/8.x/features/script-fields/built-in-script-fields/ldap-picker/ldap-customizations Implement `getActiveRecordsFilter` to filter out records that should not be selectable in new issues, such as discontinued products or inactive users. This example uses a `PresentFilter` to check for the existence of the 'pwdAccountLockedTime' attribute, effectively selecting only records that are not locked. ```groovy import org.springframework.ldap.filter.PresentFilter getActiveRecordsFilter = { new PresentFilter('pwdAccountLockedTime') } ``` -------------------------------- ### Filter components with componentMatch JQL function using regex Source: https://docs.adaptavist.com/sr4js/8.x/features/jql-functions/included-jql-functions/match-functions The componentMatch function filters component names using regular expressions. Example demonstrates selecting components whose names start with "Web". ```JQL componentMatch(reg exp) ``` ```JQL component in componentMatch("^Web.*") ``` -------------------------------- ### Script Root Usage with Utility Classes Source: https://docs.adaptavist.com/sr4js/8.x/best-practices/write-code/script-roots Demonstrates script organization using ScriptRoots with utility class imports. Shows how scripts stored in the scripts directory can import and use supporting utility classes with proper package declarations. Includes automatic dependency detection and recompilation features. ```groovy import util.Bollo log.debug ("Hello from the script") Bollo.sayHello() ``` ```groovy package util public class Bollo { public static String sayHello() { "hello sailor!!!" } } ``` -------------------------------- ### ScriptRunner REST Endpoint Example (Groovy) Source: https://docs.adaptavist.com/sr4js/8.x/features/fragments/web-item This Groovy code defines a ScriptRunner custom REST endpoint that returns a success flag. It demonstrates handling query parameters and returning a JSON response. This endpoint can be invoked via HTTP GET requests. ```groovy import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate import groovy.json.JsonOutput import groovy.transform.BaseScript import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.core.Response @BaseScript CustomEndpointDelegate delegate approve(httpMethod: "GET") { MultivaluedMap queryParams -> // the details of getting and modifying the current issue are omitted for brevity // def issueId = queryParams.getFirst("issueId") as Long // use the issueId to retrieve this issue def flag = [ type : 'success', title: "Issue approved", close: 'auto', body : "This issue has been approved for release" ] Response.ok(JsonOutput.toJson(flag)).build() } ``` -------------------------------- ### Rendering Additional Project Information Source: https://docs.adaptavist.com/sr4js/8.x/features/script-fields/built-in-script-fields/database-picker/database-picker-customizations Example showing how to display project lead information alongside project name. Uses Jira's ComponentAccessor to retrieve project objects and MarkupBuilder for HTML generation. Demonstrates accessing database row values and integrating with Jira's project management APIs. ```groovy import com.atlassian.jira.component.ComponentAccessor import groovy.xml.MarkupBuilder import groovy.sql.GroovyRowResult renderViewHtml = { String displayValue, GroovyRowResult row -> def projectManager = ComponentAccessor.projectManager def projectId = row[0] as Long def project = projectManager.getProjectObj(projectId) def writer = new StringWriter() new MarkupBuilder(writer). span(displayValue) { i("lead by ${project.projectLead?.displayName ?: 'no lead'}") } writer.toString() } ``` -------------------------------- ### Connect to External Database with Groovy SQL Source: https://docs.adaptavist.com/sr4js/8.x/features/resources/connecting-to-a-database-legacy Demonstrates how to manually load a JDBC driver and establish a connection to an external PostgreSQL database. Includes handling for OSGi classloader issues in Jira. ```groovy import groovy.sql.Sql import java.sql.Driver def driver = Class.forName('org.postgresql.Driver').newInstance() as Driver // <1> def props = new Properties() props.setProperty("user", "devtools") // <2> props.setProperty("password", "devtools") def conn = driver.connect("jdbc:postgresql://localhost:5432/jira_6.4.6", props) // <3> def sql = new Sql(conn) try { sql.eachRow("select count(*) from jiraissue") { log.debug(it) } } finally { sql.close() conn.close() } ``` -------------------------------- ### ScriptRunner Behaviours: Getting Field Value and Setting Description Source: https://docs.adaptavist.com/sr4js/8.x/integrations/vendors-api/vendors-api-example-plugin This ScriptRunner Behaviours script demonstrates retrieving the value from the 'Vendors API' custom field and setting it as the 'Description' issue field when the 'Summary' field is edited. It uses 'getFormValue' and 'setFormValue' methods. ```groovy def fieldValue = getFieldByName('Vendors API').getFormValue() getFieldByName('Description').setFormValue(fieldValue) ``` -------------------------------- ### Basic CSS Modification for View Issue Page Source: https://docs.adaptavist.com/sr4js/8.x/features/fragments/web-resource This example demonstrates how to create and apply a simple CSS rule to modify the appearance of the view issue page in Jira. It involves creating a CSS file within a configured resource directory and then installing it as a web resource fragment in ScriptRunner. ```css body { color: red !important } ``` -------------------------------- ### Configure Additional Applications in Jira Plugin Source: https://docs.adaptavist.com/sr4js/8.x/best-practices/write-code/set-up-a-dev-environment Demonstrates how to include additional Jira applications such as Jira Software or Jira Service Management in your plugin's pom.xml file. These applications are commented out by default and must be uncommented to be included during runtime. Ensure version compatibility between applications and your Jira instance. ```XML ``` -------------------------------- ### Sample Spock Test Using Expect Block Source: https://docs.adaptavist.com/sr4js/8.x/best-practices/write-and-run-tests A minimal Spock test using the 'expect:' block for simple assertions. This format is useful for straightforward validations where setup and execution are not separated. ```groovy import spock.lang.Specification class TestRunnerSampleSpec extends Specification { def "test something"() { expect: true } } ``` -------------------------------- ### Create Jira Project with Custom Details Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-projects This code snippet shows how to create a Jira project with specified details such as project lead, type, description, URL, default assignee, and avatar ID. It uses a closure to define these properties. ```groovy Projects.create("TIS", "Teams in Space") { projectLead = 'admin' projectType = "business" description = "This is a new project!" url = "https://google.com" setDefaultAssigneeToProjectLead() avatarId = 10001 } ``` -------------------------------- ### GET /rest/api/2/project/{projectIdOrKey} Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Retrieves a single project by its ID or key. Equivalent to ProjectManager get project. ```APIDOC ## GET /rest/api/2/project/{projectIdOrKey}\n\n### Description\nReturns detailed information about a specific project.\n\n### Method\nGET\n\n### Endpoint\n/rest/api/2/project/{projectIdOrKey}\n\n### Parameters\n#### Path Parameters\n- **projectIdOrKey** (string) - Required - The project ID or key.\n\n#### Query Parameters\n_None_\n\n#### Request Body\n_None_\n\n### Request Example\nGET /rest/api/2/project/TEST\n\n### Response\n#### Success Response (200)\n- **id** (string) - Project ID.\n- **key** (string) - Project key.\n- **name** (string) - Project name.\n- **projectTypeKey** (string) - Type of project.\n\n### Response Example\n{\n \"id\": \"10000\",\n \"key\": \"TEST\",\n \"name\": \"Test Project\",\n \"projectTypeKey\": \"software\"\n} ``` -------------------------------- ### GET /rest/api/2/issue/{issueIdOrKey}/watchers Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Retrieves the list of users watching a specific issue. Replaces WatcherManager get watchers. ```APIDOC ## GET /rest/api/2/issue/{issueIdOrKey}/watchers\n\n### Description\nReturns all users who are watching the specified issue.\n\n### Method\nGET\n\n### Endpoint\n/rest/api/2/issue/{issueIdOrKey}/watchers\n\n### Parameters\n#### Path Parameters\n- **issueIdOrKey** (string) - Required - Issue key or ID.\n\n#### Query Parameters\n_None_\n\n#### Request Body\n_None_\n\n### Request Example\nGET /rest/api/2/issue/PROJ-123/watchers\n\n### Response\n#### Success Response (200)\n- **watchers** (array) - List of watcher objects.\n\n### Response Example\n{\n \"watchers\": [\n {\n \"accountId\": \"5b10a2844c20165700ede21g\",\n \"displayName\": \"John Doe\"\n },\n {\n \"accountId\": \"5b10a2844c20165700ede22h\",\n \"displayName\": \"Jane Smith\"\n }\n ]\n} ``` -------------------------------- ### POST /projects/{projectKey}/archive Source: https://docs.adaptavist.com/sr4js/8.x/hapi/work-with-projects Archives a project. This action is only available in Data Center environments. ```APIDOC ## POST /projects/{projectKey}/archive ### Description Archives a project. This action is only available in Data Center environments. ### Method POST ### Endpoint /projects/{projectKey}/archive ### Parameters #### Path Parameters - **projectKey** (string) - Required - The key of the project to archive ### Response #### Success Response (200) - **message** (string) - Success message #### Response Example { "message": "Project TIS has been archived." } ``` -------------------------------- ### POST /rest/api/2/version Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Creates a new version in a project. Mirrors VersionManager create version. ```APIDOC ## POST /rest/api/2/version\n\n### Description\nCreates a new version for a project.\n\n### Method\nPOST\n\n### Endpoint\n/rest/api/2/version\n\n### Parameters\n#### Path Parameters\n_None_\n\n#### Query Parameters\n_None_\n\n#### Request Body\n- **name** (string) - Required - Version name.\n- **projectId** (string) - Required - ID of the project to which the version belongs.\n- **description** (string) - Optional - Description of the version.\n\n### Request Example\n{\n \"name\": \"v2.0\",\n \"projectId\": \"10000\",\n \"description\": \"Second major release\"\n}\n\n### Response\n#### Success Response (201)\n- Returns the created version object.\n\n### Response Example\n{\n \"id\": \"10003\",\n \"name\": \"v2.0\",\n \"projectId\": \"10000\",\n \"description\": \"Second major release\",\n \"released\": false\n} ``` -------------------------------- ### GET /rest/api/2/issue/{issueIdOrKey} Source: https://docs.adaptavist.com/sr4js/8.x/scriptrunner-migration/migrating-to-cloud/rewriting-scripts-for-cloud-hints-and-tips Retrieves a single issue by its key or numeric ID. Replaces IssueService get operations and IssueManager retrieval in Server. ```APIDOC ## GET /rest/api/2/issue/{issueIdOrKey}\n\n### Description\nRetrieves a single issue identified by its key or ID.\n\n### Method\nGET\n\n### Endpoint\n/rest/api/2/issue/{issueIdOrKey}\n\n### Parameters\n#### Path Parameters\n- **issueIdOrKey** (string) - Required - The issue key (e.g., \"PROJ-123\") or numeric ID.\n\n#### Query Parameters\n_None_\n\n#### Request Body\n_None_\n\n### Request Example\n_None_\n\n### Response\n#### Success Response (200)\n- **id** (string) - Issue ID.\n- **key** (string) - Issue key.\n- **fields** (object) - Issue fields.\n\n### Response Example\n{\n \"id\": \"10001\",\n \"key\": \"PROJ-123\",\n \"fields\": {\n \"summary\": \"Example issue\",\n \"status\": { \"name\": \"To Do\" }\n }\n} ``` -------------------------------- ### GET /rest/scriptrunner/latest/custom/doSomething Source: https://docs.adaptavist.com/sr4js/8.x/features/rest-endpoints This endpoint demonstrates a basic GET request handler in ScriptRunner. It returns a simple JSON response and requires Jira administrator privileges. ```APIDOC ## GET /rest/scriptrunner/latest/custom/doSomething ### Description Basic GET endpoint example that returns a JSON response with a numeric value. Requires Jira administrator access. ### Method GET ### Endpoint /rest/scriptrunner/latest/custom/doSomething ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **abc** (number) - Example numeric value #### Response Example { "abc": 42 } ``` -------------------------------- ### Display Project Name and Key in Dropdown Option Source: https://docs.adaptavist.com/sr4js/8.x/features/script-fields/built-in-script-fields/database-picker/database-picker-customizations Formats a dropdown option to display both the project name and its key. This example assumes the SQL query returns columns named 'PNAME' and 'PKEY'. It demonstrates accessing columns by name. ```groovy import groovy.sql.GroovyRowResult renderOptionHtml = { String displayValue, GroovyRowResult row -> "$row.PNAME ($row.PKEY)" } ``` -------------------------------- ### Create a Basic Spock Test in Groovy Source: https://docs.adaptavist.com/sr4js/8.x/best-practices/write-and-run-tests Defines a basic Spock test structure using Groovy. It includes setup, when, and then blocks for creating test data, executing the script, and asserting outcomes. Each line in the 'then:' block represents an assertion. ```groovy import spock.lang.Specification class MyVeryOwnScriptSpec extends Specification { def "test that my script does what I say it does"() { setup: "create any test data I need (projects, issues, etc.)" when: "I invoke run my script" //write code that makes your script run here then: "my script makes the changes I expect" true //Each line is an assertion 1 == 1 //Anything that returns true will let the test pass "a" == "b" //Anything that returns false will cause the test to fail } } ``` -------------------------------- ### Filter by Version Start Date using startDate() Source: https://docs.adaptavist.com/sr4js/8.x/features/jql-functions/included-jql-functions/versions The `startDate` JQL function allows filtering issues based on the start date of their associated versions. It uses similar date query predicates as `releaseDate()`, enabling queries like 'after 14d' to find versions starting in the future. ```jql fixVersion in startDate("after 14d") ``` -------------------------------- ### YAML Configuration File Example Source: https://docs.adaptavist.com/sr4js/8.x/best-practices/write-code/store-all-environment-specific-variables An example of a YAML file used to store environment-specific variables. This format is flexible and can be adapted to various configuration needs. ```yaml Approvals: customfield_12345 Long Custom Field Name: customfield_56789 ```