bash / grep: getting multiple matching elements from a json - awk

In my BitBucket+Bamboo setup, I'm trying to get a list of email addresses of people having access to a particular repository. This is the output from the BitBucket API:
{
"size": 3,
"limit": 25,
"isLastPage": true,
"values": [
{
"user": {
"name": "name1",
"emailAddress": "name1.lastname1#domain.com",
"id": 1,
"displayName": "Name1 Lastname1",
"active": true,
"slug": "name1",
"type": "NORMAL",
"links": {
"self": [
{
"href": "https://bitbucket.com/stash/users/name1"
}
]
}
},
"permission": "REPO_WRITE"
},
{
"user": {
"name": "name2",
"emailAddress": "name2.lastname2#domain.com",
"id": 2,
"displayName": "Name2 Lastname2",
"active": true,
"slug": "name2",
"type": "NORMAL",
"links": {
"self": [
{
"href": "https://bitbucket.com/stash/users/name2"
}
]
}
},
"permission": "REPO_WRITE"
},
{
"user": {
"name": "name3",
"emailAddress": "name3.lastname3#domain.com",
"id": 3,
"displayName": "Name3 Lastname3",
"active": true,
"slug": "name3",
"type": "NORMAL",
"links": {
"self": [
{
"href": "https://bitbucket.com/stash/users/name3"
}
]
}
},
"permission": "REPO_WRITE"
}
],
"start": 0
}
is there an easy way to, say, put all 3 email addresses into an array or a coma-separated variable within a bash script? I tried using grep and splitting the API output somehow (e.g. by 'permission'), but no luck so far. Let me note that I may be forced to use standard tools like grep, sed or awk, meaning I may not be able to use tools like jq (to process json in bash) since I cannot really temper with available build agents.
Any help would be much appreciated!

Consider using JQ (or another JSON query tool). It will handle any valid Json, even one that is not pretty-printed or formatted in a specific way. Ca be compined with readarray to build the array in bash.
readarray -t emails <<< "$(jq -r '.values[].user.emailAddress' < file)"
Will produce an array 'emails'
declare -p emails
declare -a emails=([0]=$'name1.lastname1#domain.com' [1]=$'name2.lastname2#domain.com' [2]=$'name3.lastname3#domain.com')
Note 2020-07-22: Added '-t' to strip trailing new lines from result array

Assuming your input is always that regular, this will work using any awk in any shell on every UNIX box:
$ awk -F'"' '$2=="emailAddress"{addrs=addrs sep $4; sep=","} END{print addrs}' file
name1.lastname1#domain.com,name2.lastname2#domain.com,name3.lastname3#domain.com
Save the output in a variable or a file as you see fit, e.g.:
$ var=$(awk -F'"' '$2=="emailAddress"{addrs=addrs sep $4; sep=","} END{print addrs}' file)
$ echo "$var"
name1.lastname1#domain.com,name2.lastname2#domain.com,name3.lastname3#domain.com

Take a look on the python:
You can access directly to your api like this:
import urllib.request
import json
with urllib.request.urlopen('http://your/api') as url:
data = json.loads(url.read().decode())
or as an example with the local file with the same data as you provided:
import json
with open('./response.json') as f:
data = json.load(f)
result = {}
for x in data['values']:
node = x['user']
result[node['emailAddress']] = x['permission']
result is {'name1.lastname1#domain.com': 'REPO_WRITE', 'name2.lastname2#domain.com': 'REPO_WRITE', 'name3.lastname3#domain.com': 'REPO_WRITE'}

$ grep -oP '(?<="emailAddress": ).*' file |
tr -d '",' |
paste -sd,
name1.lastname1#domain.com,name2.lastname2#domain.com,name3.lastname3#domain.com
or
$ grep '"emailAddress":' file |
cut -d: -f2 |
tr -d '", ' |
paste -sd,

Related

Azure Devops API Release definitions expand recursively (I need workflowTasksfrom deployPhases from environments)

Does the Azure Devops REST API allow me to expand multiple levels? When using the release definitions I specifically need the workflowtasks, which are buried a couple of lists deep.
More context:
I'm optimizing an Azure Devops extension that scans pipelines for compliancy. Right now there's a rule that scans the workflowtasks. To get the information required on all relevant pipelines, we do the following call to the Azdo API for each release definition:
https://vsrm.dev.azure.com/{Organization}/{Project}/_apis/release/definitions/{definitionID}?api-version=6.0
This returns a completely decked-out release definition including environments like this:
"environments": [{
"id": 10,
"name": "Stage 1",
... etc
"deployPhases": [{
"deploymentInput": {
"parallelExecution": {
"parallelExecutionType": "none"
},
...etc
"rank": 1,
...etc
"workflowTasks": [{
"environment": {},
"taskId": "obfuscated",
"version": "2.*",
"name": "obfuscated",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"retryCountOnTaskFailure": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"template": "obfuscated",
"assets": "obfuscated",
"duration": "60",
"title": "",
"description": "",
"implementationPlan": "obfuscated"
}
}, {
"environment": {},
"taskId": "obfuscated",
"version": "2.*",
"name": "obfuscated",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"retryCountOnTaskFailure": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"changeClosureCode": "1",
"changeClosureComments": "Successful implementation",
"changeId": ""
}
}
]
}
],
...etc
}
],
But when I try and get the list as a whole, using the following URL:
https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions?$expand=environments&api-version=6.0
My Environments arrays (there is one for each definition obviously) looks nothing like the previous one. It doesn't include deployPhases (not even as an empty array).
Since we have 2300 release definitions, you can Imagine how inconvenient it is to call the release/definitions/{definitionID} endpoint instead of the release/definitions one that fetches all of them at the same time.
Is there a way to expand the release/definitions call to fetch all environments including workflowTasks and maybe other stuff? Is there a syntax that allows for this? Something like $expand=environments>deployPhases>workflowTasks?
Is there a way to expand the release/definitions call to fetch all environments including workflowTasks and maybe other stuff? Is there a syntax that allows for this? Something like $expand=environments>deployPhases>workflowTasks?
I am afraid there is no such syntax allow you to fetch all environments including workflowTasks.
You could use the REST API with some powershell scripts to fetch all environments including workflowTasks:
The sample powershell scripts:
$url = "https://vsrm.dev.azure.com/{Organization}/{Project}/_apis/release/definitions/{definitionID}?api-version=6.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Method Get -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "workflowTasks = $($pipeline.environments.deployPhases.workflowTasks | ConvertTo-Json -Depth 100)"
The output is:

How to add test steps in a test case work item using Rest API - TFS2018 / Python

I am using Microsoft's TFS 2018 and I have started writing some Selenium test cases using Python 3.7 in Visual Studio 2018.
I have managed to use the REST API of TFS to return my TFS projects and create new test cases.
What I couldn't find is how to use this API to pass a list with all the test steps of this test case. I am not sure how and if you can add them in the body of the request as a string or array.
At the moment I am trying to make this work on Postman first and then I am going to try in python as well.
This is the request:
curl -X POST \
'https://TFSLINK:443/DefaultCollection/TFS/_apis/wit/workitems/$Test%20Case?api-version=4.1' \
-H 'Authorization: Basic MYKEY' \
-H 'Content-Type: application/json-patch+json' \
-H 'cache-control: no-cache' \
-d '[
{
"op": "add",
"path": "/fields/System.Title",
"from": null,
"value": "Sample task 2"
}
]'
Is there a way to achieve adding steps ? The API didn't mention anything about this.
In the response I get after creating a test case I get a section called 'fields' which should have included the steps but I can't see them in my response.
{
"id": 731,
"rev": 1,
"fields": {
"System.AreaPath": "TFS",
"System.TeamProject": "TFS",
"System.IterationPath": "TFS",
"System.WorkItemType": "Test Case",
"System.State": "Design",
"System.Reason": "New",
"System.AssignedTo": "Marialena <TFS\\marialena>",
"System.CreatedDate": "2019-01-09T08:00:50.51Z",
"System.CreatedBy": "Marialena <TFS\\marialena>",
"System.ChangedDate": "2019-01-09T08:00:50.51Z",
"System.ChangedBy": "Marialena <TFS\\marialena>",
"System.Title": "Sample task 2",
"Microsoft.VSTS.Common.StateChangeDate": "2019-01-09T08:00:50.51Z",
"Microsoft.VSTS.Common.ActivatedDate": "2019-01-09T08:00:50.51Z",
"Microsoft.VSTS.Common.ActivatedBy": "Marialena <TFS\\marialena>",
"Microsoft.VSTS.Common.Priority": 2,
"Microsoft.VSTS.TCM.AutomationStatus": "Not Automated"
},
"_links": {
"self": {
"href": "https://TFSLINK/DefaultCollection/_apis/wit/workItems/731"
},
"workItemUpdates": {
"href": "https://TFSLINK/DefaultCollection/_apis/wit/workItems/731/updates"
},
"workItemRevisions": {
"href": "https://TFSLINK/DefaultCollection/_apis/wit/workItems/731/revisions"
},
"workItemHistory": {
"href": "https://TFSLINK/DefaultCollection/_apis/wit/workItems/731/history"
},
"html": {
"href": "https://TFSLINK/web/wi.aspx?pcguid=07b658c4-97e5-416f-b32d-3dd48d7f56cc&id=731"
},
"workItemType": {
"href": "https://TFSLINK/DefaultCollection/18ca0a74-cf78-45bf-b163-d8dd4345b418/_apis/wit/workItemTypes/Test%20Case"
},
"fields": {
"href": "https://TFSLINK/DefaultCollection/_apis/wit/fields"
}
},
"url": "https://TFSLINK/DefaultCollection/_apis/wit/workItems/731"
}
I have tried creating this PATCH request to update the steps but it didn't work
curl -X PATCH \
'https://TFSLINK:443/DefaultCollection/TFS/_apis/wit/workItems/730?api-version=4.1' \
-H 'Authorization: Basic MYKEY' \
-H 'Content-Type: application/json-patch+json'
-d '[
{
"op": "add",
"path": "/fields/Microsoft.VSTS.TCM.Steps",
"from": null,
"value": "Test"
},
{
"op": "add",
"path": "/fields/Steps",
"from": null,
"value": "Test"
}
]'
And maybe this is a another topic but if the above is achievable, can you also pass the results after you run the test and update the test plan perhaps ? If this is unrelated please help me only with the test steps and ignore this question.
Many thanks.
This is the way to add test steps in Test Case with Rest API:
{
"op": "add",
"path": "/fields/Microsoft.VSTS.TCM.Steps",
"value": "<steps id=\"0\" last=\"1\"><step id=\"2\" type=\"ValidateStep\"><parameterizedString isformatted=\"true\">Input step 1</parameterizedString><parameterizedString isformatted=\"true\">Expectation step 1</parameterizedString><description/></step></steps>"
}
For a few steps (3 on this example):
{
"op": "add",
"path": "/fields/Microsoft.VSTS.TCM.Steps",
"value": "<steps id=\"0\" last=\"4\"><step id=\"2\" type=\"ValidateStep\"><parameterizedString isformatted=\"true\"><P>step 1 \"Action\"</P></parameterizedString><parameterizedString isformatted=\"true\"><P>step 1 \"Expected\"<BR/></P></parameterizedString><description/></step><step id=\"3\" type=\"ValidateStep\"><parameterizedString isformatted=\"true\"><P>step 2 \"Action\"<BR/></P></parameterizedString><parameterizedString isformatted=\"true\"><P>step 2 \"Expected\"<BR/></P></parameterizedString><description/></step><step id=\"4\" type=\"ValidateStep\"><parameterizedString isformatted=\"true\"><P>step 3 \"Action\"<BR/></P></parameterizedString><parameterizedString isformatted=\"true\"><P>step 3 \"Expected\"<BR/></P></parameterizedString><description/></step></steps>"
}

how to use the puppetdb API to combine facts

I'm using puppet version 5.3.6.
I'm able to query the puppetdb and get lots of useful information like this:
$ curl -s -X GET http://localhost:8080/pdb/query/v4/facts --data-urlencode 'query=["extract", [["function","count"],"value"],["=","name","operatingsystem"],["group_by", "value"]]' | python -mjson.tool
[
{
"count": 339,
"value": "OracleLinux"
},
{
"count": 73,
"value": "RedHat"
}
]
AND:
$ curl -s -X GET http://localhost:8080/pdb/query/v4/facts --data-urlencode 'query=["extract", [["function","count"],"value"],["=","name","operatingsystemmajrelease"],["group_by", "value"]]' | python -mjson.tool
[
{
"count": 38,
"value": "5"
},
{
"count": 217,
"value": "6"
},
{
"count": 157,
"value": "7"
}
]
How can I combine the two together and get each Oracle/Red Hat release & major release grouped together in an easy to see view. I've tried a few different ways to do it but I'm not able to find any examples or docs that can explain to me how to do it.
Other useful combinations would be all Red Hat servers in a particular DC running operatingsystemmajrelease 6 (or show all of them?). This would involve combining three facts.
This would be very ussful.
Thanks for your help!
Regards

How to check whether any window is open in i3

How could I find out whether any window is opened in i3 or not? Like, check if any workspace contains any window.
You can check if any 'visible' window is open in i3 by using xdotool:
You can install xdotool with sudo pacman -S xdotool
WINDOWS=$(xdotool search --all --onlyvisible --desktop $(xprop -notype -root _NET_CURRENT_DESKTOP | cut -c 24-) "" 2>/dev/null)
NUM=$(echo "$WINDOWS" | wc -l)
if [ $NUM -eq 0 ]; then
echo "No windows open."
fi
maybe try i3-save-tree. You must install perl-anyevent-i3 and perl-json-xs first.
https://i3wm.org/docs/layout-saving.html
Example:
$ i3-save-tree --workspace 10
// vim:ts=4:sw=4:et
{
"border": "pixel",
"current_border_width": 1,
"floating": "auto_off",
"geometry": {
"height": 720,
"width": 1366,
"x": 0,
"y": 0
},
"name": "Waterfox Start Page - Waterfox",
"percent": 1,
"swallows": [
{
// "class": "^Waterfox$",
// "instance": "^Navigator$",
// "title": "^Waterfox\\ Start\\ Page\\ \\-\\ Waterfox$",
// "transient_for": "^$",
// "window_role": "^browser$"
}
],
"type": "con"
}

Why rebol fails with stackoverflow api?

If I type in a browser (see https://stackapps.com/questions/2/getting-started-with-the-api) :
http://api.stackoverflow.com/1.0/stats
it returns
{
"statistics": [
{
"total_questions": 800830,
"total_unanswered": 131356,
"total_accepted": 500653,
"total_answers": 2158752,
"total_comments": 3125048,
"total_votes": 7601765,
"total_badges": 798091,
"total_users": 289282,
"questions_per_minute": 1.50,
"answers_per_minute": 3.12,
"badges_per_minute": 1.20,
"views_per_day": 455215.44,
"api_version": {
"version": "1.0",
"revision": "2010.7.17.1"
},
"site": {
"name": "Stack Overflow",
"logo_url": "http://sstatic.net/stackoverflow/img/logo.png",
"api_endpoint": "http://api.stackoverflow.com",
"site_url": "http://stackoverflow.com",
"description": "Q&A for professional and enthusiast programmers",
"icon_url": "http://sstatic.net/stackoverflow/apple-touch-icon.png",
"state": "normal",
"styling": {
"link_color": "#0077CC",
"tag_foreground_color": "#3E6D8E",
"tag_background_color": "#E0EAF1"
}
}
}
]
}
If I type this in rebol console:
read http://api.stackoverflow.com/1.0/stats
It returns some weird binary chars.
probe load to-string gunzip to-string read/binary http://api.stackoverflow.com/1.0/stats
connecting to: api.stackoverflow.com
{
"statistics": [
{
"total_questions": 801559,
"total_unanswered": 131473,
"total_accepted": 501129,
"total_answers": 2160171,
"total_comments": 3127759,
"total_votes": 7607247,
"total_badges": 798608,
"total_users": 289555,
"questions_per_minute": 0.93,
"answers_per_minute": 1.83,
"badges_per_minute": 0.73,
"views_per_day": 455579.60,
"api_version": {
"version": "1.0",
"revision": "2010.7.17.2"
},
"site": {
"name": "Stack Overflow",
"logo_url": "http://sstatic.net/stackoverflow/img/logo.png",
"api_endpoint": "http://api.stackoverflow.com",
"site_url": "http://stackoverflow.com",
"description": "Q&A for professional and enthusiast programmers",
"icon_url": "http://sstatic.net/stackoverflow/apple-touch-icon.png",
"state": "normal",
"styling": {
"link_color": "#0077CC",
"tag_foreground_color": "#3E6D8E",
"tag_background_color": "#E0EAF1"
}
}
}
]
}
REBOL is ignoring the Content-Encoding: gzip response header, which stackoverflow seems adamant to use, regardless of what you put in your Accept-Encoding: header. On Unix, wget and curl have the same problem, but I can do this to see the intended content:
curl http://api.stackoverflow.com/1.0/stats | zcat
Does REBOL have a way to uncompress gzip content?
Based on http://www.mail-archive.com/rebol-bounce#rebol.com/msg03531.html
>> do http://www.rebol.org/download-a-script.r?script-name=gunzip.r
connecting to: www.rebol.org
Script: "gunzip" (30-Dec-2004)
>> print to-string gunzip read http://api.stackoverflow.com/1.0/stats
connecting to: api.stackoverflow.com
{
"statistics": [
{
"total_questions": 801316,
"total_unanswered": 131450,
"total_accept���������������������accept������E531450,
"tocomment312672�vote7605283badge7984187946531450,
tal_unans_per_minutet.0531450,
....
almost works :)
so the core code is all there, just not exposed properly... it's a pity indeed...
but stackoverflow is not nice either not being complaint to the http specs and ignoring the accept-encoding header...