@tahminator/pipeline 1.0.77 → 1.0.78-beta.1fe28066
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/README.md +41 -1
- package/dist/protobuf/backend/artifact-keeper.d.ts +0 -1
- package/dist/protobuf/backend/artifact-keeper.js +40 -21
- package/dist/protobuf/backend/go.d.ts +22 -0
- package/dist/protobuf/backend/go.js +149 -0
- package/dist/protobuf/backend/rust-library.d.ts +2 -0
- package/dist/protobuf/backend/rust-library.js +35 -0
- package/dist/protobuf/client.js +7 -6
- package/dist/protobuf/strategy/go.d.ts +3 -1
- package/dist/protobuf/strategy/go.js +4 -1
- package/dist/protobuf/strategy/java.d.ts +4 -1
- package/dist/protobuf/strategy/java.js +10 -1
- package/dist/protobuf/strategy/rust.d.ts +8 -1
- package/dist/protobuf/strategy/rust.js +18 -1
- package/dist/protobuf/strategy/types.d.ts +5 -1
- package/dist/protobuf/types.d.ts +4 -1
- package/dist/protobuf/versions.d.ts +7 -0
- package/dist/protobuf/versions.js +17 -0
- package/dist/versioning/client.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,7 +185,7 @@ await client.promoteDockerImage({
|
|
|
185
185
|
|
|
186
186
|
### `ProtobufCompilerClient`
|
|
187
187
|
|
|
188
|
-
Generate protobuf
|
|
188
|
+
Generate protobuf messages and gRPC client/server stubs with the [Buf CLI](https://buf.build/docs/installation/) and its remote plugins. Java, Rust, and Go targets can be published to Artifact Keeper with Maven/Gradle, Cargo, or Go module uploads. The client installs Buf globally with npm when necessary.
|
|
189
189
|
|
|
190
190
|
```ts
|
|
191
191
|
const protobuf = new ProtobufCompilerClient();
|
|
@@ -210,6 +210,46 @@ await protobuf.compile({
|
|
|
210
210
|
});
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
+
Configure generated-code packages in each `.proto` file, not in `targetLanguages`. The client does not enable Buf managed mode; Buf's generators read these file options directly:
|
|
214
|
+
|
|
215
|
+
```proto
|
|
216
|
+
option go_package = "example.com/proto/helloworld/v1;helloworldv1";
|
|
217
|
+
option java_package = "org.myorg.helloworld.v1";
|
|
218
|
+
option java_multiple_files = true;
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`go_package` is required for Go generation with this client. Java package options are recommended; `java_outer_classname` is optional. Rust generation needs no language-specific file options. CI target options such as Java `groupId`/`artifactId` and Rust `crateName` are publishing metadata, not generated-code package names. Go's former unused `modulePath` option has been removed.
|
|
222
|
+
|
|
223
|
+
Every target enables both message and service generation by default:
|
|
224
|
+
|
|
225
|
+
| Target | Generated service API | Published runtime dependencies |
|
|
226
|
+
| ----------------------- | -------------------------------------------------------------------- | --------------------------------------------------- |
|
|
227
|
+
| Java (Maven and Gradle) | `<Service>Grpc.<Service>ImplBase` and client stubs | `protobuf-java`, `grpc-protobuf`, `grpc-stub` |
|
|
228
|
+
| Go | `<Service>Server`, `Unimplemented<Service>Server`, `<Service>Client` | Resolved by `go mod tidy` into the generated module |
|
|
229
|
+
| Rust | Tonic `<service>_server` traits and `<service>_client` clients | `prost`, `prost-types`, `tonic`, `tonic-prost` |
|
|
230
|
+
|
|
231
|
+
Applications implement the generated service interfaces and supply server startup, endpoints, authentication, and transport configuration. Java applications must add a transport implementation such as `io.grpc:grpc-netty-shaded:1.75.0`; the generated SDK does not choose one. Gradle publishes public runtime types as `api` dependencies so they are visible on consumers' compile classpaths.
|
|
232
|
+
|
|
233
|
+
Imported schemas are generated alongside the selected input, except standard well-known types, which use the runtime libraries. This produces self-contained schema output rather than relying on separately published schema packages. Go publishing still requires those package paths to share a valid module root.
|
|
234
|
+
|
|
235
|
+
Rust's Prost and Tonic plugins are pinned to `v0.5.0`, paired with the `0.14` runtime series. `prostVersion` overrides must remain within `0.14`. The published crate preserves proto package hierarchy (for example, `example.v1` becomes `example::v1`) and includes Tonic stubs in the same module as their messages. This replaces the previous flattened Rust module names.
|
|
236
|
+
|
|
237
|
+
For Go publishing, only the release version is needed:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
targetLanguages: {
|
|
241
|
+
[ProtobufTargetLanguage.GO]: {
|
|
242
|
+
version: "1.0.0",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The publisher generates `go.mod` using the deepest shared directory of the generated Go packages as the module root. For a single package, that package's import path becomes the module path. It never adds, strips, or rewrites version suffixes. Proto authors own package layout; invalid Go module/version combinations fail. In particular, Go does not allow a module path ending in `/v1`. Adding packages outside the existing shared directory changes the inferred module root, so keep the package layout stable across releases.
|
|
248
|
+
|
|
249
|
+
Go publishing requires `go` and `zip` on PATH. It stages generated packages without changing the original output, runs `go mod init` and `go mod tidy` to generate dependency metadata, and uploads `.mod` and `.zip` artifacts to the hosted `go` repository at `<backend.url>/go/go`. It does not lint, build, or test generated code. Dependency resolution may require network access. Versions may include a leading `v`; v2+ modules require the corresponding major-version module path suffix.
|
|
250
|
+
|
|
251
|
+
Java generation is pinned to the compiler release matching `protobufJavaVersion` (default runtime `4.32.1`, Buf Java plugin `v32.1`). The same runtime version is used in both Maven and Gradle metadata. Overrides must be exact stable versions, not ranges, and the corresponding plugin must exist in the Buf registry.
|
|
252
|
+
|
|
213
253
|
### `NPMClient`
|
|
214
254
|
|
|
215
255
|
Interface with NPM registry in order to publish packages to `npmjs.com`
|
|
@@ -14,7 +14,6 @@ export declare class ArtifactKeeperProtobufCompilerBackend implements IProtobufC
|
|
|
14
14
|
private createMavenSettings;
|
|
15
15
|
private createGradleBuild;
|
|
16
16
|
private createCargoToml;
|
|
17
|
-
private createRustLibrary;
|
|
18
17
|
private escapeXml;
|
|
19
18
|
private get artifactKeeperUrl();
|
|
20
19
|
private get mavenRepositoryUrl();
|
|
@@ -3,8 +3,9 @@ import { mkdir, mkdtemp, readdir, rename, rm, writeFile, } from "node:fs/promise
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { ProtobufTargetLanguage, } from "../types";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { DEFAULT_PROTOBUF_JAVA_VERSION, DEFAULT_PROST_VERSION, GRPC_JAVA_VERSION, TONIC_VERSION, } from "../versions";
|
|
7
|
+
import { ArtifactKeeperGoPublisher } from "./go";
|
|
8
|
+
import { createRustLibrary } from "./rust-library";
|
|
8
9
|
export class ArtifactKeeperProtobufCompilerBackend {
|
|
9
10
|
config;
|
|
10
11
|
constructor(config) {
|
|
@@ -25,7 +26,11 @@ export class ArtifactKeeperProtobufCompilerBackend {
|
|
|
25
26
|
});
|
|
26
27
|
return;
|
|
27
28
|
case ProtobufTargetLanguage.GO:
|
|
28
|
-
|
|
29
|
+
await new ArtifactKeeperGoPublisher(this.config).publish({
|
|
30
|
+
generatedDirectory,
|
|
31
|
+
options: options,
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
async publishJava({ generatedDirectory, options, }) {
|
|
@@ -60,9 +65,14 @@ export class ArtifactKeeperProtobufCompilerBackend {
|
|
|
60
65
|
await mkdir(path.join(generatedDirectory, "src"), { recursive: true });
|
|
61
66
|
await Promise.all([
|
|
62
67
|
writeFile(path.join(generatedDirectory, "Cargo.toml"), this.createCargoToml(options)),
|
|
63
|
-
writeFile(path.join(generatedDirectory, "src", "lib.rs"),
|
|
68
|
+
writeFile(path.join(generatedDirectory, "src", "lib.rs"), createRustLibrary(generatedFiles)),
|
|
64
69
|
]);
|
|
65
|
-
await
|
|
70
|
+
await $.env({
|
|
71
|
+
...process.env,
|
|
72
|
+
CARGO_REGISTRIES_CARGO_INDEX: this.cargoIndexUrl,
|
|
73
|
+
CARGO_REGISTRIES_CARGO_TOKEN: this.config.token,
|
|
74
|
+
CARGO_REGISTRIES_CARGO_CREDENTIAL_PROVIDER: "cargo:token",
|
|
75
|
+
}) `cargo publish --registry cargo`.cwd(generatedDirectory);
|
|
66
76
|
}
|
|
67
77
|
async moveJavaSources(generatedDirectory) {
|
|
68
78
|
const sourceDirectory = path.join(generatedDirectory, "src", "main", "java");
|
|
@@ -114,6 +124,22 @@ export class ArtifactKeeperProtobufCompilerBackend {
|
|
|
114
124
|
<artifactId>protobuf-java</artifactId>
|
|
115
125
|
<version>${this.escapeXml(protobufVersion)}</version>
|
|
116
126
|
</dependency>
|
|
127
|
+
<dependency>
|
|
128
|
+
<groupId>io.grpc</groupId>
|
|
129
|
+
<artifactId>grpc-protobuf</artifactId>
|
|
130
|
+
<version>${GRPC_JAVA_VERSION}</version>
|
|
131
|
+
</dependency>
|
|
132
|
+
<dependency>
|
|
133
|
+
<groupId>io.grpc</groupId>
|
|
134
|
+
<artifactId>grpc-stub</artifactId>
|
|
135
|
+
<version>${GRPC_JAVA_VERSION}</version>
|
|
136
|
+
</dependency>
|
|
137
|
+
<dependency>
|
|
138
|
+
<groupId>javax.annotation</groupId>
|
|
139
|
+
<artifactId>javax.annotation-api</artifactId>
|
|
140
|
+
<version>1.3.2</version>
|
|
141
|
+
<scope>provided</scope>
|
|
142
|
+
</dependency>
|
|
117
143
|
</dependencies>
|
|
118
144
|
<distributionManagement>
|
|
119
145
|
<repository>
|
|
@@ -139,7 +165,7 @@ export class ArtifactKeeperProtobufCompilerBackend {
|
|
|
139
165
|
createGradleBuild(options) {
|
|
140
166
|
const protobufVersion = options.protobufJavaVersion ?? DEFAULT_PROTOBUF_JAVA_VERSION;
|
|
141
167
|
return `plugins {
|
|
142
|
-
id "java"
|
|
168
|
+
id "java-library"
|
|
143
169
|
id "maven-publish"
|
|
144
170
|
}
|
|
145
171
|
|
|
@@ -151,7 +177,10 @@ repositories {
|
|
|
151
177
|
}
|
|
152
178
|
|
|
153
179
|
dependencies {
|
|
154
|
-
|
|
180
|
+
api "com.google.protobuf:protobuf-java:${protobufVersion}"
|
|
181
|
+
api "io.grpc:grpc-protobuf:${GRPC_JAVA_VERSION}"
|
|
182
|
+
api "io.grpc:grpc-stub:${GRPC_JAVA_VERSION}"
|
|
183
|
+
compileOnly "javax.annotation:javax.annotation-api:1.3.2"
|
|
155
184
|
}
|
|
156
185
|
|
|
157
186
|
java {
|
|
@@ -188,21 +217,11 @@ edition = "2021"
|
|
|
188
217
|
|
|
189
218
|
[dependencies]
|
|
190
219
|
prost = "${prostVersion}"
|
|
220
|
+
prost-types = "${prostVersion}"
|
|
221
|
+
tonic = "${TONIC_VERSION}"
|
|
222
|
+
tonic-prost = "${TONIC_VERSION}"
|
|
191
223
|
`;
|
|
192
224
|
}
|
|
193
|
-
createRustLibrary(generatedFiles) {
|
|
194
|
-
return generatedFiles
|
|
195
|
-
.map((relativePath) => {
|
|
196
|
-
const moduleName = relativePath
|
|
197
|
-
.replace(/\.rs$/, "")
|
|
198
|
-
.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
199
|
-
return `pub mod ${moduleName} {
|
|
200
|
-
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/${relativePath}"));
|
|
201
|
-
}
|
|
202
|
-
`;
|
|
203
|
-
})
|
|
204
|
-
.join("\n");
|
|
205
|
-
}
|
|
206
225
|
escapeXml(value) {
|
|
207
226
|
return value.replace(/[<>&'"]/g, (character) => {
|
|
208
227
|
switch (character) {
|
|
@@ -228,6 +247,6 @@ prost = "${prostVersion}"
|
|
|
228
247
|
return `${this.artifactKeeperUrl}/maven/maven/`;
|
|
229
248
|
}
|
|
230
249
|
get cargoIndexUrl() {
|
|
231
|
-
return
|
|
250
|
+
return `sparse+${this.artifactKeeperUrl}/cargo/cargo/`;
|
|
232
251
|
}
|
|
233
252
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ProtobufArtifactKeeperBackend, ProtobufGoTargetLanguageOptions } from "../types";
|
|
2
|
+
/** Publishes Buf's import-path output as a hosted Go proxy module. */
|
|
3
|
+
export declare class ArtifactKeeperGoPublisher {
|
|
4
|
+
private readonly config;
|
|
5
|
+
constructor(config: ProtobufArtifactKeeperBackend);
|
|
6
|
+
publish({ generatedDirectory, options, }: {
|
|
7
|
+
generatedDirectory: string;
|
|
8
|
+
options: ProtobufGoTargetLanguageOptions;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
private normalizeVersion;
|
|
11
|
+
private requireToolchains;
|
|
12
|
+
private inferModulePath;
|
|
13
|
+
private findPackageDirectories;
|
|
14
|
+
private validateModuleVersion;
|
|
15
|
+
private stageModule;
|
|
16
|
+
private packageModule;
|
|
17
|
+
private uploadArtifact;
|
|
18
|
+
private archiveRoot;
|
|
19
|
+
private escapeProxyPath;
|
|
20
|
+
private get repositoryUrl();
|
|
21
|
+
private get shell();
|
|
22
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { $ } from "bun";
|
|
2
|
+
import { cp, mkdir, mkdtemp, readdir, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import semver from "semver";
|
|
6
|
+
import { isCmdAvailable } from "../../utils/cmd";
|
|
7
|
+
/** Publishes Buf's import-path output as a hosted Go proxy module. */
|
|
8
|
+
export class ArtifactKeeperGoPublisher {
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
async publish({ generatedDirectory, options, }) {
|
|
14
|
+
const version = this.normalizeVersion(options.version);
|
|
15
|
+
await this.requireToolchains();
|
|
16
|
+
const modulePath = await this.inferModulePath(generatedDirectory);
|
|
17
|
+
this.validateModuleVersion(modulePath, version);
|
|
18
|
+
const module = { modulePath, version };
|
|
19
|
+
const stagingDirectory = await mkdtemp(path.join(tmpdir(), "protobuf-go-"));
|
|
20
|
+
try {
|
|
21
|
+
const moduleDirectory = await this.stageModule(module, generatedDirectory, stagingDirectory);
|
|
22
|
+
const artifacts = await this.packageModule(module, moduleDirectory, stagingDirectory);
|
|
23
|
+
for (const artifact of artifacts) {
|
|
24
|
+
await this.uploadArtifact(module, artifact);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await rm(stagingDirectory, { force: true, recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
normalizeVersion(value) {
|
|
32
|
+
const version = `v${value.replace(/^v/, "")}`;
|
|
33
|
+
if (!semver.valid(version) || version.includes("+")) {
|
|
34
|
+
throw new Error("Go publishing requires a semantic version without build metadata.");
|
|
35
|
+
}
|
|
36
|
+
return version;
|
|
37
|
+
}
|
|
38
|
+
async requireToolchains() {
|
|
39
|
+
for (const command of ["go", "zip"]) {
|
|
40
|
+
if (!(await isCmdAvailable(command))) {
|
|
41
|
+
throw new Error(`Go publishing requires ${command} on PATH.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async inferModulePath(generatedDirectory) {
|
|
46
|
+
const packages = await this.findPackageDirectories(generatedDirectory);
|
|
47
|
+
const prefix = packages[0]?.split("/") ?? [];
|
|
48
|
+
for (const directory of packages.slice(1)) {
|
|
49
|
+
const segments = directory.split("/");
|
|
50
|
+
while (prefix.some((segment, index) => segment !== segments[index])) {
|
|
51
|
+
prefix.pop();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
55
|
+
if (prefix.length < 2 || !prefix[0].includes(".")) {
|
|
56
|
+
throw new Error("Generated go_package paths must share a module prefix containing a domain and path.");
|
|
57
|
+
}
|
|
58
|
+
return prefix.join("/");
|
|
59
|
+
}
|
|
60
|
+
async findPackageDirectories(directory, relativeDirectory = "") {
|
|
61
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
62
|
+
const packages = [];
|
|
63
|
+
if (entries.some((entry) => entry.isFile() && entry.name.endsWith(".go"))) {
|
|
64
|
+
packages.push(relativeDirectory);
|
|
65
|
+
}
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if (entry.isDirectory()) {
|
|
68
|
+
packages.push(...(await this.findPackageDirectories(path.join(directory, entry.name), relativeDirectory ?
|
|
69
|
+
`${relativeDirectory}/${entry.name}`
|
|
70
|
+
: entry.name)));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return packages;
|
|
74
|
+
}
|
|
75
|
+
validateModuleVersion(modulePath, version) {
|
|
76
|
+
const major = semver.major(version);
|
|
77
|
+
const pathMajor = modulePath.match(/\/v([0-9]+)$/)?.[1] ??
|
|
78
|
+
(modulePath.startsWith("gopkg.in/") ?
|
|
79
|
+
modulePath.match(/\.v([0-9]+)$/)?.[1]
|
|
80
|
+
: undefined);
|
|
81
|
+
if ((pathMajor &&
|
|
82
|
+
!modulePath.startsWith("gopkg.in/") &&
|
|
83
|
+
Number(pathMajor) < 2) ||
|
|
84
|
+
(pathMajor && Number(pathMajor) !== major) ||
|
|
85
|
+
(!pathMajor && major >= 2)) {
|
|
86
|
+
throw new Error(`Go module path ${modulePath} does not match version ${version}.`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async stageModule(module, generatedDirectory, stagingDirectory) {
|
|
90
|
+
// Buf's default paths=import layout includes the full go_package import path.
|
|
91
|
+
// Strip only the module prefix, without modifying the original output.
|
|
92
|
+
const sourceDirectory = path.join(generatedDirectory, module.modulePath);
|
|
93
|
+
const moduleDirectory = path.join(stagingDirectory, this.archiveRoot(module));
|
|
94
|
+
await mkdir(path.dirname(moduleDirectory), { recursive: true });
|
|
95
|
+
await cp(sourceDirectory, moduleDirectory, { recursive: true });
|
|
96
|
+
await this.shell `go mod init ${module.modulePath}`.cwd(moduleDirectory);
|
|
97
|
+
return moduleDirectory;
|
|
98
|
+
}
|
|
99
|
+
async packageModule(module, moduleDirectory, stagingDirectory) {
|
|
100
|
+
// Resolve dependency metadata; generated code is not linted or tested.
|
|
101
|
+
await this.shell `go mod tidy`.cwd(moduleDirectory);
|
|
102
|
+
const archivePath = path.join(stagingDirectory, "module.zip");
|
|
103
|
+
const archiveRoot = this.archiveRoot(module);
|
|
104
|
+
await this
|
|
105
|
+
.shell `zip -q -r ${archivePath} ${archiveRoot} -i ${`${archiveRoot}/*`}`.cwd(stagingDirectory);
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
extension: "mod",
|
|
109
|
+
filePath: path.join(moduleDirectory, "go.mod"),
|
|
110
|
+
contentType: "text/plain",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
extension: "zip",
|
|
114
|
+
filePath: archivePath,
|
|
115
|
+
contentType: "application/zip",
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
async uploadArtifact(module, artifact) {
|
|
120
|
+
const url = `${this.repositoryUrl}/${this.escapeProxyPath(module.modulePath)}/@v/${this.escapeProxyPath(module.version)}.${artifact.extension}`;
|
|
121
|
+
const credentials = Buffer.from(`${this.config.username}:${this.config.token}`).toString("base64");
|
|
122
|
+
const response = await fetch(url, {
|
|
123
|
+
method: "PUT",
|
|
124
|
+
headers: {
|
|
125
|
+
Authorization: `Basic ${credentials}`,
|
|
126
|
+
"Content-Type": artifact.contentType,
|
|
127
|
+
},
|
|
128
|
+
body: Bun.file(artifact.filePath),
|
|
129
|
+
redirect: "error",
|
|
130
|
+
});
|
|
131
|
+
await response.body?.cancel();
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
throw new Error(`Go ${artifact.extension} upload failed: HTTP ${response.status}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
archiveRoot(module) {
|
|
137
|
+
return `${module.modulePath}@${module.version}`;
|
|
138
|
+
}
|
|
139
|
+
escapeProxyPath(value) {
|
|
140
|
+
// Go proxy URLs escape uppercase letters; archive entries do not.
|
|
141
|
+
return value.replace(/[A-Z]/g, (letter) => `!${letter.toLowerCase()}`);
|
|
142
|
+
}
|
|
143
|
+
get repositoryUrl() {
|
|
144
|
+
return `${this.config.url.replace(/\/$/, "")}/go/go`;
|
|
145
|
+
}
|
|
146
|
+
get shell() {
|
|
147
|
+
return $.env({ ...process.env, GOWORK: "off" });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/** Prost filenames encode proto packages; Tonic belongs in the same module. */
|
|
3
|
+
export function createRustLibrary(generatedFiles) {
|
|
4
|
+
const root = { files: [], children: new Map() };
|
|
5
|
+
for (const file of [...generatedFiles].sort()) {
|
|
6
|
+
const packageName = path.posix
|
|
7
|
+
.basename(file)
|
|
8
|
+
.replace(/(?:\.tonic)?\.rs$/, "");
|
|
9
|
+
let node = root;
|
|
10
|
+
for (const segment of packageName === "_" ? [] : packageName.split(".")) {
|
|
11
|
+
if (!/^(?:r#)?[a-zA-Z_][a-zA-Z0-9_]*$/.test(segment) ||
|
|
12
|
+
["self", "Self", "super", "crate"].includes(segment)) {
|
|
13
|
+
throw new Error(`Cannot represent Rust package module ${segment} from ${file}.`);
|
|
14
|
+
}
|
|
15
|
+
const name = segment.startsWith("r#") ? segment : `r#${segment}`;
|
|
16
|
+
let child = node.children.get(name);
|
|
17
|
+
if (!child) {
|
|
18
|
+
child = { files: [], children: new Map() };
|
|
19
|
+
node.children.set(name, child);
|
|
20
|
+
}
|
|
21
|
+
node = child;
|
|
22
|
+
}
|
|
23
|
+
node.files.push(file);
|
|
24
|
+
}
|
|
25
|
+
function render(node, indent = "") {
|
|
26
|
+
const includes = node.files
|
|
27
|
+
.map((file) => `${indent}include!(concat!(env!("CARGO_MANIFEST_DIR"), ${JSON.stringify(`/${file}`)}));\n`)
|
|
28
|
+
.join("");
|
|
29
|
+
const children = [...node.children]
|
|
30
|
+
.map(([name, child]) => `${indent}pub mod ${name} {\n${render(child, `${indent} `)}${indent}}\n`)
|
|
31
|
+
.join("");
|
|
32
|
+
return includes + children;
|
|
33
|
+
}
|
|
34
|
+
return render(root);
|
|
35
|
+
}
|
package/dist/protobuf/client.js
CHANGED
|
@@ -8,9 +8,9 @@ import { createProtobufCompilerBackendStrategy } from "./backend";
|
|
|
8
8
|
import { GoProtobufTargetLanguageStrategy, JavaProtobufTargetLanguageStrategy, RustProtobufTargetLanguageStrategy, } from "./strategy";
|
|
9
9
|
import { ProtobufTargetLanguage, } from "./types";
|
|
10
10
|
const TARGET_LANGUAGE_STRATEGY_FACTORIES = {
|
|
11
|
-
[ProtobufTargetLanguage.JAVA]: () => new JavaProtobufTargetLanguageStrategy(),
|
|
11
|
+
[ProtobufTargetLanguage.JAVA]: (targets) => new JavaProtobufTargetLanguageStrategy(targets[ProtobufTargetLanguage.JAVA]?.protobufJavaVersion),
|
|
12
12
|
[ProtobufTargetLanguage.GO]: () => new GoProtobufTargetLanguageStrategy(),
|
|
13
|
-
[ProtobufTargetLanguage.RUST]: () => new RustProtobufTargetLanguageStrategy(),
|
|
13
|
+
[ProtobufTargetLanguage.RUST]: (targets) => new RustProtobufTargetLanguageStrategy(targets[ProtobufTargetLanguage.RUST]?.prostVersion),
|
|
14
14
|
};
|
|
15
15
|
export class ProtobufCompilerClient {
|
|
16
16
|
async compile({ backend, bufToken, targetLanguages, protoFilesLocation, outputDirectory, }) {
|
|
@@ -58,10 +58,11 @@ export class ProtobufCompilerClient {
|
|
|
58
58
|
const pathFlag = pathFilter ? ["--path", pathFilter] : [];
|
|
59
59
|
await writeFile(templatePath, yaml.stringify({
|
|
60
60
|
version: "v2",
|
|
61
|
-
plugins: targetStrategies.
|
|
61
|
+
plugins: targetStrategies.flatMap((strategy) => strategy.plugins.map((plugin) => ({
|
|
62
|
+
...plugin,
|
|
62
63
|
out: strategy.outputDirectoryName,
|
|
63
|
-
|
|
64
|
-
})),
|
|
64
|
+
include_imports: true,
|
|
65
|
+
}))),
|
|
65
66
|
}));
|
|
66
67
|
try {
|
|
67
68
|
const command = bufToken ?
|
|
@@ -80,7 +81,7 @@ export class ProtobufCompilerClient {
|
|
|
80
81
|
return this.getConfiguredTargetLanguages(targetLanguages).map(([language, options]) => ({
|
|
81
82
|
language,
|
|
82
83
|
options,
|
|
83
|
-
strategy: TARGET_LANGUAGE_STRATEGY_FACTORIES[language](),
|
|
84
|
+
strategy: TARGET_LANGUAGE_STRATEGY_FACTORIES[language](targetLanguages),
|
|
84
85
|
}));
|
|
85
86
|
}
|
|
86
87
|
getConfiguredTargetLanguages(targetLanguages) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { IProtobufTargetLanguageStrategy } from "./types";
|
|
2
2
|
export declare class GoProtobufTargetLanguageStrategy implements IProtobufTargetLanguageStrategy {
|
|
3
3
|
readonly outputDirectoryName = "go";
|
|
4
|
-
readonly
|
|
4
|
+
readonly plugins: {
|
|
5
|
+
remote: string;
|
|
6
|
+
}[];
|
|
5
7
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { IProtobufTargetLanguageStrategy } from "./types";
|
|
2
2
|
export declare class JavaProtobufTargetLanguageStrategy implements IProtobufTargetLanguageStrategy {
|
|
3
3
|
readonly outputDirectoryName = "java";
|
|
4
|
-
readonly
|
|
4
|
+
readonly plugins: {
|
|
5
|
+
remote: string;
|
|
6
|
+
}[];
|
|
7
|
+
constructor(runtimeVersion?: string);
|
|
5
8
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import { DEFAULT_PROTOBUF_JAVA_VERSION, GRPC_JAVA_VERSION, javaGeneratorVersion, } from "../versions";
|
|
1
2
|
export class JavaProtobufTargetLanguageStrategy {
|
|
2
3
|
outputDirectoryName = "java";
|
|
3
|
-
|
|
4
|
+
plugins;
|
|
5
|
+
constructor(runtimeVersion = DEFAULT_PROTOBUF_JAVA_VERSION) {
|
|
6
|
+
this.plugins = [
|
|
7
|
+
{
|
|
8
|
+
remote: `buf.build/protocolbuffers/java:v${javaGeneratorVersion(runtimeVersion)}`,
|
|
9
|
+
},
|
|
10
|
+
{ remote: `buf.build/grpc/java:v${GRPC_JAVA_VERSION}` },
|
|
11
|
+
];
|
|
12
|
+
}
|
|
4
13
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { IProtobufTargetLanguageStrategy } from "./types";
|
|
2
2
|
export declare class RustProtobufTargetLanguageStrategy implements IProtobufTargetLanguageStrategy {
|
|
3
3
|
readonly outputDirectoryName = "rust";
|
|
4
|
-
readonly
|
|
4
|
+
readonly plugins: ({
|
|
5
|
+
remote: string;
|
|
6
|
+
opt?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
remote: string;
|
|
9
|
+
opt: string[];
|
|
10
|
+
})[];
|
|
11
|
+
constructor(prostVersion?: string);
|
|
5
12
|
}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { DEFAULT_PROST_VERSION, PROST_PLUGIN_VERSION } from "../versions";
|
|
1
3
|
export class RustProtobufTargetLanguageStrategy {
|
|
2
4
|
outputDirectoryName = "rust";
|
|
3
|
-
|
|
5
|
+
plugins = [
|
|
6
|
+
{
|
|
7
|
+
remote: `buf.build/community/neoeinstein-prost:v${PROST_PLUGIN_VERSION}`,
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
remote: `buf.build/community/neoeinstein-tonic:v${PROST_PLUGIN_VERSION}`,
|
|
11
|
+
// lib.rs includes messages and service stubs into the same package module.
|
|
12
|
+
opt: ["no_include=true"],
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
constructor(prostVersion = DEFAULT_PROST_VERSION) {
|
|
16
|
+
if (!semver.validRange(prostVersion) ||
|
|
17
|
+
!semver.subset(prostVersion, ">=0.14.0 <0.15.0")) {
|
|
18
|
+
throw new Error("The pinned Rust gRPC generators require prostVersion in the 0.14 release series.");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
4
21
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
export interface ProtobufGeneratorPlugin {
|
|
2
|
+
readonly remote: string;
|
|
3
|
+
readonly opt?: string[];
|
|
4
|
+
}
|
|
1
5
|
export interface IProtobufTargetLanguageStrategy {
|
|
2
6
|
readonly outputDirectoryName: string;
|
|
3
|
-
readonly
|
|
7
|
+
readonly plugins: ProtobufGeneratorPlugin[];
|
|
4
8
|
}
|
package/dist/protobuf/types.d.ts
CHANGED
|
@@ -17,19 +17,22 @@ export interface ProtobufArtifactKeeperBackend {
|
|
|
17
17
|
}
|
|
18
18
|
export type ProtobufCompilerBackendConfig = ProtobufArtifactKeeperBackend;
|
|
19
19
|
export interface ProtobufJavaTargetLanguageOptions {
|
|
20
|
+
/** Maven/Gradle publishing group; Java packages are configured in .proto files. */
|
|
20
21
|
groupId: string;
|
|
21
22
|
artifactId: string;
|
|
22
23
|
version: string;
|
|
23
24
|
buildTool?: "maven" | "gradle";
|
|
25
|
+
/** Exact stable Java runtime version; also pins the matching Buf generator. Defaults to 4.32.1. */
|
|
24
26
|
protobufJavaVersion?: string;
|
|
25
27
|
}
|
|
26
28
|
export interface ProtobufRustTargetLanguageOptions {
|
|
27
29
|
crateName: string;
|
|
28
30
|
version: string;
|
|
31
|
+
/** Prost runtime constraint within 0.14; matched to the pinned Prost/Tonic generators. */
|
|
29
32
|
prostVersion?: string;
|
|
30
33
|
}
|
|
34
|
+
/** Go import paths are configured with go_package in .proto files. */
|
|
31
35
|
export interface ProtobufGoTargetLanguageOptions {
|
|
32
|
-
modulePath: string;
|
|
33
36
|
version: string;
|
|
34
37
|
}
|
|
35
38
|
export type ProtobufTargetLanguageOptions = ProtobufGoTargetLanguageOptions | ProtobufJavaTargetLanguageOptions | ProtobufRustTargetLanguageOptions;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DEFAULT_PROTOBUF_JAVA_VERSION = "4.32.1";
|
|
2
|
+
export declare const GRPC_JAVA_VERSION = "1.75.0";
|
|
3
|
+
export declare const PROST_PLUGIN_VERSION = "0.5.0";
|
|
4
|
+
export declare const DEFAULT_PROST_VERSION = "0.14.1";
|
|
5
|
+
export declare const TONIC_VERSION = "0.14.1";
|
|
6
|
+
/** Java runtime releases include a language major absent from modern protoc tags. */
|
|
7
|
+
export declare function javaGeneratorVersion(runtimeVersion: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const DEFAULT_PROTOBUF_JAVA_VERSION = "4.32.1";
|
|
2
|
+
export const GRPC_JAVA_VERSION = "1.75.0";
|
|
3
|
+
export const PROST_PLUGIN_VERSION = "0.5.0";
|
|
4
|
+
export const DEFAULT_PROST_VERSION = "0.14.1";
|
|
5
|
+
export const TONIC_VERSION = "0.14.1";
|
|
6
|
+
/** Java runtime releases include a language major absent from modern protoc tags. */
|
|
7
|
+
export function javaGeneratorVersion(runtimeVersion) {
|
|
8
|
+
const match = /^(3|4)\.(\d+)\.(\d+)$/.exec(runtimeVersion);
|
|
9
|
+
if (!match) {
|
|
10
|
+
throw new Error("protobufJavaVersion must be an exact stable 3.x or 4.x version.");
|
|
11
|
+
}
|
|
12
|
+
const [, major, minor, patch] = match;
|
|
13
|
+
// Before protoc 21, compiler and Java runtime used the same 3.x version.
|
|
14
|
+
return major === "3" && Number(minor) < 21 ?
|
|
15
|
+
runtimeVersion
|
|
16
|
+
: `${minor}.${patch}`;
|
|
17
|
+
}
|
|
@@ -83,7 +83,8 @@ export class VersioningClient {
|
|
|
83
83
|
async nextBeta(sha, ...opts) {
|
|
84
84
|
const latestTag = await this.githubClient.getLatestTag(...opts);
|
|
85
85
|
if (!latestTag) {
|
|
86
|
-
|
|
86
|
+
console.warn("No latest tag yet. You should upload a tag atleast once before generating a beta tag. Defaulting to `1.0.0-beta.${sha}`");
|
|
87
|
+
return `1.0.0-beta.${sha}`;
|
|
87
88
|
}
|
|
88
89
|
const latest = this.parseOrThrow("latest tag from github", latestTag);
|
|
89
90
|
return `${latest.toString()}-beta.${sha}`;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"author": "Tahmid Ahmed",
|
|
5
5
|
"description": "A collection of Bun shell scripts that can be re-used in various CICD pipelines.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.78-beta.1fe28066",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "git+https://github.com/tahminator/pipeline.git"
|
|
9
9
|
},
|