├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package.json
├── tasks
└── umbraco_package.js
└── test
├── Gruntfile.js
├── expected
└── package.xml
├── files
├── aa332ab8-9109-2302-d683-9f06185656f1
│ └── aa332ab8-9109-2302-d683-9f06185656f1
│ │ └── package.xml
├── beec5ff0-a9a5-04ad-19b9-5cf487f240cb
│ └── beec5ff0-a9a5-04ad-19b9-5cf487f240cb
│ │ └── package.xml
└── f7770bbb-9a09-9b66-caf0-b0e79b9321a7
│ └── f7770bbb-9a09-9b66-caf0-b0e79b9321a7
│ └── package.xml
├── fixtures
├── custom-package-xml
│ └── package.xml
└── example
│ ├── App_Plugins
│ └── TestPackage
│ │ ├── package.js
│ │ └── package.manifest
│ └── scripts
│ └── script.js
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | test/artifacts
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 'stable'
4 | - '4'
5 | - '0.10'
6 | before_install: npm install -g grunt-cli
7 | install: npm install
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.0.0 - 11/24/2015
2 |
3 | #### Features:
4 |
5 | * Optionally generate `package.xml` programatically
6 | * Support for multiple build targets in grunt
7 | * Use real file names instead of guids in archive when possible
8 | * New option `outputName` to override the generated archive file name
9 |
10 | #### Misc:
11 | * General process improvements & cleanups
12 | * Introduce tests
13 |
14 | #### :bomb: Breaking Changes:
15 |
16 | This major release included a lot of breaking changes that will require you to restructure your Grunt configuration, and potentially your `package.xml` file. Here are the areas of interest:
17 |
18 | #### readme / readmeContents options merged
19 | The `readme` option has been changed to accept a string containing your desired readme content, rather than a file path to an external file. You should enter the desired content directly into this option, or use grunt templates to load the content from an external file to use the previous behavior:
20 |
21 | ```js
22 | readme: '<%= grunt.file.read("config/readme.txt") %>'
23 | ```
24 |
25 | #### multitask
26 | The task has been converted to a multiTask to enable configuring builds for multiple packages in the same repository. To support this, you need to wrap your existing configuration with a target name, such as:
27 |
28 | ```js
29 | umbracoPackage: {
30 | main: {
31 | // normal task configuration
32 | }
33 | }
34 | ```
35 | #### src/dest parameters
36 | To support glob patterns, the `sourceDir` and `outputDir` properties have been removed in favor of `src` and `dest`, which live at the root level of the task. You should move and rename these options per the example in the README.
37 |
38 | #### generated package.xml
39 | In the new version, the `manifest` option is no longer required, and the file can be generated automatically based on your configuration. To enable this, just remove this option and delete the `package.xml` file from your repository.
40 |
41 | If you wish to continue using your own `package.xml` file, you will need to make these changes:
42 |
43 | * Change `<%= file.guid %>.<%= file.ext %>` to `<%= file.guid %>`
44 | * Change `readmeContents` to `readme`
45 |
46 | ## 0.0.6 - 4/2/2015
47 |
48 | Maintenance
49 | * Replace `adm-zip` with `archiver` for better reliability
50 |
51 | ## 0.0.5 - 3/22/2014
52 |
53 | Fixes
54 | * Use Mac-friendly paths
55 |
56 | ## 0.0.4 - 2/28/2014
57 |
58 | Features
59 | * Make `readme` parameter optional to match Umbraco backoffice behavior
60 |
61 | ## 0.0.3 - 2/28/2014
62 |
63 | Fixes
64 | * Fix issue with build
65 |
66 | ## 0.0.2 - 2/17/2014
67 |
68 | Maintenance
69 | * Add license
70 |
71 | ## 0.0.1 - 2/17/2014
72 |
73 | * Initial commit
74 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Tom Fulton
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | grunt-umbraco-package [](https://travis-ci.org/tomfulton/grunt-umbraco-package)
2 | =====================
3 |
4 | > A grunt task to automate the creation of installable Umbraco packages from your files.
5 |
6 | ## Getting Started
7 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
8 |
9 | ```shell
10 | npm install grunt-umbraco-package --save-dev
11 | ```
12 |
13 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
14 |
15 | ```js
16 | grunt.loadNpmTasks('grunt-umbraco-package');
17 | ```
18 |
19 |
20 | ## Usage Example
21 |
22 | ```js
23 | grunt.initConfig({
24 | pkg: grunt.file.readJSON('package.json'),
25 | umbracoPackage: {
26 | dist: {
27 | src: 'dist', // Path to a folder containing the files to be packaged
28 | dest: 'pkg', // Path to a folder to create the package file
29 | options: { // Options for the package.xml manifest
30 | name: 'My Awesome Package',
31 | version: '0.0.1',
32 | url: 'http://our.umbraco.org/projects/developer-tools/my-awesome-package',
33 | license: 'MIT',
34 | licenseUrl: 'https://opensource.org/licenses/MIT',
35 | author: 'Benetton Concubine',
36 | authorUrl: 'http://our.umbraco.org/member/1234',
37 | readme: 'Please read this!'
38 | }
39 | }
40 | }
41 | });
42 | ```
43 |
44 | ## Options
45 | ### Files
46 | #### src
47 | **type:** string | **required**
48 | The path to the folder containing the files to be packaged. Files should be in the desired structure to install on the target Umbraco site.
49 |
50 | #### dest
51 | **type:** string | **required**
52 | The directory path to create the generated package file.
53 |
54 | ### Manifest Options
55 | #### name
56 | **type:** string | **required**
57 | The name of your package. Used in the package manifest and to generate the package file name.
58 |
59 | #### version
60 | **type:** string | **required**
61 | The version number of your package. Used in the package manifest and to generate the package file name.
62 |
63 | #### url
64 | **type:** string | **required**
65 | The URL of your package, for the package manifest.
66 |
67 | #### license
68 | **type:** string | **required**
69 | The name of your license (ex: "MIT"), for the package manifest
70 |
71 | #### licenseUrl
72 | **type:** string | **required**
73 | The URL to your license details, for the package manifest.
74 |
75 | #### author
76 | **type:** string | **required**
77 | The name of the package author, for the package manifest.
78 |
79 | #### authorUrl
80 | **type:** string | **required**
81 | The URL of the package author, for the package manifest
82 |
83 | #### manifest
84 | **type:** string | **optional**
85 | Leave empty to generate a `package.xml` manifest for your package automatically, based on the configuration above. Optionally specify a path to an existing `package.xml` to use instead.
86 |
87 | #### readme
88 | **type:** string | **optional**
89 | Contents to use for the `readme` field of the `package.xml` manifest.
90 |
91 | #### outputName
92 | **type:** string | **optional**
93 | Leave empty to have the package file name generated as `{name}_{version}.zip`. Optionally specify a custom name to use here.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-umbraco-package",
3 | "version": "1.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/tomfulton/grunt-umbraco-package.git"
7 | },
8 | "description": "A Grunt task to assist with creating Umbraco packages that can be installed through the Backoffice",
9 | "author": "Tom Fulton",
10 | "license": "MIT",
11 | "dependencies": {
12 | "archiver": "^0.14.3",
13 | "fs-extra": "~0.8.1",
14 | "grunt": "~0.4.2",
15 | "guid": "0.0.12",
16 | "path": "~0.4.9",
17 | "rimraf": "~2.2.6",
18 | "chalk": "^1.0.0",
19 | "js2xmlparser": "https://github.com/tomfulton/node-js2xmlparser/tarball/85ad382d102a9c21c75a39e20017dd5d8e44ace2"
20 | },
21 | "devDependencies": {
22 | "diff": "^2.2.1",
23 | "fs": "0.0.2",
24 | "grunt": "^0.4.5",
25 | "grunt-contrib-clean": "^0.7.0",
26 | "grunt-contrib-nodeunit": "^0.4.1",
27 | "nodeunit": "^0.9.1",
28 | "path": "^0.4.10",
29 | "unzip": "^0.1.11"
30 | },
31 | "scripts": {
32 | "test": "grunt --gruntfile test/Gruntfile.js"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tasks/umbraco_package.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerMultiTask('umbracoPackage', 'Create Umbraco Package', function () {
3 | var done = this.async();
4 | var Guid = require('guid');
5 | var path = require('path');
6 | var rimraf = require('rimraf');
7 | var archiver = require('archiver');
8 | var fs = require('fs');
9 | var fse = require('fs-extra');
10 | var chalk = require('chalk');
11 | var xml = require('js2xmlparser');
12 |
13 | var options = this.options({
14 | minimumUmbracoVersion: '',
15 | files: [],
16 | cwd: '/',
17 | readme: ''
18 | });
19 |
20 | requireOptions(['name', 'version', 'license', 'licenseUrl', 'url', 'author', 'authorUrl'], options);
21 | validateDirectories(this.files, options);
22 |
23 | // Declare the name of the generated ZIP file
24 | var packageFileName = options.outputName ? options.outputName : options.name + '_' + options.version + '.zip';
25 |
26 | // Ensure output directory exists
27 | if (!fs.existsSync(options.outputDir)) {
28 | fs.mkdirSync(options.outputDir);
29 | }
30 |
31 | // Declare the path of the generated ZIP file
32 | var tmpOutput = path.join(options.outputDir, packageFileName);
33 |
34 | // Delete the ZIP file if it already exists (eg. already been generated for same version)
35 | if (fs.existsSync(tmpOutput)) fs.unlinkSync(tmpOutput);
36 |
37 | // Gather files
38 | var filesToPackage = [];
39 | this.files.forEach(function (file) {
40 | file.src.forEach(function (sourceDir) {
41 | var sourceDirFiles = getFilesRecursive(sourceDir);
42 | filesToPackage.push.apply(filesToPackage, sourceDirFiles.map(function (f) {
43 | return {
44 | guid: f.name,
45 | dir: f.dir.replace(sourceDir, ''),
46 | sourceDir: sourceDir,
47 | name: f.name,
48 | ext: f.name.split('.').pop()
49 | };
50 | }));
51 | });
52 | });
53 |
54 | // Avoid duplicate GUIDs
55 | var guids = {};
56 | filesToPackage.forEach(function(file) {
57 | if (guids[file.guid]) {
58 | file.guid = Guid.raw() + '_' + file.guid;
59 | }
60 | guids[file.guid] = true;
61 | });
62 |
63 | // Initialize the archive and it's output stream
64 | var output = fs.createWriteStream(tmpOutput);
65 | var archive = archiver('zip');
66 |
67 | // Listen for when the ZIP is closed
68 | output.on('close', function () {
69 | console.log('Package created at ' + chalk.cyan(tmpOutput) + " (" + chalk.cyan(archive.pointer()).toString() + " bytes)");
70 | done(true);
71 | });
72 |
73 | // Listen for ZIP errors
74 | archive.on('error', function (err) {
75 | throw err;
76 | });
77 |
78 | // Set the output stream of the ZIP
79 | archive.pipe(output);
80 |
81 | if (options.manifest) {
82 |
83 | // Load / transform XML Manifest
84 | options.files = filesToPackage;
85 | var manifest = grunt.file.read(options.manifest);
86 | manifest = grunt.template.process(manifest, { data: options });
87 |
88 | // Append the manifest to the ZIP file
89 | archive.append(manifest, { name:'package.xml' });
90 |
91 | // Append files from the source directory
92 | filesToPackage.forEach(function(file) {
93 |
94 | // Get the original path of the file
95 | var src = path.join(file.sourceDir, file.dir, file.name);
96 |
97 | // Append the file to the ZIP
98 | archive.append(fs.createReadStream(src), { name: file.guid });
99 |
100 | });
101 |
102 | } else {
103 |
104 | // Build the data for the package manifest
105 | var data = {
106 | info: {
107 | package: {
108 | name: options.name,
109 | version: options.version,
110 | license: {
111 | '@': {
112 | url: ''
113 | },
114 | '#': options.license
115 | },
116 | url: options.url,
117 | requirements: {
118 | major: 0,
119 | minor: 0,
120 | patch: 0
121 | }
122 | },
123 | author: {
124 | name: options.author
125 | },
126 | readme: options.readme
127 | },
128 | DocumentTypes: {},
129 | Templates: {},
130 | Stylesheets: {},
131 | Macros: {},
132 | DictionaryItems: {},
133 | Languages: {},
134 | DataTypes: {},
135 | control: {},
136 | Actions: {},
137 | files: {},
138 | };
139 |
140 | // Set optional URLs in the manifest
141 | if (options.licenseUrl) data.info.package.license['@'].url = options.licenseUrl;
142 | if (options.authorUrl) data.info.author['website'] = options.authorUrl;
143 |
144 | // Add files to the ZIP and manifest
145 | if (filesToPackage.length > 0) {
146 | data.files = [];
147 |
148 | filesToPackage.forEach(function(file) {
149 |
150 | // Get the original path of the file
151 | var src = path.join(file.sourceDir, file.dir, file.name);
152 |
153 | // Append the file to the ZIP
154 | archive.append(fs.createReadStream(src), { name: file.guid });
155 |
156 | // Append the file to the manifest
157 | data.files.push({
158 | guid: file.guid,
159 | orgPath: file.dir,
160 | orgName: file.name
161 | });
162 |
163 | });
164 |
165 | }
166 |
167 | // Append the manifest to the ZIP file
168 | archive.append(xml('umbPackage', data, {
169 | arrayMap: {
170 | files: 'file'
171 | },
172 | prettyPrinting: {
173 | enabled: true,
174 | returnString: "\r\n"
175 | }
176 | }), { name:'package.xml' });
177 |
178 | }
179 |
180 | archive.finalize();
181 |
182 | function getFilesRecursive(dir) {
183 | var ret = [];
184 | var files = fs.readdirSync(dir);
185 | for (var i in files) {
186 | if (!files.hasOwnProperty(i)) continue;
187 |
188 | var name = dir + '/' + files[i];
189 | if (fs.statSync(name).isDirectory()) {
190 | ret.push.apply(ret, getFilesRecursive(name));
191 | } else {
192 | ret.push({ dir: dir, name: files[i] });
193 | }
194 | }
195 | return ret;
196 | }
197 |
198 | function requireOptions (opts, options) {
199 | opts.forEach(function (opt) {
200 | if (!options.hasOwnProperty(opt) || options[opt] == null || options[opt].toString().length == 0) {
201 | grunt.fail.warn('Error creating Umbraco Package - required property missing: ' + opt);
202 | return;
203 | }
204 | })
205 | };
206 |
207 | function validateDirectories (files, options) {
208 | if (files.length < 1) {
209 | grunt.fail.warn('Error creating Umbraco Package - no source specified');
210 | return;
211 | }
212 | var src = files[0].src[0];
213 | var dest = files[0].dest;
214 | if (src == null || src.length == 0) {
215 | grunt.fail.warn('Error creating Umbraco Package - no source specified');
216 | return;
217 | }
218 | if (dest == null || dest.length == 0) {
219 | grunt.fail.warn('Error creating Umbraco Package - no source specified');
220 | return;
221 | }
222 | options.sourceDir = src;
223 | options.outputDir = dest;
224 | }
225 |
226 | });
227 | };
--------------------------------------------------------------------------------
/test/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 |
3 | grunt.initConfig({
4 | umbracoPackage: {
5 | example1: {
6 | src: 'fixtures/example',
7 | dest: 'artifacts',
8 | options: {
9 | name: 'TestPackage',
10 | version: '0.0.1',
11 | url: 'http://www.google.com',
12 | license: 'MIT',
13 | licenseUrl: 'http://#',
14 | author: 'John',
15 | authorUrl: 'http://john.com',
16 | readme: 'Hello'
17 | }
18 | },
19 | example2: {
20 | src: 'fixtures/example',
21 | dest: 'artifacts',
22 | options: {
23 | name: 'TestPackage2',
24 | version: '0.0.2',
25 | url: 'http://www.google.com',
26 | license: 'MIT',
27 | licenseUrl: 'http://#',
28 | author: 'John',
29 | authorUrl: 'http://john.com',
30 | manifest: 'fixtures/custom-package-xml/package.xml'
31 | }
32 | }
33 | },
34 | nodeunit: {
35 | all: ['test.js'],
36 | options: {
37 | reporter: 'grunt',
38 | reporterOptions: {
39 | output: 'outputdir'
40 | }
41 | }
42 | },
43 | clean: {
44 | test: ['artifacts/*.*']
45 | }
46 | });
47 |
48 | grunt.loadTasks('../tasks');
49 | grunt.loadTasks('../node_modules/grunt-contrib-nodeunit/tasks');
50 | grunt.loadTasks('../node_modules/grunt-contrib-clean/tasks');
51 |
52 | grunt.registerTask('setup', ['umbracoPackage']);
53 | grunt.registerTask('teardown', ['clean']);
54 |
55 | grunt.registerTask('default', ['setup', 'nodeunit', 'teardown']);
56 | }
--------------------------------------------------------------------------------
/test/expected/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | TestPackage
6 | 0.0.1
7 | MIT
8 | http://www.google.com
9 |
10 | 0
11 | 0
12 | 0
13 |
14 |
15 |
16 | John
17 | http://john.com
18 |
19 | Hello
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | package.js
33 | /App_Plugins/TestPackage
34 | package.js
35 |
36 |
37 | package.manifest
38 | /App_Plugins/TestPackage
39 | package.manifest
40 |
41 |
42 | script.js
43 | /scripts
44 | script.js
45 |
46 |
47 |
--------------------------------------------------------------------------------
/test/files/aa332ab8-9109-2302-d683-9f06185656f1/aa332ab8-9109-2302-d683-9f06185656f1/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Archetype
6 | 1.0.0
7 | MIT
8 | https://github.com/imulus/Archetype
9 |
10 | 0
11 | 0
12 | 0
13 |
14 |
15 |
16 | Imulus
17 | http://imulus.com/
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/test/files/beec5ff0-a9a5-04ad-19b9-5cf487f240cb/beec5ff0-a9a5-04ad-19b9-5cf487f240cb/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Archetype
6 | 1.0.0
7 | MIT
8 | https://github.com/imulus/Archetype
9 |
10 | 0
11 | 0
12 | 0
13 |
14 |
15 |
16 | Imulus
17 | http://imulus.com/
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/test/files/f7770bbb-9a09-9b66-caf0-b0e79b9321a7/f7770bbb-9a09-9b66-caf0-b0e79b9321a7/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Archetype
6 | 1.0.0
7 | MIT
8 | https://github.com/imulus/Archetype
9 |
10 | 0
11 | 0
12 | 0
13 |
14 |
15 |
16 | Imulus
17 | http://imulus.com/
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/test/fixtures/custom-package-xml/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= name %>
6 | <%= version %>
7 | <%= license %>
8 | <%= url %>
9 |
10 | 0
11 | 0
12 | 0
13 |
14 |
15 |
16 | <%= author %>
17 | <%= authorUrl %>
18 |
19 | ]]>
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | <% files.forEach(function(file) { %>
32 |
33 | <%= file.guid %>
34 | <%= file.dir %>
35 | <%= file.name %>
36 |
37 | <% }); %>
38 |
39 |
--------------------------------------------------------------------------------
/test/fixtures/example/App_Plugins/TestPackage/package.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomfulton/grunt-umbraco-package/d1dc9823042d63f35eb40869b4a45d7942cdebd1/test/fixtures/example/App_Plugins/TestPackage/package.js
--------------------------------------------------------------------------------
/test/fixtures/example/App_Plugins/TestPackage/package.manifest:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomfulton/grunt-umbraco-package/d1dc9823042d63f35eb40869b4a45d7942cdebd1/test/fixtures/example/App_Plugins/TestPackage/package.manifest
--------------------------------------------------------------------------------
/test/fixtures/example/scripts/script.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomfulton/grunt-umbraco-package/d1dc9823042d63f35eb40869b4a45d7942cdebd1/test/fixtures/example/scripts/script.js
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var JsDiff = require('diff');
3 | var unzip = require('unzip');
4 | var path = require('path');
5 |
6 | module.exports = {
7 | packageCreatedWithCorrectName: function (test) {
8 | try {
9 | var file1 = fs.lstatSync(path.join('artifacts', 'TestPackage_0.0.1.zip'));
10 | var file2 = fs.lstatSync(path.join('artifacts', 'TestPackage2_0.0.2.zip'));
11 |
12 | test.ok(file1.isFile());
13 | test.ok(file2.isFile());
14 | } catch (e) {
15 | test.ok(false);
16 | }
17 | test.done();
18 | },
19 | packageContainsCorrectFiles: function (test) {
20 | var actual = [];
21 | var expected = ['package.manifest', 'package.js', 'script.js', 'package.xml'];
22 |
23 | var parse = unzip.Parse();
24 | fs.createReadStream(path.join('artifacts', 'TestPackage_0.0.1.zip')).pipe(parse);
25 | parse.on('entry', function(entry) {
26 | actual.push(entry.path);
27 | });
28 | parse.on('close', function() {
29 | actual.sort();
30 | expected.sort();
31 | test.deepEqual(actual, expected, 'package zip file should unzip and contain all of the expected files');
32 | test.done();
33 | });
34 | },
35 | packageXmlManifestGenerated: function (test) {
36 | var parse = unzip.Parse();
37 | fs.createReadStream(path.join('artifacts', 'TestPackage_0.0.1.zip')).pipe(parse);
38 | parse.on('entry', function(entry) {
39 | if (entry.path == 'package.xml') {
40 | entry
41 | .pipe(fs.createWriteStream(path.join('artifacts', 'extracted-package-xml.xml')))
42 | .on('close', function() {
43 | var file1Contents = fs.readFileSync(path.join('expected', 'package.xml')).toString();
44 | var file2Contents = fs.readFileSync(path.join('artifacts', 'extracted-package-xml.xml')).toString();
45 | var diff = JsDiff.diffLines(file1Contents, file2Contents, { ignoreWhitespace: true, newlineIsToken: true });
46 |
47 | var anyChanges = false;
48 | diff.forEach(function(part) {
49 | if (part.added || part.removed) {
50 | anyChanges = true;
51 | }
52 | });
53 |
54 | test.ok(!anyChanges);
55 | test.done();
56 | });
57 | }
58 | });
59 | }
60 | };
--------------------------------------------------------------------------------