ci: 添加小程序自动部署配置
- 添加 Gitea Actions workflow: miniapp-preview.yml - 添加 CI 脚本: upload-ci.cjs, preview-ci.cjs - 添加版本解析: resolve-version.cjs, resolve-upload-desc.cjs - 添加 mini/package.json 用于 miniprogram-ci 依赖
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
name: Publish Mini Program Dev Version
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "mini/**"
|
||||||
|
- ".gitea/workflows/miniapp-preview.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: new-pet-node
|
||||||
|
steps:
|
||||||
|
- uses: https://gitea.neatcn.com/gouki/action-checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 20
|
||||||
|
- name: Verify Node runtime
|
||||||
|
run: node --version
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: mini
|
||||||
|
run: npm ci
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: mini
|
||||||
|
run: npm test -- --runInBand
|
||||||
|
- name: Configure production API and app version
|
||||||
|
working-directory: mini
|
||||||
|
env:
|
||||||
|
MINIAPP_BUILD_NUMBER: ${{ gitea.run_number }}
|
||||||
|
MINIAPP_VERSION_OVERRIDE: ${{ vars.MINIAPP_VERSION_OVERRIDE }}
|
||||||
|
run: |
|
||||||
|
test -n "$MINIAPP_BUILD_NUMBER"
|
||||||
|
VERSION="$(node -e 'const {resolveVersion}=require("./ci/resolve-version.cjs"); process.stdout.write(resolveVersion(process.cwd()))')"
|
||||||
|
test -n "$VERSION"
|
||||||
|
mkdir -p ci-artifacts
|
||||||
|
printf '%s\n' "$VERSION" > ci-artifacts/resolved-version.txt
|
||||||
|
echo "Resolved Mini Program version for build+upload: $VERSION"
|
||||||
|
- name: Materialize the upload key
|
||||||
|
env:
|
||||||
|
WECHAT_CI_PRIVATE_KEY: ${{ secrets.WECHAT_CI_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
test -n "$WECHAT_CI_PRIVATE_KEY"
|
||||||
|
umask 077
|
||||||
|
printf '%s' "$WECHAT_CI_PRIVATE_KEY" > "$RUNNER_TEMP/wechat-ci.key"
|
||||||
|
- name: Upload WeChat development version
|
||||||
|
working-directory: mini
|
||||||
|
env:
|
||||||
|
MINIAPP_APPID: ${{ vars.MINIAPP_APPID }}
|
||||||
|
MINIAPP_ROBOT: ${{ vars.MINIAPP_ROBOT }}
|
||||||
|
MINIAPP_BUILD_NUMBER: ${{ gitea.run_number }}
|
||||||
|
MINIAPP_VERSION_OVERRIDE: ${{ vars.MINIAPP_VERSION_OVERRIDE }}
|
||||||
|
WECHAT_CI_PRIVATE_KEY_PATH: ${{ runner.temp }}/wechat-ci.key
|
||||||
|
MINIAPP_UPLOAD_RESULT: ${{ gitea.workspace }}/mini/ci-artifacts/upload-result.json
|
||||||
|
MINIAPP_VERSION_LABEL: ${{ gitea.sha }}
|
||||||
|
MINIAPP_UPLOAD_DESC_ITEMS: "3"
|
||||||
|
MINIAPP_UPLOAD_DESC_MAX: "100"
|
||||||
|
run: |
|
||||||
|
test -n "$MINIAPP_APPID"
|
||||||
|
test -n "$MINIAPP_BUILD_NUMBER"
|
||||||
|
test -s ci-artifacts/resolved-version.txt
|
||||||
|
RESOLVED_VERSION="$(tr -d '\n' < ci-artifacts/resolved-version.txt)"
|
||||||
|
export MINIAPP_VERSION_OVERRIDE="$RESOLVED_VERSION"
|
||||||
|
mkdir -p ci-artifacts
|
||||||
|
node -e 'const c=require("./project.config.json"); if(c.appid!==process.env.MINIAPP_APPID){console.error("MINIAPP_APPID mismatch with project.config.json", process.env.MINIAPP_APPID, c.appid); process.exit(1)}'
|
||||||
|
node -e 'const {resolveVersion}=require("./ci/resolve-version.cjs"); console.log("Resolved Mini Program version:", resolveVersion(process.cwd()))'
|
||||||
|
node -e 'const {resolveUploadDesc}=require("./ci/resolve-upload-desc.cjs"); console.log("Resolved upload remark:", resolveUploadDesc({repoRoot:require("path").resolve(".."), versionLabel:process.env.MINIAPP_VERSION_LABEL}))'
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
key_path = Path(os.environ["WECHAT_CI_PRIVATE_KEY_PATH"])
|
||||||
|
text = key_path.read_text()
|
||||||
|
if "\\n" in text and "BEGIN" in text:
|
||||||
|
text = text.replace("\\n", "\n")
|
||||||
|
text = text.replace("\r\n", "\n").strip() + "\n"
|
||||||
|
key_path.write_text(text)
|
||||||
|
content = key_path.read_text()
|
||||||
|
assert "BEGIN" in content and "PRIVATE KEY" in content, "WECHAT_CI_PRIVATE_KEY is not a PEM private key"
|
||||||
|
print("private_key_lines=", len(content.splitlines()))
|
||||||
|
PY
|
||||||
|
node ci/upload-ci.cjs
|
||||||
|
test -s ci-artifacts/upload-result.json
|
||||||
|
cat ci-artifacts/upload-result.json
|
||||||
|
- name: Persist upload result on runner host
|
||||||
|
run: |
|
||||||
|
test -s mini/ci-artifacts/upload-result.json
|
||||||
|
test -d /ci-artifacts
|
||||||
|
cp mini/ci-artifacts/upload-result.json "/ci-artifacts/miniapp-upload-${{ gitea.sha }}.json"
|
||||||
|
cp mini/ci-artifacts/upload-result.json /ci-artifacts/miniapp-upload-latest.json
|
||||||
|
ls -la /ci-artifacts/miniapp-upload-latest.json
|
||||||
|
echo "Upload result saved on runner host: /ci-artifacts/miniapp-upload-latest.json"
|
||||||
|
- name: Remove temporary credentials
|
||||||
|
if: always()
|
||||||
|
run: rm -f "$RUNNER_TEMP/wechat-ci.key"
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const process = require("node:process");
|
||||||
|
const ci = require("miniprogram-ci");
|
||||||
|
|
||||||
|
function requireEnvironment(name) {
|
||||||
|
const value = process.env[name];
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`${name} is required.`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const projectPath = process.cwd();
|
||||||
|
const privateKeyPath = path.resolve(
|
||||||
|
requireEnvironment("WECHAT_CI_PRIVATE_KEY_PATH"),
|
||||||
|
);
|
||||||
|
const qrcodeOutputDest = path.resolve(
|
||||||
|
requireEnvironment("MINIAPP_QR_OUTPUT"),
|
||||||
|
);
|
||||||
|
const appid = requireEnvironment("MINIAPP_APPID");
|
||||||
|
const robot = Number.parseInt(process.env.MINIAPP_ROBOT ?? "1", 10);
|
||||||
|
const versionLabel = requireEnvironment("MINIAPP_VERSION_LABEL");
|
||||||
|
|
||||||
|
if (!fs.existsSync(path.join(projectPath, "project.config.json"))) {
|
||||||
|
throw new Error("The working directory must contain project.config.json.");
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(privateKeyPath)) {
|
||||||
|
throw new Error("The WeChat code-upload key file does not exist.");
|
||||||
|
}
|
||||||
|
if (!Number.isInteger(robot) || robot < 1 || robot > 30) {
|
||||||
|
throw new Error("MINIAPP_ROBOT must be an integer from 1 to 30.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = new ci.Project({
|
||||||
|
appid,
|
||||||
|
type: "miniProgram",
|
||||||
|
projectPath,
|
||||||
|
privateKeyPath,
|
||||||
|
ignores: ["node_modules/**/*", ".git/**/*"],
|
||||||
|
});
|
||||||
|
|
||||||
|
await ci.preview({
|
||||||
|
project,
|
||||||
|
desc: `Automated preview ${versionLabel}`.slice(0, 50),
|
||||||
|
robot,
|
||||||
|
setting: {
|
||||||
|
useProjectConfig: true,
|
||||||
|
es6: true,
|
||||||
|
es7: true,
|
||||||
|
enhance: true,
|
||||||
|
minify: true,
|
||||||
|
autoPrefixWXSS: true,
|
||||||
|
},
|
||||||
|
qrcodeFormat: "image",
|
||||||
|
qrcodeOutputDest,
|
||||||
|
onProgressUpdate: (progress) => {
|
||||||
|
if (typeof progress === "string") {
|
||||||
|
console.log(progress);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Preview QR code created: ${qrcodeOutputDest}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(`Mini Program preview failed: ${error.message}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/**
|
||||||
|
* Build the WeChat upload "项目备注" from recent change summaries.
|
||||||
|
* Prefer recent git commit subjects (Chinese commit messages in this repo);
|
||||||
|
* fall back to the latest CHANGELOG bullets when git history is unavailable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const { execFileSync } = require("node:child_process");
|
||||||
|
|
||||||
|
const DEFAULT_MAX_LENGTH = 100;
|
||||||
|
|
||||||
|
function cleanCommitSubject(subject) {
|
||||||
|
return String(subject || "")
|
||||||
|
.trim()
|
||||||
|
.replace(
|
||||||
|
/^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\([^)]*\))?:\s*/i,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncateDesc(text, maxLength = DEFAULT_MAX_LENGTH) {
|
||||||
|
const value = String(text || "").trim();
|
||||||
|
if (!value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if ([...value].length <= maxLength) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const chars = [...value].slice(0, Math.max(0, maxLength - 1));
|
||||||
|
return `${chars.join("")}…`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectRecentCommitSubjects(repoRoot, limit = 5) {
|
||||||
|
try {
|
||||||
|
const output = execFileSync(
|
||||||
|
"git",
|
||||||
|
[
|
||||||
|
"log",
|
||||||
|
`-${Math.max(1, limit * 3)}`,
|
||||||
|
"--pretty=%s",
|
||||||
|
"--",
|
||||||
|
"mini/",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"Features.md",
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cwd: repoRoot,
|
||||||
|
encoding: "utf8",
|
||||||
|
stdio: ["ignore", "pipe", "ignore"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const subjects = [];
|
||||||
|
const seen = new Set();
|
||||||
|
for (const line of output.split("\n")) {
|
||||||
|
const cleaned = cleanCommitSubject(line);
|
||||||
|
if (!cleaned || seen.has(cleaned)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip pure docs/chore noise when better subjects exist.
|
||||||
|
if (/^(说明|文档|记录)/.test(cleaned) && subjects.length > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen.add(cleaned);
|
||||||
|
subjects.push(cleaned);
|
||||||
|
if (subjects.length >= limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subjects;
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectRecentChangelogBullets(repoRoot, limit = 5) {
|
||||||
|
const changelogPath = path.join(repoRoot, "CHANGELOG.md");
|
||||||
|
if (!fs.existsSync(changelogPath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = fs.readFileSync(changelogPath, "utf8").split(/\r?\n/);
|
||||||
|
const bullets = [];
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(/^\s*-\s+(.+)\s*$/);
|
||||||
|
if (!match) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const bullet = match[1].replace(/\s+/g, " ").trim();
|
||||||
|
if (!bullet || seen.has(bullet)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen.add(bullet);
|
||||||
|
bullets.push(bullet);
|
||||||
|
if (bullets.length >= limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bullets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveUploadDesc({
|
||||||
|
repoRoot,
|
||||||
|
versionLabel = "",
|
||||||
|
maxLength = DEFAULT_MAX_LENGTH,
|
||||||
|
maxItems = 3,
|
||||||
|
} = {}) {
|
||||||
|
const root = repoRoot || process.cwd();
|
||||||
|
const fromGit = collectRecentCommitSubjects(root, maxItems);
|
||||||
|
const fromChangelog = collectRecentChangelogBullets(root, maxItems);
|
||||||
|
const parts = fromGit.length > 0 ? fromGit : fromChangelog;
|
||||||
|
|
||||||
|
if (parts.length === 0) {
|
||||||
|
const shortSha = String(versionLabel || "")
|
||||||
|
.trim()
|
||||||
|
.slice(0, 7);
|
||||||
|
return truncateDesc(
|
||||||
|
shortSha ? `CI upload ${shortSha}` : "CI upload",
|
||||||
|
maxLength,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fit as many summaries as possible within the WeChat remark limit.
|
||||||
|
const selected = [];
|
||||||
|
for (const part of parts) {
|
||||||
|
const candidate = [...selected, part].join(";");
|
||||||
|
if ([...candidate].length > maxLength) {
|
||||||
|
if (selected.length === 0) {
|
||||||
|
return truncateDesc(part, maxLength);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
selected.push(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return truncateDesc(selected.join(";"), maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
cleanCommitSubject,
|
||||||
|
collectRecentChangelogBullets,
|
||||||
|
collectRecentCommitSubjects,
|
||||||
|
resolveUploadDesc,
|
||||||
|
truncateDesc,
|
||||||
|
};
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Resolve the WeChat Mini Program upload version.
|
||||||
|
*
|
||||||
|
* WeChat requires x.y.z with each segment in 0..999.
|
||||||
|
* Server and miniapp versions are independent on purpose.
|
||||||
|
*
|
||||||
|
* Priority:
|
||||||
|
* 1. MINIAPP_VERSION_OVERRIDE — full manual version (rare / release pinning)
|
||||||
|
* 2. MINIAPP_BUILD_NUMBER — auto version from CI run number
|
||||||
|
* 3. package.json version — local / fallback
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
|
||||||
|
function readPackageVersion(projectPath) {
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
fs.readFileSync(path.join(projectPath, "package.json"), "utf8"),
|
||||||
|
);
|
||||||
|
if (!packageJson.version) {
|
||||||
|
throw new Error("package.json version is missing.");
|
||||||
|
}
|
||||||
|
return String(packageJson.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSemverParts(version) {
|
||||||
|
const parts = String(version)
|
||||||
|
.trim()
|
||||||
|
.split(".")
|
||||||
|
.map((part) => Number.parseInt(part, 10));
|
||||||
|
if (
|
||||||
|
parts.length < 1 ||
|
||||||
|
parts.some((part) => !Number.isInteger(part) || part < 0 || part > 999)
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid version "${version}". WeChat requires x.y.z with each segment 0-999.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
major: parts[0] ?? 0,
|
||||||
|
minor: parts[1] ?? 0,
|
||||||
|
patch: parts[2] ?? 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a monotonic CI build number into WeChat x.y.z.
|
||||||
|
* Keeps package.json major; puts build into minor.patch with base 100.
|
||||||
|
* Examples (major=1): build 99 → 1.0.99, build 100 → 1.1.0, build 101 → 1.1.1
|
||||||
|
*/
|
||||||
|
function versionFromBuildNumber(major, buildNumber) {
|
||||||
|
if (!Number.isInteger(buildNumber) || buildNumber < 1) {
|
||||||
|
throw new Error("MINIAPP_BUILD_NUMBER must be a positive integer.");
|
||||||
|
}
|
||||||
|
if (!Number.isInteger(major) || major < 0 || major > 999) {
|
||||||
|
throw new Error("package.json major version must be an integer 0-999.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const minor = Math.floor(buildNumber / 100) % 1000;
|
||||||
|
const patch = buildNumber % 100;
|
||||||
|
return `${major}.${minor}.${patch}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {Record<string, string | undefined>} [env] */
|
||||||
|
function resolveVersion(projectPath, env = process.env) {
|
||||||
|
const override = (env.MINIAPP_VERSION_OVERRIDE || "").trim();
|
||||||
|
if (override) {
|
||||||
|
parseSemverParts(override);
|
||||||
|
return override;
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageVersion = readPackageVersion(projectPath);
|
||||||
|
const { major } = parseSemverParts(packageVersion);
|
||||||
|
|
||||||
|
const buildRaw = (env.MINIAPP_BUILD_NUMBER || "").trim();
|
||||||
|
if (buildRaw) {
|
||||||
|
const buildNumber = Number.parseInt(buildRaw, 10);
|
||||||
|
return versionFromBuildNumber(major, buildNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy fixed override — prefer not to use; keeps version stuck across uploads.
|
||||||
|
const legacy = (env.MINIAPP_VERSION || "").trim();
|
||||||
|
if (legacy) {
|
||||||
|
parseSemverParts(legacy);
|
||||||
|
return legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packageVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parseSemverParts,
|
||||||
|
resolveVersion,
|
||||||
|
versionFromBuildNumber,
|
||||||
|
};
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const process = require("node:process");
|
||||||
|
const ci = require("miniprogram-ci");
|
||||||
|
const { resolveVersion } = require("./resolve-version.cjs");
|
||||||
|
const { resolveUploadDesc } = require("./resolve-upload-desc.cjs");
|
||||||
|
|
||||||
|
function requireEnvironment(name) {
|
||||||
|
const value = process.env[name];
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`${name} is required.`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const projectPath = process.cwd();
|
||||||
|
const repoRoot = path.resolve(projectPath, "..");
|
||||||
|
const privateKeyPath = path.resolve(
|
||||||
|
requireEnvironment("WECHAT_CI_PRIVATE_KEY_PATH"),
|
||||||
|
);
|
||||||
|
const appid = requireEnvironment("MINIAPP_APPID");
|
||||||
|
const robot = Number.parseInt(process.env.MINIAPP_ROBOT ?? "1", 10);
|
||||||
|
const versionLabel = requireEnvironment("MINIAPP_VERSION_LABEL");
|
||||||
|
const version = resolveVersion(projectPath);
|
||||||
|
const resultPath = path.resolve(
|
||||||
|
process.env.MINIAPP_UPLOAD_RESULT ||
|
||||||
|
path.join(projectPath, "ci-artifacts", "upload-result.json"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!fs.existsSync(path.join(projectPath, "project.config.json"))) {
|
||||||
|
throw new Error("The working directory must contain project.config.json.");
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(privateKeyPath)) {
|
||||||
|
throw new Error("The WeChat code-upload key file does not exist.");
|
||||||
|
}
|
||||||
|
if (!Number.isInteger(robot) || robot < 1 || robot > 30) {
|
||||||
|
throw new Error("MINIAPP_ROBOT must be an integer from 1 to 30.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = new ci.Project({
|
||||||
|
appid,
|
||||||
|
type: "miniProgram",
|
||||||
|
projectPath,
|
||||||
|
privateKeyPath,
|
||||||
|
ignores: ["node_modules/**/*", ".git/**/*", "ci-artifacts/**/*"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const desc = resolveUploadDesc({
|
||||||
|
repoRoot,
|
||||||
|
versionLabel,
|
||||||
|
maxLength: Number.parseInt(process.env.MINIAPP_UPLOAD_DESC_MAX || "100", 10),
|
||||||
|
maxItems: Number.parseInt(process.env.MINIAPP_UPLOAD_DESC_ITEMS || "3", 10),
|
||||||
|
});
|
||||||
|
console.log(`Uploading Mini Program version=${version} robot=${robot}`);
|
||||||
|
console.log(`Upload remark: ${desc}`);
|
||||||
|
|
||||||
|
const uploadResult = await ci.upload({
|
||||||
|
project,
|
||||||
|
version,
|
||||||
|
desc,
|
||||||
|
robot,
|
||||||
|
setting: {
|
||||||
|
useProjectConfig: true,
|
||||||
|
es6: true,
|
||||||
|
es7: true,
|
||||||
|
enhance: true,
|
||||||
|
minify: true,
|
||||||
|
autoPrefixWXSS: true,
|
||||||
|
},
|
||||||
|
onProgressUpdate: (progress) => {
|
||||||
|
if (typeof progress === "string") {
|
||||||
|
console.log(progress);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.mkdirSync(path.dirname(resultPath), { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
resultPath,
|
||||||
|
`${JSON.stringify(
|
||||||
|
{
|
||||||
|
appid,
|
||||||
|
version,
|
||||||
|
robot,
|
||||||
|
desc,
|
||||||
|
versionLabel,
|
||||||
|
uploadedAt: new Date().toISOString(),
|
||||||
|
result: uploadResult,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\n`,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Upload succeeded: version ${version}`);
|
||||||
|
console.log(`Upload result saved: ${resultPath}`);
|
||||||
|
console.log(
|
||||||
|
"If this robot upload is already selected as 体验版 in WeChat admin, it becomes the new experience version automatically. Otherwise open 版本管理 → 开发版本 → 选为体验版 once.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(`Mini Program upload failed: ${error.message}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "lunar-mini",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "祈福小助手 - 万年历微信小程序",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"No tests yet\" && exit 0",
|
||||||
|
"upload": "node ci/upload-ci.cjs",
|
||||||
|
"preview": "node ci/preview-ci.cjs"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"miniprogram-ci": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user