@@ -2,76 +2,71 @@ import * as fs from 'fs'
22import { glob } from 'glob'
33import * as path from 'path'
44import { z } from 'zod'
5- import { IntegrationsAPI , VariableGroupConfig } from './lib/generated'
6- import HCL from './lib/hcl'
7- import {
8- Component ,
9- Integration ,
10- Variable ,
11- VariableGroup ,
12- } from './schemas/integration'
13- import MetadataHCLSchema from './schemas/metadata.hcl'
14- import { getVariablesSchema } from './schemas/variables.hcl'
5+ import { IntegrationsAPI } from './lib/generated'
6+ import { Integration } from './schemas/integration'
7+ import { loadDefaultIntegrationDirectory } from './strategies/default/load_default_directory'
8+ import { loadNomadPackIntegrationDirectory } from './strategies/nomad-pack/load_pack_directory'
159
1610const Config = z . object ( {
1711 identifier : z . string ( ) ,
1812 repo_path : z . string ( ) ,
1913 version : z . string ( ) ,
14+ strategy : z . enum ( [ 'default' , 'nomad-pack' ] ) . default ( 'default' ) . optional ( ) ,
2015} )
2116type Config = z . infer < typeof Config >
2217
2318export default async function LoadFilesystemIntegration (
2419 config : Config
2520) : Promise < Integration > {
26- // Create the API client
27- const client = new IntegrationsAPI ( {
21+ // Create an API client instance
22+ const apiClient = new IntegrationsAPI ( {
2823 BASE : process . env . INPUT_INTEGRATIONS_API_BASE_URL ,
2924 } )
3025
31- // Fetch the Integration from the API that we're looking to update
26+ // Parse & Validate the Integration Identifier
3227 const [ productSlug , organizationSlug , integrationSlug ] =
3328 config . identifier . split ( '/' )
34-
35- // Throw if the identifier is invalid
3629 if ( ! productSlug || ! organizationSlug || ! integrationSlug ) {
30+ // Throw if the identifier is invalid
3731 throw new Error (
3832 `Invalid integration identifier: '${ config . identifier } '.` +
3933 ` The expected format is 'productSlug/organizationSlug/integrationSlug'`
4034 )
4135 }
4236
43- const organization = await client . organizations . fetchOrganization (
37+ // Validate the Organization as specified in the identifier exists
38+ const organization = await apiClient . organizations . fetchOrganization (
4439 organizationSlug
4540 )
46-
4741 if ( organization . meta . status_code != 200 ) {
4842 throw new Error (
4943 `Organization not found for integration identifier: '${ config . identifier } '`
5044 )
5145 }
5246
53- const integrationFetchResult = await client . integrations . fetchIntegration (
47+ // Fetch the Integration from the API. We need to ensure that it exists,
48+ // and therefore has already been registered.
49+ const integrationFetchResult = await apiClient . integrations . fetchIntegration (
5450 productSlug ,
5551 organization . result . id ,
5652 integrationSlug
5753 )
58-
5954 if ( integrationFetchResult . meta . status_code !== 200 ) {
6055 throw new Error (
6156 `Integration not found for integration identifier: '${ config . identifier } '`
6257 )
6358 }
64-
6559 const apiIntegration = integrationFetchResult . result
6660
67- // Parse out & validate the metadata.hcl file
68- const repoRootDirectory = path . join (
61+ // Determine the location of the Integration & validate that it has a metadata.hcl file
62+ const integrationDirectory = path . join (
6963 config . repo_path ,
7064 apiIntegration . subdirectory || ''
7165 )
72- const metadataFilePath = path . join ( repoRootDirectory , 'metadata.hcl' )
66+ const metadataFilePath = path . join ( integrationDirectory , 'metadata.hcl' )
7367
74- // Throw if the metadata.hcl file doesn't exist
68+ // Throw if the metadata.hcl file doesn't exist. We don't validate it at
69+ // this point beyond checking that it exists.
7570 if ( ! fs . existsSync ( metadataFilePath ) ) {
7671 const matches = await glob ( '**/metadata.hcl' , { cwd : config . repo_path } )
7772 // If no metadata.hcl files were found, throw a helpful error
@@ -100,152 +95,39 @@ export default async function LoadFilesystemIntegration(
10095 }
10196 }
10297
103- // @todo (kevinwang):
104- // Maybe lift file content reading into HCL class and throw a more helpful error message
105- const fileContent = fs . readFileSync ( metadataFilePath , 'utf8' )
106- const hclConfig = new HCL ( fileContent , MetadataHCLSchema )
107- // throw a verbose error message with the filepath and contents
108- if ( ! hclConfig . result . data ) {
109- throw new Error (
110- hclConfig . result . error . message +
111- '\n' +
112- 'File: ' +
113- metadataFilePath +
114- '\n' +
115- fileContent
116- )
117- }
118-
119- const hclIntegration = hclConfig . result . data . integration [ 0 ]
120-
121- // Read the README
122- let readmeContent : string | null = null
123- if ( hclIntegration . docs [ 0 ] . process_docs ) {
124- const readmeFile = path . join (
125- repoRootDirectory ,
126- hclIntegration . docs [ 0 ] . readme_location
127- )
128-
129- // Throw if the README file doesn't exist
130- if ( ! fs . existsSync ( readmeFile ) ) {
131- throw new Error (
132- `The README file, ${ readmeFile } , was derived from config values and integration data, but it does not exist.` +
133- ` ` +
134- `Please double check the "readme_location" value in ${ metadataFilePath } , and try again.`
135- )
136- }
137- readmeContent = fs . readFileSync ( readmeFile , 'utf8' )
138- }
139-
140- // Load the Products VariableGroupConfigs so we can load any component variables
98+ // Load the Integration's product VariableGroupConfigs. This is information
99+ // that we need to parse out the Integration from the Filesystem.
141100 const variableGroupConfigs =
142- await client . variableGroupConfigs . fetchVariableGroupConfigs (
101+ await apiClient . variableGroupConfigs . fetchVariableGroupConfigs (
143102 apiIntegration . product . slug ,
144103 '100'
145104 )
146-
147105 if ( variableGroupConfigs . meta . status_code !== 200 ) {
148106 throw new Error (
149107 `Failed to load 'variable_group' configs for product: '${ apiIntegration . product . slug } '`
150108 )
151109 }
152110
153- // Calculate each Component object
154- const allComponents : Array < Component > = [ ]
155- for ( let i = 0 ; i < hclIntegration . component . length ; i ++ ) {
156- allComponents . push (
157- await loadComponent (
158- repoRootDirectory ,
159- hclIntegration . component [ i ] . type ,
160- hclIntegration . component [ i ] . name ,
161- hclIntegration . component [ i ] . slug ,
162- variableGroupConfigs . result
111+ // Depending on the Strategy that is specified, we read the filesystem and coerce the
112+ // configuration to a standardized Integrations object.
113+ switch ( config . strategy ) {
114+ case 'nomad-pack' : {
115+ return loadNomadPackIntegrationDirectory (
116+ integrationDirectory ,
117+ apiIntegration . id ,
118+ apiIntegration . product . slug ,
119+ config . version
163120 )
164- )
165- }
166-
167- // Return Integration with all defaults set
168- return {
169- id : apiIntegration . id ,
170- product : apiIntegration . product . slug ,
171- identifier : hclIntegration . identifier ,
172- name : hclIntegration . name ,
173- description : hclIntegration . description ,
174- current_release : {
175- version : config . version ,
176- readme : readmeContent ,
177- components : allComponents ,
178- } ,
179- flags : hclIntegration . flags ,
180- docs : hclIntegration . docs [ 0 ] ,
181- hide_versions : hclIntegration . hide_versions ,
182- license : hclIntegration . license [ 0 ] ,
183- integration_type : hclIntegration . integration_type ,
184- }
185- }
186-
187- async function loadComponent (
188- repoRootDirectory : string ,
189- componentType : string ,
190- componentName : string ,
191- componentSlug : string ,
192- variableGroupConfigs : Array < VariableGroupConfig >
193- ) : Promise < Component > {
194- // Calculate the location of the folder where the README / variables, etc reside
195- const componentFolder = `${ repoRootDirectory } /components/${ componentType } /${ componentSlug } `
196-
197- // Load the README if it exists
198- const componentReadmeFile = `${ componentFolder } /README.md`
199- let readmeContent : string | null = null
200- try {
201- readmeContent = fs . readFileSync ( componentReadmeFile , 'utf8' )
202- } catch ( err ) {
203- // No issue, there's just no README, which is OK!
204- }
205-
206- // Go through each VariableGroupConfig to try see if we need to load them
207- const variableGroups : Array < VariableGroup > = [ ]
121+ }
208122
209- for ( let i = 0 ; i < variableGroupConfigs . length ; i ++ ) {
210- const variableGroupConfig = variableGroupConfigs [ i ]
211- const variableGroupFile = `${ componentFolder } /${ variableGroupConfig . filename } `
212- if ( fs . existsSync ( variableGroupFile ) ) {
213- // Load & Validate the Variable Files (parameters.hcl, outputs.hcl, etc.)
214- const fileContent = fs . readFileSync ( variableGroupFile , 'utf8' )
215- const hclConfig = new HCL (
216- fileContent ,
217- getVariablesSchema ( variableGroupConfig . stanza )
123+ default : {
124+ return loadDefaultIntegrationDirectory (
125+ integrationDirectory ,
126+ apiIntegration . id ,
127+ apiIntegration . product . slug ,
128+ config . version ,
129+ variableGroupConfigs . result
218130 )
219- if ( ! hclConfig . result . data ) {
220- throw new Error ( hclConfig . result . error . message )
221- }
222-
223- // Map the HCL File variable configuration to the Variable defaults
224- const variables : Array < Variable > = hclConfig . result . data [
225- variableGroupConfig . stanza
226- ] . map ( ( v ) => {
227- return {
228- key : v . key ,
229- description : v . description ? v . description : null ,
230- type : v . type ? v . type : null ,
231- required : typeof v . required != 'undefined' ? v . required : null ,
232- default_value : v . default_value ? v . default_value : null ,
233- }
234- } )
235- variableGroups . push ( {
236- variable_group_config_id : variableGroupConfig . id ,
237- variables,
238- } )
239- } else {
240- console . warn ( `Variable Group File '${ variableGroupFile } ' not found.` )
241131 }
242132 }
243-
244- return {
245- type : componentType ,
246- name : componentName ,
247- slug : componentSlug ,
248- readme : readmeContent ,
249- variable_groups : variableGroups ,
250- }
251133}
0 commit comments