const fs = require('fs'); const path = require('path'); const archiver = require('archiver'); const fetch = require('node-fetch'); const FormData = require('form-data'); function packDirToZip(srcDir, outPath) { return new Promise((resolve, reject) => { const output = fs.createWriteStream(outPath); const archive = archiver('zip', { zlib: { level: 9 } }); output.on('close', () => resolve({ bytes: archive.pointer(), path: outPath })); archive.on('error', err => reject(err)); archive.pipe(output); archive.directory(srcDir, false); archive.finalize(); }); } async function uploadZip(url, token, zipPath, extraFields = {}) { const form = new FormData(); form.append('file', fs.createReadStream(zipPath)); for (const k of Object.keys(extraFields)) form.append(k, extraFields[k]); const headers = token ? { Authorization: `Bearer ${token}` } : {}; const resp = await fetch(url, { method: 'POST', headers: Object.assign(headers, form.getHeaders()), body: form }); const text = await resp.text(); let json; try { json = JSON.parse(text); } catch (e) { json = { statusText: text }; } return { ok: resp.ok, status: resp.status, body: json }; } async function triggerDeployApi(deployApi, deployToken, payload = {}) { const headers = { 'Content-Type': 'application/json' }; if (deployToken) headers.Authorization = `Bearer ${deployToken}`; const resp = await fetch(deployApi, { method: 'POST', headers, body: JSON.stringify(payload) }); const json = await resp.json().catch(() => null); return { ok: resp.ok, status: resp.status, body: json }; } async function invokeFunction(funcUrl, pushToken, testCid, title = 'CI Test', content = 'hello from backend') { const body = { token: pushToken, push_clientid: testCid, title, content, payload: {} }; const resp = await fetch(funcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); const json = await resp.json().catch(() => null); return { ok: resp.ok, status: resp.status, body: json }; } async function deployCloudFunction(options = {}) { const funcDir = options.funcDir || path.join(__dirname, '..', '..', 'uniCloud-alipay', 'cloudfunctions', 'testUnipush2'); const outDir = path.join(__dirname, '..', 'dist'); if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }); const zipPath = path.join(outDir, path.basename(funcDir) + '.zip'); const result = { packed: null, uploaded: null, deployed: null, invoked: null }; // pack const packRes = await packDirToZip(funcDir, zipPath); result.packed = packRes; // upload if (!options.uploadUrl) return result; const extra = {}; if (options.uniAppId) extra.appId = options.uniAppId; const up = await uploadZip(options.uploadUrl, options.uploadToken, zipPath, extra); result.uploaded = up; // trigger deploy API (optional) if (options.deployApi) { const payload = Object.assign({}, options.deployPayload || {}, { uploadUrl: options.uploadUrl, uploadResponse: up.body }); const dp = await triggerDeployApi(options.deployApi, options.deployToken, payload); result.deployed = dp; } // invoke function for smoke test (optional) if (options.funcInvokeUrl && options.pushToken && options.testCid) { const iv = await invokeFunction(options.funcInvokeUrl, options.pushToken, options.testCid, options.testTitle, options.testContent); result.invoked = iv; } return result; } module.exports = { deployCloudFunction, packDirToZip, uploadZip, triggerDeployApi, invokeFunction };