UNPKG

6.65 kBJavaScriptView Raw
1const findCacheDir = require('find-cache-dir');
2const Git = require('./git.js');
3const filenamify = require('filenamify');
4const copy = require('./util.js').copy;
5const getUser = require('./util.js').getUser;
6const fs = require('fs-extra');
7const globby = require('globby');
8const path = require('path');
9const util = require('util');
10
11const log = util.debuglog('gh-pages');
12
13/**
14 * Get the cache directory.
15 * @param {string} [optPath] Optional path.
16 * @return {string} The full path to the cache directory.
17 */
18function getCacheDir(optPath) {
19 const dir = findCacheDir({name: 'gh-pages'});
20 if (!optPath) {
21 return dir;
22 }
23
24 return path.join(dir, filenamify(optPath));
25}
26exports.getCacheDir = getCacheDir;
27
28function getRepo(options) {
29 if (options.repo) {
30 return Promise.resolve(options.repo);
31 } else {
32 const git = new Git(process.cwd(), options.git);
33 return git.getRemoteUrl(options.remote);
34 }
35}
36
37exports.defaults = {
38 dest: '.',
39 add: false,
40 git: 'git',
41 depth: 1,
42 dotfiles: false,
43 branch: 'gh-pages',
44 remote: 'origin',
45 src: '**/*',
46 remove: '.',
47 push: true,
48 history: true,
49 message: 'Updates',
50 silent: false,
51};
52
53/**
54 * Push a git branch to a remote (pushes gh-pages by default).
55 * @param {string} basePath The base path.
56 * @param {object} config Publish options.
57 * @param {Function} callback Callback.
58 * @return {Promise} A promise.
59 */
60exports.publish = function publish(basePath, config, callback) {
61 if (typeof config === 'function') {
62 callback = config;
63 config = {};
64 }
65
66 const options = Object.assign({}, exports.defaults, config);
67
68 // For backward compatibility before fixing #334
69 if (options.only) {
70 options.remove = options.only;
71 }
72
73 if (!callback) {
74 callback = function (err) {
75 if (err) {
76 log(err.message);
77 }
78 };
79 }
80
81 function done(err) {
82 try {
83 callback(err);
84 } catch (err2) {
85 log('Publish callback threw: %s', err2.message);
86 }
87 }
88
89 try {
90 if (!fs.statSync(basePath).isDirectory()) {
91 const err = new Error('The "base" option must be an existing directory');
92 done(err);
93 return Promise.reject(err);
94 }
95 } catch (err) {
96 done(err);
97 return Promise.reject(err);
98 }
99
100 const files = globby
101 .sync(options.src, {
102 cwd: basePath,
103 dot: options.dotfiles,
104 })
105 .filter((file) => {
106 return !fs.statSync(path.join(basePath, file)).isDirectory();
107 });
108
109 if (!Array.isArray(files) || files.length === 0) {
110 done(
111 new Error('The pattern in the "src" property didn\'t match any files.')
112 );
113 return;
114 }
115
116 let repoUrl;
117 let userPromise;
118 if (options.user) {
119 userPromise = Promise.resolve(options.user);
120 } else {
121 userPromise = getUser();
122 }
123 return userPromise.then((user) =>
124 getRepo(options)
125 .then((repo) => {
126 repoUrl = repo;
127 const clone = getCacheDir(repo);
128 log('Cloning %s into %s', repo, clone);
129 return Git.clone(repo, clone, options.branch, options);
130 })
131 .then((git) => {
132 return git.getRemoteUrl(options.remote).then((url) => {
133 if (url !== repoUrl) {
134 const message =
135 'Remote url mismatch. Got "' +
136 url +
137 '" ' +
138 'but expected "' +
139 repoUrl +
140 '" in ' +
141 git.cwd +
142 '. Try running the `gh-pages-clean` script first.';
143 throw new Error(message);
144 }
145 return git;
146 });
147 })
148 .then((git) => {
149 // only required if someone mucks with the checkout between builds
150 log('Cleaning');
151 return git.clean();
152 })
153 .then((git) => {
154 log('Fetching %s', options.remote);
155 return git.fetch(options.remote);
156 })
157 .then((git) => {
158 log('Checking out %s/%s ', options.remote, options.branch);
159 return git.checkout(options.remote, options.branch);
160 })
161 .then((git) => {
162 if (!options.history) {
163 return git.deleteRef(options.branch);
164 } else {
165 return git;
166 }
167 })
168 .then((git) => {
169 if (options.add) {
170 return git;
171 }
172
173 log('Removing files');
174 const files = globby
175 .sync(options.remove, {
176 cwd: path.join(git.cwd, options.dest),
177 })
178 .map((file) => path.join(options.dest, file));
179 if (files.length > 0) {
180 return git.rm(files);
181 } else {
182 return git;
183 }
184 })
185 .then((git) => {
186 if (options.nojekyll) {
187 log('Creating .nojekyll');
188 fs.createFileSync(path.join(git.cwd, '.nojekyll'));
189 }
190 if (options.cname) {
191 log('Creating CNAME for %s', options.cname);
192 fs.writeFileSync(path.join(git.cwd, 'CNAME'), options.cname);
193 }
194 log('Copying files');
195 return copy(files, basePath, path.join(git.cwd, options.dest)).then(
196 function () {
197 return git;
198 }
199 );
200 })
201 .then((git) => {
202 return Promise.resolve(
203 options.beforeAdd && options.beforeAdd(git)
204 ).then(() => git);
205 })
206 .then((git) => {
207 log('Adding all');
208 return git.add('.');
209 })
210 .then((git) => {
211 if (!user) {
212 return git;
213 }
214 return git.exec('config', 'user.email', user.email).then(() => {
215 if (!user.name) {
216 return git;
217 }
218 return git.exec('config', 'user.name', user.name);
219 });
220 })
221 .then((git) => {
222 log('Committing');
223 return git.commit(options.message);
224 })
225 .then((git) => {
226 if (options.tag) {
227 log('Tagging');
228 return git.tag(options.tag).catch((error) => {
229 // tagging failed probably because this tag alredy exists
230 log(error);
231 log('Tagging failed, continuing');
232 return git;
233 });
234 } else {
235 return git;
236 }
237 })
238 .then((git) => {
239 if (options.push) {
240 log('Pushing');
241 return git.push(options.remote, options.branch, !options.history);
242 } else {
243 return git;
244 }
245 })
246 .then(
247 () => done(),
248 (error) => {
249 if (options.silent) {
250 error = new Error(
251 'Unspecified error (run without silent option for detail)'
252 );
253 }
254 done(error);
255 }
256 )
257 );
258};
259
260/**
261 * Clean the cache directory.
262 */
263exports.clean = function clean() {
264 fs.removeSync(getCacheDir());
265};