mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-16 16:40:06 +00:00
feat(job-execution): support absolute paths to SAS jobs
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
|||||||
parseAndSubmitAuthorizeForm,
|
parseAndSubmitAuthorizeForm,
|
||||||
convertToCSV,
|
convertToCSV,
|
||||||
makeRequest,
|
makeRequest,
|
||||||
|
isRelativePath,
|
||||||
isUri,
|
isUri,
|
||||||
isUrl
|
isUrl
|
||||||
} from './utils'
|
} from './utils'
|
||||||
@@ -32,10 +33,6 @@ export class SASViyaApiClient {
|
|||||||
private setCsrfToken: (csrfToken: CsrfToken) => void,
|
private setCsrfToken: (csrfToken: CsrfToken) => void,
|
||||||
private rootFolderMap = new Map<string, Job[]>()
|
private rootFolderMap = new Map<string, Job[]>()
|
||||||
) {
|
) {
|
||||||
if (!rootFolderName) {
|
|
||||||
throw new Error('Root folder must be provided.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverUrl) isUrl(serverUrl)
|
if (serverUrl) isUrl(serverUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +44,7 @@ export class SASViyaApiClient {
|
|||||||
this.setCsrfToken
|
this.setCsrfToken
|
||||||
)
|
)
|
||||||
private isForceDeploy: boolean = false
|
private isForceDeploy: boolean = false
|
||||||
|
private folderMap = new Map<string, Job[]>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a map containing the directory structure in the currently set root folder.
|
* Returns a map containing the directory structure in the currently set root folder.
|
||||||
@@ -192,7 +190,7 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { result: contexts } = await this.request<{ items: Context[] }>(
|
const { result: contexts } = await this.request<{ items: Context[] }>(
|
||||||
`${this.serverUrl}/compute/contexts`,
|
`${this.serverUrl}/compute/contexts?limit=10000`,
|
||||||
{ headers }
|
{ headers }
|
||||||
)
|
)
|
||||||
const executionContext =
|
const executionContext =
|
||||||
@@ -892,32 +890,56 @@ export class SASViyaApiClient {
|
|||||||
data?: any,
|
data?: any,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
if (!this.rootFolder) {
|
if (isRelativePath(sasJob) && !this.rootFolderName) {
|
||||||
await this.populateRootFolder(accessToken)
|
|
||||||
}
|
|
||||||
if (!this.rootFolder) {
|
|
||||||
console.error('Root folder was not found')
|
|
||||||
throw new Error('Root folder was not found')
|
|
||||||
}
|
|
||||||
if (!this.rootFolderMap.size) {
|
|
||||||
await this.populateRootFolderMap(accessToken)
|
|
||||||
}
|
|
||||||
if (!this.rootFolderMap.size) {
|
|
||||||
console.error(`The job ${sasJob} was not found in ${this.rootFolderName}`)
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The job ${sasJob} was not found in ${this.rootFolderName}`
|
'Relative paths cannot be used without specifying a root folder name'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isRelativePath(sasJob)) {
|
||||||
|
if (!this.rootFolder) {
|
||||||
|
await this.populateRootFolder(accessToken)
|
||||||
|
}
|
||||||
|
if (!this.rootFolder) {
|
||||||
|
console.error('Root folder was not found')
|
||||||
|
throw new Error('Root folder was not found')
|
||||||
|
}
|
||||||
|
if (!this.rootFolderMap.size) {
|
||||||
|
await this.populateRootFolderMap(accessToken)
|
||||||
|
}
|
||||||
|
if (!this.rootFolderMap.size) {
|
||||||
|
console.error(
|
||||||
|
`The job ${sasJob} was not found in ${this.rootFolderName}`
|
||||||
|
)
|
||||||
|
throw new Error(
|
||||||
|
`The job ${sasJob} was not found in ${this.rootFolderName}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const folderPathParts = sasJob.split('/')
|
||||||
|
folderPathParts.pop()
|
||||||
|
const folderPath = folderPathParts.join('/')
|
||||||
|
await this.populateFolderMap(folderPath, accessToken)
|
||||||
|
}
|
||||||
|
|
||||||
const headers: any = { 'Content-Type': 'application/json' }
|
const headers: any = { 'Content-Type': 'application/json' }
|
||||||
if (!!accessToken) {
|
if (!!accessToken) {
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const folderName = sasJob.split('/')[0]
|
let jobToExecute
|
||||||
const jobName = sasJob.split('/')[1]
|
if (isRelativePath(sasJob)) {
|
||||||
const jobFolder = this.rootFolderMap.get(folderName)
|
const folderName = sasJob.split('/')[0]
|
||||||
const jobToExecute = jobFolder?.find((item) => item.name === jobName)
|
const jobName = sasJob.split('/')[1]
|
||||||
|
const jobFolder = this.rootFolderMap.get(folderName)
|
||||||
|
jobToExecute = jobFolder?.find((item) => item.name === jobName)
|
||||||
|
} else {
|
||||||
|
const folderPathParts = sasJob.split('/')
|
||||||
|
const jobName = folderPathParts.pop()
|
||||||
|
const folderPath = folderPathParts.join('/')
|
||||||
|
const jobFolder = this.folderMap.get(folderPath)
|
||||||
|
jobToExecute = jobFolder?.find((item) => item.name === jobName)
|
||||||
|
}
|
||||||
|
|
||||||
if (!jobToExecute) {
|
if (!jobToExecute) {
|
||||||
throw new Error('Job was not found.')
|
throw new Error('Job was not found.')
|
||||||
@@ -1100,6 +1122,32 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async populateFolderMap(folderPath: string, accessToken?: string) {
|
||||||
|
const url = '/folders/folders/@item?path=' + folderPath
|
||||||
|
const requestInfo: any = {
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
if (accessToken) {
|
||||||
|
requestInfo.headers = { Authorization: `Bearer ${accessToken}` }
|
||||||
|
}
|
||||||
|
const { result: folder } = await this.request<Folder>(
|
||||||
|
`${this.serverUrl}${url}`,
|
||||||
|
requestInfo
|
||||||
|
)
|
||||||
|
if (!folder) {
|
||||||
|
throw new Error(
|
||||||
|
`The path ${folderPath} does not exist on ${this.serverUrl}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const { result: members } = await this.request<{ items: any[] }>(
|
||||||
|
`${this.serverUrl}/folders/folders/${folder.id}/members`,
|
||||||
|
requestInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
const itemsAtRoot = members.items
|
||||||
|
this.folderMap.set(folderPath, itemsAtRoot)
|
||||||
|
}
|
||||||
|
|
||||||
private async populateRootFolderMap(accessToken?: string) {
|
private async populateRootFolderMap(accessToken?: string) {
|
||||||
const allItems = new Map<string, Job[]>()
|
const allItems = new Map<string, Job[]>()
|
||||||
const url = '/folders/folders/@item?path=' + this.rootFolderName
|
const url = '/folders/folders/@item?path=' + this.rootFolderName
|
||||||
|
|||||||
@@ -515,8 +515,6 @@ export default class SASjs {
|
|||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
|
|
||||||
sasJob = sasJob.startsWith('/') ? sasJob.replace('/', '') : sasJob
|
|
||||||
|
|
||||||
if (config.serverType === ServerType.SASViya && config.contextName) {
|
if (config.serverType === ServerType.SASViya && config.contextName) {
|
||||||
if (config.useComputeApi) {
|
if (config.useComputeApi) {
|
||||||
requestResponse = await this.executeJobViaComputeApi(
|
requestResponse = await this.executeJobViaComputeApi(
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export class SessionManager {
|
|||||||
if (!this.currentContext) {
|
if (!this.currentContext) {
|
||||||
const { result: contexts } = await this.request<{
|
const { result: contexts } = await this.request<{
|
||||||
items: Context[]
|
items: Context[]
|
||||||
}>(`${this.serverUrl}/compute/contexts`, {
|
}>(`${this.serverUrl}/compute/contexts?limit=10000`, {
|
||||||
headers: this.getHeaders(accessToken)
|
headers: this.getHeaders(accessToken)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ export * from './convertToCsv'
|
|||||||
export * from './isAuthorizeFormRequired'
|
export * from './isAuthorizeFormRequired'
|
||||||
export * from './isLoginRequired'
|
export * from './isLoginRequired'
|
||||||
export * from './isLoginSuccess'
|
export * from './isLoginSuccess'
|
||||||
|
export * from './isRelativePath'
|
||||||
|
export * from './isUri'
|
||||||
|
export * from './isUrl'
|
||||||
export * from './makeRequest'
|
export * from './makeRequest'
|
||||||
export * from './needsRetry'
|
export * from './needsRetry'
|
||||||
export * from './parseAndSubmitAuthorizeForm'
|
export * from './parseAndSubmitAuthorizeForm'
|
||||||
@@ -13,5 +16,3 @@ export * from './parseSasViyaLog'
|
|||||||
export * from './serialize'
|
export * from './serialize'
|
||||||
export * from './splitChunks'
|
export * from './splitChunks'
|
||||||
export * from './parseWeboutResponse'
|
export * from './parseWeboutResponse'
|
||||||
export * from './isUri'
|
|
||||||
export * from './isUrl'
|
|
||||||
|
|||||||
2
src/utils/isRelativePath.ts
Normal file
2
src/utils/isRelativePath.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const isRelativePath = (uri: string): boolean =>
|
||||||
|
!!uri && !uri.startsWith('/')
|
||||||
Reference in New Issue
Block a user