@tahminator/pipeline 1.0.91 → 1.0.92-beta.g1f7c613a
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 +15 -1
- package/dist/docker/client.js +6 -1
- package/dist/flux/client.js +4 -11
- package/dist/flux/render.d.ts +8 -0
- package/dist/flux/render.js +20 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -327,12 +327,14 @@ await flux.diff({
|
|
|
327
327
|
|
|
328
328
|
Each Kustomization is rendered as `kustomize build` of `spec.path` with `targetNamespace`, `namePrefix`, `nameSuffix`, `components`, `images`, `patches` and `commonMetadata` applied on top, followed by `postBuild.substitute`. Paths without a `kustomization.yaml` get one generated, as Flux does. Values from `postBuild.substituteFrom` live in the cluster, so those variables are left as-is and listed in the diff's notes. A build failure is shown in the comment instead of being skipped. `HelmRelease` objects are diffed as manifests; charts are not templated.
|
|
329
329
|
|
|
330
|
-
The diff is split per Kubernetes object (matched by API group, kind, namespace and name), and each object is labelled with the file that defines it, taken from kustomize's `originAnnotations`. Generated ConfigMaps and Secrets point at the `kustomization.yaml` whose generator creates them. Files that only patch an object are not recorded, so a change made by a patch is attributed to the object's original file.
|
|
330
|
+
The diff is split per Kubernetes object (matched by API group, kind, namespace and name), and each object is labelled with the file that defines it, taken from kustomize's `originAnnotations`. Generated ConfigMaps and Secrets point at the `kustomization.yaml` whose generator creates them, and are matched without their content-hash suffix, so editing a generator's data shows as a line diff of the same object rather than a removal and an addition. Files that only patch an object are not recorded, so a change made by a patch is attributed to the object's original file. Any other renamed object shows as one removal and one addition.
|
|
331
331
|
|
|
332
332
|
### `DockerClient`
|
|
333
333
|
|
|
334
334
|
Interface with Docker to build & deploy images
|
|
335
335
|
|
|
336
|
+
`buildImage` runs BuildKit on the runner's network with `--network host`, so every `RUN` instruction can reach whatever the runner can, including hosts on the Headscale VPN connected by the setup action. Dockerfiles don't need `RUN --network=host`.
|
|
337
|
+
|
|
336
338
|
```ts
|
|
337
339
|
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management
|
|
338
340
|
await using client = await DockerClient.create(
|
|
@@ -423,6 +425,18 @@ View the [action file](./actions/setup/action.yaml) for all available inputs.
|
|
|
423
425
|
cargo-nextest@0.9.100
|
|
424
426
|
```
|
|
425
427
|
|
|
428
|
+
Language toolchains are installed and cached by the setup action, so jobs don't need separate `setup-go` / `setup-java` / `rust-toolchain` steps:
|
|
429
|
+
|
|
430
|
+
```yaml
|
|
431
|
+
- uses: tahminator/pipeline/actions/setup@<version>
|
|
432
|
+
with:
|
|
433
|
+
INSTALL_GO: "true" # version read from GO_VERSION_FILE (default go.mod) unless GO_VERSION is set
|
|
434
|
+
INSTALL_JAVA: "true" # JAVA_VERSION "21", JAVA_DISTRIBUTION "temurin", JAVA_CACHE "maven" by default
|
|
435
|
+
INSTALL_RUST: "true" # also caches the Cargo registry and target dir
|
|
436
|
+
RUST_TOOLCHAIN: "1.93.0"
|
|
437
|
+
RUST_COMPONENTS: "clippy, rustfmt"
|
|
438
|
+
```
|
|
439
|
+
|
|
426
440
|
### `NPMClient`
|
|
427
441
|
|
|
428
442
|
Interface with NPM registry in order to publish packages to `npmjs.com`
|
package/dist/docker/client.js
CHANGED
|
@@ -48,7 +48,10 @@ export class DockerClient {
|
|
|
48
48
|
console.log("Building image with following tags:");
|
|
49
49
|
tags.forEach((tag) => console.log(Utils.Colors.cyan(tag)));
|
|
50
50
|
try {
|
|
51
|
-
await $ `docker buildx create --use --name ${dockerRepository}-builder
|
|
51
|
+
await $ `docker buildx create --use --name ${dockerRepository}-builder \
|
|
52
|
+
--driver docker-container \
|
|
53
|
+
--driver-opt network=host \
|
|
54
|
+
--buildkitd-flags ${"--allow-insecure-entitlement network.host"}`;
|
|
52
55
|
}
|
|
53
56
|
catch {
|
|
54
57
|
await $ `docker buildx use ${dockerRepository}-builder`;
|
|
@@ -68,6 +71,8 @@ export class DockerClient {
|
|
|
68
71
|
--cache-from=type=gha \
|
|
69
72
|
--cache-to=type=gha,mode=max \
|
|
70
73
|
${buildArgFlags} \
|
|
74
|
+
--network host \
|
|
75
|
+
--allow network.host \
|
|
71
76
|
${tagFlags} \
|
|
72
77
|
.`;
|
|
73
78
|
console.log(shouldUpload ?
|
package/dist/flux/client.js
CHANGED
|
@@ -4,7 +4,7 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { findFluxKustomizations } from "./discover";
|
|
6
6
|
import { formatFluxDiff, label } from "./format";
|
|
7
|
-
import { renderKustomization } from "./render";
|
|
7
|
+
import { objectKey, renderKustomization } from "./render";
|
|
8
8
|
import {} from "./types";
|
|
9
9
|
/** GitHub rejects comment bodies above 65536 characters. */
|
|
10
10
|
const MAX_COMMENT_LENGTH = 65_536;
|
|
@@ -155,21 +155,14 @@ export class FluxClient {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
/**
|
|
159
|
-
* Pairs base and head objects by API group, kind, namespace and name, and diffs the ones whose
|
|
160
|
-
* rendered YAML differs. An apiVersion bump within a group is a change, not a remove + add.
|
|
161
|
-
*/
|
|
158
|
+
/** Pairs base and head objects by {@link objectKey} and diffs the ones whose rendered YAML differs. */
|
|
162
159
|
async function diffObjects(baseObjects, headObjects, nextDir) {
|
|
163
|
-
const key = (object) => {
|
|
164
|
-
const group = object.apiVersion.includes("/") ? object.apiVersion.split("/")[0] : "";
|
|
165
|
-
return [group, object.kind, object.namespace, object.name].join("\0");
|
|
166
|
-
};
|
|
167
160
|
const pairs = new Map();
|
|
168
161
|
for (const object of baseObjects) {
|
|
169
|
-
pairs.set(
|
|
162
|
+
pairs.set(objectKey(object), { base: object });
|
|
170
163
|
}
|
|
171
164
|
for (const object of headObjects) {
|
|
172
|
-
const k =
|
|
165
|
+
const k = objectKey(object);
|
|
173
166
|
pairs.set(k, { ...pairs.get(k), head: object });
|
|
174
167
|
}
|
|
175
168
|
const diffs = await Promise.all([...pairs.values()].map(async ({ base, head }) => {
|
package/dist/flux/render.d.ts
CHANGED
|
@@ -9,9 +9,17 @@ export type RenderedObject = {
|
|
|
9
9
|
* kustomization.yaml whose generator creates it); `undefined` if kustomize did not record one
|
|
10
10
|
*/
|
|
11
11
|
file?: string;
|
|
12
|
+
/** created by a ConfigMap/Secret generator, so `name` may end in a content hash */
|
|
13
|
+
generated: boolean;
|
|
12
14
|
/** the object's rendered YAML, without the origin annotation */
|
|
13
15
|
yaml: string;
|
|
14
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Identifies the same object across two renders: API group, kind, namespace and name.
|
|
19
|
+
* An apiVersion bump within a group keeps the key; generated objects drop the content hash
|
|
20
|
+
* from their name so an edited ConfigMap/Secret pairs with its previous version.
|
|
21
|
+
*/
|
|
22
|
+
export declare function objectKey(object: RenderedObject): string;
|
|
15
23
|
type RenderedKustomization = {
|
|
16
24
|
/** rendered objects, in kustomize's output order; empty when `error` is set */
|
|
17
25
|
objects: RenderedObject[];
|
package/dist/flux/render.js
CHANGED
|
@@ -12,6 +12,19 @@ const SUBSTITUTE_DISABLED = /kustomize\.toolkit\.fluxcd\.io\/substitute:\s*["']?
|
|
|
12
12
|
const VARIABLE = /\$(\$)?\{([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-=])([^}]*))?\}/g;
|
|
13
13
|
/** kustomize's `originAnnotations` build metadata; records the file that defines each object. */
|
|
14
14
|
const ORIGIN_ANNOTATION = "config.kubernetes.io/origin";
|
|
15
|
+
const GENERATORS = ["ConfigMapGenerator", "SecretGenerator"];
|
|
16
|
+
/** kustomize's name hash: 10 characters from its vowel-free alphabet, appended last. */
|
|
17
|
+
const NAME_HASH = /-[2456789bcdfghkmt]{10}$/;
|
|
18
|
+
/**
|
|
19
|
+
* Identifies the same object across two renders: API group, kind, namespace and name.
|
|
20
|
+
* An apiVersion bump within a group keeps the key; generated objects drop the content hash
|
|
21
|
+
* from their name so an edited ConfigMap/Secret pairs with its previous version.
|
|
22
|
+
*/
|
|
23
|
+
export function objectKey(object) {
|
|
24
|
+
const group = object.apiVersion.includes("/") ? object.apiVersion.split("/")[0] : "";
|
|
25
|
+
const name = object.generated ? object.name.replace(NAME_HASH, "") : object.name;
|
|
26
|
+
return [group, object.kind, object.namespace, name].join("\0");
|
|
27
|
+
}
|
|
15
28
|
/**
|
|
16
29
|
* Renders a Flux `Kustomization` the way kustomize-controller does: `kustomize build` of
|
|
17
30
|
* `spec.path` with the overlay fields from the spec (`targetNamespace`, `namePrefix`,
|
|
@@ -86,21 +99,21 @@ export async function renderKustomization(root, kustomization) {
|
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
101
|
function toRenderedObject(doc, root, wrapper) {
|
|
89
|
-
const
|
|
102
|
+
const raw = doc.getIn(["metadata", "annotations", ORIGIN_ANNOTATION]);
|
|
90
103
|
doc.deleteIn(["metadata", "annotations", ORIGIN_ANNOTATION]);
|
|
91
104
|
const annotations = doc.getIn(["metadata", "annotations"]);
|
|
92
105
|
if (yaml.isMap(annotations) && annotations.items.length === 0) {
|
|
93
106
|
doc.deleteIn(["metadata", "annotations"]);
|
|
94
107
|
}
|
|
108
|
+
const origin = typeof raw === "string" ? yaml.parse(raw) : null;
|
|
95
109
|
const value = (doc.toJS() ?? {});
|
|
96
110
|
return {
|
|
97
111
|
apiVersion: String(value.apiVersion ?? ""),
|
|
98
112
|
kind: String(value.kind ?? ""),
|
|
99
113
|
namespace: String(value.metadata?.namespace ?? ""),
|
|
100
114
|
name: String(value.metadata?.name ?? ""),
|
|
101
|
-
file:
|
|
102
|
-
|
|
103
|
-
: undefined,
|
|
115
|
+
file: origin ? originFile(origin, root, wrapper) : undefined,
|
|
116
|
+
generated: GENERATORS.includes(origin?.configuredBy?.kind ?? ""),
|
|
104
117
|
yaml: doc.toString({ lineWidth: 0 }).replace(/^---\n/, ""),
|
|
105
118
|
};
|
|
106
119
|
}
|
|
@@ -110,10 +123,9 @@ function toRenderedObject(doc, root, wrapper) {
|
|
|
110
123
|
* `<repo>//<path>?ref=<ref>`.
|
|
111
124
|
*/
|
|
112
125
|
function originFile(origin, root, wrapper) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return `${parsed.repo}//${file ?? ""}${parsed.ref ? `?ref=${parsed.ref}` : ""}`;
|
|
126
|
+
const file = origin.path ?? origin.configuredIn;
|
|
127
|
+
if (origin.repo) {
|
|
128
|
+
return `${origin.repo}//${file ?? ""}${origin.ref ? `?ref=${origin.ref}` : ""}`;
|
|
117
129
|
}
|
|
118
130
|
return file ? path.relative(root, path.resolve(wrapper, file)) : undefined;
|
|
119
131
|
}
|
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.92-beta.g1f7c613a",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "git+https://github.com/tahminator/pipeline.git"
|
|
9
9
|
},
|