Jenkinsfile pipeline construct JSON object and write to file - jenkins

I would like to construct a JSON object and write the content to file.
Originally I was inspired by this and tried:
def data = [
a:"test: ${myVar}"
]
writeJSON(file: 'message1.json', json: data)
But this failed with:
Could not instantiate {file=message1.json, json={a=test}} for WriteJSONStep(file: String, json: JSON{}, pretty?: int): java.lang.UnsupportedOperationException: must specify $class with an implementation of interface net.sf.json.JSON
So next I tried:
def data = readJSON text: '{}'
data.a = "test: ${myVar}"
writeJSON(file: 'message1.json', json: data, pretty: 4)
Now the build passes, but the content of the file looks like:
{
"a": {
"bytes": [
114,
101,
108,
101,
97,
115,
101
50
],
"strings": [
"test: ",
""
],
"valueCount": 1,
"values": ["v1.0.2"]
}
}
Whereas my intention was {"a": "test: v1.0.2"}
My end goal is that I want to dynamically construct a JSON object, set some properties with some dynamic data and then write the JSON file.
Is there some syntax that can be used to assign the values as strings, rather than some bytes.

It seems one solution to this is changing the code that adds to the map to specify as String:
def data = readJSON text: '{}'
data.a = "test: ${myVar}" as String
writeJSON(file: 'message1.json', json: data, pretty: 4)

regarding your first attempt, it seems there is a JSONObject.fromObject() function you can use.
def data = JSONObject.fromObject([
a:"test: ${myVar}".toString()
])
writeJSON(file: 'message1.json', json: data)

Related

Using Json Slurper + Groovy + Azure answer

So I am trying to write a Jenkins job using groovy to fetch me some data
The data inside the variable answer after the 3rd line would be some like
[
{
"endIpAddress": "11.21.115.9",
"id": "blabla1",
"name": "blabla",
"resourceGroup": "stg",
"startIpAddress": "11.12.115.9",
"type": "blablafirewallRules"
},
{
"endIpAddress": "1.2.15.9",
"id": "blabla2",
"name": "function1-blabla",
"resourceGroup": "stg",
"startIpAddress": "1.2.15.9",
"type": "blablafirewallRules"
},
{
"endIpAddress": "7.7.7.7",
"id": "blabla2",
"name": "function2-blabla",
"resourceGroup": "stg",
"startIpAddress": "7.7.7.7",
"type": "blablafirewallRules"
},
.
.
.
.
]
What id like to do is to build a list or a 2-dimentions-array that would parse this json and the it will hold all the startipaddress of all the items where name contains "function", so based on this JSON, the data should be
desiredData[0] = [function1-blabla, 1.2.15.9]
desiredData[1] = [function2-blabla, 7.7.7.7]
Up until now I wasn't using JsonSlurper and I was manipulating the text and building the array which is pretty stupid thing to do since this is kind of what JSON is all about I guess.
import groovy.json.JsonSlurper
command = "az mysql server firewall-rule list --resource-group ${rgNameSrvr} --server-name ${BLA} --output json"
answer = azure.executeAzureCliCommand(command, "BLA")
def jsonSlurper = new JsonSlurper()
def json = new JsonSlurper().parseText(answer)
def data = json.findAll{ it.name =~ /^function/ }.collectEntries{ [it.name, it.startIpAddress] }
Code above returns map where key=name and value=ip
If you want 2dim array:
def data = json.findAll{ it.name =~ /^function/ }.collect{ [it.name, it.startIpAddress] }

Stringify/Parse request data through rspec

I'm submitting requests on the frontend where I stringify my data (array of objects) and then parse it in the backend.
When I run my specs, I'm getting the error no implicit conversion of Array into String
How can I stringify my data in my spec so that it's consistent with what I'm doing in the frontend? Or is there another way where I don't have to stringify/parse my data to handle all of this?
This is how my frontend data structure looks like:
"categories_and_years": JSON.stringify(
[
{"category_id": 1, "year_ids":[1, 2, 3]},
{"category_id": 2, "year_ids":[2, 3]},
]
)
In my controller, I'm validating the data is an array first:
def validate_categories_and_years_array
#cats_and_yrs = JSON.parse(params[:categories_and_years])
return unless #cats_and_yrs
if !#cats_and_yrs.is_a?(Array)
render_response(:unprocessable_entity, { description_detailed: "categories_and_years must be an array of objects"})
end
end
In my specs, I'm setting my params like this:
context "when all categories and years are valid" do
let(:params) do
{
school_id: school.id,
id: standard_group.id,
categories_and_years: [
{ category_id: category_1.id, year_ids: [ year_1.id ] }
]
}
end
it "adds standards from specific categories and years to the school" do
post :add, params: params, as: :json
expect(school.achievement_standards).to contain_exactly( std_1 )
end
end
This post explains the difference between a regular ruby hash which you have in your spec and a HashWithIndifferentAccess.
Can you also try to_json?
Params hash keys as symbols vs strings
params = ActiveSupport::HashWithIndifferentAccess.new()
params['school_id'] = school.id
params['id'] = standard_group.id
params['categories_and_years'] = [
{ category_id: category_1.id, year_ids: [ year_1.id ] }
]
params = params.to_json
let(:params) { params }

Remove metadata from json results

I'm using ActiveResource to establish a REST connection with rails 4.2 to an ADS Advantage server using the WebPlatform from ADS. It returns json with "__metadata". How can I remove the "__metadata"?
{
"__metadata": {
"uri": "http://.....",
"key_fields": "ID",
"rows_affected": 0,
"last_autoinc": 0
},
In my class I have added self.include_format_in_path = false, to remove the .json from the end of the uri.
Thanks.
you can achieve this in the following steps:
parse the JSON:
parsed_json = JSON.parse('{ "__metadata": { "uri": "http://.....", "key_fields": "ID", "rows_affected": 0, "last_autoinc": 0 }}')
then you will get a hash type and you just need to get the inside of __metadata:
result = parsed_json['__metadata']
then you can just return it or print it:
puts result.to_json
#=> {"uri"=>"http://.....", "key_fields"=>"ID", "rows_affected"=>0, "last_autoinc"=>0}

rails render extract value from json response

I have a Rails app and I am trying to render an array of items from a parsed JSON hash.
My current render statement looks like this
resp = JSON.parse(response.body)
render json: resp
I am using Typheous and this code did not work for me:
resp = JSON.parse(response.body).fetch("item")
The following is the JSON hash (the item key has many values but I'm only displaying one for brevity):
{
ebay: [{
findItemsByKeywordsResponse: [{
ack: [],
version: [],
timestamp: [],
searchResult: [{
count: "91",
item: [{
itemId: [ "321453454731" ]
}]
}]
}]
}]
}
How can I render an array of items from the parsed JSON hash?
Since there is only one value for the ebay and findItemsByKeywordsResponse keys (per the OP's comment), you could retrieve an array of items by doing something like this:
resp = JSON.parse(response.body)
resp[:ebay].first[:findItemsByKeywordsResponse].first[:searchResult].first[:item]
This will give you an array of hashes containing the itemId and any other key-value pairs.
The reason you want to include the .first (or [0]) is because based on the parsed JSON response, your hash contains an array of hashes nested all the way to the item array. If there are multiple searchResult values, you'll need to iterate through those before getting your item array.

rails extract data from simple json response

I need to extract some data from a JSON response i'm serving up from curb.
Previously I wasn't calling symbolize_keys, but i thought that would make my attempt work.
The controller action:
http = Curl.get("http://api.foobar.com/thing/thing_name/catalog_items.json?per_page=1&page=1") do|http|
http.headers['X-Api-Key'] = 'georgeBushSucks'
end
pre_keys = http.body_str
#foobar = ActiveSupport::JSON.decode(pre_keys).symbolize_keys
In the view (getting undefined method `current_price' )
#foobar.current_price
I also tried #foobar.data[0]['current_price'] with the same result
JSON response from action:
{
"data": {
"catalog_items": [
{
"current_price": "9999.0",
"close_date": "2013-05-14T16:08:00-04:00",
"open_date": "2013-04-24T11:00:00-04:00",
"stuff_count": 82,
"minimum_price": "590000.0",
"id": 337478,
"estimated_price": "50000.0",
"name": "This is a really cool name",
"current_winner_id": 696969,
"images": [
{
"thumb_url": "http://foobar.com/images/93695/thumb.png?1365714300",
"detail_url": "http://foobar.com/images/93695/detail.png?1365714300",
"position": 1
},
{
"thumb_url": "http://foobar.com/images/95090/thumb.jpg?1366813823",
"detail_url": "http://foobar.com/images/95090/detail.jpg?1366813823",
"position": 2
}
]
}
]
},
"pagination": {
"per_page": 1,
"page": 1,
"total_pages": 131,
"total_objects": 131
}
}
Please note that accessing hash's element in Rails work in models. To use it on hash, you have to use OpenStruct object. It's part of standard library in rails.
Considering, #foobar has decoded JSON as you have.
obj = OpenStruct.new(#foobar)
obj.data
#=> Hash
But, note that, obj.data.catalog_items willn't work, because that is an hash, and again not an OpenStruct object. To aid this, we have recursive-open-struct, which will do the job for you.
Alternative solution [1]:
#foobar[:data]['catalog_items'].first['current_price']
But, ugly.
Alternative solution [2]:
Open Hash class, use method_missing ability as :
class Hash
def method_missing(key)
self[key.to_s]
end
end
Hope it helps. :)

Resources