@ankhorage/devtools 1.10.0 → 1.10.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.
@@ -3,6 +3,7 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { applyBunRuntimePolicy } from '../policy/applyBunRuntimePolicy.js';
5
5
  import { nodeRuntimePolicy } from '../policy/bunRuntimePolicy.js';
6
+ import { renderRenovateWorkflowAsync } from '../tools/workflows/renderRenovateWorkflowAsync.js';
6
7
  import { renderWorkflowAsync } from '../tools/workflows/renderWorkflowAsync.js';
7
8
  export async function synchronizeRenovateOwnerAsync(operation, targetDirectory, options = {}) {
8
9
  const target = resolve(targetDirectory);
@@ -52,7 +53,7 @@ async function createManagedDefinitionsAsync(targetDirectory, policy) {
52
53
  },
53
54
  {
54
55
  relativePath: '.github/workflows/renovate.yml',
55
- contents: await renderWorkflowAsync(new URL('../tools/workflows/files/renovate.yml', import.meta.url), workflowPolicy),
56
+ contents: await renderRenovateWorkflowAsync(new URL('../tools/workflows/files/renovate.yml', import.meta.url), targetDirectory, workflowPolicy),
56
57
  },
57
58
  {
58
59
  relativePath: 'README.md',
@@ -1,9 +1,10 @@
1
1
  import { bunRuntimePolicy, nodeRuntimePolicy } from '../../policy/bunRuntimePolicy.js';
2
+ import { renderRenovateWorkflowAsync } from './renderRenovateWorkflowAsync.js';
2
3
  import { renderWorkflowAsync } from './renderWorkflowAsync.js';
3
4
  export const workflowManagedFiles = [
4
5
  createWorkflowDefinition('.github/workflows/ci.yml', './files/ci.yml'),
5
6
  createWorkflowDefinition('.github/workflows/release.yml', './files/release.yml'),
6
- createWorkflowDefinition('.github/workflows/renovate.yml', './files/renovate.yml'),
7
+ createRenovateWorkflowDefinition(),
7
8
  ];
8
9
  function createWorkflowDefinition(relativePath, sourcePath) {
9
10
  const sourceUrl = new URL(sourcePath, import.meta.url);
@@ -15,3 +16,14 @@ function createWorkflowDefinition(relativePath, sourcePath) {
15
16
  }),
16
17
  };
17
18
  }
19
+ /*** Creates the managed workflow whose immutable digest remains Renovate-owned. */
20
+ function createRenovateWorkflowDefinition() {
21
+ const sourceUrl = new URL('./files/renovate.yml', import.meta.url);
22
+ return {
23
+ relativePath: '.github/workflows/renovate.yml',
24
+ render: async (targetDirectory) => await renderRenovateWorkflowAsync(sourceUrl, targetDirectory, {
25
+ bunVersion: bunRuntimePolicy.version,
26
+ nodeVersion: nodeRuntimePolicy.setupVersion,
27
+ }),
28
+ };
29
+ }
@@ -0,0 +1,3 @@
1
+ import { type WorkflowPolicy } from './renderWorkflowAsync.js';
2
+ /*** Renders the canonical workflow while retaining Renovate's exact trusted digest. */
3
+ export declare function renderRenovateWorkflowAsync(sourceUrl: URL, targetDirectory: string, policy: WorkflowPolicy): Promise<string>;
@@ -0,0 +1,39 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { renderWorkflowAsync } from './renderWorkflowAsync.js';
4
+ /*** Renders the canonical workflow while retaining Renovate's exact trusted digest. */
5
+ export async function renderRenovateWorkflowAsync(sourceUrl, targetDirectory, policy) {
6
+ const template = await renderWorkflowAsync(sourceUrl, policy);
7
+ readSingleRenovateWorkflowDigest(template, 'Devtools workflow template');
8
+ const target = await readOptionalWorkflowAsync(resolve(targetDirectory, RENOVATE_WORKFLOW_RELATIVE_PATH));
9
+ if (target === null)
10
+ return template;
11
+ const digest = readSingleRenovateWorkflowDigest(target, 'target workflow');
12
+ return template.replace(RENOVATE_WORKFLOW_REFERENCE_PATTERN, (_reference, prefix, _templateDigest, suffix) => `${prefix}${digest}${suffix}`);
13
+ }
14
+ /*** Reads one exact immutable digest from the canonical Renovate workflow reference. */
15
+ function readSingleRenovateWorkflowDigest(contents, source) {
16
+ const matches = [...contents.matchAll(RENOVATE_WORKFLOW_REFERENCE_PATTERN)];
17
+ const digest = matches.length === 1 ? matches[0]?.[2] : undefined;
18
+ if (digest === undefined) {
19
+ throw new Error(`Expected exactly one immutable Renovate digest in the ${source}.`);
20
+ }
21
+ return digest;
22
+ }
23
+ /*** Reads an existing managed workflow without treating first-time creation as an error. */
24
+ async function readOptionalWorkflowAsync(path) {
25
+ try {
26
+ return await readFile(path, 'utf8');
27
+ }
28
+ catch (error) {
29
+ if (isNodeError(error) && error.code === 'ENOENT')
30
+ return null;
31
+ throw error;
32
+ }
33
+ }
34
+ /*** Narrows filesystem failures to Node errors with stable codes. */
35
+ function isNodeError(error) {
36
+ return error instanceof Error && 'code' in error;
37
+ }
38
+ const RENOVATE_WORKFLOW_REFERENCE_PATTERN = /^([ \t]*uses:[ \t]+ankhorage\/renovate\/\.github\/workflows\/changeset\.yml@)([0-9a-f]{40})([ \t]*)$/gmu;
39
+ const RENOVATE_WORKFLOW_RELATIVE_PATH = '.github/workflows/renovate.yml';
@@ -1,4 +1,6 @@
1
- export declare function renderWorkflowAsync(sourceUrl: URL, policy: {
1
+ export interface WorkflowPolicy {
2
2
  readonly bunVersion: string;
3
3
  readonly nodeVersion: string;
4
- }): Promise<string>;
4
+ }
5
+ /*** Renders one workflow template with the canonical runtime and Changesets policy. */
6
+ export declare function renderWorkflowAsync(sourceUrl: URL, policy: WorkflowPolicy): Promise<string>;
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { changesetsPolicy } from '../../policy/changesetsPolicy.js';
3
+ /*** Renders one workflow template with the canonical runtime and Changesets policy. */
3
4
  export async function renderWorkflowAsync(sourceUrl, policy) {
4
5
  const template = await readFile(sourceUrl, 'utf8');
5
6
  return template
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/devtools",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "Shared development tools and repository standards for Ankhorage",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/ankhorage/devtools#readme",