-
Notifications
You must be signed in to change notification settings - Fork 18
/
gulpfile.js
196 lines (168 loc) · 7.93 KB
/
gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var argv = require('yargs').argv;
var del = require('del');
var gulp = require('gulp');
var gulp_exec = require('gulp-exec');
var gulpif = require('gulp-if');
var multidest = require('gulp-multi-dest');
var rename = require('gulp-rename');
var replace = require('gulp-replace');
var tsc = require('gulp-typescript');
const EXTENSION_MANIFEST = 'vss-extension.json';
const BUILD_DIR = 'build/';
const COMMON_TASK_DIR = 'common';
const TASKS_DIR = 'tasks';
const DEV_MANIFEST_OVERRIDE = {
public: false,
"id": "windows-store-publish-dev",
"name": "Windows Store Dev",
};
// Get all task directories except common and transform them into gulp dests of the corresponding build directory
// This is not the most optimal, but the 'best' way barring having a dest-like plugin that takes a glob.
const TASK_DIRECTORIES = fs.readdirSync(TASKS_DIR)
.filter(function(p) { return fs.statSync(path.join(TASKS_DIR, p)).isDirectory() && p !== COMMON_TASK_DIR; });
// Construct gulp destinations out of the task directories.
function getTaskDestinations()
{
return TASK_DIRECTORIES.map(function(p) { return path.join(BUILD_DIR, p); });
}
// Convert the override JavaScript object to a JSON string, adding a backslash before any double quotes as that's needed for the shell exec
function toOverrideString(object) {
return JSON.stringify(object).replace(/"/g, '\\"');
}
/* *****
Main tasks (that you would want to typically run)
***** */
// Remove everything in the build directory.
gulp.task('clean', function ()
{
return del([BUILD_DIR + '**/*']);
});
/* *****
"Internal" tasks below.
There should be no need to call these tasks directly.
***** */
gulp.task('_extension_metadata', function ()
{
return gulp
.src([EXTENSION_MANIFEST
, 'images/*.png' // Extension logo
, 'ThirdPartyNotices.txt' // 3rd-party notices
, 'README.md' // Information to appear on the marketplace page
, 'docs/**/*' // Copy all content to be addressed by documentation
],
{ base: '.'})
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/vss-extension\.json/); }, replace('devCenterApiEndpoint','devCenterApiEndpoint-dev')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/vss-extension\.json/); }, replace('"displayName": "Windows Dev Center"','"displayName": "Windows Dev Center Dev"')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/vss-extension\.json/); }, replace('"name": "devCenter"','"name": "devCenter-dev"')))
.pipe(gulp.dest(BUILD_DIR));
})
gulp.task('_task_metadata', function ()
{
return gulp
// Copy over non-code files of the extension
.src(['tasks/*/*.png' // Task icons
, 'tasks/*/task.json' // Task manifest
])
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/task\.json/); }, replace('8e70da9d-532d-4416-a07f-5ec10f84339f','81e53284-f02d-4878-abca-20f08327121c')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/task\.json/); }, replace('"friendlyName": "Windows Store - Publish"','"friendlyName": "Windows Store - Publish Dev"')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/task\.json/); }, replace('13dee6a7-3698-4b12-bbb4-b393560a3ebc','91c056be-bd43-4b3f-a4bf-6eb489bc121d')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/task\.json/); }, replace('"friendlyName": "Windows Store - Flight"','"friendlyName": "Windows Store - Flight Dev"')))
.pipe(gulpif(function(file) { return argv.dev && file.path.match(/task\.json/); }, replace('connectedService:devCenter','connectedService:devCenter-dev')))
.pipe(gulp.dest(BUILD_DIR));
});
/* When compiling, we want to go from the structure on the left to the one on the right.
[SOURCE TREE] [BUILD TREE]
tasks tasks
\- TaskA \- TaskA
| \- a.ts | \- common
| \- aHelper.ts | | \- common.js
| \- task.json | | \- util.js
| | |
\- TaskB | \- local
| \... | | \- a.js
| | | \- aHelper.js
\- common | \- task.json
\- common.ts \- TaskB
\- util.ts \...
The reasoning is:
1) We want to have access to common code, so in the source tree we need a common directory.
2) Tasks are self-contained, so the common code must be copied in each task in the build tree.
3) The relative path between a task file and a common file should stay the same so that both our IDE and node can
find the appropriate files. Therefore each task needs a 'local' directory in the build tree so that the relative
path from <task-specific>.[ts|js] to <common>.[ts.js] is always '../common/'.
The node_modules directory is populated by the 'dependencies' gulp task at the root of each task in the build
tree (e.g. tasks/tasksA/). node will be smart enough to find that folder even from common/*.js and local/*.js
Note that task metadata (task.json, icon.png, package.json, etc.) remain in the task root folder.
The below tasks are in charge of creating that folder structure
*/
gulp.task('_compile_only', function ()
{
var tsconfig = require('./tsconfig.json').compilerOptions;
return gulp
.src(['tasks/*/*.ts'])
.pipe(tsc(tsconfig))
.pipe(rename(p =>
{
// Redirect non-common task .ts files to a 'local' subdirectory
if (!p.dirname.endsWith(COMMON_TASK_DIR))
{
p.dirname += '/local';
}
}))
.pipe(gulp.dest(BUILD_DIR));
});
// Copy the code under common/ into every task directory.
gulp.task('_copy_common', function ()
{
return gulp
.src([BUILD_DIR + COMMON_TASK_DIR + '/*.js'], { base: BUILD_DIR }) // Note: already built, so .js and not .ts
.pipe(multidest(getTaskDestinations()));
});
// Copy the master package.json file into each task folder in the build tree, so that
// packages can be properly installed for each task.
gulp.task('_copy_dependency_list', function ()
{
return gulp
.src(['package.json'])
.pipe(multidest(getTaskDestinations()));
});
// Remove the common directory under the build tree, so that it doesn't get packaged in the VSIX file for nothing.
gulp.task('_remove_common', function ()
{
return del([BUILD_DIR + COMMON_TASK_DIR]);
});
// Install node dependencies for each task that has been built.
gulp.task('dependencies', gulp.series('_copy_dependency_list', function ()
{
var taskDirsInBuildTree = TASK_DIRECTORIES.map(p => path.join(BUILD_DIR, p));
return gulp
.src(taskDirsInBuildTree) // Any task directory...
.pipe(gulp_exec('cd <%= file.path %> && npm install --production')); // ...go in and install
}));
// Compile all tasks
gulp.task('compile', gulp.series('_compile_only', 'dependencies', '_copy_common', '_remove_common'));
// Create a VSIX package for the extension. --publisher specifies the publisher to use, if different from the manifest.
gulp.task('package', gulp.series(gulp.series('compile', '_task_metadata', '_extension_metadata', 'dependencies'), function(callback)
{
var cmd = 'tfx extension create'
+ ' --root ' + BUILD_DIR
+ ' --manifest-globs ' + EXTENSION_MANIFEST
+ ' --output-path ' + BUILD_DIR + 'extension';
if (argv.publisher)
{
cmd += ' --publisher ' + argv.publisher;
}
if (argv.public)
{
cmd += ' --override {\\"public\\": true}';
}
else if (argv.dev)
{
cmd += ' --override ' + toOverrideString(DEV_MANIFEST_OVERRIDE);
}
exec(cmd, callback);
}));
gulp.task('default', gulp.series('package'));