-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
180 lines (165 loc) · 5.49 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import SemanticReleaseError from "@semantic-release/error";
import readPackage from "read-pkg";
import semver from "semver";
import { PluginConfig } from "./pluginConfig.js";
import { Yarn } from "./yarn.js";
let verified = false;
let prepared = false;
const yarn = new Yarn();
export type { PluginConfig };
export async function verifyConditions(
config: PluginConfig | undefined = undefined,
context: Context
): Promise<void> {
config = PluginConfig.normalize(config);
context.logger.log(`read ${context.cwd}/package.json`);
const pkg = await getPackage(context.cwd);
if (pkg.private === true) {
context.logger.log("skipping to verify npm auth since package is private");
return;
}
if (config.npmPublish === false) {
context.logger.log("skipping to verify npm auth since npmPublish is false");
return;
}
context.logger.log('set npmRegistryServer: "https://registry.npmjs.org"');
await yarn.setNpmRegistryServer("https://registry.npmjs.org");
context.logger.log("set NPM_TOKEN to yarn config npmAuthToken");
await yarn.setNpmAuthToken(getNpmToken(context.env));
context.logger.log("verify npm auth");
if (!(await yarn.authenticated())) {
throw PluginError.EINVALIDNPMTOKEN();
}
context.logger.log("install version plugin");
await yarn.pluginImportVersion();
verified = true;
}
export async function prepare(
config: PluginConfig | undefined = undefined,
context: PrepareContext
) {
config = PluginConfig.normalize(config);
if (!verified) {
return;
}
// Reload package.json in case a previous external step updated it
context.logger.log(`read ${context.cwd}/package.json`);
const pkg = await getPackage(context.cwd);
if (pkg.private === true) {
context.logger.log("skipping to prepare since package is private");
return;
}
if (config.npmPublish === false) {
context.logger.log("skipping to prepare since npmPublish is false");
return;
}
context.logger.log(
`rewrite the "version" field in the package.json: ${context.nextRelease.version}`
);
const tarballDir = config.tarballDir ?? ".";
await yarn.version(context.nextRelease.version);
if (typeof tarballDir === "string") {
const tarballName = tarballDir + "/package.tgz";
context.logger.log(`creating a tarball: ${tarballName}`);
await yarn.pack(tarballName);
}
context.logger.log(`package contents:`);
const tarballContents = await yarn.packDryRun();
for (const tarballContent of tarballContents) {
context.logger.log(` ${tarballContent}`);
}
prepared = true;
}
export async function publish(
config: PluginConfig | undefined = undefined,
context: PrepareContext
) {
config = PluginConfig.normalize(config);
if (!verified || !prepared) {
return;
}
// Reload package.json in case a previous external step updated it
context.logger.log(`read ${context.cwd}/package.json`);
const pkg = await getPackage(context.cwd);
if (pkg.private === true) {
context.logger.log("skipping to publish since package is private");
return;
}
if (config.npmPublish === false) {
context.logger.log("skipping to publish since npmPublish is false");
return;
}
const { version } = context.nextRelease;
const distTag = getChannel(context.nextRelease.channel);
context.logger.log(
`Publishing version ${version} to npm registry on dist-tag ${distTag}`
);
await yarn.publish(distTag);
context.logger.log(
`Published ${pkg.name}@${version} to dist-tag @${distTag}`
);
}
interface Context {
readonly cwd: string;
readonly env: NodeJS.ProcessEnv;
readonly stdout: NodeJS.WriteStream;
readonly stderr: NodeJS.WriteStream;
readonly logger: {
readonly log: (message: string, ...vars: any[]) => void;
readonly error: (message: string, ...vars: any[]) => void;
};
}
interface PrepareContext extends Context {
readonly nextRelease: {
readonly version: string;
readonly channel: string;
};
}
class PluginError extends SemanticReleaseError {
static ENOPKGNAME() {
return new PluginError(
"Missing `name` property in `package.json`.",
"ENOPKGNAME"
);
}
static ENOPKG() {
return new PluginError("Missing `package.json`.", "ENOPKG");
}
static EINVALIDNPMTOKEN() {
return new PluginError(
"Invalid npm token.",
"EINVALIDNPMTOKEN",
`The npm token configured in the \`NPM_TOKEN\` environment variable must be a valid [token](https://docs.npmjs.com/getting-started/working_with_tokens) allowing to publish to the registry \`\`.
If you are using Two Factor Authentication for your account, set its level to ["Authorization only"](https://docs.npmjs.com/getting-started/using-two-factor-authentication#levels-of-authentication) in your account settings. **semantic-release** cannot publish with the default "
Authorization and writes" level.
Please make sure to set the \`NPM_TOKEN\` environment variable in your CI with the exact value of the npm token.`
);
}
}
async function getPackage(cwd: string) {
let pkg;
try {
pkg = await readPackage({ cwd });
} catch (error) {
if ((error as any).code === "ENOENT") {
throw PluginError.ENOPKG();
}
throw new AggregateError([error]);
}
if (!pkg.name) {
throw PluginError.ENOPKGNAME();
}
return pkg;
}
function getNpmToken(env: NodeJS.ProcessEnv): string {
if (typeof env["NPM_TOKEN"] !== "string") {
throw PluginError.EINVALIDNPMTOKEN();
}
return env["NPM_TOKEN"];
}
const getChannel = (channel: string) =>
channel
? semver.validRange(channel)
? `release-${channel}`
: channel
: "latest";