monecromanci 0.0.0

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.
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Step 04 — Publish libraries.
5
+ *
6
+ * Versions are managed manually: a developer sets the `version` in each
7
+ * library's `package.json`. This step publishes every affected
8
+ * `type:publishable-lib` at the version already declared on disk, skipping any
9
+ * version already present on the registry. It does not bump versions, create
10
+ * tags, or push commits.
11
+ *
12
+ * Gated by the YAML step to non-PR builds on a release branch (master/main).
13
+ */
14
+
15
+ import path from 'node:path'
16
+ import process from 'node:process'
17
+ import {
18
+ banner,
19
+ isWindows,
20
+ log,
21
+ readJsonSafe,
22
+ run,
23
+ runInherit,
24
+ runSafe,
25
+ section,
26
+ setVariable,
27
+ shellEscape,
28
+ warn,
29
+ } from './lib/_h.mjs'
30
+ import { loadContext, selectAffected } from './lib/context.mjs'
31
+ import { runNxInherit } from './lib/nx.mjs'
32
+
33
+ const WORKSPACE_ROOT = process.cwd()
34
+ const NPM_BIN = isWindows() ? 'npm.cmd' : 'npm'
35
+ const NPM_USER_CONFIG = path.join(WORKSPACE_ROOT, '.npmrc')
36
+
37
+ /**
38
+ * Returns whether the current build is a pull request validation.
39
+ *
40
+ * @returns {boolean} Returns true for pull request builds.
41
+ */
42
+ function isPullRequest () {
43
+ return String(process.env.BUILD_REASON || '').toLowerCase() === 'pullrequest'
44
+ }
45
+
46
+ /**
47
+ * Returns whether the current branch is allowed to publish.
48
+ *
49
+ * The allowed branches default to `master` and `main` and can be overridden with
50
+ * the `RELEASE_BRANCHES` environment variable (comma-separated).
51
+ *
52
+ * @returns {boolean} Returns true when the current branch may publish.
53
+ */
54
+ function isReleaseBranch () {
55
+ const allowed = (process.env.RELEASE_BRANCHES || 'master,main')
56
+ .split(',')
57
+ .map(branch => branch.trim().toLowerCase())
58
+ .filter(Boolean)
59
+ const current = String(process.env.BUILD_SOURCEBRANCHNAME || runSafe('git rev-parse --abbrev-ref HEAD')).trim().toLowerCase()
60
+
61
+ return allowed.includes(current)
62
+ }
63
+
64
+ /**
65
+ * Resolves whether a package version is already on the registry.
66
+ *
67
+ * @param {string} packageName The package name.
68
+ * @param {string} packageVersion The package version.
69
+ * @returns {boolean} Returns true when the version already exists.
70
+ */
71
+ function isVersionPublished (packageName, packageVersion) {
72
+ try {
73
+ const output = run(`${NPM_BIN} view ${shellEscape(`${packageName}@${packageVersion}`)} version --json --userconfig ${shellEscape(NPM_USER_CONFIG)}`)
74
+
75
+ return JSON.parse(output) === packageVersion
76
+ } catch {
77
+ return false
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Publishes a single library at its declared version and records the outcome.
83
+ *
84
+ * @param {Record<string, any>} project The library project data.
85
+ * @param {{published: string[], skipped: string[]}} results The publish result accumulator.
86
+ */
87
+ function publishLibrary (project, results) {
88
+ const projectRoot = path.join(WORKSPACE_ROOT, project.root)
89
+ const packageJson = readJsonSafe(path.join(projectRoot, 'package.json'))
90
+ const packageName = String(packageJson.name || '').trim()
91
+ const packageVersion = String(packageJson.version || '').trim()
92
+
93
+ if (packageJson.private === true) {
94
+ log(`[${project.name}] skipped — package is private`)
95
+ return
96
+ }
97
+
98
+ if (!packageName || !packageVersion) {
99
+ log(`[${project.name}] skipped — missing package name or version in package.json`)
100
+ return
101
+ }
102
+
103
+ if (isVersionPublished(packageName, packageVersion)) {
104
+ log(`[${project.name}] skipped — ${packageName}@${packageVersion} already published`)
105
+ results.skipped.push(`${packageName}@${packageVersion}`)
106
+ return
107
+ }
108
+
109
+ log(`[${project.name}] building before publish`)
110
+ runNxInherit(`run ${project.name}:build`)
111
+
112
+ log(`[${project.name}] publishing ${packageName}@${packageVersion}`)
113
+ runInherit(`${NPM_BIN} publish --userconfig ${shellEscape(NPM_USER_CONFIG)}`, { cwd: projectRoot })
114
+ results.published.push(`${packageName}@${packageVersion}`)
115
+ }
116
+
117
+ /**
118
+ * Runs the manual-version publish workflow.
119
+ */
120
+ function main () {
121
+ banner('[04] Publish libraries (versions managed manually in package.json)')
122
+
123
+ const context = loadContext()
124
+ const publishableLibraries = selectAffected(context, project => project.type.externalPackage)
125
+
126
+ if (publishableLibraries.length === 0) {
127
+ banner('[04] No affected publishable libraries — nothing to publish')
128
+ return
129
+ }
130
+
131
+ if (isPullRequest()) {
132
+ warn('Pull request build — skipping publish (validation only).')
133
+ return
134
+ }
135
+
136
+ if (!isReleaseBranch()) {
137
+ warn(`Branch "${process.env.BUILD_SOURCEBRANCHNAME || '(unknown)'}" is not a publish branch (${process.env.RELEASE_BRANCHES || 'master,main'}) — skipping publish.`)
138
+ return
139
+ }
140
+
141
+ log(`Candidates (${publishableLibraries.length}): ${publishableLibraries.map(project => project.name).join(', ')}`)
142
+
143
+ const results = { published: [], skipped: [] }
144
+ for (const project of publishableLibraries) {
145
+ section(`Publish: ${project.name}`)
146
+ publishLibrary(project, results)
147
+ }
148
+
149
+ setVariable('PUBLISHED_LIBS', results.published.join(', '))
150
+ setVariable('SKIPPED_LIBS', results.skipped.join(', '))
151
+
152
+ banner(`[04] Publish complete — published ${results.published.length}, skipped ${results.skipped.length}`)
153
+ }
154
+
155
+ main()
@@ -0,0 +1,20 @@
1
+ steps:
2
+ - task: npmAuthenticate@0
3
+ displayName: "[04] Authenticate npm registry"
4
+ condition: and(succeeded(), eq(variables['HAS_PUBLISHABLE_LIBS'], 'true'))
5
+ inputs:
6
+ workingFile: .npmrc
7
+
8
+ # Versions are set manually in each library's package.json. This step only
9
+ # publishes (skipping versions already on the registry), so it runs on a
10
+ # publish branch (master or main) for non-PR builds. The script re-checks these.
11
+ - script: node .build-templates/04-publish-libs.mjs
12
+ displayName: "[04] Publish affected libraries"
13
+ condition: >
14
+ and(succeeded(),
15
+ eq(variables['HAS_PUBLISHABLE_LIBS'], 'true'),
16
+ ne(variables['Build.Reason'], 'PullRequest'),
17
+ or(eq(variables['Build.SourceBranchName'], 'master'),
18
+ eq(variables['Build.SourceBranchName'], 'main')))
19
+ env:
20
+ NODE_AUTH_TOKEN: $(NODE_AUTH_TOKEN)
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Step 05 — Publish documentation.
5
+ *
6
+ * Uploads generated TypeDoc output for every affected library (internal or
7
+ * publishable) to the documentation blob container. Each project is uploaded to
8
+ * its own destination so projects never overwrite each other.
9
+ */
10
+
11
+ import { existsSync } from 'node:fs'
12
+ import path from 'node:path'
13
+ import process from 'node:process'
14
+ import { banner, log, run, runInherit, section, shellEscape, warn } from './lib/_h.mjs'
15
+ import { loadContext, selectAffected } from './lib/context.mjs'
16
+ import { runNxInherit } from './lib/nx.mjs'
17
+
18
+ const WORKSPACE_ROOT = process.cwd()
19
+
20
+ /**
21
+ * Resolves the base blob destination for documentation.
22
+ *
23
+ * @returns {string} Returns the base blob destination path.
24
+ */
25
+ function getDocumentationDestination () {
26
+ const buildDefinitionName = process.env.BUILD_DEFINITIONNAME || 'local'
27
+
28
+ return `$web/${buildDefinitionName}`
29
+ }
30
+
31
+ /**
32
+ * Ensures the Azure CLI is available before uploading.
33
+ */
34
+ function ensureAzureCliAvailable () {
35
+ run('az --version')
36
+ }
37
+
38
+ /**
39
+ * Publishes generated documentation for affected library projects.
40
+ */
41
+ function main () {
42
+ banner('[05] Publish documentation')
43
+
44
+ const context = loadContext()
45
+ const documentationProjects = selectAffected(context, project => project.type.internalPackage || project.type.externalPackage)
46
+
47
+ if (documentationProjects.length === 0) {
48
+ banner('[05] No affected library documentation to publish')
49
+ return
50
+ }
51
+
52
+ // Generate the docs for the affected range (no-ops for projects without a doc target).
53
+ section('Generating documentation')
54
+ const base = process.env.NX_BASE || ''
55
+ const head = process.env.NX_HEAD || ''
56
+ const range = base && head ? ` --base=${shellEscape(base)} --head=${shellEscape(head)}` : ''
57
+ runNxInherit(`affected -t doc${range} --outputStyle=static`)
58
+
59
+ const connectionString = process.env.saDevConnectionString
60
+ if (!connectionString) {
61
+ banner('[05] Documentation hosting not configured (saDevConnectionString unset) — skipping upload')
62
+ return
63
+ }
64
+
65
+ ensureAzureCliAvailable()
66
+ const destination = getDocumentationDestination()
67
+
68
+ for (const project of documentationProjects) {
69
+ section(`Documentation: ${project.name}`)
70
+
71
+ const documentationPath = path.join(WORKSPACE_ROOT, project.root, 'doc')
72
+ const markerPath = path.join(documentationPath, 'index.html')
73
+ const projectToken = String(project.packageName || project.name || '').trim()
74
+ const projectDestination = `${destination}/${projectToken}`
75
+
76
+ if (!existsSync(markerPath)) {
77
+ warn(`[${project.name}] skipped — missing ${path.relative(WORKSPACE_ROOT, markerPath)}`)
78
+ continue
79
+ }
80
+
81
+ log(`[${project.name}] uploading to ${projectDestination}`)
82
+ runInherit(`az storage blob upload-batch -d ${shellEscape(projectDestination)} -s ${shellEscape(documentationPath)} --connection-string ${shellEscape(connectionString)} --overwrite`)
83
+ }
84
+
85
+ banner('[05] Documentation publish complete')
86
+ }
87
+
88
+ main()
@@ -0,0 +1,20 @@
1
+ steps:
2
+ - task: AzureCLI@2
3
+ displayName: "[05] Build and publish affected library documentation"
4
+ # Skipped entirely unless a docs service connection is configured.
5
+ condition: >
6
+ and(succeeded(),
7
+ ne(variables['docsAzureSubscription'], ''),
8
+ or(eq(variables['HAS_INTERNAL_PACKAGES'], 'true'),
9
+ eq(variables['HAS_PUBLISHABLE_LIBS'], 'true')))
10
+ env:
11
+ BUILD_DEFINITIONNAME: $(Build.DefinitionName)
12
+ MONOREPO_CONTEXT_FILE: $(MONOREPO_CONTEXT_FILE)
13
+ NX_BASE: $(NX_BASE)
14
+ NX_HEAD: $(NX_HEAD)
15
+ saDevConnectionString: $(saDevConnectionString)
16
+ inputs:
17
+ azureSubscription: $(docsAzureSubscription)
18
+ scriptType: pscore
19
+ scriptLocation: inlineScript
20
+ inlineScript: node .build-templates/05-publish-documentation.mjs