@dbx-tools/projen 0.6.153 → 0.6.160
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 +53 -29
- package/index.ts +2 -0
- package/package.json +4 -4
- package/src/pnpm-workspace.ts +8 -1
- package/src/project-js.ts +64 -5
- package/src/project-py.ts +221 -42
- package/src/project-rs.ts +382 -92
- package/src/release-dispatch.ts +36 -0
- package/src/release.ts +187 -17
- package/tasks/bump.ts +21 -3
- package/tasks/uniffi-release.mjs +14 -2
package/src/project-py.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/** Reusable uv workspace generation for Python packages hosted in a projen tree. */
|
|
2
|
+
import { project as coreProject } from "@dbx-tools/core";
|
|
2
3
|
import { string } from "@dbx-tools/shared-core";
|
|
3
4
|
import { Component, TextFile, type Project, javascript, python, vscode } from "projen";
|
|
4
5
|
import type { IResolver } from "projen/lib/file";
|
|
5
6
|
import { GithubWorkflow } from "projen/lib/github";
|
|
6
7
|
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
7
8
|
import { parse, stringify } from "smol-toml";
|
|
9
|
+
import { projectReleaseBranch, projectRepositoryUrl } from "./project-js.ts";
|
|
8
10
|
import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
|
|
11
|
+
import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
12
|
+
import { DOWNSTREAM_RELEASE_EVENT, RELEASE_TAG, releaseSourceSteps } from "./release-dispatch.ts";
|
|
9
13
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
10
14
|
|
|
11
15
|
/** Git location used by direct `#subdirectory=` package dependencies. */
|
|
@@ -18,17 +22,26 @@ export interface PythonRepositoryOptions {
|
|
|
18
22
|
/** One independently installable Python package in the uv workspace. */
|
|
19
23
|
export interface PythonPackageOptions extends DBXToolsProjectOptions {
|
|
20
24
|
readonly directory: string;
|
|
21
|
-
readonly name
|
|
22
|
-
readonly module
|
|
25
|
+
readonly name?: string;
|
|
26
|
+
readonly module?: string;
|
|
23
27
|
readonly description: string;
|
|
24
28
|
readonly dependencies?: readonly string[];
|
|
29
|
+
/** Workspace package directories rendered as standalone Git dependencies. */
|
|
30
|
+
readonly internalDependencies?: readonly string[];
|
|
25
31
|
readonly scripts?: Readonly<Record<string, string>>;
|
|
26
32
|
/** Keep this package unpublished and out of public docs and releases. */
|
|
27
33
|
readonly private?: boolean;
|
|
34
|
+
/** Generated source files excluded from strict static analysis. Package-relative. */
|
|
35
|
+
readonly generatedSources?: readonly string[];
|
|
28
36
|
/** Trusted publisher used outside the standard Python release workflow. */
|
|
29
37
|
readonly trustedPublisher?: PythonTrustedPublisherOptions;
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
interface ResolvedPythonPackageOptions extends PythonPackageOptions {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly module: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
/** GitHub Actions publisher for a Python package released by another workflow. */
|
|
33
46
|
export interface PythonTrustedPublisherOptions {
|
|
34
47
|
readonly workflowName: string;
|
|
@@ -39,7 +52,7 @@ export interface PythonTrustedPublisherOptions {
|
|
|
39
52
|
/** Options for one projen-native Python workspace member. */
|
|
40
53
|
export interface DBXToolsPythonProjectOptions extends DBXToolsProjectOptions {
|
|
41
54
|
readonly parent: Project;
|
|
42
|
-
readonly package:
|
|
55
|
+
readonly package: ResolvedPythonPackageOptions;
|
|
43
56
|
readonly repository: Required<PythonRepositoryOptions>;
|
|
44
57
|
readonly requiresPython: string;
|
|
45
58
|
/** Workspace version copied onto this package's `pyproject.toml`. */
|
|
@@ -67,7 +80,9 @@ interface PythonPublication {
|
|
|
67
80
|
/** Options for {@link DBXToolsPythonWorkspace}. */
|
|
68
81
|
export interface DBXToolsPythonWorkspaceOptions {
|
|
69
82
|
readonly packages: readonly PythonPackageOptions[];
|
|
70
|
-
readonly repository
|
|
83
|
+
readonly repository?: PythonRepositoryOptions;
|
|
84
|
+
/** Repository-relative Python package root. Defaults to `packages/py`. */
|
|
85
|
+
readonly root?: string;
|
|
71
86
|
/** Workspace packages exposed as commands from the repository root. */
|
|
72
87
|
readonly dependencies?: readonly string[];
|
|
73
88
|
readonly requiresPython?: string;
|
|
@@ -126,6 +141,11 @@ export function pythonGitDependency(
|
|
|
126
141
|
return `${name} @ git+${repository.url}@${repository.ref ?? "main"}#subdirectory=${pythonPackagePath(repository, directory)}`;
|
|
127
142
|
}
|
|
128
143
|
|
|
144
|
+
/** Derive a dotted Python module from an npm-style scope and package directory. */
|
|
145
|
+
export function pythonModuleName(scope: string, directory: string): string {
|
|
146
|
+
return [scope, ...directory.split("/")].map((part) => part.replaceAll("-", "_")).join(".");
|
|
147
|
+
}
|
|
148
|
+
|
|
129
149
|
function projectVscode(project: Project): vscode.VsCode | undefined {
|
|
130
150
|
return (project as Project & { readonly vscode?: vscode.VsCode }).vscode;
|
|
131
151
|
}
|
|
@@ -133,7 +153,7 @@ function projectVscode(project: Project): vscode.VsCode | undefined {
|
|
|
133
153
|
/** A Python package implemented with projen's `PythonProject` and uv backend. */
|
|
134
154
|
export class DBXToolsPythonProject extends python.PythonProject implements DBXToolsProject {
|
|
135
155
|
readonly language = "python" as const;
|
|
136
|
-
readonly packageOptions:
|
|
156
|
+
readonly packageOptions: ResolvedPythonPackageOptions;
|
|
137
157
|
readonly uv: python.Uv;
|
|
138
158
|
|
|
139
159
|
constructor(options: DBXToolsPythonProjectOptions) {
|
|
@@ -222,17 +242,49 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
222
242
|
|
|
223
243
|
constructor(project: javascript.NodeProject, options: DBXToolsPythonWorkspaceOptions) {
|
|
224
244
|
super(project);
|
|
245
|
+
const scope = isDBXToolsJavaScriptProject()(project)
|
|
246
|
+
? string.toSlug(project.scope)
|
|
247
|
+
: string.toSlug(project.name).replace(/-root$/, "");
|
|
248
|
+
const repositoryUrl =
|
|
249
|
+
options.repository?.url ??
|
|
250
|
+
projectRepositoryUrl(project) ??
|
|
251
|
+
coreProject.repositoryUrl(project.outdir);
|
|
252
|
+
if (!repositoryUrl) {
|
|
253
|
+
throw new Error("Python workspace repository URL was not configured or detected");
|
|
254
|
+
}
|
|
225
255
|
this.repository = {
|
|
226
|
-
url:
|
|
227
|
-
ref: options.repository
|
|
228
|
-
root: options.repository
|
|
256
|
+
url: repositoryUrl.endsWith(".git") ? repositoryUrl : `${repositoryUrl}.git`,
|
|
257
|
+
ref: options.repository?.ref ?? "main",
|
|
258
|
+
root: options.root ?? options.repository?.root ?? "packages/py",
|
|
229
259
|
};
|
|
260
|
+
const packageIdentities: ResolvedPythonPackageOptions[] = options.packages.map((pkg) => ({
|
|
261
|
+
...pkg,
|
|
262
|
+
name: pkg.name ?? `${scope}-${string.toSlug(pkg.directory)}`,
|
|
263
|
+
module: pkg.module ?? pythonModuleName(scope, pkg.directory),
|
|
264
|
+
}));
|
|
265
|
+
const packagesByDirectory = new Map(packageIdentities.map((pkg) => [pkg.directory, pkg]));
|
|
266
|
+
const packages = packageIdentities.map((pkg) => ({
|
|
267
|
+
...pkg,
|
|
268
|
+
dependencies: [
|
|
269
|
+
...(pkg.dependencies ?? []),
|
|
270
|
+
...(pkg.internalDependencies ?? []).map((directory) => {
|
|
271
|
+
const dependency = packagesByDirectory.get(directory);
|
|
272
|
+
if (!dependency) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`Python package ${pkg.directory} references unknown internal package ${directory}`,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
return pythonGitDependency(this.repository, dependency.name, dependency.directory);
|
|
278
|
+
}),
|
|
279
|
+
],
|
|
280
|
+
}));
|
|
281
|
+
const resolvedOptions = { ...options, packages };
|
|
230
282
|
this.requiresPython = options.requiresPython ?? ">=3.10";
|
|
231
283
|
// The single workspace version, copied from the root `VERSION` file so Python
|
|
232
284
|
// members carry the same number as their JS siblings.
|
|
233
285
|
this.version = readWorkspaceVersion(project.outdir);
|
|
234
|
-
this.file = this.emitWorkspace(project,
|
|
235
|
-
this.packages =
|
|
286
|
+
this.file = this.emitWorkspace(project, resolvedOptions, scope);
|
|
287
|
+
this.packages = packages.map(
|
|
236
288
|
(pkg) =>
|
|
237
289
|
new DBXToolsPythonProject({
|
|
238
290
|
parent: project,
|
|
@@ -248,9 +300,18 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
248
300
|
project.gitattributes.addAttributes(pyproject, "linguist-generated");
|
|
249
301
|
project.prettier?.addIgnorePattern(pyproject.slice(1));
|
|
250
302
|
}
|
|
251
|
-
|
|
303
|
+
project.gitignore.addPatterns(
|
|
304
|
+
".venv/",
|
|
305
|
+
".pytest_cache/",
|
|
306
|
+
".ruff_cache/",
|
|
307
|
+
"**/__pycache__/",
|
|
308
|
+
"**/*.py[cod]",
|
|
309
|
+
`${this.repository.root}/**/dist/`,
|
|
310
|
+
);
|
|
311
|
+
this.addTasks(project, resolvedOptions);
|
|
252
312
|
|
|
253
|
-
const
|
|
313
|
+
const configuredReleaseOptions = options.release === true ? {} : options.release || {};
|
|
314
|
+
const releaseOptions = { ...configuredReleaseOptions };
|
|
254
315
|
this.addTrustedPublisherInstructionsTask(project, releaseOptions);
|
|
255
316
|
|
|
256
317
|
const interpreterPath = options.interpreterPath ?? "${workspaceFolder}/.venv/bin/python";
|
|
@@ -258,7 +319,11 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
258
319
|
projectVscode(project)?.settings.addSetting("python.defaultInterpreterPath", interpreterPath);
|
|
259
320
|
}
|
|
260
321
|
|
|
261
|
-
if (options.release) {
|
|
322
|
+
if (options.release && this.packages.some((pkg) => !pkg.packageOptions.private)) {
|
|
323
|
+
if (isDBXToolsJavaScriptProject()(project)) {
|
|
324
|
+
project.dbxToolsConfig.pythonReleaseWorkflow =
|
|
325
|
+
releaseOptions.workflowName ?? "python-release";
|
|
326
|
+
}
|
|
262
327
|
this.addReleaseWorkflow(project, releaseOptions);
|
|
263
328
|
}
|
|
264
329
|
}
|
|
@@ -276,12 +341,13 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
276
341
|
private emitWorkspace(
|
|
277
342
|
project: javascript.NodeProject,
|
|
278
343
|
options: DBXToolsPythonWorkspaceOptions,
|
|
344
|
+
scope: string,
|
|
279
345
|
): python.PyprojectTomlFile {
|
|
280
346
|
const testPaths = options.testPaths ?? [this.repository.root];
|
|
281
347
|
const perFileIgnores = options.ruffPerFileIgnores ?? {};
|
|
282
348
|
const file = new python.PyprojectTomlFile(project, {
|
|
283
349
|
project: {
|
|
284
|
-
name: options.workspaceName ?? `${
|
|
350
|
+
name: options.workspaceName ?? `${scope}-python-workspace`,
|
|
285
351
|
version: this.version,
|
|
286
352
|
requiresPython: this.requiresPython,
|
|
287
353
|
dependencies: [...(options.dependencies ?? [])],
|
|
@@ -315,8 +381,16 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
315
381
|
file.addOverride("tool.uv.index-strategy", options.indexStrategy);
|
|
316
382
|
}
|
|
317
383
|
file.addOverride("tool.pyrefly.ignore-errors-in-generated-code", true);
|
|
318
|
-
|
|
319
|
-
|
|
384
|
+
const projectExcludes = [
|
|
385
|
+
...(options.pyreflyProjectExcludes ?? []),
|
|
386
|
+
...options.packages.flatMap((pkg) =>
|
|
387
|
+
(pkg.generatedSources ?? []).map(
|
|
388
|
+
(source) => `${this.repository.root}/${pkg.directory}/${source}`,
|
|
389
|
+
),
|
|
390
|
+
),
|
|
391
|
+
];
|
|
392
|
+
if (projectExcludes.length) {
|
|
393
|
+
file.addOverride("tool.pyrefly.project-excludes", [...new Set(projectExcludes)]);
|
|
320
394
|
}
|
|
321
395
|
file.addOverride(
|
|
322
396
|
"tool.uv.sources",
|
|
@@ -356,63 +430,153 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
356
430
|
const publications = this.publications(options);
|
|
357
431
|
if (publications.length === 0) return;
|
|
358
432
|
const workflow = new GithubWorkflow(project.github, options.workflowName ?? "python-release");
|
|
359
|
-
workflow.file?.addOverride("permissions", {
|
|
433
|
+
workflow.file?.addOverride("permissions", {
|
|
434
|
+
contents: "read",
|
|
435
|
+
...(options.upstreamWorkflow ? { actions: "read" } : {}),
|
|
436
|
+
});
|
|
360
437
|
const upstreamWorkflow = options.upstreamWorkflow;
|
|
438
|
+
const branchDispatch = upstreamWorkflow === undefined && isDBXToolsJavaScriptProject()(project);
|
|
361
439
|
if (upstreamWorkflow) {
|
|
362
440
|
workflow.file?.addOverride("on.workflow_run", {
|
|
363
441
|
workflows: [upstreamWorkflow],
|
|
364
442
|
types: ["completed"],
|
|
365
443
|
});
|
|
366
444
|
workflow.on({ workflowDispatch: {} });
|
|
445
|
+
} else if (branchDispatch) {
|
|
446
|
+
workflow.file?.addOverride("on.repository_dispatch", {
|
|
447
|
+
types: [DOWNSTREAM_RELEASE_EVENT],
|
|
448
|
+
});
|
|
449
|
+
workflow.on({ workflowDispatch: {} });
|
|
367
450
|
} else {
|
|
368
451
|
workflow.on({ push: { tags: ["v*"] }, workflowDispatch: {} });
|
|
369
452
|
}
|
|
370
453
|
workflow.file?.addOverride("on.workflow_dispatch", {
|
|
371
454
|
inputs: {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
455
|
+
...(branchDispatch
|
|
456
|
+
? {
|
|
457
|
+
release_tag: {
|
|
458
|
+
description: "Release tag to package during a dry run",
|
|
459
|
+
type: "string",
|
|
460
|
+
required: true,
|
|
461
|
+
},
|
|
462
|
+
expected_sha: {
|
|
463
|
+
description: "Commit the release tag must reference",
|
|
464
|
+
type: "string",
|
|
465
|
+
required: true,
|
|
466
|
+
},
|
|
467
|
+
}
|
|
468
|
+
: {
|
|
469
|
+
version: {
|
|
470
|
+
description: "Python package version to build",
|
|
471
|
+
type: "string",
|
|
472
|
+
required: true,
|
|
473
|
+
},
|
|
474
|
+
}),
|
|
377
475
|
},
|
|
378
476
|
});
|
|
379
477
|
workflow.addJob("build", {
|
|
380
478
|
...(upstreamWorkflow
|
|
381
479
|
? {
|
|
382
|
-
if: "${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push') }}",
|
|
480
|
+
if: "${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.event == 'push' || github.event.workflow_run.event == 'repository_dispatch')) }}",
|
|
383
481
|
}
|
|
384
482
|
: {}),
|
|
385
483
|
runsOn: ["ubuntu-latest"],
|
|
386
|
-
permissions: {
|
|
484
|
+
permissions: {
|
|
485
|
+
contents: JobPermission.READ,
|
|
486
|
+
...(upstreamWorkflow ? { actions: JobPermission.READ } : {}),
|
|
487
|
+
},
|
|
387
488
|
timeoutMinutes: 20,
|
|
388
489
|
steps: [
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
490
|
+
...(upstreamWorkflow
|
|
491
|
+
? [
|
|
492
|
+
{
|
|
493
|
+
name: "Download release metadata",
|
|
494
|
+
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
495
|
+
uses: "actions/download-artifact@v8",
|
|
496
|
+
with: {
|
|
497
|
+
name: "release-metadata",
|
|
498
|
+
path: ".release",
|
|
499
|
+
"run-id": "${{ github.event.workflow_run.id }}",
|
|
500
|
+
"github-token": "${{ github.token }}",
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: "Read release metadata",
|
|
505
|
+
id: "release_metadata",
|
|
506
|
+
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
507
|
+
shell: "bash",
|
|
508
|
+
run: [
|
|
509
|
+
'RELEASE_TAG="$(cat .release/tag)"',
|
|
510
|
+
'EXPECTED_SHA="$(cat .release/sha)"',
|
|
511
|
+
'test -n "$RELEASE_TAG"',
|
|
512
|
+
'test -n "$EXPECTED_SHA"',
|
|
513
|
+
'echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"',
|
|
514
|
+
'echo "expected_sha=$EXPECTED_SHA" >> "$GITHUB_OUTPUT"',
|
|
515
|
+
].join("\n"),
|
|
516
|
+
},
|
|
517
|
+
]
|
|
518
|
+
: []),
|
|
519
|
+
...(branchDispatch
|
|
520
|
+
? releaseSourceSteps()
|
|
521
|
+
: [
|
|
522
|
+
{
|
|
523
|
+
name: "Checkout",
|
|
524
|
+
uses: "actions/checkout@v6",
|
|
525
|
+
with: {
|
|
526
|
+
"fetch-depth": 0,
|
|
527
|
+
...(upstreamWorkflow
|
|
528
|
+
? {
|
|
529
|
+
ref: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' && steps.release_metadata.outputs.expected_sha || github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}",
|
|
530
|
+
}
|
|
531
|
+
: {}),
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
]),
|
|
535
|
+
...(upstreamWorkflow
|
|
536
|
+
? [
|
|
537
|
+
{
|
|
538
|
+
name: "Verify release source",
|
|
539
|
+
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
540
|
+
shell: "bash",
|
|
541
|
+
env: {
|
|
542
|
+
RELEASE_TAG: "${{ steps.release_metadata.outputs.release_tag }}",
|
|
543
|
+
EXPECTED_SHA: "${{ steps.release_metadata.outputs.expected_sha }}",
|
|
544
|
+
},
|
|
545
|
+
run: [
|
|
546
|
+
'git fetch --force origin "+refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"',
|
|
547
|
+
'test "$(git rev-parse "$RELEASE_TAG^{commit}")" = "$EXPECTED_SHA"',
|
|
548
|
+
'test "$(git rev-parse HEAD)" = "$EXPECTED_SHA"',
|
|
549
|
+
].join("\n"),
|
|
550
|
+
},
|
|
551
|
+
]
|
|
552
|
+
: []),
|
|
401
553
|
{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" },
|
|
402
554
|
{
|
|
403
555
|
name: "Stamp workspace versions",
|
|
404
556
|
env: {
|
|
405
|
-
VERSION:
|
|
557
|
+
VERSION: branchDispatch
|
|
558
|
+
? RELEASE_TAG
|
|
559
|
+
: "${{ github.event_name == 'push' && github.ref_name || github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' && steps.release_metadata.outputs.release_tag || inputs.version }}",
|
|
406
560
|
},
|
|
407
561
|
run: upstreamWorkflow
|
|
408
562
|
? [
|
|
409
563
|
'if [ "$GITHUB_EVENT_NAME" = "workflow_run" ]; then',
|
|
410
|
-
'
|
|
564
|
+
' if [ "${{ github.event.workflow_run.event }}" != "repository_dispatch" ]; then',
|
|
565
|
+
' VERSION="$(git tag --points-at HEAD --list "v*" | sort -V | tail -1)"',
|
|
566
|
+
" fi",
|
|
411
567
|
' test -n "$VERSION"',
|
|
412
568
|
"fi",
|
|
413
569
|
this.renderVersionStampScript(),
|
|
570
|
+
"mkdir -p .release",
|
|
571
|
+
'printf "%s\\n" "$VERSION" > .release/tag',
|
|
572
|
+
"git rev-parse HEAD > .release/sha",
|
|
414
573
|
].join("\n")
|
|
415
|
-
:
|
|
574
|
+
: [
|
|
575
|
+
this.renderVersionStampScript(),
|
|
576
|
+
"mkdir -p .release",
|
|
577
|
+
'printf "%s\\n" "$VERSION" > .release/tag',
|
|
578
|
+
"git rev-parse HEAD > .release/sha",
|
|
579
|
+
].join("\n"),
|
|
416
580
|
},
|
|
417
581
|
{
|
|
418
582
|
name: "Build distributions",
|
|
@@ -435,11 +599,18 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
435
599
|
uses: "actions/upload-artifact@v7",
|
|
436
600
|
with: { name: "python-distributions", path: "dist" },
|
|
437
601
|
},
|
|
602
|
+
{
|
|
603
|
+
name: "Upload release metadata",
|
|
604
|
+
uses: "actions/upload-artifact@v7",
|
|
605
|
+
with: { name: "release-metadata", path: ".release" },
|
|
606
|
+
},
|
|
438
607
|
],
|
|
439
608
|
});
|
|
440
609
|
for (const publication of publications) {
|
|
441
610
|
workflow.addJob(`publish-${publication.directory}`, {
|
|
442
|
-
if:
|
|
611
|
+
if: branchDispatch
|
|
612
|
+
? "${{ github.event_name == 'repository_dispatch' }}"
|
|
613
|
+
: "${{ github.event_name == 'push' || github.event_name == 'workflow_run' }}",
|
|
443
614
|
needs: ["build"],
|
|
444
615
|
environment: {
|
|
445
616
|
name: publication.environment,
|
|
@@ -504,6 +675,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
504
675
|
): void {
|
|
505
676
|
const repository = this.githubRepository();
|
|
506
677
|
const publications = this.trustedPublisherPublications(options);
|
|
678
|
+
const releaseBranch = projectReleaseBranch(project);
|
|
507
679
|
const linesBeforeAuthentication = [
|
|
508
680
|
"# PyPI Trusted Publisher Setup Instructions",
|
|
509
681
|
"",
|
|
@@ -513,7 +685,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
513
685
|
"",
|
|
514
686
|
"Before making any changes, complete a read-only audit:",
|
|
515
687
|
"",
|
|
516
|
-
|
|
688
|
+
"- Confirm that the active PyPI account can administer the listed projects and pending publishers.",
|
|
517
689
|
"- Start at https://pypi.org/manage/projects/ and determine which listed projects exist.",
|
|
518
690
|
"- Inspect every existing GitHub publisher for each project and compare its owner, repository name, workflow name, and environment name with the desired values below.",
|
|
519
691
|
"- Identify duplicate and mismatched trusted publishers that must be replaced by removing the publisher entry and adding the correct one.",
|
|
@@ -522,11 +694,17 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
522
694
|
"- Ask the user to confirm the complete proposed plan before submitting any change.",
|
|
523
695
|
"- After confirmation, perform the authorized plan without asking for additional confirmation unless authentication or a CAPTCHA requires user action.",
|
|
524
696
|
"",
|
|
697
|
+
"## GitHub environment policy",
|
|
698
|
+
"",
|
|
699
|
+
`- Configure every environment listed below to permit deployments from the ${releaseBranch} branch.`,
|
|
700
|
+
"- Branch-scoped release workflows use the environment names below; tag-only deployment policies reject their trusted-publishing jobs.",
|
|
701
|
+
"- Keep the GitHub environment name synchronized with the PyPI trusted publisher environment.",
|
|
702
|
+
"",
|
|
525
703
|
"## Authentication",
|
|
526
704
|
"",
|
|
527
705
|
];
|
|
528
706
|
const linesAfterAuthentication = [
|
|
529
|
-
|
|
707
|
+
"- If the active account cannot administer the listed projects or pending publishers, pause and ask the user to sign in to an authorized account.",
|
|
530
708
|
"- Pause and ask the user to complete every CAPTCHA. Do not attempt to solve or bypass a CAPTCHA.",
|
|
531
709
|
"- After the user completes an authentication or CAPTCHA step, continue from the current browser session.",
|
|
532
710
|
"",
|
|
@@ -560,6 +738,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
560
738
|
`- Repository name: ${repository.name}`,
|
|
561
739
|
`- Workflow name: ${workflowName}`,
|
|
562
740
|
`- Environment name: ${publication.environment}`,
|
|
741
|
+
`- GitHub environment branch: ${releaseBranch}`,
|
|
563
742
|
...(publication.artifacts ? [`- Artifacts: ${publication.artifacts}`] : []),
|
|
564
743
|
"",
|
|
565
744
|
];
|