mirror of
https://github.com/LukeHagar/api-specs.git
synced 2025-12-06 12:27:48 +00:00
initial script creation
This commit is contained in:
@@ -47,8 +47,10 @@ fs.readFile(args[2], 'utf8', (err, data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Write the modified JSON content back to the file
|
// Write the modified JSON content back to the file
|
||||||
|
// Use the line below if you need it to be in a format that can be uploaded to postman
|
||||||
|
//fs.writeFile(args[2], JSON.stringify({"collection": jsonObject}, null, 2), (writeErr) => {
|
||||||
fs.writeFile(args[2], JSON.stringify(jsonObject, null, 2), (writeErr) => {
|
fs.writeFile(args[2], JSON.stringify(jsonObject, null, 2), (writeErr) => {
|
||||||
if (writeErr) {
|
if (writeErr) {
|
||||||
console.error('Error writing the file:', writeErr);
|
console.error('Error writing the file:', writeErr);
|
||||||
|
|||||||
2
postman-script/partialUpdate/.gitignore
vendored
Normal file
2
postman-script/partialUpdate/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
node_modules
|
||||||
507
postman-script/partialUpdate/DeployIncremental.js
Normal file
507
postman-script/partialUpdate/DeployIncremental.js
Normal file
@@ -0,0 +1,507 @@
|
|||||||
|
// Deploy collection inncrementally
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Cycle through the collection objects and deploy them one by one
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Folders -> Requests -> Responses
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// An updated object has a different id.
|
||||||
|
// If the id matches, then the object is unchanged.
|
||||||
|
// If the id does not match, then the object is new.
|
||||||
|
// In the end delete all objects that are not in the updated collection.
|
||||||
|
// Sort the objects and update the parent order property.
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Except for folders which would force the update of the entire collection.
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
const pmConvert = require('./PostmanCovertions')
|
||||||
|
const pmAPI = require('./postmanAPI')
|
||||||
|
var crypto = require('crypto');
|
||||||
|
const { GenID } = require('./Utils')
|
||||||
|
|
||||||
|
const deployIncremental = async (privateRemoteCollectionId, localCollection, publicRemoteCollectionId) => {
|
||||||
|
let remoteCollection = await refreshRemoteCollection(privateRemoteCollectionId)
|
||||||
|
|
||||||
|
console.log('Incremental deployment of collection ', localCollection.info.name)
|
||||||
|
|
||||||
|
// const collectioHeadHasChanged =
|
||||||
|
await upadteCollectionHead(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
remoteCollection = await refreshRemoteCollection(privateRemoteCollectionId)
|
||||||
|
|
||||||
|
// const foldersHaveChanged =
|
||||||
|
await mergeFolders(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
remoteCollection = await refreshRemoteCollection(privateRemoteCollectionId)
|
||||||
|
|
||||||
|
// const requestsHaveChanged =
|
||||||
|
await mergeRequests(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
remoteCollection = await refreshRemoteCollection(privateRemoteCollectionId)
|
||||||
|
|
||||||
|
// const responsesHaveChanged =
|
||||||
|
await mergeResponses(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
// should we always merge into the public collection?
|
||||||
|
// There is teh case that if an error happens in the merge phase
|
||||||
|
// the private collection is fully updated
|
||||||
|
// and in the next run the public collection will NOT be updated
|
||||||
|
// because there are no changes in the private collection
|
||||||
|
|
||||||
|
// if (!(collectioHeadHasChanged || foldersHaveChanged || requestsHaveChanged || responsesHaveChanged)) {
|
||||||
|
// console.log('Incremental deployment of collection ', localCollection.info.name, ' completed\n\n')
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
const msg = 'Merging to public collection'
|
||||||
|
console.log('\n' + msg + '...')
|
||||||
|
await new pmAPI.Collection(privateRemoteCollectionId).merge(publicRemoteCollectionId)
|
||||||
|
.then(() => { console.log(msg, '-> OK\n') })
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
console.log('Incremental deployment of collection ', localCollection.info.name, ' completed\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function upadteCollectionHead (remoteCollection, localCollection) {
|
||||||
|
// the colelction head shoul dbe updated if there are changes in
|
||||||
|
// Authorization
|
||||||
|
// Pre-request Script
|
||||||
|
// Tests
|
||||||
|
// Variables
|
||||||
|
|
||||||
|
const localEmptyCollection = { ...localCollection }
|
||||||
|
localEmptyCollection.item = []
|
||||||
|
|
||||||
|
// Check changes in info
|
||||||
|
const hasChangesInfo = checkInfoChanges(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
// Check if there are changes in the Authorization
|
||||||
|
const hasChangesAuth = checkObjectChanges(remoteCollection.collection.auth, localEmptyCollection.auth)
|
||||||
|
|
||||||
|
// Check if there are changes in the Scripts (pre-request and tests)
|
||||||
|
const hasChangesPreRequestScript = checkScriptChanges('prerequest', remoteCollection, localEmptyCollection)
|
||||||
|
|
||||||
|
const hasChangesTestScript = checkScriptChanges('test', remoteCollection, localEmptyCollection)
|
||||||
|
|
||||||
|
// Check if there are changes in the Variables
|
||||||
|
const hasChangesVariables = checkVariableChanges(remoteCollection, localEmptyCollection)
|
||||||
|
|
||||||
|
const hasFolderSortChanges = checkFolderSortChanges(remoteCollection, localCollection)
|
||||||
|
|
||||||
|
const hasChanges = (
|
||||||
|
hasFolderSortChanges ||
|
||||||
|
hasChangesInfo ||
|
||||||
|
hasChangesAuth ||
|
||||||
|
hasChangesPreRequestScript ||
|
||||||
|
hasChangesTestScript ||
|
||||||
|
hasChangesVariables
|
||||||
|
)
|
||||||
|
|
||||||
|
if (hasChanges) {
|
||||||
|
const msg = 'Updating collection head'
|
||||||
|
console.log('\n' + msg + '...')
|
||||||
|
await new pmAPI.Collection(remoteCollection.collection.info.uid)
|
||||||
|
.update({ collection: localEmptyCollection })
|
||||||
|
.then(() => { console.log(msg, '-> OK\n') })
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return hasChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkFolderSortChanges = (remoteCollection, localCollection) => {
|
||||||
|
const remoteFolders = remoteCollection.collection.item
|
||||||
|
.map(folder => ({ id: folder.id }))
|
||||||
|
const localFolders = localCollection.item
|
||||||
|
.filter(folder => !folder.folder)
|
||||||
|
.map(folder => ({ id: folder.id }))
|
||||||
|
|
||||||
|
const remoteFoldersHash = GenID(JSON.stringify(remoteFolders))
|
||||||
|
const localFoldersHash = GenID(JSON.stringify(localFolders))
|
||||||
|
|
||||||
|
return remoteFoldersHash !== localFoldersHash
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkInfoChanges = (remoteCollection, localEmptyCollection) => {
|
||||||
|
// collection info does not have a specific id
|
||||||
|
// so we need to generate a hash and compare them
|
||||||
|
// The hash is only beig generated for name, description and schema
|
||||||
|
|
||||||
|
const { name, description, schema } = remoteCollection.collection.info
|
||||||
|
const remoteInfo = { name, description, schema }
|
||||||
|
|
||||||
|
const { name: localName, description: localDescription, schema: localSchema } = localEmptyCollection.info
|
||||||
|
const localInfo = { name: localName, description: localDescription, schema: localSchema }
|
||||||
|
|
||||||
|
const remoteInfoHash = calculateHash(JSON.stringify(remoteInfo))
|
||||||
|
const localInfoHash = calculateHash(JSON.stringify(localInfo))
|
||||||
|
|
||||||
|
return remoteInfoHash !== localInfoHash
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkObjectChanges = (remoteCollectionObject, localCollectionObject) => {
|
||||||
|
if (!remoteCollectionObject && !localCollectionObject) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!remoteCollectionObject || !localCollectionObject) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// certain object like auth do not have an id,
|
||||||
|
// so we need to generate on and compare them
|
||||||
|
const remoteCollectionAuthID = GenID(JSON.stringify(remoteCollectionObject))
|
||||||
|
const localCollectionAuthID = GenID(JSON.stringify(localCollectionObject))
|
||||||
|
return remoteCollectionAuthID !== localCollectionAuthID
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkScriptChanges = (scriptType, remoteCollection, localCollection) => {
|
||||||
|
// RB 2020-10-20: The collection may be empty or have no events at all
|
||||||
|
let remoteScript = null
|
||||||
|
let localScript = null
|
||||||
|
if (remoteCollection.collection.event) {
|
||||||
|
remoteScript = remoteCollection.collection.event.find(event => event.listen === scriptType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localCollection.event) {
|
||||||
|
localScript = localCollection.event.find(event => event.listen === scriptType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// const remoteScript = remoteCollection.collection.event.find(event => event.listen === scriptType)
|
||||||
|
// const localScript = localCollection.event.find(event => event.listen === scriptType)
|
||||||
|
|
||||||
|
if (!remoteScript && !localScript) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!remoteScript || !localScript) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// files can be big, so we hash them
|
||||||
|
const remoteHash = calculateHash(remoteScript.script.exec[0])
|
||||||
|
const localHash = calculateHash(localScript.script.exec[0])
|
||||||
|
|
||||||
|
return remoteHash !== localHash
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkVariableChanges = (remoteCollection, localCollection) => {
|
||||||
|
const remoteVariables = remoteCollection.collection.variable
|
||||||
|
const localVariables = localCollection.variable.map(variable => ({ key: variable.key, value: variable.value }))
|
||||||
|
|
||||||
|
// check if null
|
||||||
|
if (!remoteVariables && !localVariables) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!remoteVariables || !localVariables) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// although the local collection does have a deterministic id
|
||||||
|
// the remote variable looses that value when it is updated
|
||||||
|
// so we need to generate an id for the remote variable
|
||||||
|
|
||||||
|
const remoteVariablesHash = GenID(remoteVariables)
|
||||||
|
const localVariablesHash = GenID(localVariables)
|
||||||
|
|
||||||
|
return remoteVariablesHash !== localVariablesHash
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mergeFolders (remoteCollection, localCollection) {
|
||||||
|
console.log(' Deploying Folders:')
|
||||||
|
|
||||||
|
const remoteFolders = getAllFoldersFromCollectionItem(remoteCollection.collection.item)
|
||||||
|
const localFolders = localCollection.item // all folders
|
||||||
|
|
||||||
|
const newFolders = localFolders.filter(localFolder => !remoteFolders.find(remoteFolder => remoteFolder.id === localFolder.id))
|
||||||
|
const oldFolders = remoteFolders.filter(remoteFolder => !localFolders.find(localFolder => localFolder.id === remoteFolder.id))
|
||||||
|
|
||||||
|
let hasChanges = newFolders.length > 0 || oldFolders.length > 0
|
||||||
|
|
||||||
|
if (!hasChanges) {
|
||||||
|
console.log(' -> No changes')
|
||||||
|
return hasChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new folders
|
||||||
|
for (const folder of newFolders) {
|
||||||
|
const msg = ` Creating new folder [${folder.name}]`
|
||||||
|
await new pmAPI.Folder(remoteCollection.collection.info.uid)
|
||||||
|
.create(folder)
|
||||||
|
.then(() => {
|
||||||
|
hasChanges = true
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete old folders
|
||||||
|
for (const folder of oldFolders) {
|
||||||
|
const msg = ` Deleting old folder [${folder.name}]`
|
||||||
|
await new pmAPI.Folder(remoteCollection.collection.info.uid)
|
||||||
|
.delete(folder.id)
|
||||||
|
.then(() => {
|
||||||
|
hasChanges = true
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort folders is not supported for now
|
||||||
|
// const order = localFolders.map(folder => folder.id)
|
||||||
|
// const msg = ' Sorting folders'
|
||||||
|
|
||||||
|
// // create a temporsary root folder
|
||||||
|
// const rootFolder = await new pmAPI.Folder(remoteCollection.collection.info.uid)
|
||||||
|
// .create({ id: GenID(), name: 'root', folders: order })
|
||||||
|
// .catch((error) => {
|
||||||
|
// console.log(msg, '-> FAIL')
|
||||||
|
// handlePostmanAPIError(error)
|
||||||
|
// })
|
||||||
|
// console.log('root folder', rootFolder)
|
||||||
|
// // move all remote folders into root folder
|
||||||
|
|
||||||
|
return hasChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mergeRequests (remoteCollection, localCollection) {
|
||||||
|
const remoteFolders = getAllFoldersFromCollectionItem(remoteCollection.collection.item)
|
||||||
|
const localFolders = localCollection.item // all folders
|
||||||
|
|
||||||
|
console.log('\n Deploying Requests:')
|
||||||
|
let anyRequestHasChanged = false
|
||||||
|
|
||||||
|
// loop folders
|
||||||
|
for (const localFolder of localFolders) {
|
||||||
|
const remoteRemoteFolder = remoteFolders.find(remoteFolder => ((remoteFolder.id === localFolder.id)))
|
||||||
|
|
||||||
|
// TODO: RB: get requests by folder
|
||||||
|
// handle undefined items
|
||||||
|
remoteRemoteFolder.item = remoteRemoteFolder.item || []
|
||||||
|
|
||||||
|
// filter out anything that is not a request
|
||||||
|
remoteRemoteFolder.item = remoteRemoteFolder.item.filter(request => request.request)
|
||||||
|
|
||||||
|
const remoteRequests = remoteRemoteFolder.item
|
||||||
|
const localRequests = localFolder.item
|
||||||
|
|
||||||
|
// Identify old and new requests
|
||||||
|
const newRequests = localRequests.filter(localRequest => !remoteRequests.find(remoteRequest => remoteRequest.id === localRequest.id))
|
||||||
|
const oldRequests = remoteRequests.filter(remoteRequest => !localRequests.find(localRequest => localRequest.id === remoteRequest.id))
|
||||||
|
|
||||||
|
const requestsInFolderHaveChanges = newRequests.length > 0 || oldRequests.length > 0
|
||||||
|
|
||||||
|
if (!requestsInFolderHaveChanges) {
|
||||||
|
console.log(' In Folder: ', localFolder.name, '-> No changes')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
console.log(' In Folder: ', localFolder.name)
|
||||||
|
|
||||||
|
// create new requests
|
||||||
|
for (const request of newRequests) {
|
||||||
|
// check request format and convert if necessary
|
||||||
|
let pmRequest = null
|
||||||
|
if (!request.request) { // => Postman Format
|
||||||
|
pmRequest = request
|
||||||
|
} else { // => OpenAPI Format
|
||||||
|
pmRequest = pmConvert.requestFromLocal(request)
|
||||||
|
}
|
||||||
|
const msg = ` Creating new request [${request.name}]`
|
||||||
|
|
||||||
|
await new pmAPI.Request(remoteCollection.collection.info.uid)
|
||||||
|
.create(pmRequest, localFolder.id)
|
||||||
|
.then((req) => {
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
return req
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
// console.log('\nequest', request)
|
||||||
|
// console.log('\npmRequest', pmRequest)
|
||||||
|
// console.log('\nremoteRequest', remoteRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete old requests
|
||||||
|
for (const request of oldRequests) {
|
||||||
|
const msg = ` Deleting old request [${request.name}]`
|
||||||
|
await new pmAPI.Request(remoteCollection.collection.info.uid)
|
||||||
|
.delete(request.id)
|
||||||
|
.then(() => {
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestsInFolderHaveChanges) {
|
||||||
|
// sort requests in folder
|
||||||
|
const order = localRequests.map(request => request.id)
|
||||||
|
const msg = ` Sorting requests in folder [${localFolder.name}]`
|
||||||
|
await new pmAPI.Folder(remoteCollection.collection.info.uid)
|
||||||
|
.update(localFolder.id, { order })
|
||||||
|
.then(() => { console.log(msg, '-> OK') })
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
anyRequestHasChanged = anyRequestHasChanged || requestsInFolderHaveChanges
|
||||||
|
}
|
||||||
|
return anyRequestHasChanged
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mergeResponses (remoteCollection, localCollection) {
|
||||||
|
console.log('\n Deploying Response:')
|
||||||
|
const remoteFolders = getAllFoldersFromCollectionItem(remoteCollection.collection.item)
|
||||||
|
const localFolders = localCollection.item
|
||||||
|
|
||||||
|
let anyResponseHasChanged = false
|
||||||
|
// loop folders
|
||||||
|
for (const localFolder of localFolders) {
|
||||||
|
const remoteRemoteFolder = remoteFolders.find(remoteFolder => ((remoteFolder.id === localFolder.id)))
|
||||||
|
|
||||||
|
// handle undefined items
|
||||||
|
remoteRemoteFolder.item = remoteRemoteFolder.item || []
|
||||||
|
|
||||||
|
// filter out anything that is not a request
|
||||||
|
remoteRemoteFolder.item = remoteRemoteFolder.item.filter(request => request.request)
|
||||||
|
|
||||||
|
const remoteRequests = remoteRemoteFolder.item
|
||||||
|
const localRequests = localFolder.item
|
||||||
|
|
||||||
|
console.log(' In Folder: ', localFolder.name)
|
||||||
|
// loop requests
|
||||||
|
for (const localRequest of localRequests) {
|
||||||
|
// Postman Request format does not have a response property
|
||||||
|
const remoteResponses = remoteRequests.find(remoteRequest => remoteRequest.id === localRequest.id).response
|
||||||
|
const localResponses = localRequest.response
|
||||||
|
// the request may not have responses
|
||||||
|
if (!localResponses) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const newResponses = localResponses.filter(localResponse => !remoteResponses.find(remoteResponse => remoteResponse.id === localResponse.id))
|
||||||
|
const oldResponses = remoteResponses.filter(remoteResponse => !localResponses.find(localResponse => localResponse.id === remoteResponse.id))
|
||||||
|
|
||||||
|
const ResponsesInReqquestHaveChanges = newResponses.length > 0 || oldResponses.length > 0
|
||||||
|
if (!ResponsesInReqquestHaveChanges) {
|
||||||
|
console.log(' In Request: ', localRequest.name, '-> No changes')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
console.log(' In Request: ', localRequest.name)
|
||||||
|
|
||||||
|
// create new responses
|
||||||
|
for (const response of newResponses) {
|
||||||
|
const pmResponse = pmConvert.responseFromLocal(response)
|
||||||
|
const msg = ` Creating new response [${response.code} ${response.status}]`
|
||||||
|
await new pmAPI.Response(remoteCollection.collection.info.uid)
|
||||||
|
.create(pmResponse, localRequest.id)
|
||||||
|
.then(() => {
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete old responses
|
||||||
|
for (const response of oldResponses) {
|
||||||
|
const msg = ` Deleting old response [${response.code} ${response.status}]`
|
||||||
|
await new pmAPI.Response(remoteCollection.collection.info.uid)
|
||||||
|
.delete(response.id)
|
||||||
|
.then(() => {
|
||||||
|
console.log(msg, '-> OK')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// updating the requests with the order of the responses, doesn't seem to be necessary
|
||||||
|
if (ResponsesInReqquestHaveChanges) {
|
||||||
|
// sort responses in requests
|
||||||
|
const responsesOrder = localResponses.map(response => response.id)
|
||||||
|
const msg = ` Sorting responses in request [${localRequest.name}]`
|
||||||
|
await new pmAPI.Request(remoteCollection.collection.info._postman_id)
|
||||||
|
.update(localRequest.id,
|
||||||
|
{
|
||||||
|
responses_order: responsesOrder
|
||||||
|
})
|
||||||
|
.then(() => { console.log(msg, '-> OK') })
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
anyResponseHasChanged = anyResponseHasChanged || ResponsesInReqquestHaveChanges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anyResponseHasChanged
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshRemoteCollection (remoteCollectionID) {
|
||||||
|
const msg = 'Refreshing remote collection'
|
||||||
|
console.log('\n' + msg + '...\n')
|
||||||
|
const remoteCollection = await new pmAPI.Collection(remoteCollectionID).get()
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
return remoteCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
// return all folders in the collection
|
||||||
|
// independently of where they are
|
||||||
|
const getAllFoldersFromCollectionItem = (collectionItem) => {
|
||||||
|
const folders = []
|
||||||
|
const processItem = (item) => {
|
||||||
|
if (!item.request && !item.responses) {
|
||||||
|
folders.push({ id: item.id, name: item.name, item: item.item })
|
||||||
|
}
|
||||||
|
if (item.item) {
|
||||||
|
item.item.forEach(processItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectionItem.forEach(processItem)
|
||||||
|
return folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle axios error
|
||||||
|
const handlePostmanAPIError = (error) => {
|
||||||
|
if (error.response) {
|
||||||
|
// The request was made and the server responded with a status code
|
||||||
|
// that falls out of the range of 2xx
|
||||||
|
console.log('API ERROR:', error.response.data)
|
||||||
|
} else {
|
||||||
|
// The request was made but no response was received
|
||||||
|
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||||
|
// http.ClientRequest in node.js
|
||||||
|
console.log('NO RESPONSE:', error.message)
|
||||||
|
if (error.cause) {
|
||||||
|
console.log('CAUSE:', error.cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { method, url, data } = error.config
|
||||||
|
const smallData = data.substring(0, 1000)
|
||||||
|
console.log('REQUEST DETAILS', { method, url, smallData })
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateHash = (stringToHash) => {
|
||||||
|
return crypto.createHash('sha256').update(stringToHash).digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
deployIncremental
|
||||||
|
}
|
||||||
143
postman-script/partialUpdate/PostmanCovertions.js
Normal file
143
postman-script/partialUpdate/PostmanCovertions.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// Postman Convertions
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Handles the conversions from the local generated object
|
||||||
|
// to the postman api specific objects.
|
||||||
|
// The converted objects are necessary for the updates to work.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// The interesting part is that the postman api uses a different
|
||||||
|
// object structure for folders, requests, adn responses,
|
||||||
|
// when compared to what you get from the collection json file.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
|
const requestFromLocal = (localRequest) => {
|
||||||
|
// console.log('localRequest', localRequest)
|
||||||
|
let url = localRequest.request.url.protocol + '://' + localRequest.request.url.host + localRequest.request.url.path
|
||||||
|
|
||||||
|
let data = []
|
||||||
|
let dataMode = null
|
||||||
|
let rawModeData = null
|
||||||
|
if (localRequest.request.body && localRequest.request.body.urlencoded) {
|
||||||
|
data = dataFromLocalURLEncode(localRequest.request.body.urlencoded)
|
||||||
|
dataMode = localRequest.request.body.mode
|
||||||
|
rawModeData = localRequest.request.body.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryParams = []
|
||||||
|
if (localRequest.request.url.query) {
|
||||||
|
queryParams = dataFromLocalURLEncode(localRequest.request.url.query)
|
||||||
|
url += '?'
|
||||||
|
for (const param of queryParams) {
|
||||||
|
if (param.enabled === false) continue
|
||||||
|
url += param.key + '=' + param.value + '&'
|
||||||
|
}
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathVariableData = []
|
||||||
|
if (localRequest.request.url.variable) {
|
||||||
|
pathVariableData = dataFromLocalURLEncode(localRequest.request.url.variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
let headerData = []
|
||||||
|
if (localRequest.request.header) {
|
||||||
|
headerData = dataFromLocalURLEncode(localRequest.request.header)
|
||||||
|
.map((header) => ({ key: header.key, value: header.value, enabled: header.enabled, description: header.description }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
// owner: '8119550',
|
||||||
|
// lastUpdatedBy: '8119550',
|
||||||
|
// lastRevision: 32526900683,
|
||||||
|
// folder: 'dfa47710-b3d3-4a2c-bbc8-fbd25ad12244',
|
||||||
|
// collection: 'fa89c950-c947-4061-9d13-fb18d7c6bc51',
|
||||||
|
|
||||||
|
id: localRequest.id, //
|
||||||
|
name: localRequest.name, //
|
||||||
|
|
||||||
|
dataMode, //
|
||||||
|
data, //
|
||||||
|
auth: localRequest.request.auth, //
|
||||||
|
events: localRequest.events, //
|
||||||
|
//
|
||||||
|
rawModeData, // body os request
|
||||||
|
//
|
||||||
|
descriptionFormat: localRequest.descriptionFormat, // it can be in either ``html`` or ``markdown`` formats.
|
||||||
|
description: localRequest.request.description, //
|
||||||
|
// Headers
|
||||||
|
headers: null,
|
||||||
|
headerData,
|
||||||
|
//
|
||||||
|
variables: localRequest.variables,
|
||||||
|
method: localRequest.request.method, //
|
||||||
|
|
||||||
|
// Path Variables
|
||||||
|
pathVariables: pathVariableData, //
|
||||||
|
pathVariableData, //
|
||||||
|
//
|
||||||
|
url, //
|
||||||
|
preRequestScript: localRequest.preRequestScript,
|
||||||
|
tests: localRequest.tests,
|
||||||
|
currentHelper: localRequest.currentHelper,
|
||||||
|
helperAttributes: localRequest.helperAttributes,
|
||||||
|
queryParams, //
|
||||||
|
|
||||||
|
protocolProfileBehavior: localRequest.protocolProfileBehavior,
|
||||||
|
dataDisabled: localRequest.dataDisabled,
|
||||||
|
responses_order: localRequest.responses_order
|
||||||
|
|
||||||
|
// createdAt: '2023-09-12T16:25:20.000Z',
|
||||||
|
// updatedAt: '2023-09-12T16:25:23.000Z',
|
||||||
|
// dataOptions: {{"raw":{}}},
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseFromLocal = (localResponse) => {
|
||||||
|
const headers = localResponse.header.map((item) => ({ key: item.key, value: item.value }))
|
||||||
|
const response = {
|
||||||
|
// owner: '8119550',
|
||||||
|
// lastUpdatedBy: '8119550',
|
||||||
|
// lastRevision: 32546597265,
|
||||||
|
// request: '331bbc94-5425-46f3-8c02-31c353d2ced8',
|
||||||
|
|
||||||
|
id: localResponse.id, //
|
||||||
|
name: localResponse.name, //
|
||||||
|
status: localResponse.status, //
|
||||||
|
responseCode: {
|
||||||
|
code: localResponse.code, //
|
||||||
|
name: localResponse.status, //
|
||||||
|
detail: ''
|
||||||
|
},
|
||||||
|
// time: null,
|
||||||
|
headers, //
|
||||||
|
cookies: [],
|
||||||
|
mime: null,
|
||||||
|
text: localResponse.body, //
|
||||||
|
language: 'Text', //
|
||||||
|
rawDataType: 'text'//
|
||||||
|
// requestObject: null,
|
||||||
|
// createdAt: '2023-09-13T14:53:05.000Z',
|
||||||
|
// updatedAt: '2023-09-13T14:53:05.000Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataFromLocalURLEncode = (localFormData) => {
|
||||||
|
const data = []
|
||||||
|
for (const param of localFormData) {
|
||||||
|
const item = {
|
||||||
|
key: param.key,
|
||||||
|
description: param.description,
|
||||||
|
value: param.value,
|
||||||
|
enabled: !param.disabled
|
||||||
|
}
|
||||||
|
data.push(item)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
requestFromLocal,
|
||||||
|
responseFromLocal
|
||||||
|
}
|
||||||
37
postman-script/partialUpdate/Utils.js
Normal file
37
postman-script/partialUpdate/Utils.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const uuid = require('uuid')
|
||||||
|
const NAMESPACE = '33c4e6fc-44cb-4190-b19f-4a02821bc8c3'
|
||||||
|
|
||||||
|
const genID = (objectJSON = null) => {
|
||||||
|
if (objectJSON) {
|
||||||
|
return uuid.v5(objectJSON, NAMESPACE)
|
||||||
|
} else {
|
||||||
|
return uuid.v4()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort 2 objects by name
|
||||||
|
const byName = (a, b) => {
|
||||||
|
if (a.name < b.name) {
|
||||||
|
return -1
|
||||||
|
} else if (a.name > b.name) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort two object by priority
|
||||||
|
const byPriority = (a, b) => {
|
||||||
|
if (a['x-box-priority']) {
|
||||||
|
return -1
|
||||||
|
} else if (b['x-box-priority']) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
GenID: genID,
|
||||||
|
ByName: byName,
|
||||||
|
ByPriority: byPriority
|
||||||
|
// logAxiosError
|
||||||
|
}
|
||||||
11
postman-script/partialUpdate/index.js
Normal file
11
postman-script/partialUpdate/index.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const { deployIncremental } = require('./DeployIncremental')
|
||||||
|
|
||||||
|
const release = async () => {
|
||||||
|
let privateRemoteCollectionId = '23836355-c5640083-7523-4ad7-9f92-b23e079cbb7b'
|
||||||
|
let publicRemoteCollectionId = '23836355-6224d51a-d924-4c39-a58f-6970735aac8e'
|
||||||
|
let localCollection = JSON.parse(fs.readFileSync(`C:\\git\\api-specs\\postman\\collections\\sailpoint-api-v3.json`).toString())
|
||||||
|
await deployIncremental(privateRemoteCollectionId, localCollection, publicRemoteCollectionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
release()
|
||||||
131
postman-script/partialUpdate/package-lock.json
generated
Normal file
131
postman-script/partialUpdate/package-lock.json
generated
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||||
|
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.4",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "16.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
|
||||||
|
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
postman-script/partialUpdate/package.json
Normal file
16
postman-script/partialUpdate/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "partial updates to postman files",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
236
postman-script/partialUpdate/postmanAPI.js
Normal file
236
postman-script/partialUpdate/postmanAPI.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
require('dotenv').config()
|
||||||
|
const axios = require('axios')
|
||||||
|
|
||||||
|
class Collection {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 60, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get () {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}`
|
||||||
|
, { timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting collection ${this.collectionId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async merge (destinationCollectionId, strategy = 'updateSourceWithDestination') {
|
||||||
|
return await this.axios.post(
|
||||||
|
'https://api.getpostman.com/collections/merge',
|
||||||
|
{ source: this.collectionId, destination: destinationCollectionId, strategy },
|
||||||
|
{ timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error merging collection from ${this.collectionId} to ${destinationCollectionId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (collection) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}`,
|
||||||
|
collection,
|
||||||
|
{ timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating collection ${collection.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Folder {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 60, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (folderId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting folder ${folderId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (folder) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders`,
|
||||||
|
folder
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error creating folder ${folder.Id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (folderId, folder) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`,
|
||||||
|
folder
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating folder ${folder.Id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (folderId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`
|
||||||
|
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error deleting folder ${folderId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Folder
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 60, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (requestId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting request ${requestId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (request, folderId) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests`,
|
||||||
|
request,
|
||||||
|
{ params: { folder: folderId } }
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error creating request ${request.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (requestId, request) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`,
|
||||||
|
request
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating request ${request.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (requestId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`
|
||||||
|
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error deleting request ${requestId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Request
|
||||||
|
|
||||||
|
class Response {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 60, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (responseId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses/${responseId}`
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error getting response ${responseId}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (response, requestId) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses`,
|
||||||
|
response,
|
||||||
|
{ params: { request: requestId } }
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error creating response ${response.id}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (responseId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses/${responseId}`
|
||||||
|
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error deleting response ${responseId}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Response
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Collection,
|
||||||
|
Folder,
|
||||||
|
Request,
|
||||||
|
Response
|
||||||
|
}
|
||||||
2
postman-script/updateByFolder/.gitignore
vendored
Normal file
2
postman-script/updateByFolder/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
node_modules
|
||||||
147
postman-script/updateByFolder/PostmanCovertions.js
Normal file
147
postman-script/updateByFolder/PostmanCovertions.js
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// Postman Convertions
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Handles the conversions from the local generated object
|
||||||
|
// to the postman api specific objects.
|
||||||
|
// The converted objects are necessary for the updates to work.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// The interesting part is that the postman api uses a different
|
||||||
|
// object structure for folders, requests, adn responses,
|
||||||
|
// when compared to what you get from the collection json file.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
const requestFromLocal = (localRequest) => {
|
||||||
|
// console.log('localRequest', localRequest)
|
||||||
|
let url = localRequest.request.url.host + '/' + localRequest.request.url.path
|
||||||
|
|
||||||
|
let data = []
|
||||||
|
let dataMode = null
|
||||||
|
let rawModeData = null
|
||||||
|
if (localRequest.request.body && localRequest.request.body.urlencoded) {
|
||||||
|
data = dataFromLocalURLEncode(localRequest.request.body.urlencoded)
|
||||||
|
dataMode = localRequest.request.body.mode
|
||||||
|
rawModeData = localRequest.request.body.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryParams = []
|
||||||
|
if (localRequest.request.url.query) {
|
||||||
|
queryParams = dataFromLocalURLEncode(localRequest.request.url.query)
|
||||||
|
url += '?'
|
||||||
|
for (const param of queryParams) {
|
||||||
|
if (param.description.content) {
|
||||||
|
param.description = param.description.content
|
||||||
|
}
|
||||||
|
if (param.enabled === false) continue
|
||||||
|
url += param.key + '=' + param.value + '&'
|
||||||
|
}
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathVariableData = []
|
||||||
|
if (localRequest.request.url.variable) {
|
||||||
|
pathVariableData = dataFromLocalURLEncode(localRequest.request.url.variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
let headerData = []
|
||||||
|
if (localRequest.request.header) {
|
||||||
|
headerData = dataFromLocalURLEncode(localRequest.request.header)
|
||||||
|
.map((header) => ({ key: header.key, value: header.value, enabled: header.enabled, description: header.description }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
// owner: '8119550',
|
||||||
|
// lastUpdatedBy: '8119550',
|
||||||
|
// lastRevision: 32526900683,
|
||||||
|
// folder: 'dfa47710-b3d3-4a2c-bbc8-fbd25ad12244',
|
||||||
|
// collection: 'fa89c950-c947-4061-9d13-fb18d7c6bc51',
|
||||||
|
|
||||||
|
id: localRequest.id, //
|
||||||
|
name: localRequest.name, //
|
||||||
|
|
||||||
|
dataMode, //
|
||||||
|
data, //
|
||||||
|
auth: localRequest.request.auth, //
|
||||||
|
events: localRequest.events, //
|
||||||
|
//
|
||||||
|
rawModeData, // body os request
|
||||||
|
//
|
||||||
|
descriptionFormat: localRequest.descriptionFormat, // it can be in either ``html`` or ``markdown`` formats.
|
||||||
|
description: localRequest.request.description.content ? localRequest.request.description.content : localRequest.request.description, //
|
||||||
|
// Headers
|
||||||
|
headers: localRequest.request.header,
|
||||||
|
headerData,
|
||||||
|
//
|
||||||
|
variables: localRequest.variables,
|
||||||
|
method: localRequest.request.method, //
|
||||||
|
|
||||||
|
// Path Variables
|
||||||
|
pathVariables: pathVariableData, //
|
||||||
|
pathVariableData, //
|
||||||
|
//
|
||||||
|
url, //
|
||||||
|
preRequestScript: localRequest.preRequestScript,
|
||||||
|
tests: localRequest.tests,
|
||||||
|
currentHelper: localRequest.currentHelper,
|
||||||
|
helperAttributes: localRequest.helperAttributes,
|
||||||
|
queryParams, //
|
||||||
|
|
||||||
|
protocolProfileBehavior: localRequest.protocolProfileBehavior,
|
||||||
|
dataDisabled: localRequest.dataDisabled,
|
||||||
|
responses_order: localRequest.responses_order
|
||||||
|
|
||||||
|
// createdAt: '2023-09-12T16:25:20.000Z',
|
||||||
|
// updatedAt: '2023-09-12T16:25:23.000Z',
|
||||||
|
// dataOptions: {{"raw":{}}},
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseFromLocal = (localResponse, requestObject) => {
|
||||||
|
const headers = localResponse.header.map((item) => ({ key: item.key, value: item.value }))
|
||||||
|
const response = {
|
||||||
|
// owner: '8119550',
|
||||||
|
// lastUpdatedBy: '8119550',
|
||||||
|
// lastRevision: 32546597265,
|
||||||
|
// request: '331bbc94-5425-46f3-8c02-31c353d2ced8',
|
||||||
|
|
||||||
|
id: localResponse.id, //
|
||||||
|
name: localResponse.name, //
|
||||||
|
status: localResponse.status, //
|
||||||
|
responseCode: {
|
||||||
|
code: localResponse.code, //
|
||||||
|
name: localResponse.status, //
|
||||||
|
detail: ''
|
||||||
|
},
|
||||||
|
// time: null,
|
||||||
|
headers, //
|
||||||
|
cookies: [],
|
||||||
|
mime: null,
|
||||||
|
text: localResponse.body, //
|
||||||
|
language: 'json', //
|
||||||
|
rawDataType: 'text',//
|
||||||
|
requestObject: requestObject,
|
||||||
|
// createdAt: '2023-09-13T14:53:05.000Z',
|
||||||
|
// updatedAt: '2023-09-13T14:53:05.000Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataFromLocalURLEncode = (localFormData) => {
|
||||||
|
const data = []
|
||||||
|
for (const param of localFormData) {
|
||||||
|
const item = {
|
||||||
|
key: param.key,
|
||||||
|
description: param.description,
|
||||||
|
value: param.value,
|
||||||
|
enabled: !param.disabled
|
||||||
|
}
|
||||||
|
data.push(item)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
requestFromLocal,
|
||||||
|
responseFromLocal
|
||||||
|
}
|
||||||
57
postman-script/updateByFolder/index.js
Normal file
57
postman-script/updateByFolder/index.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const pmConvert = require('./PostmanCovertions')
|
||||||
|
const pmAPI = require('./postmanAPI')
|
||||||
|
let privateRemoteCollectionId = '23836355-c5640083-7523-4ad7-9f92-b23e079cbb7b'
|
||||||
|
let publicRemoteCollectionId = '23836355-6224d51a-d924-4c39-a58f-6970735aac8e'
|
||||||
|
let localCollection = JSON.parse(fs.readFileSync(`C:\\git\\api-specs\\postman\\collections\\sailpoint-api-v3.json`).toString())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const release = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
let remoteCollection = await refreshRemoteCollection(publicRemoteCollectionId)
|
||||||
|
for (let item of remoteCollection.collection.item) {
|
||||||
|
new pmAPI.Folder(publicRemoteCollectionId).delete(item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let item of localCollection.item) {
|
||||||
|
await updateItem(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(remoteCollection)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function updateItem(item, folderId) {
|
||||||
|
if (item.item && !folderId) {
|
||||||
|
let newFolder = await new pmAPI.Folder(publicRemoteCollectionId).create(item)
|
||||||
|
await updateItem(item.item, newFolder.data.id)
|
||||||
|
} else {
|
||||||
|
for (let items of item) {
|
||||||
|
let postmanRequestBody = pmConvert.requestFromLocal(items)
|
||||||
|
let newRequest = await new pmAPI.Request(publicRemoteCollectionId).create(postmanRequestBody, folderId)
|
||||||
|
for (let response of items.response) {
|
||||||
|
let postmanResponseBody = pmConvert.responseFromLocal(response, {})
|
||||||
|
let newResponse = await new pmAPI.Response(publicRemoteCollectionId).create(postmanResponseBody, newRequest.data.id)
|
||||||
|
console.log(newResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshRemoteCollection (remoteCollectionID) {
|
||||||
|
const msg = 'Refreshing remote collection'
|
||||||
|
console.log('\n' + msg + '...\n')
|
||||||
|
const remoteCollection = await new pmAPI.Collection(remoteCollectionID).get()
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(msg, '-> FAIL')
|
||||||
|
handlePostmanAPIError(error)
|
||||||
|
})
|
||||||
|
return remoteCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
release()
|
||||||
154
postman-script/updateByFolder/package-lock.json
generated
Normal file
154
postman-script/updateByFolder/package-lock.json
generated
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"axios-retry": "^4.0.0",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||||
|
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.4",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/axios-retry": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-F6P4HVGITD/v4z9Lw2mIA24IabTajvpDZmKa6zq/gGwn57wN5j1P3uWrAV0+diqnW6kTM2fTqmWNfgYWGmMuiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-retry-allowed": "^2.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"axios": "0.x || 1.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "16.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
|
||||||
|
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-retry-allowed": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
postman-script/updateByFolder/package.json
Normal file
17
postman-script/updateByFolder/package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "partialupdate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "partial updates to postman files",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"axios-retry": "^4.0.0",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
241
postman-script/updateByFolder/postmanAPI.js
Normal file
241
postman-script/updateByFolder/postmanAPI.js
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
require('dotenv').config()
|
||||||
|
const axiosRetry = require('axios-retry').default
|
||||||
|
const axios = require('axios')
|
||||||
|
|
||||||
|
class Collection {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 5, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
axiosRetry(this.axios, {retries: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get () {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}`
|
||||||
|
, { timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting collection ${this.collectionId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async merge (destinationCollectionId, strategy = 'updateSourceWithDestination') {
|
||||||
|
return await this.axios.post(
|
||||||
|
'https://api.getpostman.com/collections/merge',
|
||||||
|
{ source: this.collectionId, destination: destinationCollectionId, strategy },
|
||||||
|
{ timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error merging collection from ${this.collectionId} to ${destinationCollectionId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (collection) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}`,
|
||||||
|
collection,
|
||||||
|
{ timeout: 1000 * 60 * 5 } // 5 minutes
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating collection ${collection.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Folder {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 5, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
axiosRetry(this.axios, {retries: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (folderId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting folder ${folderId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (folder) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders`,
|
||||||
|
folder
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error creating folder ${folder.Id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (folderId, folder) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`,
|
||||||
|
folder
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating folder ${folder.Id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (folderId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/folders/${folderId}`
|
||||||
|
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error deleting folder ${folderId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Folder
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 5, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
axiosRetry(this.axios, {retries: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (requestId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error getting request ${requestId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (request, folderId) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests`,
|
||||||
|
request,
|
||||||
|
{ params: { folder: folderId } }
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error creating request ${request.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async update (requestId, request) {
|
||||||
|
return await this.axios.put(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`,
|
||||||
|
request
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error updating request ${request.id}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (requestId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/requests/${requestId}`
|
||||||
|
|
||||||
|
).then(function (response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error(`Error deleting request ${requestId}: ${response.status} ${response.statusText}`)
|
||||||
|
} else {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Request
|
||||||
|
|
||||||
|
class Response {
|
||||||
|
constructor (collectionId) {
|
||||||
|
this.collectionId = collectionId
|
||||||
|
this.apiKey = process.env.POSTMAN_API_KEY
|
||||||
|
this.axios = axios.create({
|
||||||
|
timeout: 1000 * 5, // 60 seconds
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-Api-Key': this.apiKey }
|
||||||
|
})
|
||||||
|
axiosRetry(this.axios, {retries: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (responseId) {
|
||||||
|
return await this.axios.get(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses/${responseId}`
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error getting response ${responseId}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async create (response, requestId) {
|
||||||
|
return await this.axios.post(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses`,
|
||||||
|
response,
|
||||||
|
{ params: { request: requestId } }
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error creating response ${response.id}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete (responseId) {
|
||||||
|
return await this.axios.delete(
|
||||||
|
`https://api.getpostman.com/collections/${this.collectionId}/responses/${responseId}`
|
||||||
|
|
||||||
|
).then(function (axiosResp) {
|
||||||
|
if (axiosResp.status !== 200) {
|
||||||
|
throw new Error(`Error deleting response ${responseId}: ${axiosResp.status} ${axiosResp.statusText}`)
|
||||||
|
} else {
|
||||||
|
return axiosResp.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // class Response
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Collection,
|
||||||
|
Folder,
|
||||||
|
Request,
|
||||||
|
Response
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user