-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Migrate API Doc Preview #35018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Migrate API Doc Preview #35018
Changes from 114 commits
Commits
Show all changes
116 commits
Select commit
Hold shift + click to select a range
13dc6c0
Add package.json
danieljurek bb7d024
Enable eng/tools in JS
danieljurek 7c8ebe1
First cut at direct port
danieljurek f9089e7
Wire up command, move some functions into changed-files.js
danieljurek 909e216
Move, pipeline, refactor
danieljurek abb8b30
Trivial test change to a spec file
danieljurek fc265e2
Usage, logging, add pathExists to changed-files.js, types in doc-prev…
danieljurek f1485ea
Prettier
danieljurek 3cad9ae
SkipCheckoutNone
danieljurek ef1e1bd
Git token auth
danieljurek ebb9b99
--
danieljurek 2a627e8
../
danieljurek 99387fd
Pool
danieljurek 8dae139
fetchDepth: 2
danieljurek 8a31cc7
Get-ChildItem
danieljurek 7fd80bd
More logging
danieljurek 3b1fc64
Directory
danieljurek 87b0480
BaseRepoOwner
danieljurek 36a8d4a
Cleanup
danieljurek 2e2cae3
02
danieljurek 97933ba
Comment
danieljurek 91f2706
Test a change that should break the docs build
danieljurek f164da2
Queue docs build
danieljurek 8b8e43f
02
danieljurek 32bbcf7
Tab
danieljurek 8fcf1a0
Add wait and result output
danieljurek 98300ed
Log files
danieljurek 43e07c8
Direct invocation with valid path
danieljurek b1667ff
Output buildstart.json
danieljurek 044323a
Fixes
danieljurek 541a4b0
Remove BOM
danieljurek 05ce4e2
PR Number
danieljurek eb65d1c
Test changes that won't break the build
danieljurek e52370e
encodeURIComponent
danieljurek f23fef2
-pwsh
danieljurek d6b28c5
Revert BatchService.json testing
danieljurek 04aeecc
Test from another PR
danieljurek 12968c4
Test timeouts
danieljurek 0e8dd88
Test timeout in script
danieljurek 8f13d13
>
danieljurek 8bf334e
Remove test exception
danieljurek 974c8c1
Show token scope
danieljurek 47da581
Set status on PR
danieljurek 5d84748
git rev-parse HEAD
danieljurek f1b510c
SourceCommitId
danieljurek 74d76c8
-Azure/
danieljurek 485e748
Set check state in DevOps pipeline
danieljurek 64636e7
set-pr-check.yml
danieljurek e4ef673
-description
danieljurek 050bccf
Can't enforce values for macro (defined at runtime) syntax at templat…
danieljurek 11a717f
.mjs -> .js
danieljurek 2948b84
.js, other documentation
danieljurek 0bfe5e5
vso
danieljurek 9a7f7da
displayName
danieljurek ae4adba
Add package.json to eng/scripts, wire up to github-test.yaml (might n…
danieljurek 682a510
sparse checkout eng/scripts
danieljurek 422b94e
eng/scripts/package-lock.json
danieljurek f5d640b
package.json
danieljurek a512962
npm i
danieljurek 656639b
prettier -> format
danieljurek 2b0930a
package-lock.json
danieljurek bcaa4c4
--output
danieljurek 1c350d9
Path
danieljurek 73b1ffa
Revert test changes in specification/
danieljurek 429dc7b
Revert "Test from another PR"
danieljurek 7fd4c3b
Architecture feedback
danieljurek 1a1b5cc
Paths
danieljurek c1d356e
Docs preview
danieljurek e911f00
pscore
danieljurek c01a4db
`
danieljurek 6ec290d
copy
danieljurek 224d360
$buildStart
danieljurek b040cfe
Test: timeout
danieljurek 76f4d29
(
danieljurek 9141932
Remove test timeout
danieljurek c4de2fd
Test orchestration build failure
danieljurek 234ecf3
Revert contrived orchestration failure
danieljurek 0523e95
Contrive a docs build failure
danieljurek 2470642
Test success case
danieljurek 25cc59c
Revert spec change
danieljurek 1e1847a
Add support for filtering quickstart templates
danieljurek 8b58e31
Use aka.ms link for docs support teams channel
danieljurek 4f1a085
Sparse checkout might work but that can be investigated elsewhere
danieljurek f0e7864
Improve param validation
danieljurek 929d33c
Test api-doc-preview param validation in practice
danieljurek 670515b
Revert github-test.yaml
danieljurek 100f4cf
Revert .gitignore
danieljurek dc24f8d
Remove unnecessary files
danieljurek c5c72e7
More status update messages
danieljurek 2ed2bb3
Revert "Test api-doc-preview param validation in practice"
danieljurek 55c560a
Fix package.json/package-lock.json
danieljurek dd2d433
package-lock.json
danieljurek 1f86abe
Merge branch 'main' into djurek/migrate-apidocpreview
danieljurek a7811ca
npm i
danieljurek 4919a94
Format
danieljurek 3bdb0b5
Apply suggestions from code review
danieljurek 6c8ee1a
inline, fix ts-check errors
danieljurek 99f1430
Use getChangedFilesStatuses to exclude deleted files instead of query…
danieljurek dde8c41
Comments
danieljurek 6fd04c0
Named typedefs, more exceptions, expand "key" to a couple variables
danieljurek 1872b4a
Adjust PR triggers
danieljurek d5af561
Remove fs/promises/access
danieljurek 2a45ee2
Add WorkingDirectory to npm-install.yml, use shebang invocation
danieljurek be52827
Remove infinite loop condition
danieljurek f6aafa0
pathExists
danieljurek 0833e32
.js
danieljurek 48145c2
(
danieljurek 32f69d2
Only run docs build if there are changes to push
danieljurek 77de6d1
DisplayName
danieljurek 894bd87
Final TODOs
danieljurek 4d93c98
Merge branch 'main' into djurek/migrate-apidocpreview
danieljurek 34b3c0c
Merge branch 'main' into djurek/migrate-apidocpreview
danieljurek fac26bc
Format
danieljurek 2172995
Merge branch 'main' into djurek/migrate-apidocpreview
danieljurek 8311106
Update eng/pipelines/swagger-api-doc-preview.yml
danieljurek 7dcbba5
Merge branch 'main' into djurek/migrate-apidocpreview
danieljurek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| #!/usr/bin/env node | ||
| // @ts-check | ||
|
|
||
| import { mkdir, writeFile } from "fs/promises"; | ||
| import { dirname, join, resolve } from "path"; | ||
| import { fileURLToPath } from "url"; | ||
| import { parseArgs } from "util"; | ||
|
|
||
| import { getChangedFilesStatuses, swagger } from "../src/changed-files.js"; | ||
|
|
||
| import { | ||
| getSwaggersToProcess, | ||
| indexMd, | ||
| mappingJSONTemplate, | ||
| repoJSONTemplate, | ||
| } from "../src/doc-preview.js"; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| function usage() { | ||
| console.log(`Usage: | ||
| npx api-doc-preview --output <output-dir> | ||
|
|
||
| parameters: | ||
| --output <output-dir> Directory to write documentation artifacts to. | ||
| --build-id <build-id> Build ID, used in the documentation index. Defaults to BUILD_BUILDID environment variable. | ||
| --spec-repo-name <name> Name of the repository containing the swagger files of the form <org>/<repo-name>. Defaults to BUILD_REPOSITORY_NAME environment variable. | ||
| --spec-repo-pr-number <pr-number> PR number of the repository containing the swagger files. Defaults to SYSTEM_PULLREQUEST_PULLREQUESTNUMBER environment variable. | ||
| --spec-repo-root <path> Root path of the repository containing the swagger files. Defaults to the root of the repository containing this script.`); | ||
| } | ||
|
|
||
| const { | ||
| values: { | ||
| output: outputDir, | ||
| "build-id": buildId, | ||
| "spec-repo-name": specRepoName, | ||
| "spec-repo-pr-number": specRepoPrNumber, | ||
| "spec-repo-root": specRepoRoot, | ||
| }, | ||
| } = parseArgs({ | ||
| options: { | ||
| output: { type: "string", default: "" }, | ||
| "build-id": { | ||
| type: "string", | ||
| default: process.env.BUILD_BUILDID || "", | ||
| }, | ||
| "spec-repo-name": { | ||
| type: "string", | ||
| default: process.env.BUILD_REPOSITORY_NAME || "", | ||
| }, | ||
| "spec-repo-pr-number": { | ||
| type: "string", | ||
| default: process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER || "", | ||
| }, | ||
| "spec-repo-root": { | ||
| type: "string", | ||
| default: resolve(__dirname, "../../../"), | ||
| }, | ||
| }, | ||
| allowPositionals: false, | ||
| }); | ||
|
|
||
| let validArgs = true; | ||
|
|
||
| if (!outputDir) { | ||
| console.log(`Missing required parameter --output. Value given: ${outputDir || "<empty>"}`); | ||
| validArgs = false; | ||
| } | ||
|
|
||
| if (!specRepoName) { | ||
| console.log( | ||
| `Missing required parameter --spec-repo-name. Value given: ${specRepoName || "<empty>"}`, | ||
| ); | ||
| validArgs = false; | ||
| } | ||
|
|
||
| if (!specRepoPrNumber) { | ||
| console.log( | ||
| `Missing required parameter --spec-repo-pr-number. Value given: ${specRepoPrNumber || "<empty>"}`, | ||
| ); | ||
| validArgs = false; | ||
| } | ||
|
|
||
| if (!specRepoRoot) { | ||
| console.log(`Invalid parameter --spec-repo-root. Value given: ${specRepoRoot || "<empty>"}`); | ||
| validArgs = false; | ||
| } | ||
|
|
||
| if (!validArgs) { | ||
| usage(); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| // Get selected version and swaggers to process | ||
|
|
||
| const changedFileStatuses = await getChangedFilesStatuses({ | ||
| cwd: specRepoRoot, | ||
| paths: ["specification"], | ||
| }); | ||
|
|
||
| // Exclude deleted files as they are not relevant for generating documentation. | ||
| const changedFiles = [ | ||
| ...changedFileStatuses.additions, | ||
| ...changedFileStatuses.modifications, | ||
| // Current names of renamed files are interesting, previous names are not. | ||
| ...changedFileStatuses.renames.map((r) => r.to), | ||
| ]; | ||
| console.log(`Found ${changedFiles.length} relevant changed files in ${specRepoRoot}`); | ||
| console.log("Changed files:"); | ||
| changedFiles.forEach((file) => console.log(` - ${file}`)); | ||
| const swaggerPaths = changedFiles.filter(swagger); | ||
|
|
||
| if (swaggerPaths.length === 0) { | ||
| console.log("No eligible swagger files found. No documentation artifacts will be written."); | ||
| process.exit(0); | ||
| } | ||
|
|
||
| const { selectedVersion, swaggersToProcess } = getSwaggersToProcess(swaggerPaths); | ||
|
|
||
| const repoName = specRepoName; | ||
| const prNumber = specRepoPrNumber; | ||
|
|
||
| await mkdir(outputDir, { recursive: true }); | ||
| await writeFile( | ||
| join(outputDir, "repo.json"), | ||
| JSON.stringify(repoJSONTemplate(repoName, prNumber), null, 2), | ||
| ); | ||
| await writeFile( | ||
| join(outputDir, "mapping.json"), | ||
| JSON.stringify(mappingJSONTemplate(swaggersToProcess), null, 2), | ||
| ); | ||
| await writeFile(join(outputDir, "index.md"), indexMd(buildId, repoName, prNumber)); | ||
| console.log(`Documentation preview artifacts written to ${outputDir}`); | ||
|
|
||
| console.log(`Doc preview for API version ${selectedVersion} includes:`); | ||
| swaggersToProcess.forEach((swagger) => console.log(` - ${swagger}`)); | ||
| console.log(`Artifacts written to: ${outputDir}`); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| // @ts-check | ||
| const DOCS_NAMESPACE = "_swagger_specs"; | ||
| const SPEC_FILE_REGEX = | ||
| "(specification/)+(.*)/(resourcemanager|resource-manager|dataplane|data-plane|control-plane)/(.*)/(preview|stable|privatepreview)/(.*?)/(example)?(.*)"; | ||
|
|
||
| /** | ||
| * @typedef {Object} SwaggerFileMetadata | ||
| * @property {string} path | ||
| * @property {string} serviceName | ||
| * @property {string} serviceType | ||
| * @property {string} resourceProvider | ||
| * @property {string} releaseState | ||
| * @property {string} apiVersion | ||
| * @property {string} fileName | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef {Object} RepoJSONTemplate | ||
| * @property {Object[]} repo | ||
| * @property {string} repo[].url | ||
| * @property {string} repo[].prNumber | ||
| * @property {string} repo[].name | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef {Object} MappingJSONStructure | ||
| * @property {string} target_api_root_dir | ||
| * @property {boolean} enable_markdown_fragment | ||
| * @property {string} markdown_fragment_folder | ||
| * @property {boolean} use_yaml_toc | ||
| * @property {boolean} formalize_url | ||
| * @property {string[]} version_list | ||
| * @property {Object[]} organizations | ||
| * @property {string} organizations[].index | ||
| * @property {string} organizations[].default_toc_title | ||
| * @property {string} organizations[].version | ||
| * @property {Object[]} organizations[].services | ||
| * @property {string} organizations[].services[].toc_title | ||
| * @property {string} organizations[].services[].url_group | ||
| * @property {Object[]} organizations[].services[].swagger_files | ||
| * @property {string} organizations[].services[].swagger_files[].source | ||
| */ | ||
|
|
||
| /** | ||
| * Extract swagger file metadata from path. | ||
| * @param {string} specPath | ||
| * @returns {SwaggerFileMetadata} | ||
| */ | ||
| export function parseSwaggerFilePath(specPath) { | ||
| const m = specPath.match(SPEC_FILE_REGEX); | ||
| if (!m) { | ||
| throw new Error(`Path "${specPath}" does not match expected swagger file pattern.`); | ||
| } | ||
| const [path, , serviceName, serviceType, resourceProvider, releaseState, apiVersion, , fileName] = | ||
| m; | ||
| return { | ||
| path, | ||
| serviceName, | ||
| serviceType, | ||
| resourceProvider, | ||
| releaseState, | ||
| apiVersion, | ||
| fileName, | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * @param {string} repoName | ||
| * @param {string} prNumber | ||
| * @returns {object} | ||
danieljurek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| */ | ||
| export function repoJSONTemplate(repoName, prNumber) { | ||
| return { | ||
| repo: [ | ||
| { | ||
| url: `https://github.com/${repoName}`, | ||
| prNumber: prNumber, | ||
| name: DOCS_NAMESPACE, | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * @param {string[]} files | ||
| * @returns {MappingJSONStructure} | ||
| */ | ||
| export function mappingJSONTemplate(files) { | ||
| return { | ||
| target_api_root_dir: "structured", | ||
| enable_markdown_fragment: true, | ||
| markdown_fragment_folder: "authored", | ||
| use_yaml_toc: true, | ||
| formalize_url: true, | ||
| version_list: ["default"], | ||
| organizations: [ | ||
| { | ||
| index: "index.md", | ||
| default_toc_title: "Getting Started", | ||
| version: "default", | ||
| services: [ | ||
| { | ||
| toc_title: "Documentation Preview", | ||
| url_group: "documentation-preview", | ||
| swagger_files: files.map((source) => ({ | ||
| source: `${DOCS_NAMESPACE}/${source}`, | ||
| })), | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * @param {string} buildId | ||
| * @param {string} repoName | ||
| * @param {string} prNumber | ||
| * @returns {string} | ||
| */ | ||
| export function indexMd(buildId, repoName, prNumber) { | ||
| return `# Documentation Preview for swagger pipeline build #${buildId} | ||
|
|
||
| Welcome to documentation preview for ${repoName}/pull/${prNumber} | ||
| created via the swagger pipeline. | ||
|
|
||
| Your documentation may be viewed in the menu on the left hand side. | ||
|
|
||
| If you have issues around documentation generation, please feel free to contact | ||
| us in the [Docs Support Teams Channel](https://aka.ms/ci-fix/api-docs-help)`; | ||
| } | ||
|
|
||
| /** | ||
| * Given a list of changed swagger files, select an API version and a list of | ||
| * swagger files in that API version to process. | ||
| * @param {string[]} swaggerFiles | ||
| **/ | ||
| export function getSwaggersToProcess(swaggerFiles) { | ||
| const swaggerFileObjs = swaggerFiles.map(parseSwaggerFilePath); | ||
|
|
||
| const versions = swaggerFileObjs.map((obj) => obj.apiVersion).filter(Boolean); | ||
| if (versions.length === 0) { | ||
| throw new Error("No new API versions found in eligible swagger files."); | ||
| } | ||
| const uniqueVersions = Array.from(new Set(versions)); | ||
|
|
||
| let selectedVersion; | ||
| if (uniqueVersions.length === 1) { | ||
| selectedVersion = uniqueVersions[0]; | ||
| console.log(`Single API version found: ${selectedVersion}`); | ||
| } else { | ||
| // This sorting logic is ported from the original code which sorts only the | ||
| // strings and doesn't attempt to parse versions for more semantically-aware | ||
| // sorting. | ||
| const sortedVersions = [...uniqueVersions].sort(); | ||
danieljurek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| selectedVersion = sortedVersions[sortedVersions.length - 1]; | ||
| console.log( | ||
| `Multiple API versions found: ${JSON.stringify(sortedVersions)}. Selected version: ${selectedVersion}`, | ||
| ); | ||
| } | ||
|
|
||
| const swaggersToProcess = swaggerFileObjs | ||
| .filter((obj) => obj.apiVersion === selectedVersion) | ||
| .map((obj) => obj.path); | ||
|
|
||
| return { selectedVersion, swaggersToProcess }; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.