How to sync Groups with the Team field on Jira
Tired of bumping up against the restrictions of Team fields? Wish they were a little more like Groups? In this tutorial, you’ll learn how to go beyond what's possible with native Jira automation and consolidate the Team field with Groups to harness their combined power.
When the assignee field isn't enough
The assignee field in Jira is what keeps tickets moving forward, allowing you to get issues in the hands of the right person. Jira users tag someone knowledgeable about the issue at hand, but two things often happen here:
- A small group of go-to people get overloaded because everyone is assigning them tickets
- The assignee is on annual leave and the person who tagged them for help didn't know
Either way, the work sits, and it's good for nobody. A better approach is to assign the ticket to lots of people. This is done through either Jira Teams, or Jira Groups. But how do you choose which is the best option?
Using the Team field, you can assign people to a network and any work assigned to that team sits within their team page. However, you’re missing out on key functionality, such as workflows and approvals, plus teams won’t work with JQL, such as the membersOf() function.
Using Jira Groups, you can take advantage of that functionality, but the group members can’t be assigned to alerts, components or services, plus the group can’t be used in plans and advanced roadmaps.
Whether you choose Jira Groups or the Team field, both options offer limited functionality. In this tutorial, we'll show you how you can use ScriptRunner to go beyond native Jira by combining the functionality of Jira Groups and the Team field while keeping your members in sync.
Refresher: Teams versus Groups
What if there was a way to get the benefits of both?
What if, rather than choosing between the Team field and groups, you could combine them and benefit from the superpowers of both?
Actually, that’s exactly what Atlassian is thinking too.
Atlassian currently has a feature request to Consolidate Groups and Teams, and there’s an Early Access Program to import/sync teams with various idPs.
In the meantime, we’ve written a ScriptRunner script that can be run as a scheduled job to sync the members of your groups to a corresponding Team. This solution gives you the ability to use a common Team name for assignment and then the group for management of product access, permissions and more.
How to use teams and groups for assignment
Note: You need access to admin.atlassian.com as a site or user admin to manage groups.
1. Create a custom field using Group Picker (single).
- Name this ‘GroupAssigned’.
- Don’t place this field on any screens. The users should only interact with the Team field. Only the automation rule will update the ‘GroupAssigned’ field.
2. Set the ‘Assignable user’ project permission to only use the custom group field ‘GroupAssigned’.
- This will ensure that the assignee must be a member of the group selected using the ‘GroupAssigned’. For example, if the ‘GroupAssigned’ = Network, then the assignee must be a member of the Network group.
- This prompts a warning in the project settings page as it does not align with Atlassian’s recommended permission scheme. These warnings can be ignored.
3. Set up the required teams.
- Go to the Teams dropdown in the top menu and select ‘Create a team’.
- Leave the below checkbox unchecked:
- Anyone can join this team without approval.
- Make a note of the team ID.
- View the team page and the team ID will be present in the URL:
- https://YOUR-SITE.atlassian.net/jira/people/team/YOUR-TEAM-ID
- View the team page and the team ID will be present in the URL:
- Go to Operations
- From your team page, click on the Operations card and ‘Go to operations'
- This is needed to allow the team to be assigned as a service owner/responder team
4. Set up the required groups.
- Go to admin.atlassian.com and create the groups for your corresponding teams.
- Make a note of the group ID.
- View the group and the group ID will be present in the URL.
- https://admin.atlassian.com/o/XXXXXXXXXXXXXXXXXX/groups/YOUR-GROUP-ID
- You can also assign JSM Agent product access to ensure that group members are licenced to access JSM.
5. Assign project roles to your groups.
- Go to Project Settings > People > Add People.
- Select your relevant groups and assign a ‘Service Desk Team’ role.
- With the default project permissions this will ensure that your group members have access to the expected JSM Agent features.
6. Create a project automation.
- Here we will map the Team field to the corresponding group using the ‘GroupAssigned’ field.
- An example automation rule can be found at the bottom of the page.
- The lookup table for TeamIDs must have the correct Team name as the key and the Team ID as the value.
- The lookup table for GroupIDs must have the corresponding Team name as the key and then the GroupID as the value.
- This allows you to have group names that are different to the team names.
- This can happen if you have a naming convention for your groups that are synced from your IDP.
- Optional extra!
- Record the number of successful assignments in a custom number field ‘Assignment Count’.
- Edit the action select the ‘Assignment Count’ field and use the below smartvalue:
- {{#increment}}{{Assignment Count}}{{/}}
- This is handy for identifying tickets that have bounced around multiple teams, usually indicating a lack of knowledge around the subject and who is best placed to resolve the issue.
- Make this read only by including it on an issue type view screen but not the edit screen.
7. Test your configuration.
- Add some test users to some of your groups.
- Group1 (PersonA,PersonB,PersonC).
- Group2 (PersonD,PersonE,PersonF).
- You should see that when the team field is changed, the automation rule gets triggered, and the corresponding group is assigned in the ‘GroupAssigned’ field.
- Only members of the group selected in GroupAssigned can be added.
- If the team field is cleared the last value will be readded.
- There needs to be a team that is taking accountability for the issue.
- If the team selected is not configured in the lookup table to be used as an assignment group, the last value will be added again.
- This allows your org to have other teams in use but restricts them from being assigned tickets unless explicitly configured in the automation rule lookup table.
- If the current assignee is not a member of the new group, they will be unassigned.
Congratulations! You’ve now set up team assignment functionality for your project and it should look like this:
How to sync group members to Teams with ScriptRunner
This is especially handy if you’re already syncing your group members from your IDP like OKTA/AAD via Atlassian Guard. It will enable you to sync members from:
IDP Group > Atlassian Group > Atlassian Team
The master list of members used for the sync will be the IDP Group (if you use Atlassian Guard) or the Atlassian Group and these members will be synced to the Atlassian Team.
To set this up we’ll need to set up a script that runs regularly to keep members in sync so we'll create a scheduled job in ScriptRunner.
Many thanks to our very own (and amazingly talented!) Andrea Robbins who is an experienced technical consultant and power-user of ScriptRunner!
1. Add script.
- The script template can be found at the bottom of this page.
- Add the relevant org id.
- This can be found by going to admin.atlassian.com and selecting your org.
- The URL will contain the org ID: https://admin.atlassian.com/o/YOUR-ORG-ID/overview.
- Add the authentication token details for the user that will be executing the script.
- Build a string with the format: your.email@somewhere.com:yourGeneratedAPIToken
- This will then need to be encoded in base64.
1def apiToken = 'Basic base64encodedstring'
2. Add the relevant team and group IDs to the script.
3. Test your configuration.
- You should see that the team field is updated to only include members of the corresponding groups.
4. Schedule for an appropriate time.
ScriptRunner superpowers
Keep your Jira, and users, perfectly in sync by combining the Team field and groups using this ScriptRunner script.
Search, filter and position Scripted Fields like Jira custom fields
Did you know, you can now move your Scripted Fields anywhere on a screen and even view them in search results?
Example automation rule
1{
2 "cloud": true,
3 "rules": [
4 {
5 "id": 21774350,
6 "name": "Team Assignment Template",
7 "state": "ENABLED",
8 "description": "This rule runs when the Team field is updated.\n\nIf it matches a configured teamID, the corresponding group will be added to the GroupAssigned field. Else, if the Team field is blank or is not configured for assignment an error is commented to the initiator.\n\nThe assignee must be a member of the group selected in GroupAssigned or they will be removed.",
9 "created": 1725721198507,
10 "updated": 1725979753004,
11 "trigger": {
12 "id": "588070099",
13 "component": "TRIGGER",
14 "parentId": null,
15 "conditionParentId": null,
16 "schemaVersion": 2,
17 "type": "jira.issue.field.changed",
18 "value": {
19 "changeType": "ANY_CHANGE",
20 "fields": [
21 {
22 "value": "Team",
23 "type": "fieldName"
24 }
25 ],
26 "actions": []
27 },
28 "children": [],
29 "conditions": [],
30 "connectionId": null
31 },
32 "components": [
33 {
34 "id": "588070100",
35 "component": "ACTION",
36 "parentId": null,
37 "conditionParentId": null,
38 "schemaVersion": 1,
39 "type": "jira.create.mapping-variable",
40 "value": {
41 "name": {
42 "type": "FREE",
43 "value": "teamIDs"
44 },
45 "mappings": [
46 {
47 "key": "TEAM NAME 1",
48 "value": "TeamID1"
49 },
50 {
51 "key": "TEAM NAME 2",
52 "value": "TeamID2"
53 },
54 {
55 "key": "TEAM NAME 3",
56 "value": "TeamID3"
57 }
58 ]
59 },
60 "children": [],
61 "conditions": [],
62 "connectionId": null
63 },
64 {
65 "id": "588070101",
66 "component": "ACTION",
67 "parentId": null,
68 "conditionParentId": null,
69 "schemaVersion": 1,
70 "type": "jira.create.mapping-variable",
71 "value": {
72 "name": {
73 "type": "FREE",
74 "value": "groupIDs"
75 },
76 "mappings": [
77 {
78 "key": "TEAM NAME 1",
79 "value": "GroupID1"
80 },
81 {
82 "key": "TEAM NAME 2",
83 "value": "GroupID2"
84 },
85 {
86 "key": "TEAM NAME 3",
87 "value": "GroupID3"
88 }
89 ]
90 },
91 "children": [],
92 "conditions": [],
93 "connectionId": null
94 },
95 {
96 "id": "588070102",
97 "component": "ACTION",
98 "parentId": null,
99 "conditionParentId": null,
100 "schemaVersion": 1,
101 "type": "codebarrel.action.log",
102 "value": "Team value changed to: {{fieldChange.toString}}",
103 "children": [],
104 "conditions": [],
105 "connectionId": null
106 },
107 {
108 "id": "588070103",
109 "component": "CONDITION",
110 "parentId": null,
111 "conditionParentId": null,
112 "schemaVersion": 1,
113 "type": "jira.condition.container.block",
114 "value": null,
115 "children": [
116 {
117 "id": "588070104",
118 "component": "CONDITION_BLOCK",
119 "parentId": "588070103",
120 "conditionParentId": null,
121 "schemaVersion": 1,
122 "type": "jira.condition.if.block",
123 "value": {
124 "conditionMatchType": "ALL"
125 },
126 "children": [
127 {
128 "id": "588070106",
129 "component": "ACTION",
130 "parentId": "588070104",
131 "conditionParentId": null,
132 "schemaVersion": 1,
133 "type": "codebarrel.action.log",
134 "value": "Updating TeamAssigned group to: {{fieldChange.toString}}",
135 "children": [],
136 "conditions": [],
137 "connectionId": null
138 },
139 {
140 "id": "588070107",
141 "component": "ACTION",
142 "parentId": "588070104",
143 "conditionParentId": null,
144 "schemaVersion": 12,
145 "type": "jira.issue.edit",
146 "value": {
147 "operations": [
148 {
149 "field": {
150 "type": "NAME",
151 "value": "Assignment Count"
152 },
153 "fieldType": "com.atlassian.jira.plugin.system.customfieldtypes:float",
154 "type": "SET",
155 "value": "{{#increment}}{{Assignment Count}}{{/}}"
156 }
157 ],
158 "advancedFields": "{\n \"fields\": {\n \"GroupAssigned\": {\n \"groupId\": \"{{groupIDs.get(fieldChange.toString)}}\"\n }\n }\n}",
159 "sendNotifications": false
160 },
161 "children": [],
162 "conditions": [],
163 "connectionId": null
164 }
165 ],
166 "conditions": [
167 {
168 "id": "588070105",
169 "component": "CONDITION",
170 "parentId": null,
171 "conditionParentId": "588070104",
172 "schemaVersion": 1,
173 "type": "jira.comparator.condition",
174 "value": {
175 "first": "{{teamIDs.get(fieldChange.toString)}}",
176 "second": "",
177 "operator": "NOT_EQUALS"
178 },
179 "children": [],
180 "conditions": [],
181 "connectionId": null
182 }
183 ],
184 "connectionId": null
185 },
186 {
187 "id": "588070108",
188 "component": "CONDITION_BLOCK",
189 "parentId": "588070103",
190 "conditionParentId": null,
191 "schemaVersion": 1,
192 "type": "jira.condition.if.block",
193 "value": {
194 "conditionMatchType": "ALL"
195 },
196 "children": [
197 {
198 "id": "588070110",
199 "component": "ACTION",
200 "parentId": "588070108",
201 "conditionParentId": null,
202 "schemaVersion": 1,
203 "type": "jira.create.variable",
204 "value": {
205 "id": "_customsmartvalue_id_1725650177774",
206 "name": {
207 "type": "FREE",
208 "value": "deletedValue"
209 },
210 "type": "SMART",
211 "query": {
212 "type": "SMART",
213 "value": "{{deletedFieldChange.values}}"
214 },
215 "lazy": false
216 },
217 "children": [],
218 "conditions": [],
219 "connectionId": null
220 },
221 {
222 "id": "588070111",
223 "component": "ACTION",
224 "parentId": "588070108",
225 "conditionParentId": null,
226 "schemaVersion": 1,
227 "type": "codebarrel.action.log",
228 "value": "Deleted value was: {{deletedValue}}",
229 "children": [],
230 "conditions": [],
231 "connectionId": null
232 },
233 {
234 "id": "588070112",
235 "component": "ACTION",
236 "parentId": "588070108",
237 "conditionParentId": null,
238 "schemaVersion": 1,
239 "type": "jira.create.variable",
240 "value": {
241 "id": "_customsmartvalue_id_1725650214362",
242 "name": {
243 "type": "FREE",
244 "value": "teamID"
245 },
246 "type": "SMART",
247 "query": {
248 "type": "SMART",
249 "value": "{{teamIDs.get(deletedValue)}}"
250 },
251 "lazy": false
252 },
253 "children": [],
254 "conditions": [],
255 "connectionId": null
256 },
257 {
258 "id": "588070113",
259 "component": "ACTION",
260 "parentId": "588070108",
261 "conditionParentId": null,
262 "schemaVersion": 12,
263 "type": "jira.issue.edit",
264 "value": {
265 "operations": [],
266 "advancedFields": "{\n \"fields\": {\n \"Team\": \"{{teamID}}\"\n }\n}\n}",
267 "sendNotifications": false
268 },
269 "children": [],
270 "conditions": [],
271 "connectionId": null
272 },
273 {
274 "id": "588070114",
275 "component": "ACTION",
276 "parentId": "588070108",
277 "conditionParentId": null,
278 "schemaVersion": 2,
279 "type": "jira.issue.comment",
280 "value": {
281 "comment": "Hi [~accountid:{{initiator.accountId}}]! The Team field cannot be left blank. The previous value of '{{deletedValue}}' has been readded. ",
282 "publicComment": false,
283 "commentVisibility": null,
284 "sendNotifications": true,
285 "addCommentOnce": false
286 },
287 "children": [],
288 "conditions": [],
289 "connectionId": null
290 }
291 ],
292 "conditions": [
293 {
294 "id": "588070109",
295 "component": "CONDITION",
296 "parentId": null,
297 "conditionParentId": "588070108",
298 "schemaVersion": 1,
299 "type": "jira.comparator.condition",
300 "value": {
301 "first": "{{team}}",
302 "second": "",
303 "operator": "EQUALS"
304 },
305 "children": [],
306 "conditions": [],
307 "connectionId": null
308 }
309 ],
310 "connectionId": null
311 },
312 {
313 "id": "588070115",
314 "component": "CONDITION_BLOCK",
315 "parentId": "588070103",
316 "conditionParentId": null,
317 "schemaVersion": 1,
318 "type": "jira.condition.if.block",
319 "value": {
320 "conditionMatchType": "ALL"
321 },
322 "children": [
323 {
324 "id": "588070117",
325 "component": "ACTION",
326 "parentId": "588070115",
327 "conditionParentId": null,
328 "schemaVersion": 1,
329 "type": "jira.create.variable",
330 "value": {
331 "id": "_customsmartvalue_id_1725650177774",
332 "name": {
333 "type": "FREE",
334 "value": "oldValue"
335 },
336 "type": "SMART",
337 "query": {
338 "type": "SMART",
339 "value": "{{deletedFieldChange.values}}"
340 },
341 "lazy": false
342 },
343 "children": [],
344 "conditions": [],
345 "connectionId": null
346 },
347 {
348 "id": "588070118",
349 "component": "ACTION",
350 "parentId": "588070115",
351 "conditionParentId": null,
352 "schemaVersion": 1,
353 "type": "codebarrel.action.log",
354 "value": "Old value was: {{oldValue}}",
355 "children": [],
356 "conditions": [],
357 "connectionId": null
358 },
359 {
360 "id": "588070119",
361 "component": "ACTION",
362 "parentId": "588070115",
363 "conditionParentId": null,
364 "schemaVersion": 1,
365 "type": "jira.create.variable",
366 "value": {
367 "id": "_customsmartvalue_id_1725650214362",
368 "name": {
369 "type": "FREE",
370 "value": "teamID"
371 },
372 "type": "SMART",
373 "query": {
374 "type": "SMART",
375 "value": "{{teamIDs.get(oldValue)}}"
376 },
377 "lazy": false
378 },
379 "children": [],
380 "conditions": [],
381 "connectionId": null
382 },
383 {
384 "id": "588070120",
385 "component": "ACTION",
386 "parentId": "588070115",
387 "conditionParentId": null,
388 "schemaVersion": 12,
389 "type": "jira.issue.edit",
390 "value": {
391 "operations": [],
392 "advancedFields": "{\n \"fields\": {\n \"Team\": \"{{teamID}}\"\n }\n}",
393 "sendNotifications": false
394 },
395 "children": [],
396 "conditions": [],
397 "connectionId": null
398 },
399 {
400 "id": "588070121",
401 "component": "ACTION",
402 "parentId": "588070115",
403 "conditionParentId": null,
404 "schemaVersion": 2,
405 "type": "jira.issue.comment",
406 "value": {
407 "comment": "Hi [~accountid:{{initiator.accountId}}]! The team '{{fieldChange.toString}}' has not been set up to be assigned tickets. The previous value of '{{oldValue}}' has been readded. Please select an alternative team.",
408 "publicComment": false,
409 "commentVisibility": null,
410 "sendNotifications": true,
411 "addCommentOnce": false
412 },
413 "children": [],
414 "conditions": [],
415 "connectionId": null
416 }
417 ],
418 "conditions": [
419 {
420 "id": "588070116",
421 "component": "CONDITION",
422 "parentId": null,
423 "conditionParentId": "588070115",
424 "schemaVersion": 1,
425 "type": "jira.comparator.condition",
426 "value": {
427 "first": "{{teamIDs.get(fieldChange.toString)}}",
428 "second": "",
429 "operator": "EQUALS"
430 },
431 "children": [],
432 "conditions": [],
433 "connectionId": null
434 }
435 ],
436 "connectionId": null
437 }
438 ],
439 "conditions": [],
440 "connectionId": null
441 },
442 {
443 "id": "588070122",
444 "component": "ACTION",
445 "parentId": null,
446 "conditionParentId": null,
447 "schemaVersion": 1,
448 "type": "jira.issue.refresh.issue",
449 "value": {
450 "delayMs": null
451 },
452 "children": [],
453 "conditions": [],
454 "connectionId": null
455 },
456 {
457 "id": "588070123",
458 "component": "CONDITION",
459 "parentId": null,
460 "conditionParentId": null,
461 "schemaVersion": 6,
462 "type": "jira.user.condition",
463 "value": {
464 "conditions": [
465 {
466 "field": "assignee",
467 "check": "USER_IS_NOT",
468 "criteria": []
469 },
470 {
471 "field": "assignee",
472 "check": "NOT_IN_GROUP",
473 "criteria": [
474 {
475 "type": "SMART",
476 "value": "{{GroupAssigned}}"
477 }
478 ]
479 }
480 ],
481 "operator": "AND"
482 },
483 "children": [],
484 "conditions": [],
485 "connectionId": null
486 },
487 {
488 "id": "588070124",
489 "component": "ACTION",
490 "parentId": null,
491 "conditionParentId": null,
492 "schemaVersion": 5,
493 "type": "jira.issue.assign",
494 "value": {
495 "assignType": "SPECIFY_USER",
496 "smartValue": null,
497 "itsmOpsOncall": null,
498 "jql": null,
499 "issueToCopy": null,
500 "fieldToCopy": null,
501 "listAssignMethod": null,
502 "assignee": {
503 "type": "CLEAR",
504 "value": "clear"
505 },
506 "restrictedToGroup": null,
507 "group": null,
508 "role": null,
509 "excludedUsers": [],
510 "userList": []
511 },
512 "children": [],
513 "conditions": [],
514 "connectionId": null
515 },
516 {
517 "id": "588070125",
518 "component": "ACTION",
519 "parentId": null,
520 "conditionParentId": null,
521 "schemaVersion": 1,
522 "type": "codebarrel.action.log",
523 "value": "{{assignee.displayName}} is not a member of the '{{TeamAssigned}}' team. Removed from Assignee.",
524 "children": [],
525 "conditions": [],
526 "connectionId": null
527 }
528 ],
529 "canOtherRuleTrigger": false,
530 "notifyOnError": "FIRSTERROR",
531 "projects": [],
532 "labels": [],
533 "tags": [
534 {
535 "id": 87423467,
536 "ruleIdUuid": "0191ccff-bfac-7fbe-aa94-f38196b75deb",
537 "tagType": "IS_RULE_UPDATED",
538 "tagValue": "true"
539 }
540 ],
541 "ruleScope": {
542 "resources": [
543 "ari:cloud:jira:03b3b892-4330-40a5-98fd-fd07d073133f:project/10002"
544 ]
545 },
546 "ruleHome": {
547 "ruleLifecycleHome": {
548 "locationARI": "ari:cloud:jira:03b3b892-4330-40a5-98fd-fd07d073133f:project/10002"
549 },
550 "ruleBillingHome": {
551 "locationARI": "ari:cloud:jira-servicedesk::site/03b3b892-4330-40a5-98fd-fd07d073133f"
552 }
553 },
554 "writeAccessType": "UNRESTRICTED",
555 "collaborators": [],
556 "billingType": "NORMAL",
557 "idUuid": "0191ccff-bfac-7fbe-aa94-f38196b75deb"
558 }
559 ]
560}
Script: sync groups and teams
1import groovy.json.JsonSlurper
2import groovy.json.JsonOutput
3
4/*
5 TITLE: SYNC GROUPS & TEAMS
6
7 AUTHOR: ANDREA ROBBINS
8
9 INSTRUCTIONS:
10 1. ADD THE ORG ID AS A SCRIPT VARIABLE
11 2. ADD YOUR API TOKEN AS A SCRIPT VARIABLE
12 3. MAP YOUR GROUPS AND TEAMS USING THEIR IDS IN THE "teamMappingList"
13
14*/
15
16//get values from Script Variables
17def orgId = '' // Enter your ORGID
18def apiToken = '' // Create a string with the format your.email@somewhere.com:yourGeneratedAPIToken then encode this in base64.
19//map the groups to the teams
20def teamMappingList = [
21 // Add as many Teams + Groups as needed
22 [
23 // TEAM1
24 groupId: 'GROUP1',
25 teamId: 'TEAM1'
26 ],
27 [
28 // TEAM2
29 groupId: 'GROUP2',
30 teamId: 'TEAM2'
31 ],
32 [
33 // TEAM3
34 groupId: 'GROUP3',
35 teamId: 'TEAM3'
36 ]
37]
38
39//go through each mapping
40teamMappingList.each {
41 //get the current group members
42 def response = get("/rest/api/3/group/member?groupId=${it.groupId}")
43 .header('Content-Type', 'application/json')
44 .asString()
45
46 if (response.status == 200) {
47 def existingGroupMembers = new JsonSlurper().parseText(response.body)
48 logger.info("these are the existing users in the group: ${existingGroupMembers.toString()}")
49
50 // collect the group members' account IDs
51 def groupMemberIds = existingGroupMembers.values.collect { it.accountId }
52 logger.info(groupMemberIds.toString())
53
54
55 //get the current team members
56 def getTeamsResponse = post("/gateway/api/public/teams/v1/org/${orgId}/teams/${it.teamId}/members")
57 .header('Content-Type', 'application/json')
58 .header('Authorization', apiToken)
59 .asString()
60
61 def existingTeamMembers = new JsonSlurper().parseText(getTeamsResponse.body)
62 logger.info("these are the existing users in the team ${existingTeamMembers.toString()}")
63
64 // collect the team members' account IDs
65 def teamMemberIds = existingTeamMembers.results.collect {it.accountId}
66 logger.info("these are the existing users in the team's ID ${teamMemberIds.toString()}")
67
68
69 // Determine members to add
70 def membersToAdd = groupMemberIds - teamMemberIds
71 println "the members to add: ${membersToAdd}"
72
73 // Determine members to remove
74 def membersToRemove = teamMemberIds - groupMemberIds
75 println "the members to remove: ${membersToRemove}"
76
77 // if members need to be added,
78 if (membersToAdd) {
79 //construct the add members body
80 def addRequestBody = [
81 members: membersToAdd.collect { accountId -> [accountId: accountId] }
82 ]
83 def addRequestBodyJson = JsonOutput.toJson(addRequestBody)
84 logger.info("Add Request Body: ${addRequestBodyJson}")
85
86 // send request to add users to the team
87 def addUsersResponse = post("/gateway/api/public/teams/v1/org/${orgId}/teams/${it.teamId}/members/add")
88 .header('Content-Type', 'application/json')
89 .header('Accept', '*/*')
90 .header('Authorization', apiToken)
91 .body(addRequestBodyJson)
92 .asString()
93
94 if (addUsersResponse.status == 200) {
95 logger.info("Users added successfully: ${addUsersResponse.body}")
96 } else {
97 logger.error("Failed to add users: ${addUsersResponse.status} - ${addUsersResponse.body}")
98 }
99 }
100
101 // if members need to be removed,
102 if (membersToRemove) {
103 //construct the remove members body
104 def removeRequestBody = [
105 members: membersToRemove.collect { accountId -> [accountId: accountId] }
106 ]
107 def removeRequestBodyJson = JsonOutput.toJson(removeRequestBody)
108 logger.info("Remove Request Body: ${removeRequestBodyJson}")
109
110 // send request to remove users to the team
111 def removeUsersResponse = post("/gateway/api/public/teams/v1/org/${orgId}/teams/${it.teamId}/members/remove")
112 .header('Content-Type', 'application/json')
113 .header('Accept', '*/*')
114 .header('Authorization', apiToken)
115 .body(removeRequestBodyJson)
116 .asString()
117
118 if (removeUsersResponse.status == 200) {
119 logger.info("Users removed successfully: ${removeUsersResponse.body}")
120 } else {
121 logger.error("Failed to remove users: ${removeUsersResponse.status} - ${removeUsersResponse.body}")
122 }
123 }
124 } else {
125 logger.error("Failed to fetch group members: ${response.status} - ${response.body}")
126 }
127}