15
15
using Azure . Functions . Cli . Interfaces ;
16
16
using Colors . Net ;
17
17
using Fclp ;
18
- using Microsoft . Azure . WebJobs . Script ;
19
18
using static Azure . Functions . Cli . Common . OutputTheme ;
20
19
21
20
namespace Azure . Functions . Cli . Actions . AzureActions
@@ -29,6 +28,8 @@ internal class PublishFunctionApp : BaseFunctionAppAction
29
28
public bool PublishLocalSettings { get ; set ; }
30
29
public bool OverwriteSettings { get ; set ; }
31
30
public bool PublishLocalSettingsOnly { get ; set ; }
31
+ public bool ListIgnoredFiles { get ; set ; }
32
+ public bool ListIncludedFiles { get ; set ; }
32
33
33
34
public PublishFunctionApp ( IArmManager armManager , ISettings settings , ISecretsManager secretsManager )
34
35
: base ( armManager )
@@ -51,62 +52,143 @@ public override ICommandLineParserResult ParseArgs(string[] args)
51
52
. Setup < bool > ( 'y' , "overwrite-settings" )
52
53
. WithDescription ( "Only to be used in conjunction with -i or -o. Overwrites AppSettings in Azure with local value if different. Default is prompt." )
53
54
. Callback ( f => OverwriteSettings = f ) ;
55
+ Parser
56
+ . Setup < bool > ( "list-ignored-files" )
57
+ . WithDescription ( "Displays a list of files that will be ignored from publishing based on .funcignore" )
58
+ . Callback ( f => ListIgnoredFiles = f ) ;
59
+ Parser
60
+ . Setup < bool > ( "list-included-files" )
61
+ . WithDescription ( "Displays a list of files that will be included in publishing based on .funcignore" )
62
+ . Callback ( f => ListIncludedFiles = f ) ;
54
63
55
64
return base . ParseArgs ( args ) ;
56
65
}
57
66
58
67
public override async Task RunAsync ( )
59
68
{
60
- ColoredConsole . WriteLine ( "Getting site publishing info..." ) ;
61
- var functionApp = await _armManager . GetFunctionAppAsync ( FunctionAppName ) ;
62
- if ( PublishLocalSettingsOnly )
69
+ GitIgnoreParser ignoreParser = null ;
70
+ try
63
71
{
64
- var isSuccessful = await PublishAppSettings ( functionApp ) ;
65
- if ( ! isSuccessful )
72
+ var path = Path . Combine ( Environment . CurrentDirectory , Constants . FuncIgnoreFile ) ;
73
+ if ( FileSystemHelpers . FileExists ( path ) )
66
74
{
67
- return ;
75
+ ignoreParser = new GitIgnoreParser ( FileSystemHelpers . ReadAllTextFromFile ( path ) ) ;
68
76
}
69
77
}
78
+ catch { }
79
+
80
+ if ( ListIncludedFiles )
81
+ {
82
+ InternalListIncludedFiles ( ignoreParser ) ;
83
+ }
84
+ else if ( ListIgnoredFiles )
85
+ {
86
+ InternalListIgnoredFiles ( ignoreParser ) ;
87
+ }
70
88
else
71
89
{
72
- var functionAppRoot = ScriptHostHelpers . GetFunctionAppRootDirectory ( Environment . CurrentDirectory ) ;
73
- ColoredConsole . WriteLine ( WarningColor ( $ "Publish { functionAppRoot } contents to an Azure Function App. Locally deleted files are not removed from destination.") ) ;
74
- await RetryHelper . Retry ( async ( ) =>
90
+ if ( PublishLocalSettingsOnly )
75
91
{
76
- using ( var client = await GetRemoteZipClient ( new Uri ( $ "https://{ functionApp . ScmUri } ") ) )
77
- using ( var request = new HttpRequestMessage ( HttpMethod . Put , new Uri ( "api/zip/site/wwwroot" , UriKind . Relative ) ) )
78
- {
79
- request . Headers . IfMatch . Add ( EntityTagHeaderValue . Any ) ;
92
+ await InternalPublishLocalSettingsOnly ( ) ;
93
+ }
94
+ else
95
+ {
96
+ await InternalPublishFunctionApp ( ignoreParser ) ;
97
+ }
98
+ }
99
+ }
100
+
101
+ private async Task InternalPublishFunctionApp ( GitIgnoreParser ignoreParser )
102
+ {
103
+ ColoredConsole . WriteLine ( "Getting site publishing info..." ) ;
104
+ var functionApp = await _armManager . GetFunctionAppAsync ( FunctionAppName ) ;
105
+ var functionAppRoot = ScriptHostHelpers . GetFunctionAppRootDirectory ( Environment . CurrentDirectory ) ;
106
+ ColoredConsole . WriteLine ( WarningColor ( $ "Publish { functionAppRoot } contents to an Azure Function App. Locally deleted files are not removed from destination.") ) ;
107
+ await RetryHelper . Retry ( async ( ) =>
108
+ {
109
+ using ( var client = await GetRemoteZipClient ( new Uri ( $ "https://{ functionApp . ScmUri } ") ) )
110
+ using ( var request = new HttpRequestMessage ( HttpMethod . Put , new Uri ( "api/zip/site/wwwroot" , UriKind . Relative ) ) )
111
+ {
112
+ request . Headers . IfMatch . Add ( EntityTagHeaderValue . Any ) ;
80
113
81
- ColoredConsole . WriteLine ( "Creating archive for current directory..." ) ;
114
+ ColoredConsole . WriteLine ( "Creating archive for current directory..." ) ;
82
115
83
- request . Content = CreateZip ( functionAppRoot ) ;
116
+ request . Content = CreateZip ( functionAppRoot , ignoreParser ) ;
84
117
85
- ColoredConsole . WriteLine ( "Uploading archive..." ) ;
86
- var response = await client . SendAsync ( request ) ;
87
- if ( ! response . IsSuccessStatusCode )
88
- {
89
- throw new CliException ( $ "Error uploading archive ({ response . StatusCode } ).") ;
90
- }
118
+ ColoredConsole . WriteLine ( "Uploading archive..." ) ;
119
+ var response = await client . SendAsync ( request ) ;
120
+ if ( ! response . IsSuccessStatusCode )
121
+ {
122
+ throw new CliException ( $ "Error uploading archive ({ response . StatusCode } ).") ;
123
+ }
91
124
92
- response = await client . PostAsync ( "api/functions/synctriggers" , content : null ) ;
93
- if ( ! response . IsSuccessStatusCode )
94
- {
95
- throw new CliException ( $ "Error calling sync triggers ({ response . StatusCode } ).") ;
96
- }
125
+ response = await client . PostAsync ( "api/functions/synctriggers" , content : null ) ;
126
+ if ( ! response . IsSuccessStatusCode )
127
+ {
128
+ throw new CliException ( $ "Error calling sync triggers ({ response . StatusCode } ).") ;
129
+ }
97
130
98
- if ( PublishLocalSettings )
131
+ if ( PublishLocalSettings )
132
+ {
133
+ var isSuccessful = await PublishAppSettings ( functionApp ) ;
134
+ if ( ! isSuccessful )
99
135
{
100
- var isSuccessful = await PublishAppSettings ( functionApp ) ;
101
- if ( ! isSuccessful )
102
- {
103
- return ;
104
- }
136
+ return ;
105
137
}
106
-
107
- ColoredConsole . WriteLine ( "Upload completed successfully." ) ;
108
138
}
109
- } , 2 ) ;
139
+
140
+ ColoredConsole . WriteLine ( "Upload completed successfully." ) ;
141
+ }
142
+ } , 2 ) ;
143
+ }
144
+
145
+ private static IEnumerable < string > GetFiles ( string path )
146
+ {
147
+ return FileSystemHelpers . GetFiles ( path , new [ ] { ".git" , ".vscode" } , new [ ] { ".funcignore" , ".gitignore" , "appsettings.json" , "local.settings.json" , "project.lock.json" } ) ;
148
+ }
149
+
150
+ private async Task InternalPublishLocalSettingsOnly ( )
151
+ {
152
+ ColoredConsole . WriteLine ( "Getting site publishing info..." ) ;
153
+ var functionApp = await _armManager . GetFunctionAppAsync ( FunctionAppName ) ;
154
+ var isSuccessful = await PublishAppSettings ( functionApp ) ;
155
+ if ( ! isSuccessful )
156
+ {
157
+ return ;
158
+ }
159
+ }
160
+
161
+ private static void InternalListIgnoredFiles ( GitIgnoreParser ignoreParser )
162
+ {
163
+ if ( ignoreParser == null )
164
+ {
165
+ ColoredConsole . Error . WriteLine ( "No .funcignore file" ) ;
166
+ return ;
167
+ }
168
+
169
+ foreach ( var file in GetFiles ( Environment . CurrentDirectory ) . Select ( f => f . Replace ( Environment . CurrentDirectory , "" ) . Trim ( Path . DirectorySeparatorChar ) . Replace ( "\\ " , "/" ) ) )
170
+ {
171
+ if ( ignoreParser . Denies ( file ) )
172
+ {
173
+ ColoredConsole . WriteLine ( file ) ;
174
+ }
175
+ }
176
+ }
177
+
178
+ private static void InternalListIncludedFiles ( GitIgnoreParser ignoreParser )
179
+ {
180
+ if ( ignoreParser == null )
181
+ {
182
+ ColoredConsole . Error . WriteLine ( "No .funcignore file" ) ;
183
+ return ;
184
+ }
185
+
186
+ foreach ( var file in GetFiles ( Environment . CurrentDirectory ) . Select ( f => f . Replace ( Environment . CurrentDirectory , "" ) . Trim ( Path . DirectorySeparatorChar ) . Replace ( "\\ " , "/" ) ) )
187
+ {
188
+ if ( ignoreParser . Accepts ( file ) )
189
+ {
190
+ ColoredConsole . WriteLine ( file ) ;
191
+ }
110
192
}
111
193
}
112
194
@@ -173,14 +255,17 @@ private IDictionary<string, string> MergeAppSettings(IDictionary<string, string>
173
255
return result ;
174
256
}
175
257
176
- private static StreamContent CreateZip ( string path )
258
+ private static StreamContent CreateZip ( string path , GitIgnoreParser ignoreParser )
177
259
{
178
260
var memoryStream = new MemoryStream ( ) ;
179
261
using ( var zip = new ZipArchive ( memoryStream , ZipArchiveMode . Create , leaveOpen : true ) )
180
262
{
181
- foreach ( var fileName in FileSystemHelpers . GetFiles ( path , new [ ] { ".git" , ".vscode" } , new [ ] { ".gitignore" , "appsettings.json" , "local.settings.json" , "project.lock.json" } ) )
263
+ foreach ( var fileName in GetFiles ( path ) )
182
264
{
183
- zip . AddFile ( fileName , fileName , path ) ;
265
+ if ( ignoreParser ? . Accepts ( fileName . Replace ( path , "" ) . Trim ( Path . DirectorySeparatorChar ) . Replace ( "\\ " , "/" ) ) ?? true )
266
+ {
267
+ zip . AddFile ( fileName , fileName , path ) ;
268
+ }
184
269
}
185
270
}
186
271
memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
0 commit comments