11import path = require( 'path' ) ;
22import tl = require( 'azure-pipelines-task-lib/task' ) ;
33import trm = require( 'azure-pipelines-task-lib/toolrunner' ) ;
4+ import fs = require( 'fs' ) ;
5+
6+ const appLocationInputName = 'app_location' ;
7+ const appBuildCommandInputName = 'app_build_command' ;
8+ const outputLocationInputName = 'output_location' ;
9+ const apiLocationInputName = 'api_location' ;
10+ const apiBuildCommandInputName = 'api_build_command' ;
11+ const routesLocationInputName = 'routes_location' ;
12+ const buildTimeoutInMinutesInputName = 'build_timeout_in_minutes' ;
13+ const configFileLocationInputName = 'config_file_location' ;
14+ const apiTokenInputName = 'azure_static_web_apps_api_token' ;
415
516async function run ( ) {
17+ const envVarFilePath : string = path . join ( __dirname , 'env.list' ) ;
18+
619 try {
720 tl . setResourcePath ( path . join ( __dirname , 'task.json' ) ) ;
821
@@ -19,39 +32,126 @@ async function run() {
1932
2033 bash . line ( tl . getInput ( 'args' , false ) ) ;
2134
22- const deploymentClient = "mcr.microsoft.com/appsvc/staticappsclient:stable" ;
23-
24- const workingDirectory : string = tl . getInput ( 'cwd' , false ) || "" ;
25- const appLocation : string = tl . getInput ( 'app_location' , false ) || "" ;
26- const appBuildCommand : string = tl . getInput ( 'app_build_command' , false ) || "" ;
27- const outputLoction : string = tl . getInput ( 'output_location' , false ) || "" ;
28- const apiLocation : string = tl . getInput ( 'api_location' , false ) || "" ;
29- const apiBuildCommand : string = tl . getInput ( 'api_build_command' , false ) || "" ;
30- const routesLocation : string = tl . getInput ( 'routes_location' , false ) || "" ;
31- const skipAppBuild : boolean = tl . getBoolInput ( 'skip_app_build' , false ) ;
32- const apiToken : string = process . env [ 'azure_static_web_apps_api_token' ] || tl . getInput ( 'azure_static_web_apps_api_token' , false ) || "" ;
33-
34- process . env [ 'SWA_WORKING_DIR' ] = workingDirectory ;
35- process . env [ 'SWA_APP_LOCATION' ] = appLocation ;
36- process . env [ 'SWA_APP_BUILD_COMMAND' ] = appBuildCommand ;
37- process . env [ 'SWA_OUTPUT_LOCATION' ] = outputLoction ;
38- process . env [ 'SWA_API_LOCATION' ] = apiLocation ;
39- process . env [ 'SWA_API_BUILD_COMMAND' ] = apiBuildCommand ;
40- process . env [ 'SWA_ROUTES_LOCATION' ] = routesLocation ;
41- process . env [ 'SWA_DEPLOYMENT_CLIENT' ] = deploymentClient ;
42- process . env [ 'SWA_SKIP_APP_BUILD' ] = skipAppBuild . toString ( ) ;
43- process . env [ 'SWA_API_TOKEN' ] = apiToken ;
44-
35+ await createDockerEnvVarFile ( envVarFilePath ) ;
36+
4537 const options = {
4638 failOnStdErr : false
4739 } ;
4840
4941 await bash . exec ( < any > options ) ;
5042 tl . setResult ( tl . TaskResult . Succeeded , null ) ;
43+ } catch ( err ) {
44+ tl . setResult ( tl . TaskResult . Failed , err ) ;
45+ } finally {
46+ await fs . promises . unlink ( envVarFilePath ) . catch ( ( ) => tl . warning ( "Unable to delete env file" ) ) ;
47+ }
48+ }
49+
50+ async function createDockerEnvVarFile ( envVarFilePath : string ) {
51+ var variableString : string = ""
52+
53+ const systemVariableNames : Set < string > = new Set < string > ( ) ;
54+
55+ const addVariableToString = ( envVarName : string , envVarValue : string ) => variableString += envVarName + "=" + envVarValue + "\n"
56+
57+ const addSystemVariableToString = ( envVarName : string , envVarValue : string ) => {
58+ addVariableToString ( envVarName , envVarValue )
59+ systemVariableNames . add ( envVarName )
60+ }
61+
62+ const addInputStringToString = ( envVarName : string , envVarValue : string , inputName : string , ) => {
63+ if ( envVarValue . includes ( "\n" ) ) {
64+ throw "Input " + inputName + " is a multiline string and cannot be added to the build environment." ;
65+ }
66+
67+ addSystemVariableToString ( envVarName , envVarValue )
68+ }
69+
70+ const workingDirectory : string = tl . getInput ( 'cwd' , false ) || process . env . SYSTEM_DEFAULTWORKINGDIRECTORY ;
71+ const appLocation : string = tl . getInput ( appLocationInputName , false ) || "" ;
72+ const appBuildCommand : string = tl . getInput ( appBuildCommandInputName , false ) || "" ;
73+ const outputLocation : string = tl . getInput ( outputLocationInputName , false ) || "" ;
74+ const apiLocation : string = tl . getInput ( apiLocationInputName , false ) || "" ;
75+ const apiBuildCommand : string = tl . getInput ( apiBuildCommandInputName , false ) || "" ;
76+ const routesLocation : string = tl . getInput ( routesLocationInputName , false ) || "" ;
77+ const buildTimeoutInMinutes : string = tl . getInput ( buildTimeoutInMinutesInputName , false ) || "" ;
78+ const configFileLocation : string = tl . getInput ( configFileLocationInputName , false ) || "" ;
79+
80+ const skipAppBuild : boolean = tl . getBoolInput ( 'skip_app_build' , false ) ;
81+ const apiToken : string = process . env [ apiTokenInputName ] || tl . getInput ( apiTokenInputName , false ) || "" ;
82+
83+ const systemVerbose = getNullableBooleanFromString ( process . env [ 'SYSTEM_DEBUG' ] ) ;
84+ const inputVerbose = getNullableBooleanFromString ( tl . getInput ( 'verbose' , false ) ) ;
85+
86+ const verbose = inputVerbose === true ? true : ( inputVerbose === false ? false : systemVerbose === true ) ;
87+
88+ const deploymentClient = "mcr.microsoft.com/appsvc/staticappsclient:stable" ;
89+ const containerWorkingDir = "/working_dir" ;
90+
91+ addInputStringToString ( "APP_LOCATION" , appLocation , appLocationInputName ) ;
92+ addInputStringToString ( "APP_BUILD_COMMAND" , appBuildCommand , appBuildCommandInputName ) ;
93+ addInputStringToString ( "OUTPUT_LOCATION" , outputLocation , outputLocationInputName ) ;
94+ addInputStringToString ( "API_LOCATION" , apiLocation , apiLocationInputName ) ;
95+ addInputStringToString ( "API_BUILD_COMMAND" , apiBuildCommand , apiBuildCommandInputName ) ;
96+ addInputStringToString ( "ROUTES_LOCATION" , routesLocation , routesLocationInputName ) ;
97+ addInputStringToString ( "BUILD_TIMEOUT_IN_MINUTES" , buildTimeoutInMinutes , buildTimeoutInMinutesInputName ) ;
98+ addInputStringToString ( "CONFIG_FILE_LOCATION" , configFileLocation , configFileLocationInputName ) ;
99+
100+ addSystemVariableToString ( "SKIP_APP_BUILD" , skipAppBuild . toString ( ) ) ;
101+ addSystemVariableToString ( "VERBOSE" , verbose . toString ( ) ) ;
102+
103+ addInputStringToString ( "DEPLOYMENT_TOKEN" , apiToken , apiTokenInputName ) ;
104+
105+ process . env [ 'SWA_DEPLOYMENT_CLIENT' ] = deploymentClient ;
106+ process . env [ 'SWA_WORKING_DIR' ] = workingDirectory ;
107+ process . env [ 'SWA_WORKSPACE_DIR' ] = containerWorkingDir ;
108+
109+ addSystemVariableToString ( "GITHUB_WORKSPACE" , "" ) ;
110+ addSystemVariableToString ( "DEPLOYMENT_PROVIDER" , "DevOps" ) ;
111+ addSystemVariableToString ( "REPOSITORY_URL" , process . env . BUILD_REPOSITORY_URI || "" ) ;
112+ addSystemVariableToString ( "IS_PULL_REQUEST" , "" ) ;
113+ addSystemVariableToString ( "BASE_BRANCH" , "" ) ;
114+ addSystemVariableToString ( "REPOSITORY_BASE" , containerWorkingDir ) ;
115+ addSystemVariableToString ( "BRANCH" , process . env . BUILD_SOURCEBRANCHNAME || "" ) ;
116+ addSystemVariableToString ( "DEPLOYMENT_ACTION" , "upload" ) ;
117+
118+ const denylistString = await fs . promises . readFile ( path . join ( __dirname , 'envVarDenylist.json' ) , 'utf8' ) ;
119+ const denylist = JSON . parse ( denylistString ) ;
120+
121+ Object . keys ( process . env ) . forEach ( ( envVarKey : string ) => {
122+ const envVarValue = process . env [ envVarKey ] ;
123+
124+ if ( envVarValue . includes ( "\n" ) ) {
125+ tl . warning ( "Environment variable " + envVarKey + " is a multiline string and cannot be added to the build environment." ) ;
126+ return ;
127+ }
128+
129+ if ( systemVariableNames . has ( envVarKey ) ) {
130+ tl . warning ( "custom variable overlapping with reserved SWA variable: " + envVarKey ) ;
131+ return ;
132+ }
133+
134+ if ( ! denylist . includes ( envVarKey . toUpperCase ( ) ) ) {
135+ addVariableToString ( envVarKey , envVarValue ) ;
136+ }
137+ } ) ;
138+
139+ await fs . promises . writeFile ( envVarFilePath , variableString ) ;
140+ }
141+
142+ function getNullableBooleanFromString ( boolString :string ) : boolean {
143+ if ( boolString == null ) return null ;
144+ boolString = boolString . toLowerCase ( ) ;
145+
146+ if ( boolString === "true" ) {
147+ return true ;
51148 }
52- catch ( err ) {
53- tl . setResult ( tl . TaskResult . Failed , null ) ;
149+
150+ if ( boolString === "false" ) {
151+ return false ;
54152 }
153+
154+ return null ;
55155}
56156
57157run ( ) ;
0 commit comments