@myna-sh/cli 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +307 -219
- package/dist/main.js.map +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -90,9 +90,9 @@ function buildQuery(query) {
|
|
|
90
90
|
return qs ? `?${qs}` : "";
|
|
91
91
|
}
|
|
92
92
|
function sleep(ms, signal) {
|
|
93
|
-
return new Promise((
|
|
93
|
+
return new Promise((resolve4, reject) => {
|
|
94
94
|
if (signal?.aborted) return reject(signal.reason ?? new Error("Aborted"));
|
|
95
|
-
const timer = setTimeout(
|
|
95
|
+
const timer = setTimeout(resolve4, ms);
|
|
96
96
|
signal?.addEventListener(
|
|
97
97
|
"abort",
|
|
98
98
|
() => {
|
|
@@ -1801,9 +1801,22 @@ function branchForContent(contents) {
|
|
|
1801
1801
|
const digest = createHash2("sha256").update(contents.join("\0")).digest("hex").slice(0, 8);
|
|
1802
1802
|
return `myna/schema-${digest}`;
|
|
1803
1803
|
}
|
|
1804
|
-
function
|
|
1805
|
-
|
|
1806
|
-
|
|
1804
|
+
function branchExists(cwd, branch) {
|
|
1805
|
+
try {
|
|
1806
|
+
execFileSync2("git", ["rev-parse", "--verify", `refs/heads/${branch}`], { cwd, stdio: "ignore" });
|
|
1807
|
+
return true;
|
|
1808
|
+
} catch {
|
|
1809
|
+
}
|
|
1810
|
+
try {
|
|
1811
|
+
const out = execFileSync2("git", ["ls-remote", "--heads", "origin", branch], {
|
|
1812
|
+
cwd,
|
|
1813
|
+
encoding: "utf8",
|
|
1814
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1815
|
+
});
|
|
1816
|
+
return out.trim().length > 0;
|
|
1817
|
+
} catch {
|
|
1818
|
+
return false;
|
|
1819
|
+
}
|
|
1807
1820
|
}
|
|
1808
1821
|
function openPullRequest(input) {
|
|
1809
1822
|
if (!available("git")) throw new CliError("git is required to open a pull request.");
|
|
@@ -1817,18 +1830,9 @@ function openPullRequest(input) {
|
|
|
1817
1830
|
if (base === "HEAD") {
|
|
1818
1831
|
throw new CliError("HEAD is detached; pass --base to say which branch to open the pull request against.");
|
|
1819
1832
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
cwd: input.cwd,
|
|
1824
|
-
stdio: "ignore"
|
|
1825
|
-
});
|
|
1826
|
-
return true;
|
|
1827
|
-
} catch {
|
|
1828
|
-
return false;
|
|
1829
|
-
}
|
|
1830
|
-
})();
|
|
1831
|
-
if (exists) return { opened: false, branch: input.branch, base, url: null, reason: "branch-exists" };
|
|
1833
|
+
if (branchExists(input.cwd, input.branch)) {
|
|
1834
|
+
return { opened: false, branch: input.branch, base, url: null, reason: "branch-exists" };
|
|
1835
|
+
}
|
|
1832
1836
|
git(["checkout", "-b", input.branch], input.cwd);
|
|
1833
1837
|
let pushed = false;
|
|
1834
1838
|
try {
|
|
@@ -1855,10 +1859,32 @@ function dirtyFiles(cwd, paths) {
|
|
|
1855
1859
|
return run("git", ["status", "--porcelain", "--", ...paths], cwd).split("\n").filter(Boolean).map((line) => line.slice(3).trim());
|
|
1856
1860
|
}
|
|
1857
1861
|
function repositoryRoot(cwd) {
|
|
1858
|
-
|
|
1862
|
+
try {
|
|
1863
|
+
return execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
1864
|
+
cwd,
|
|
1865
|
+
encoding: "utf8",
|
|
1866
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1867
|
+
}).trim();
|
|
1868
|
+
} catch {
|
|
1869
|
+
return void 0;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
function trackedLockfiles(cwd) {
|
|
1873
|
+
const root = repositoryRoot(cwd);
|
|
1874
|
+
if (!root) return [];
|
|
1875
|
+
try {
|
|
1876
|
+
return execFileSync2("git", ["ls-files", "--full-name", "*myna.lock", "myna.lock"], {
|
|
1877
|
+
cwd: root,
|
|
1878
|
+
encoding: "utf8",
|
|
1879
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1880
|
+
}).split("\n").filter(Boolean).map((f) => join4(root, f));
|
|
1881
|
+
} catch {
|
|
1882
|
+
return [];
|
|
1883
|
+
}
|
|
1859
1884
|
}
|
|
1860
1885
|
function worktreeChanges(cwd) {
|
|
1861
1886
|
const root = repositoryRoot(cwd);
|
|
1887
|
+
if (!root) throw new CliError(`${cwd} is not inside a git repository.`);
|
|
1862
1888
|
return run("git", ["status", "--porcelain"], cwd).split("\n").filter(Boolean).map((line) => ({
|
|
1863
1889
|
file: join4(root, line.slice(3).trim()),
|
|
1864
1890
|
untracked: line.startsWith("??")
|
|
@@ -2898,11 +2924,25 @@ function registerReleases(program) {
|
|
|
2898
2924
|
// src/commands/pull.ts
|
|
2899
2925
|
import { execSync } from "child_process";
|
|
2900
2926
|
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
2901
|
-
import { join as
|
|
2927
|
+
import { join as join8 } from "path";
|
|
2902
2928
|
|
|
2903
2929
|
// ../sdk/dist/lock.js
|
|
2904
2930
|
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2931
|
+
import { dirname as dirname2, join as join7, resolve as resolve3 } from "path";
|
|
2905
2932
|
var LOCKFILE_NAME = "myna.lock";
|
|
2933
|
+
function formatLock(lock) {
|
|
2934
|
+
const ordered = {
|
|
2935
|
+
project: lock.project,
|
|
2936
|
+
release: lock.release,
|
|
2937
|
+
publishedAt: lock.publishedAt
|
|
2938
|
+
};
|
|
2939
|
+
if (lock.title)
|
|
2940
|
+
ordered.title = lock.title;
|
|
2941
|
+
if (lock.apiUrl)
|
|
2942
|
+
ordered.apiUrl = lock.apiUrl;
|
|
2943
|
+
return `${JSON.stringify(ordered, null, 2)}
|
|
2944
|
+
`;
|
|
2945
|
+
}
|
|
2906
2946
|
function parseLock(source, origin = LOCKFILE_NAME) {
|
|
2907
2947
|
let parsed;
|
|
2908
2948
|
try {
|
|
@@ -2925,29 +2965,226 @@ function parseLock(source, origin = LOCKFILE_NAME) {
|
|
|
2925
2965
|
...lock.apiUrl ? { apiUrl: lock.apiUrl } : {}
|
|
2926
2966
|
};
|
|
2927
2967
|
}
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2968
|
+
var LOCKFILE_NAME2 = "myna.lock";
|
|
2969
|
+
function formatLock2(lock) {
|
|
2970
|
+
return formatLock(lock);
|
|
2971
|
+
}
|
|
2972
|
+
function parseLock2(source, origin = LOCKFILE_NAME2) {
|
|
2973
|
+
return parseLock(source, origin);
|
|
2974
|
+
}
|
|
2975
|
+
function findLockfile(startDir = process.cwd()) {
|
|
2976
|
+
let dir = resolve3(startDir);
|
|
2977
|
+
for (; ; ) {
|
|
2978
|
+
const file = join7(dir, LOCKFILE_NAME2);
|
|
2979
|
+
if (existsSync5(file)) return file;
|
|
2980
|
+
const parent = dirname2(dir);
|
|
2981
|
+
if (parent === dir) return void 0;
|
|
2982
|
+
dir = parent;
|
|
2983
|
+
}
|
|
2938
2984
|
}
|
|
2939
2985
|
function writeLock(file, lock) {
|
|
2940
|
-
writeFileSync4(file,
|
|
2986
|
+
writeFileSync4(file, formatLock2(lock));
|
|
2941
2987
|
}
|
|
2942
2988
|
|
|
2943
|
-
//
|
|
2989
|
+
// ../shared/dist/ids.js
|
|
2990
|
+
var ID_PREFIXES = {
|
|
2991
|
+
user: "usr",
|
|
2992
|
+
oauthAccount: "oau",
|
|
2993
|
+
session: "ses",
|
|
2994
|
+
organization: "org",
|
|
2995
|
+
organizationMember: "mem",
|
|
2996
|
+
organizationInvitation: "inv",
|
|
2997
|
+
project: "prj",
|
|
2998
|
+
projectOrigin: "por",
|
|
2999
|
+
apiKey: "key",
|
|
3000
|
+
collection: "col",
|
|
3001
|
+
collectionVersion: "clv",
|
|
3002
|
+
entry: "ent",
|
|
3003
|
+
entrySlugAlias: "als",
|
|
3004
|
+
entryRevision: "rev",
|
|
3005
|
+
changeSet: "chs",
|
|
3006
|
+
changeSetItem: "csi",
|
|
3007
|
+
changeSetReview: "csr",
|
|
3008
|
+
changeSetComment: "csc",
|
|
3009
|
+
changeSetCheck: "chk",
|
|
3010
|
+
projectCheck: "pck",
|
|
3011
|
+
asset: "ast",
|
|
3012
|
+
assetUpload: "upl",
|
|
3013
|
+
savedView: "viw",
|
|
3014
|
+
previewToken: "prv",
|
|
3015
|
+
webhookEndpoint: "whk",
|
|
3016
|
+
webhookEvent: "whe",
|
|
3017
|
+
webhookDelivery: "whd",
|
|
3018
|
+
auditEvent: "aud",
|
|
3019
|
+
job: "job",
|
|
3020
|
+
idempotencyKey: "idm",
|
|
3021
|
+
billingCustomer: "bcu",
|
|
3022
|
+
billingSubscription: "bsu",
|
|
3023
|
+
billingProviderEvent: "evt",
|
|
3024
|
+
usagePeriod: "usp",
|
|
3025
|
+
mcpClient: "mcl",
|
|
3026
|
+
mcpGrant: "mgr",
|
|
3027
|
+
mcpAuthorizationCode: "mac",
|
|
3028
|
+
mcpToken: "mtk",
|
|
3029
|
+
deviceAuthorization: "dev",
|
|
3030
|
+
githubInstallation: "ghi",
|
|
3031
|
+
projectRepository: "prp"
|
|
3032
|
+
};
|
|
3033
|
+
var PREFIX_SET = new Set(Object.values(ID_PREFIXES));
|
|
3034
|
+
|
|
3035
|
+
// ../shared/dist/dates.js
|
|
3036
|
+
var HOURS = 60 * 60;
|
|
3037
|
+
var DAYS = 24 * 60 * 60;
|
|
3038
|
+
|
|
3039
|
+
// ../shared/dist/origins.js
|
|
3040
|
+
function normalizeOrigin(value) {
|
|
3041
|
+
try {
|
|
3042
|
+
const url = new URL(value.trim());
|
|
3043
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
3044
|
+
return void 0;
|
|
3045
|
+
return url.origin;
|
|
3046
|
+
} catch {
|
|
3047
|
+
return void 0;
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
// ../shared/dist/plans.js
|
|
3052
|
+
var GB = 1024 ** 3;
|
|
3053
|
+
var MB = 1024 ** 2;
|
|
3054
|
+
var UNLIMITED = Number.MAX_SAFE_INTEGER;
|
|
3055
|
+
var PLANS = {
|
|
3056
|
+
free: {
|
|
3057
|
+
key: "free",
|
|
3058
|
+
priceEurMonthly: 0,
|
|
3059
|
+
priceEurYearly: 0,
|
|
3060
|
+
maxProjects: 2,
|
|
3061
|
+
maxMembers: 2,
|
|
3062
|
+
storageBytes: 1 * GB,
|
|
3063
|
+
monthlyBandwidthBytes: 25 * GB,
|
|
3064
|
+
monthlyPublicApiRequests: 1e4,
|
|
3065
|
+
maxWebhookEndpoints: 1,
|
|
3066
|
+
revisionRetentionDays: 30,
|
|
3067
|
+
maxUploadBytes: 50 * MB
|
|
3068
|
+
},
|
|
3069
|
+
pro: {
|
|
3070
|
+
key: "pro",
|
|
3071
|
+
priceEurMonthly: 9,
|
|
3072
|
+
priceEurYearly: 90,
|
|
3073
|
+
maxProjects: 10,
|
|
3074
|
+
maxMembers: 5,
|
|
3075
|
+
storageBytes: 10 * GB,
|
|
3076
|
+
monthlyBandwidthBytes: 250 * GB,
|
|
3077
|
+
monthlyPublicApiRequests: 5e5,
|
|
3078
|
+
maxWebhookEndpoints: 10,
|
|
3079
|
+
revisionRetentionDays: null,
|
|
3080
|
+
maxUploadBytes: 250 * MB
|
|
3081
|
+
},
|
|
3082
|
+
/**
|
|
3083
|
+
* Myna's own organizations — the changelog, and anything else we run on the
|
|
3084
|
+
* product we sell. It is never sold, never offered at checkout, and cannot be
|
|
3085
|
+
* reached through the API: `scripts/bootstrap-internal-org.mjs` writes it
|
|
3086
|
+
* directly, and billing refuses to move an organization on or off it.
|
|
3087
|
+
*/
|
|
3088
|
+
internal: {
|
|
3089
|
+
key: "internal",
|
|
3090
|
+
priceEurMonthly: 0,
|
|
3091
|
+
priceEurYearly: null,
|
|
3092
|
+
maxProjects: UNLIMITED,
|
|
3093
|
+
maxMembers: UNLIMITED,
|
|
3094
|
+
storageBytes: UNLIMITED,
|
|
3095
|
+
monthlyBandwidthBytes: UNLIMITED,
|
|
3096
|
+
monthlyPublicApiRequests: UNLIMITED,
|
|
3097
|
+
maxWebhookEndpoints: UNLIMITED,
|
|
3098
|
+
revisionRetentionDays: null,
|
|
3099
|
+
maxUploadBytes: UNLIMITED
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
|
|
3103
|
+
// ../shared/dist/rank.js
|
|
3104
|
+
var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
3105
|
+
var MIN_DIGIT = DIGITS[0];
|
|
3106
|
+
var LAST_INDEX = DIGITS.length - 1;
|
|
3107
|
+
var MID_DIGIT = DIGITS[Math.floor(DIGITS.length / 2)];
|
|
3108
|
+
|
|
3109
|
+
// ../shared/dist/release.js
|
|
3110
|
+
function parseSemVer(version) {
|
|
3111
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version.trim());
|
|
3112
|
+
if (!match)
|
|
3113
|
+
return void 0;
|
|
3114
|
+
return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) };
|
|
3115
|
+
}
|
|
3116
|
+
function compareSemVer(a, b) {
|
|
3117
|
+
const left = parseSemVer(a);
|
|
3118
|
+
const right = parseSemVer(b);
|
|
3119
|
+
if (!left || !right)
|
|
3120
|
+
throw new Error(`Cannot compare versions "${a}" and "${b}".`);
|
|
3121
|
+
return left.major - right.major || left.minor - right.minor || left.patch - right.patch;
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
// ../shared/dist/lock.js
|
|
3125
|
+
var LOCKFILE_NAME3 = "myna.lock";
|
|
3126
|
+
function branchForRelease(project, release) {
|
|
3127
|
+
const slug = project.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "project";
|
|
3128
|
+
return `myna/content-${slug}-r${release}`;
|
|
3129
|
+
}
|
|
2944
3130
|
var MAX_DETAILED_RELEASES = 20;
|
|
3131
|
+
function releasePullRequestTitle(input) {
|
|
3132
|
+
return input.rollback ? `chore(content): roll ${input.project} back to release #${input.to.number}` : `chore(content): ${input.project} release #${input.to.number} \u2014 ${input.to.title}`;
|
|
3133
|
+
}
|
|
3134
|
+
function releasePullRequestBody(input) {
|
|
3135
|
+
const { project, from, to, releases, rollback } = input;
|
|
3136
|
+
const lines = [
|
|
3137
|
+
from === null ? `Pins \`${LOCKFILE_NAME3}\` for \`${project}\` to release #${to.number}.` : rollback ? `Rolls \`${LOCKFILE_NAME3}\` for \`${project}\` back from release #${from} to #${to.number}.` : `Moves \`${LOCKFILE_NAME3}\` for \`${project}\` from release #${from} to #${to.number}.`,
|
|
3138
|
+
"",
|
|
3139
|
+
rollback ? `${releases.length} release(s) are being undone for this repository. The content itself is untouched \u2014 nothing is unpublished \u2014 this only changes which release the build reads.` : `${releases.length} release(s). The build reads content at this release, so CI on this pull request is running against exactly the content that will ship.`
|
|
3140
|
+
];
|
|
3141
|
+
const detailed = releases.slice(-MAX_DETAILED_RELEASES);
|
|
3142
|
+
if (detailed.length < releases.length) {
|
|
3143
|
+
const omitted = releases.length - detailed.length;
|
|
3144
|
+
lines.push("", `_Showing the newest ${detailed.length} of ${releases.length} releases. The remaining ${omitted} are listed without field detail._`, "", ...releases.slice(0, omitted).map((r) => `- #${r.number} \u2014 ${r.title} (${r.itemCount ?? 0} item(s))`));
|
|
3145
|
+
}
|
|
3146
|
+
for (const release of detailed) {
|
|
3147
|
+
lines.push("", `### #${release.number} \u2014 ${release.title}`);
|
|
3148
|
+
if (release.description)
|
|
3149
|
+
lines.push("", release.description);
|
|
3150
|
+
if (!release.diff) {
|
|
3151
|
+
lines.push("", `_Diff unavailable; ${release.itemCount ?? 0} item(s) changed._`);
|
|
3152
|
+
continue;
|
|
3153
|
+
}
|
|
3154
|
+
for (const item of release.diff.items) {
|
|
3155
|
+
const name = item.collection && item.slug ? `${item.collection}/${item.slug}` : item.resourceId;
|
|
3156
|
+
lines.push("", `- **${item.operation} ${name}**`);
|
|
3157
|
+
if (item.changeSummary)
|
|
3158
|
+
lines.push(` - _${item.changeSummary}_`);
|
|
3159
|
+
for (const change of item.changes)
|
|
3160
|
+
lines.push(` - \`${change.path}\` ${change.kind}`);
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
return lines.join("\n");
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
// src/commands/pull.ts
|
|
2945
3167
|
function lockPath(ctx) {
|
|
2946
|
-
|
|
3168
|
+
const cwd = ctx.linkedRoot ?? process.cwd();
|
|
3169
|
+
const found = findLockfile(cwd);
|
|
3170
|
+
if (found) {
|
|
3171
|
+
const boundary = repositoryRoot(cwd);
|
|
3172
|
+
if (!boundary || found.startsWith(boundary)) return found;
|
|
3173
|
+
}
|
|
3174
|
+
return join8(cwd, LOCKFILE_NAME2);
|
|
3175
|
+
}
|
|
3176
|
+
function assertOneLockfile(cwd, active) {
|
|
3177
|
+
const all = trackedLockfiles(cwd);
|
|
3178
|
+
if (all.length <= 1) return;
|
|
3179
|
+
throw new UsageError(
|
|
3180
|
+
`This repository has ${all.length} lockfiles:
|
|
3181
|
+
` + all.map((f) => ` ${f}${f === active ? " (the one this would move)" : ""}`).join("\n") + `
|
|
3182
|
+
Reads take the one nearest the build, which may not be that one. Delete the extras and keep a single ${LOCKFILE_NAME2}.`
|
|
3183
|
+
);
|
|
2947
3184
|
}
|
|
2948
3185
|
function readLockAt(file) {
|
|
2949
3186
|
if (!existsSync6(file)) return void 0;
|
|
2950
|
-
return
|
|
3187
|
+
return parseLock2(readFileSync5(file, "utf8"), file);
|
|
2951
3188
|
}
|
|
2952
3189
|
async function latestRelease(ctx, project) {
|
|
2953
3190
|
const page = await ctx.management().releases.list(project, { limit: 1 });
|
|
@@ -2973,71 +3210,55 @@ async function releasesBetween(ctx, project, from, to) {
|
|
|
2973
3210
|
cursor = page.nextCursor;
|
|
2974
3211
|
}
|
|
2975
3212
|
}
|
|
2976
|
-
function
|
|
2977
|
-
const
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
}
|
|
2995
|
-
for (const release of detailed) {
|
|
2996
|
-
lines.push("", `### #${release.number} \u2014 ${release.title}`);
|
|
2997
|
-
if (release.description) lines.push("", release.description);
|
|
2998
|
-
let diff;
|
|
2999
|
-
try {
|
|
3000
|
-
diff = await ctx.management().changeSets.diff(project, release.id);
|
|
3001
|
-
} catch {
|
|
3002
|
-
lines.push("", `_Diff unavailable; ${release.itemCount} item(s) changed._`);
|
|
3003
|
-
continue;
|
|
3004
|
-
}
|
|
3005
|
-
for (const item of diff.items) {
|
|
3006
|
-
lines.push("", `- **${itemLabel(item)}**`);
|
|
3007
|
-
if (item.changeSummary) lines.push(` - _${item.changeSummary}_`);
|
|
3008
|
-
for (const change of item.changes) lines.push(` - \`${change.path}\` ${change.kind}`);
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
return lines.join("\n");
|
|
3213
|
+
async function pullRequestText(ctx, project, from, to, releases, rollback) {
|
|
3214
|
+
const summaries = await Promise.all(
|
|
3215
|
+
releases.map(async (release) => ({
|
|
3216
|
+
number: release.number,
|
|
3217
|
+
title: release.title,
|
|
3218
|
+
description: release.description,
|
|
3219
|
+
itemCount: release.itemCount,
|
|
3220
|
+
// A release whose diff cannot be read is still a release worth naming.
|
|
3221
|
+
diff: await ctx.management().changeSets.diff(project, release.id).catch(() => null)
|
|
3222
|
+
}))
|
|
3223
|
+
);
|
|
3224
|
+
const input = {
|
|
3225
|
+
project,
|
|
3226
|
+
from: from?.release ?? null,
|
|
3227
|
+
to: { number: to.number, title: to.title, description: to.description, itemCount: to.itemCount },
|
|
3228
|
+
releases: summaries,
|
|
3229
|
+
rollback
|
|
3230
|
+
};
|
|
3231
|
+
return { title: releasePullRequestTitle(input), body: releasePullRequestBody(input) };
|
|
3012
3232
|
}
|
|
3013
3233
|
function registerPull(program) {
|
|
3014
|
-
program.command("pull").description(`Pin this repository's content to a release in ${
|
|
3234
|
+
program.command("pull").description(`Pin this repository's content to a release in ${LOCKFILE_NAME2}`).option("--release <n>", "release number to pin to (default: the newest)").option("--check", "report whether the pin is behind and exit non-zero if it is", false).option("--open-pr", "commit the bump onto a branch and open a pull request", false).option(
|
|
3015
3235
|
"--run <command>",
|
|
3016
3236
|
"shell command to run after moving the pin; anything it changes is committed with the lockfile"
|
|
3017
3237
|
).option("--branch <name>", "branch to use with --open-pr (default: derived from the release)").option("--base <branch>", "branch to open the pull request against (default: the current branch)").action(
|
|
3018
3238
|
handle(async (ctx, _args, opts) => {
|
|
3019
3239
|
const project = ctx.requireProject();
|
|
3020
3240
|
const file = lockPath(ctx);
|
|
3241
|
+
assertOneLockfile(ctx.linkedRoot ?? process.cwd(), file);
|
|
3021
3242
|
const current = readLockAt(file);
|
|
3022
3243
|
if (current && current.project !== project) {
|
|
3023
3244
|
throw new UsageError(
|
|
3024
|
-
`${
|
|
3245
|
+
`${LOCKFILE_NAME2} pins project "${current.project}" but the selected project is "${project}". Pass --project ${current.project}, or delete the lockfile.`
|
|
3025
3246
|
);
|
|
3026
3247
|
}
|
|
3027
3248
|
const target = opts.release ? await ctx.management().releases.get(project, String(opts.release)) : await latestRelease(ctx, project);
|
|
3028
3249
|
if (opts.check) {
|
|
3029
3250
|
if (!current) {
|
|
3030
|
-
throw new UsageError(`No ${
|
|
3251
|
+
throw new UsageError(`No ${LOCKFILE_NAME2} here. Run \`myna pull\` to create one.`);
|
|
3031
3252
|
}
|
|
3032
3253
|
const behind = await releasesBetween(ctx, project, current.release, target.number);
|
|
3033
3254
|
emit(
|
|
3034
3255
|
{ lockfile: file, release: current.release, latest: target.number, behind: behind.map((r) => r.number) },
|
|
3035
3256
|
() => {
|
|
3036
3257
|
if (behind.length === 0) {
|
|
3037
|
-
diag(`${
|
|
3258
|
+
diag(`${LOCKFILE_NAME2} is at release #${current.release} \u2014 current.`);
|
|
3038
3259
|
return;
|
|
3039
3260
|
}
|
|
3040
|
-
diag(`${
|
|
3261
|
+
diag(`${LOCKFILE_NAME2} is at release #${current.release}; #${target.number} is available.`);
|
|
3041
3262
|
table(behind, [
|
|
3042
3263
|
{ header: "#", value: (r) => String(r.number) },
|
|
3043
3264
|
{ header: "TITLE", value: (r) => r.title },
|
|
@@ -3056,10 +3277,10 @@ function registerPull(program) {
|
|
|
3056
3277
|
title: target.title,
|
|
3057
3278
|
...ctx.apiUrl && !ctx.apiUrl.startsWith("https://api.myna.sh") ? { apiUrl: ctx.apiUrl } : {}
|
|
3058
3279
|
};
|
|
3059
|
-
if (current &&
|
|
3280
|
+
if (current && formatLock2(current) === formatLock2(next)) {
|
|
3060
3281
|
emit(
|
|
3061
3282
|
{ lockfile: file, release: target.number, changed: false, pullRequest: null },
|
|
3062
|
-
() => diag(`${
|
|
3283
|
+
() => diag(`${LOCKFILE_NAME2} is already at release #${target.number}.`)
|
|
3063
3284
|
);
|
|
3064
3285
|
return;
|
|
3065
3286
|
}
|
|
@@ -3079,11 +3300,11 @@ function registerPull(program) {
|
|
|
3079
3300
|
},
|
|
3080
3301
|
() => {
|
|
3081
3302
|
if (!current) {
|
|
3082
|
-
diag(`${
|
|
3303
|
+
diag(`${LOCKFILE_NAME2}: pinned to #${target.number}.`);
|
|
3083
3304
|
return;
|
|
3084
3305
|
}
|
|
3085
3306
|
diag(
|
|
3086
|
-
rollback ? `${
|
|
3307
|
+
rollback ? `${LOCKFILE_NAME2}: #${current.release} \u2192 #${target.number}, rolling back ${releases.length} release(s).` : `${LOCKFILE_NAME2}: #${current.release} \u2192 #${target.number} (${releases.length} release(s)).`
|
|
3087
3308
|
);
|
|
3088
3309
|
}
|
|
3089
3310
|
);
|
|
@@ -3095,7 +3316,7 @@ function registerPull(program) {
|
|
|
3095
3316
|
if (dirty.length > 0) {
|
|
3096
3317
|
throw new UsageError(`Commit or stash ${dirty.join(", ")} first.`);
|
|
3097
3318
|
}
|
|
3098
|
-
const
|
|
3319
|
+
const text = await pullRequestText(ctx, project, current, target, releases, rollback);
|
|
3099
3320
|
writeLock(file, next);
|
|
3100
3321
|
if (command) {
|
|
3101
3322
|
try {
|
|
@@ -3114,8 +3335,8 @@ function registerPull(program) {
|
|
|
3114
3335
|
files: changes.map((c) => c.file),
|
|
3115
3336
|
branch,
|
|
3116
3337
|
base: opts.base,
|
|
3117
|
-
title:
|
|
3118
|
-
body
|
|
3338
|
+
title: text.title,
|
|
3339
|
+
body: text.body
|
|
3119
3340
|
});
|
|
3120
3341
|
} catch (error) {
|
|
3121
3342
|
discardChanges(root, changes);
|
|
@@ -3303,139 +3524,6 @@ function registerAssets(program) {
|
|
|
3303
3524
|
);
|
|
3304
3525
|
}
|
|
3305
3526
|
|
|
3306
|
-
// ../shared/dist/ids.js
|
|
3307
|
-
var ID_PREFIXES = {
|
|
3308
|
-
user: "usr",
|
|
3309
|
-
oauthAccount: "oau",
|
|
3310
|
-
session: "ses",
|
|
3311
|
-
organization: "org",
|
|
3312
|
-
organizationMember: "mem",
|
|
3313
|
-
organizationInvitation: "inv",
|
|
3314
|
-
project: "prj",
|
|
3315
|
-
projectOrigin: "por",
|
|
3316
|
-
apiKey: "key",
|
|
3317
|
-
collection: "col",
|
|
3318
|
-
collectionVersion: "clv",
|
|
3319
|
-
entry: "ent",
|
|
3320
|
-
entrySlugAlias: "als",
|
|
3321
|
-
entryRevision: "rev",
|
|
3322
|
-
changeSet: "chs",
|
|
3323
|
-
changeSetItem: "csi",
|
|
3324
|
-
changeSetReview: "csr",
|
|
3325
|
-
changeSetComment: "csc",
|
|
3326
|
-
changeSetCheck: "chk",
|
|
3327
|
-
projectCheck: "pck",
|
|
3328
|
-
asset: "ast",
|
|
3329
|
-
assetUpload: "upl",
|
|
3330
|
-
savedView: "viw",
|
|
3331
|
-
previewToken: "prv",
|
|
3332
|
-
webhookEndpoint: "whk",
|
|
3333
|
-
webhookEvent: "whe",
|
|
3334
|
-
webhookDelivery: "whd",
|
|
3335
|
-
auditEvent: "aud",
|
|
3336
|
-
job: "job",
|
|
3337
|
-
idempotencyKey: "idm",
|
|
3338
|
-
billingCustomer: "bcu",
|
|
3339
|
-
billingSubscription: "bsu",
|
|
3340
|
-
billingProviderEvent: "evt",
|
|
3341
|
-
usagePeriod: "usp",
|
|
3342
|
-
mcpClient: "mcl",
|
|
3343
|
-
mcpGrant: "mgr",
|
|
3344
|
-
mcpAuthorizationCode: "mac",
|
|
3345
|
-
mcpToken: "mtk",
|
|
3346
|
-
deviceAuthorization: "dev"
|
|
3347
|
-
};
|
|
3348
|
-
var PREFIX_SET = new Set(Object.values(ID_PREFIXES));
|
|
3349
|
-
|
|
3350
|
-
// ../shared/dist/dates.js
|
|
3351
|
-
var HOURS = 60 * 60;
|
|
3352
|
-
var DAYS = 24 * 60 * 60;
|
|
3353
|
-
|
|
3354
|
-
// ../shared/dist/origins.js
|
|
3355
|
-
function normalizeOrigin(value) {
|
|
3356
|
-
try {
|
|
3357
|
-
const url = new URL(value.trim());
|
|
3358
|
-
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
3359
|
-
return void 0;
|
|
3360
|
-
return url.origin;
|
|
3361
|
-
} catch {
|
|
3362
|
-
return void 0;
|
|
3363
|
-
}
|
|
3364
|
-
}
|
|
3365
|
-
|
|
3366
|
-
// ../shared/dist/plans.js
|
|
3367
|
-
var GB = 1024 ** 3;
|
|
3368
|
-
var MB = 1024 ** 2;
|
|
3369
|
-
var UNLIMITED = Number.MAX_SAFE_INTEGER;
|
|
3370
|
-
var PLANS = {
|
|
3371
|
-
free: {
|
|
3372
|
-
key: "free",
|
|
3373
|
-
priceEurMonthly: 0,
|
|
3374
|
-
priceEurYearly: 0,
|
|
3375
|
-
maxProjects: 2,
|
|
3376
|
-
maxMembers: 2,
|
|
3377
|
-
storageBytes: 1 * GB,
|
|
3378
|
-
monthlyBandwidthBytes: 25 * GB,
|
|
3379
|
-
monthlyPublicApiRequests: 1e4,
|
|
3380
|
-
maxWebhookEndpoints: 1,
|
|
3381
|
-
revisionRetentionDays: 30,
|
|
3382
|
-
maxUploadBytes: 50 * MB
|
|
3383
|
-
},
|
|
3384
|
-
pro: {
|
|
3385
|
-
key: "pro",
|
|
3386
|
-
priceEurMonthly: 9,
|
|
3387
|
-
priceEurYearly: 90,
|
|
3388
|
-
maxProjects: 10,
|
|
3389
|
-
maxMembers: 5,
|
|
3390
|
-
storageBytes: 10 * GB,
|
|
3391
|
-
monthlyBandwidthBytes: 250 * GB,
|
|
3392
|
-
monthlyPublicApiRequests: 5e5,
|
|
3393
|
-
maxWebhookEndpoints: 10,
|
|
3394
|
-
revisionRetentionDays: null,
|
|
3395
|
-
maxUploadBytes: 250 * MB
|
|
3396
|
-
},
|
|
3397
|
-
/**
|
|
3398
|
-
* Myna's own organizations — the changelog, and anything else we run on the
|
|
3399
|
-
* product we sell. It is never sold, never offered at checkout, and cannot be
|
|
3400
|
-
* reached through the API: `scripts/bootstrap-internal-org.mjs` writes it
|
|
3401
|
-
* directly, and billing refuses to move an organization on or off it.
|
|
3402
|
-
*/
|
|
3403
|
-
internal: {
|
|
3404
|
-
key: "internal",
|
|
3405
|
-
priceEurMonthly: 0,
|
|
3406
|
-
priceEurYearly: null,
|
|
3407
|
-
maxProjects: UNLIMITED,
|
|
3408
|
-
maxMembers: UNLIMITED,
|
|
3409
|
-
storageBytes: UNLIMITED,
|
|
3410
|
-
monthlyBandwidthBytes: UNLIMITED,
|
|
3411
|
-
monthlyPublicApiRequests: UNLIMITED,
|
|
3412
|
-
maxWebhookEndpoints: UNLIMITED,
|
|
3413
|
-
revisionRetentionDays: null,
|
|
3414
|
-
maxUploadBytes: UNLIMITED
|
|
3415
|
-
}
|
|
3416
|
-
};
|
|
3417
|
-
|
|
3418
|
-
// ../shared/dist/rank.js
|
|
3419
|
-
var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
3420
|
-
var MIN_DIGIT = DIGITS[0];
|
|
3421
|
-
var LAST_INDEX = DIGITS.length - 1;
|
|
3422
|
-
var MID_DIGIT = DIGITS[Math.floor(DIGITS.length / 2)];
|
|
3423
|
-
|
|
3424
|
-
// ../shared/dist/release.js
|
|
3425
|
-
function parseSemVer(version) {
|
|
3426
|
-
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version.trim());
|
|
3427
|
-
if (!match)
|
|
3428
|
-
return void 0;
|
|
3429
|
-
return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) };
|
|
3430
|
-
}
|
|
3431
|
-
function compareSemVer(a, b) {
|
|
3432
|
-
const left = parseSemVer(a);
|
|
3433
|
-
const right = parseSemVer(b);
|
|
3434
|
-
if (!left || !right)
|
|
3435
|
-
throw new Error(`Cannot compare versions "${a}" and "${b}".`);
|
|
3436
|
-
return left.major - right.major || left.minor - right.minor || left.patch - right.patch;
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
3527
|
// src/commands/admin.ts
|
|
3440
3528
|
function csv(value) {
|
|
3441
3529
|
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -3978,7 +4066,7 @@ function registerBilling(program) {
|
|
|
3978
4066
|
|
|
3979
4067
|
// src/commands/doctor.ts
|
|
3980
4068
|
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3981
|
-
import { join as
|
|
4069
|
+
import { join as join9 } from "path";
|
|
3982
4070
|
|
|
3983
4071
|
// src/registry.ts
|
|
3984
4072
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -4017,7 +4105,7 @@ function installCommand(manager, version) {
|
|
|
4017
4105
|
}
|
|
4018
4106
|
|
|
4019
4107
|
// src/version.ts
|
|
4020
|
-
var VERSION = true ? "0.12.
|
|
4108
|
+
var VERSION = true ? "0.12.1" : "0.0.0-dev";
|
|
4021
4109
|
var IS_RELEASE_BUILD = true;
|
|
4022
4110
|
|
|
4023
4111
|
// src/commands/doctor.ts
|
|
@@ -4241,7 +4329,7 @@ function findGeneratedTypes(root, depth = 4) {
|
|
|
4241
4329
|
const dirs = [];
|
|
4242
4330
|
for (const entry of entries) {
|
|
4243
4331
|
if (SCAN_IGNORE.has(entry) || entry.startsWith(".")) continue;
|
|
4244
|
-
const full =
|
|
4332
|
+
const full = join9(root, entry);
|
|
4245
4333
|
let stats;
|
|
4246
4334
|
try {
|
|
4247
4335
|
stats = statSync2(full);
|
|
@@ -4396,7 +4484,7 @@ function registerUpdate(program) {
|
|
|
4396
4484
|
|
|
4397
4485
|
// src/commands/sync.ts
|
|
4398
4486
|
import { readdir as readdir2, stat as stat2 } from "fs/promises";
|
|
4399
|
-
import { join as
|
|
4487
|
+
import { join as join10 } from "path";
|
|
4400
4488
|
async function isDirectory(path) {
|
|
4401
4489
|
const info = await stat2(path).catch(() => void 0);
|
|
4402
4490
|
return Boolean(info?.isDirectory());
|
|
@@ -4411,7 +4499,7 @@ async function planDirectories(dir, collection) {
|
|
|
4411
4499
|
const plan = [];
|
|
4412
4500
|
for (const name of children.sort()) {
|
|
4413
4501
|
if (name.startsWith(".")) continue;
|
|
4414
|
-
const full =
|
|
4502
|
+
const full = join10(dir, name);
|
|
4415
4503
|
if (await isDirectory(full)) plan.push({ collection: name, path: full });
|
|
4416
4504
|
}
|
|
4417
4505
|
if (plan.length === 0) {
|