@tahminator/pipeline 1.0.91 → 1.0.92-beta.gba48c7d3

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 CHANGED
@@ -327,7 +327,7 @@ 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. A renamed object (e.g. a new generator hash suffix) shows as one removal and one addition.
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
 
@@ -423,6 +423,18 @@ View the [action file](./actions/setup/action.yaml) for all available inputs.
423
423
  cargo-nextest@0.9.100
424
424
  ```
425
425
 
426
+ Language toolchains are installed and cached by the setup action, so jobs don't need separate `setup-go` / `setup-java` / `rust-toolchain` steps:
427
+
428
+ ```yaml
429
+ - uses: tahminator/pipeline/actions/setup@<version>
430
+ with:
431
+ INSTALL_GO: "true" # version read from GO_VERSION_FILE (default go.mod) unless GO_VERSION is set
432
+ INSTALL_JAVA: "true" # JAVA_VERSION "21", JAVA_DISTRIBUTION "temurin", JAVA_CACHE "maven" by default
433
+ INSTALL_RUST: "true" # also caches the Cargo registry and target dir
434
+ RUST_TOOLCHAIN: "1.93.0"
435
+ RUST_COMPONENTS: "clippy, rustfmt"
436
+ ```
437
+
426
438
  ### `NPMClient`
427
439
 
428
440
  Interface with NPM registry in order to publish packages to `npmjs.com`
@@ -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(key(object), { base: object });
162
+ pairs.set(objectKey(object), { base: object });
170
163
  }
171
164
  for (const object of headObjects) {
172
- const k = key(object);
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 }) => {
@@ -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[];
@@ -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 origin = doc.getIn(["metadata", "annotations", ORIGIN_ANNOTATION]);
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: typeof origin === "string" ?
102
- originFile(origin, root, wrapper)
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 parsed = yaml.parse(origin);
114
- const file = parsed?.path ?? parsed?.configuredIn;
115
- if (parsed?.repo) {
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.91",
6
+ "version": "1.0.92-beta.gba48c7d3",
7
7
  "repository": {
8
8
  "url": "git+https://github.com/tahminator/pipeline.git"
9
9
  },