44import { hooks } from "@feathersjs/hooks/lib" ;
55import {
66 Colors ,
7- FxError ,
8- Result ,
9- err ,
10- ok ,
11- PluginManifestSchema ,
127 DeclarativeCopilotCapabilityName ,
138 EmbeddedKnowledgeCapability ,
9+ err ,
1410 FunctionObject ,
11+ FxError ,
12+ ok ,
13+ PluginManifestSchema ,
14+ Result ,
15+ TeamsManifestV1D17 ,
16+ TeamsManifestV1D19 ,
17+ TeamsManifestV1D21 ,
18+ TeamsManifestV1D5 ,
1519} from "@microsoft/teamsfx-api" ;
1620import AdmZip from "adm-zip" ;
1721import fs from "fs-extra" ;
1822import * as path from "path" ;
19- import * as uuid from "uuid " ;
23+ import semver from "semver " ;
2024import { Service } from "typedi" ;
21- import { getLocalizedString } from "../../../common/localizeUtils" ;
25+ import * as uuid from "uuid" ;
26+ import { featureFlagManager , FeatureFlags } from "../../../common/featureFlags" ;
2227import { ErrorContextMW } from "../../../common/globalVars" ;
28+ import { getLocalizedString } from "../../../common/localizeUtils" ;
2329import { FileNotFoundError , InvalidActionInputError , JSONSyntaxError } from "../../../error/common" ;
30+ import { InvalidFileOutsideOfTheDirectotryError } from "../../../error/teamsApp" ;
31+ import { getAbsolutePath } from "../../utils/common" ;
32+ import { expandVariableWithFunction , ManifestType } from "../../utils/envFunctionUtils" ;
2433import { DriverContext } from "../interface/commonArgs" ;
2534import { ExecutionResult , StepDriver } from "../interface/stepDriver" ;
2635import { addStartAndEndTelemetry } from "../middleware/addStartAndEndTelemetry" ;
36+ import { updateVersionForTeamsAppYamlFile } from "../util/utils" ;
2737import { WrapDriverContext } from "../util/wrapUtil" ;
2838import { Constants } from "./constants" ;
2939import { CreateAppPackageArgs } from "./interfaces/CreateAppPackageArgs" ;
40+ import { copilotGptManifestUtils } from "./utils/CopilotGptManifestUtils" ;
3041import { manifestUtils } from "./utils/ManifestUtils" ;
31- import { InvalidFileOutsideOfTheDirectotryError } from "../../../error/teamsApp" ;
3242import { getResolvedManifest , normalizePath } from "./utils/utils" ;
33- import { copilotGptManifestUtils } from "./utils/CopilotGptManifestUtils" ;
34- import { expandVariableWithFunction , ManifestType } from "../../utils/envFunctionUtils" ;
35- import { getAbsolutePath } from "../../utils/common" ;
36- import { featureFlagManager , FeatureFlags } from "../../../common/featureFlags" ;
37- import { updateVersionForTeamsAppYamlFile } from "../util/utils" ;
3843
3944export const actionName = "teamsApp/zipAppPackage" ;
4045
@@ -111,43 +116,60 @@ export class CreateAppPackageDriver implements StepDriver {
111116
112117 const appDirectory = path . dirname ( hasTTKGeneratedFolder ? generatedFolder : manifestPath ) ;
113118
114- const colorFile = path . resolve ( appDirectory , manifest . icons . color ) ;
115- if ( ! ( await fs . pathExists ( colorFile ) ) ) {
116- const error = new FileNotFoundError (
117- actionName ,
118- colorFile ,
119- "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"
120- ) ;
121- return err ( error ) ;
122- }
123- const colorFileRelativePath = path . relative ( appDirectory , colorFile ) ;
124- if ( colorFileRelativePath . startsWith ( ".." ) ) {
125- return err ( new InvalidFileOutsideOfTheDirectotryError ( colorFile ) ) ;
126- }
127-
128- const outlineFile = path . resolve ( appDirectory , manifest . icons . outline ) ;
129- if ( ! ( await fs . pathExists ( outlineFile ) ) ) {
130- const error = new FileNotFoundError (
131- actionName ,
132- outlineFile ,
133- "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"
134- ) ;
135- return err ( error ) ;
119+ // check and include all relative file paths in manifest
120+ const relativeFiles = [ manifest . icons . color , manifest . icons . outline ] ;
121+ const manifestVersion = semver . coerce ( manifest . manifestVersion ) ; // ensure manifestVersion is a valid semver
122+ if ( manifestVersion && semver . gte ( manifestVersion , "1.21.0" ) ) {
123+ const color32x32 = ( manifest as TeamsManifestV1D21 . TeamsManifestV1D21 ) . icons . color32x32 ;
124+ if ( color32x32 ) {
125+ relativeFiles . push ( color32x32 ) ;
126+ }
136127 }
137- const outlineFileRelativePath = path . relative ( appDirectory , outlineFile ) ;
138- if ( outlineFileRelativePath . startsWith ( ".." ) ) {
139- return err ( new InvalidFileOutsideOfTheDirectotryError ( outlineFile ) ) ;
128+ for ( const file of relativeFiles ) {
129+ const filePath = path . resolve ( appDirectory , file ) ;
130+ if ( ! ( await fs . pathExists ( filePath ) ) ) {
131+ const error = new FileNotFoundError (
132+ actionName ,
133+ filePath ,
134+ "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"
135+ ) ;
136+ return err ( error ) ;
137+ }
138+ const fileRelativePath = path . relative ( appDirectory , filePath ) ;
139+ if ( fileRelativePath . startsWith ( ".." ) ) {
140+ return err ( new InvalidFileOutsideOfTheDirectotryError ( filePath ) ) ;
141+ }
140142 }
141143
142144 // pre-check existence
143- if (
144- manifest . localizationInfo &&
145- manifest . localizationInfo . additionalLanguages &&
146- manifest . localizationInfo . additionalLanguages . length > 0
147- ) {
148- for ( const language of manifest . localizationInfo . additionalLanguages ) {
145+ let additionalLanguages : TeamsManifestV1D5 . AdditionalLanguage [ ] | undefined ;
146+ if ( manifestVersion && semver . gte ( manifestVersion , "1.5.0" ) ) {
147+ additionalLanguages = ( manifest as TeamsManifestV1D5 . TeamsManifestV1D5 ) . localizationInfo
148+ ?. additionalLanguages ;
149+ }
150+ let composeExtensionType : string | undefined ;
151+ let apiSpecificationFile : string | undefined ;
152+ let commands : TeamsManifestV1D17 . ComposeExtensionCommand [ ] | undefined ;
153+ if ( manifestVersion && semver . gte ( manifestVersion , "1.17.0" ) ) {
154+ composeExtensionType = ( manifest as TeamsManifestV1D17 . TeamsManifestV1D17 )
155+ . composeExtensions ?. [ 0 ] ?. composeExtensionType ;
156+ apiSpecificationFile = ( manifest as TeamsManifestV1D17 . TeamsManifestV1D17 )
157+ . composeExtensions ?. [ 0 ] ?. apiSpecificationFile ;
158+ commands = ( manifest as TeamsManifestV1D17 . TeamsManifestV1D17 ) . composeExtensions ?. [ 0 ]
159+ ?. commands ;
160+ }
161+ let defaultLanguageFile : string | undefined ;
162+ let declarativeAgents : TeamsManifestV1D19 . DeclarativeAgentRef [ ] | undefined ;
163+ if ( manifestVersion && semver . gte ( manifestVersion , "1.19.0" ) ) {
164+ defaultLanguageFile = ( manifest as TeamsManifestV1D19 . TeamsManifestV1D19 ) . localizationInfo
165+ ?. defaultLanguageFile ;
166+ declarativeAgents = ( manifest as TeamsManifestV1D19 . TeamsManifestV1D19 ) . copilotAgents
167+ ?. declarativeAgents ;
168+ }
169+ if ( additionalLanguages && additionalLanguages . length > 0 ) {
170+ for ( const language of additionalLanguages ) {
149171 const file = language . file ;
150- const fileName = ` ${ appDirectory } / ${ file } ` ;
172+ const fileName = path . join ( appDirectory , file ) ;
151173 if ( ! ( await fs . pathExists ( fileName ) ) ) {
152174 return err (
153175 new FileNotFoundError (
@@ -159,9 +181,8 @@ export class CreateAppPackageDriver implements StepDriver {
159181 }
160182 }
161183 }
162- if ( manifest . localizationInfo && manifest . localizationInfo . defaultLanguageFile ) {
163- const file = manifest . localizationInfo . defaultLanguageFile ;
164- const fileName = `${ appDirectory } /${ file } ` ;
184+ if ( defaultLanguageFile ) {
185+ const fileName = path . join ( appDirectory , defaultLanguageFile ) ;
165186 if ( ! ( await fs . pathExists ( fileName ) ) ) {
166187 return err (
167188 new FileNotFoundError (
@@ -176,19 +197,15 @@ export class CreateAppPackageDriver implements StepDriver {
176197 const zip = new AdmZip ( ) ;
177198 zip . addFile ( Constants . MANIFEST_FILE , Buffer . from ( JSON . stringify ( manifest , null , 4 ) ) ) ;
178199
179- // outline.png & color.png , relative path
180- let dir = path . dirname ( manifest . icons . color ) ;
181- zip . addLocalFile ( colorFile , dir === "." ? "" : dir ) ;
182- dir = path . dirname ( manifest . icons . outline ) ;
183- zip . addLocalFile ( outlineFile , dir === "." ? "" : dir ) ;
200+ // icon images , relative path
201+ for ( const icon of relativeFiles ) {
202+ const dir = path . dirname ( icon ) ;
203+ zip . addLocalFile ( path . resolve ( appDirectory , icon ) , dir === "." ? "" : dir ) ;
204+ }
184205
185206 // localization file
186- if (
187- manifest . localizationInfo &&
188- manifest . localizationInfo . additionalLanguages &&
189- manifest . localizationInfo . additionalLanguages . length > 0
190- ) {
191- for ( const language of manifest . localizationInfo . additionalLanguages ) {
207+ if ( additionalLanguages && additionalLanguages . length > 0 ) {
208+ for ( const language of additionalLanguages ) {
192209 const file = language . file ;
193210 const fileName = path . resolve ( appDirectory , file ) ;
194211 const relativePath = path . relative ( appDirectory , fileName ) ;
@@ -204,9 +221,8 @@ export class CreateAppPackageDriver implements StepDriver {
204221 }
205222 }
206223 }
207- if ( manifest . localizationInfo && manifest . localizationInfo . defaultLanguageFile ) {
208- const file = manifest . localizationInfo . defaultLanguageFile ;
209- const fileName = path . resolve ( appDirectory , file ) ;
224+ if ( defaultLanguageFile ) {
225+ const fileName = path . resolve ( appDirectory , defaultLanguageFile ) ;
210226 const relativePath = path . relative ( appDirectory , fileName ) ;
211227 if ( relativePath . startsWith ( ".." ) ) {
212228 return err ( new InvalidFileOutsideOfTheDirectotryError ( fileName ) ) ;
@@ -222,18 +238,10 @@ export class CreateAppPackageDriver implements StepDriver {
222238 }
223239
224240 // API ME, API specification and Adaptive card templates
225- if (
226- manifest . composeExtensions &&
227- manifest . composeExtensions . length > 0 &&
228- manifest . composeExtensions [ 0 ] . composeExtensionType == "apiBased" &&
229- manifest . composeExtensions [ 0 ] . apiSpecificationFile
230- ) {
231- const apiSpecificationFile = path . resolve (
232- appDirectory ,
233- manifest . composeExtensions [ 0 ] . apiSpecificationFile
234- ) ;
241+ if ( composeExtensionType == "apiBased" && apiSpecificationFile ) {
242+ const apiSpecificationFilePath = path . resolve ( appDirectory , apiSpecificationFile ) ;
235243 const checkExistenceRes = await this . validateReferencedFile (
236- apiSpecificationFile ,
244+ apiSpecificationFilePath ,
237245 appDirectory
238246 ) ;
239247 if ( checkExistenceRes . isErr ( ) ) {
@@ -242,17 +250,17 @@ export class CreateAppPackageDriver implements StepDriver {
242250
243251 const addFileWithVariableRes = await this . addFileWithVariable (
244252 zip ,
245- manifest . composeExtensions [ 0 ] . apiSpecificationFile ,
246253 apiSpecificationFile ,
254+ apiSpecificationFilePath ,
247255 ManifestType . ApiSpec ,
248256 context
249257 ) ;
250258 if ( addFileWithVariableRes . isErr ( ) ) {
251259 return err ( addFileWithVariableRes . error ) ;
252260 }
253261
254- if ( manifest . composeExtensions [ 0 ] . commands . length > 0 ) {
255- for ( const command of manifest . composeExtensions [ 0 ] . commands ) {
262+ if ( commands && commands . length > 0 ) {
263+ for ( const command of commands ) {
256264 if ( command . apiResponseRenderingTemplateFile ) {
257265 const adaptiveCardFile = path . resolve (
258266 appDirectory ,
@@ -272,31 +280,11 @@ export class CreateAppPackageDriver implements StepDriver {
272280 }
273281 }
274282
275- const plugins = manifest . copilotExtensions
276- ? manifest . copilotExtensions . plugins
277- : manifest . copilotAgents ?. plugins ;
278- if ( plugins ?. length && plugins [ 0 ] . file ) {
279- // API plugin
280- const addFilesRes = await this . addPlugin (
281- zip ,
282- plugins [ 0 ] . file ,
283- appDirectory ,
284- context ,
285- ! shouldwriteAllManifest ? undefined : jsonFileDir
286- ) ;
287- if ( addFilesRes . isErr ( ) ) {
288- return err ( addFilesRes . error ) ;
289- }
290- }
291-
292- const declarativeCopilots = manifest . copilotExtensions
293- ? manifest . copilotExtensions . declarativeCopilots
294- : manifest . copilotAgents ?. declarativeAgents ;
295283 // Copilot GPT
296- if ( declarativeCopilots ?. length && declarativeCopilots [ 0 ] . file ) {
284+ if ( declarativeAgents ?. length && declarativeAgents [ 0 ] . file ) {
297285 const declarativeAgentManifestFile = path . resolve (
298286 hasTTKGeneratedFolder ? generatedFolder : appDirectory ,
299- declarativeCopilots [ 0 ] . file
287+ declarativeAgents [ 0 ] . file
300288 ) ;
301289 const checkExistenceRes = await this . validateReferencedFile (
302290 declarativeAgentManifestFile ,
@@ -308,7 +296,7 @@ export class CreateAppPackageDriver implements StepDriver {
308296
309297 const addFileWithVariableRes = await this . addFileWithVariable (
310298 zip ,
311- declarativeCopilots [ 0 ] . file ,
299+ declarativeAgents [ 0 ] . file ,
312300 declarativeAgentManifestFile ,
313301 ManifestType . DeclarativeCopilotManifest ,
314302 context ,
@@ -338,7 +326,7 @@ export class CreateAppPackageDriver implements StepDriver {
338326 hasTTKGeneratedFolder ? generatedFolder : appDirectory ,
339327 pluginFileAbsolutePath
340328 ) ;
341- const useForwardSlash = declarativeCopilots [ 0 ] . file . concat ( pluginFile ) . includes ( "/" ) ;
329+ const useForwardSlash = declarativeAgents [ 0 ] . file . concat ( pluginFile ) . includes ( "/" ) ;
342330
343331 const addPluginRes = await this . addPlugin (
344332 zip ,
0 commit comments