mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: publish docs-content bazel artifacts (#14634)
This commit is contained in:
committed by
vivian-hu
parent
5773a5b694
commit
2307489dff
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Bazel workspace status script that is responsible for creating Bazel stamping variables.
|
||||
* The stamping variables will be used by the NodeJS Bazel rules to provide proper version
|
||||
* placeholder replacements. Read more about variable stamping within Bazel:
|
||||
* https://docs.bazel.build/versions/master/user-manual.html#flag--workspace_status_command
|
||||
*/
|
||||
|
||||
const spawnSync = require('child_process').spawnSync;
|
||||
const packageJson = require('../package');
|
||||
|
||||
const currentCommitSha = getCurrentCommitSha();
|
||||
|
||||
// The "BUILD_SCM_VERSION" will be picked up by the "npm_package" and "ng_package" rule
|
||||
// in order to replace the "0.0.0-PLACEHOLDER" with a proper version
|
||||
console.log(`BUILD_SCM_VERSION ${packageJson.version}-${currentCommitSha.substr(0, 7)}`);
|
||||
console.log(`BUILD_SCM_COMMIT_SHA ${currentCommitSha}`);
|
||||
console.log(`BUILD_SCM_BRANCH ${getCurrentBranchName()}`);
|
||||
console.log(`BUILD_SCM_USER ${getCurrentGitUser()}`);
|
||||
|
||||
/** Returns the commit SHA for the current git HEAD of the project. */
|
||||
function getCurrentCommitSha() {
|
||||
return spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim();
|
||||
}
|
||||
|
||||
/** Returns the name of the currently checked out branch of the project. */
|
||||
function getCurrentBranchName() {
|
||||
return spawnSync('git', ['symbolic-ref', '--short', 'HEAD']).stdout.toString().trim();
|
||||
}
|
||||
|
||||
/** Returns the name and email of the Git user that creates this release build. */
|
||||
function getCurrentGitUser() {
|
||||
const userName = spawnSync('git', ['config', 'user.name']).stdout.toString().trim();
|
||||
const userEmail = spawnSync('git', ['config', 'user.email']).stdout.toString().trim();
|
||||
|
||||
return `${userName} <${userEmail}>`;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Generates the data used by the stamping feature in bazel.
|
||||
# This script is intended to be used as a Bazel workspace_status_command, which
|
||||
# prints out a set of key-value pairs.
|
||||
# See https://github.com/angular/angular/blob/master/docs/BAZEL.md for more explanation
|
||||
set -u -e -E -o pipefail
|
||||
|
||||
function onError {
|
||||
echo "Failed to execute: $0"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Setup crash trap
|
||||
trap 'onError' ERR
|
||||
|
||||
if [[ "$(git tag)" == "" ]]; then
|
||||
echo "No git tags found, can't stamp the build."
|
||||
echo "Either fetch the tags:"
|
||||
echo " git fetch git@github.com:angular/material2.git --tags"
|
||||
echo "or build without stamping by giving an empty workspace_status_command:"
|
||||
echo " bazel build --workspace_status_command= ..."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Gets a human-readable name for HEAD, e.g. "6.0.0-rc.0-15-g846ddfa"
|
||||
git_version_raw=$(git describe --abbrev=7 --tags HEAD)
|
||||
|
||||
# Find out if there are any uncommitted local changes
|
||||
if [[ $(git status --untracked-files=no --porcelain) ]]; then
|
||||
local_changes_suffix=".with-local-changes";
|
||||
else
|
||||
local_changes_suffix="";
|
||||
fi
|
||||
|
||||
# Reformat `git describe` version string into a more semver-ish string
|
||||
# From: 5.2.0-rc.0-57-g757f886
|
||||
# To: 5.2.0-rc.0+57.sha-757f886
|
||||
# Or: 5.2.0-rc.0+57.sha-757f886.with-local-changes
|
||||
|
||||
semver_style_version="$(echo ${git_version_raw} | sed -E 's/-([0-9]+)-g/+\1.sha-/g')"
|
||||
version_stamp="${semver_style_version}${local_changes_suffix}"
|
||||
echo "BUILD_SCM_VERSION ${version_stamp}"
|
||||
@@ -21,7 +21,6 @@ import './tasks/ci';
|
||||
import './tasks/clean';
|
||||
import './tasks/default';
|
||||
import './tasks/development';
|
||||
import './tasks/docs';
|
||||
import './tasks/example-module';
|
||||
import './tasks/lint';
|
||||
import './tasks/material-release';
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
import {task, src, dest} from 'gulp';
|
||||
import {Dgeni} from 'dgeni';
|
||||
import * as path from 'path';
|
||||
import {buildConfig, sequenceTask} from 'material2-build-tools';
|
||||
import {apiDocsPackage} from '../../dgeni/index';
|
||||
|
||||
// There are no type definitions available for these imports.
|
||||
const markdown = require('gulp-markdown');
|
||||
const transform = require('gulp-transform');
|
||||
const highlight = require('gulp-highlight-files');
|
||||
const rename = require('gulp-rename');
|
||||
const flatten = require('gulp-flatten');
|
||||
const htmlmin = require('gulp-htmlmin');
|
||||
const hljs = require('highlight.js');
|
||||
const dom = require('gulp-dom');
|
||||
|
||||
const {outputDir, packagesDir} = buildConfig;
|
||||
|
||||
const DIST_DOCS = path.join(outputDir, 'docs');
|
||||
|
||||
// Our docs contain comments of the form `<!-- example(...) -->` which serve as placeholders where
|
||||
// example code should be inserted. We replace these comments with divs that have a
|
||||
// `material-docs-example` attribute which can be used to locate the divs and initialize the example
|
||||
// viewer.
|
||||
const EXAMPLE_PATTERN = /<!--\W*example\(([^)]+)\)\W*-->/g;
|
||||
|
||||
// Markdown files can contain links to other markdown files.
|
||||
// Most of those links don't work in the Material docs, because the paths are invalid in the
|
||||
// documentation page. Using a RegExp to rewrite links in HTML files to work in the docs.
|
||||
const LINK_PATTERN = /(<a[^>]*) href="([^"]*)"/g;
|
||||
|
||||
// HTML tags in the markdown generated files that should receive a .docs-markdown-${tagName} class
|
||||
// for styling purposes.
|
||||
const MARKDOWN_TAGS_TO_CLASS_ALIAS = [
|
||||
'a',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'li',
|
||||
'ol',
|
||||
'p',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'th',
|
||||
'tr',
|
||||
'ul',
|
||||
'pre',
|
||||
'code',
|
||||
];
|
||||
|
||||
// Options for the html-minifier that minifies the generated HTML files.
|
||||
const htmlMinifierOptions = {
|
||||
collapseWhitespace: true,
|
||||
removeComments: true,
|
||||
caseSensitive: true,
|
||||
removeAttributeQuotes: false
|
||||
};
|
||||
|
||||
const markdownOptions = {
|
||||
// Add syntax highlight using highlight.js
|
||||
highlight: (code: string, language: string): string => {
|
||||
if (language) {
|
||||
// highlight.js expects "typescript" written out, while Github supports "ts".
|
||||
let lang = language.toLowerCase() === 'ts' ? 'typescript' : language;
|
||||
return hljs.highlight(lang, code).value;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
/** Generate all docs content. */
|
||||
task('docs', sequenceTask(
|
||||
[
|
||||
'markdown-docs-material',
|
||||
'markdown-docs-cdk',
|
||||
'build-highlighted-examples',
|
||||
'build-examples-module',
|
||||
'api-docs',
|
||||
'copy-stackblitz-examples'
|
||||
],
|
||||
'minify-html-files'
|
||||
));
|
||||
|
||||
/** Generates html files from the markdown overviews and guides for material. */
|
||||
task('markdown-docs-material', () => {
|
||||
// Extend the renderer for custom heading anchor rendering
|
||||
markdown.marked.Renderer.prototype.heading = (text: string, level: number): string => {
|
||||
if (level === 3 || level === 4) {
|
||||
const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');
|
||||
return `
|
||||
<h${level} id="${escapedText}" class="docs-header-link">
|
||||
<span header-link="${escapedText}"></span>
|
||||
${text}
|
||||
</h${level}>
|
||||
`;
|
||||
} else {
|
||||
return `<h${level}>${text}</h${level}>`;
|
||||
}
|
||||
};
|
||||
|
||||
return src(['src/lib/**/!(README).md', 'guides/*.md'])
|
||||
.pipe(rename({prefix: 'material-'}))
|
||||
.pipe(markdown(markdownOptions))
|
||||
.pipe(transform(transformMarkdownFiles))
|
||||
.pipe(dom(createTagNameAliaser('docs-markdown')))
|
||||
.pipe(dest('dist/docs/markdown'));
|
||||
});
|
||||
|
||||
// TODO(jelbourn): figure out how to avoid duplicating this task w/ material while still
|
||||
// disambiguating the output.
|
||||
/** Generates html files from the markdown overviews and guides for the cdk. */
|
||||
task('markdown-docs-cdk', () => {
|
||||
return src(['src/cdk/**/!(README).md'])
|
||||
.pipe(rename({prefix: 'cdk-'}))
|
||||
.pipe(markdown(markdownOptions))
|
||||
.pipe(transform(transformMarkdownFiles))
|
||||
.pipe(dom(createTagNameAliaser('docs-markdown')))
|
||||
.pipe(dest('dist/docs/markdown'));
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates syntax-highlighted html files from the examples to be used for the source view of
|
||||
* live examples on the docs site.
|
||||
*/
|
||||
task('build-highlighted-examples', () => {
|
||||
// rename files to fit format: [filename]-[filetype].html
|
||||
const renameFile = (filePath: any) => {
|
||||
const extension = filePath.extname.slice(1);
|
||||
filePath.basename = `${filePath.basename}-${extension}`;
|
||||
};
|
||||
|
||||
return src('src/material-examples/**/*.+(html|css|ts)')
|
||||
.pipe(flatten())
|
||||
.pipe(rename(renameFile))
|
||||
.pipe(highlight())
|
||||
.pipe(dest('dist/docs/examples'));
|
||||
});
|
||||
|
||||
/** Generates API docs from the source JsDoc using dgeni. */
|
||||
task('api-docs', () => {
|
||||
const docs = new Dgeni([apiDocsPackage]);
|
||||
return docs.generate();
|
||||
});
|
||||
|
||||
/**
|
||||
* Minifies all HTML files that have been generated. The HTML files for the
|
||||
* highlighted examples can be skipped, because it won't have any effect.
|
||||
*/
|
||||
task('minify-html-files', () => {
|
||||
return src('dist/docs/+(api|markdown)/**/*.html')
|
||||
.pipe(htmlmin(htmlMinifierOptions))
|
||||
.pipe(dest('dist/docs'));
|
||||
});
|
||||
|
||||
/** Copies example sources to be used as stackblitz assets for the docs site. */
|
||||
task('copy-stackblitz-examples', () => {
|
||||
src(path.join(packagesDir, 'material-examples', '**/*'))
|
||||
.pipe(dest(path.join(DIST_DOCS, 'stackblitz', 'examples')));
|
||||
});
|
||||
|
||||
/** Updates the markdown file's content to work inside of the docs app. */
|
||||
function transformMarkdownFiles(buffer: Buffer, file: any): string {
|
||||
let content = buffer.toString('utf-8');
|
||||
|
||||
// Replace <!-- example(..) --> comments with HTML elements.
|
||||
content = content.replace(EXAMPLE_PATTERN, (_match: string, name: string) =>
|
||||
`<div material-docs-example="${name}"></div>`
|
||||
);
|
||||
|
||||
// Replace the URL in anchor elements inside of compiled markdown files.
|
||||
content = content.replace(LINK_PATTERN, (_match: string, head: string, link: string) =>
|
||||
// The head is the first match of the RegExp and is necessary to ensure that the RegExp matches
|
||||
// an anchor element. The head will be then used to re-create the existing anchor element.
|
||||
// If the head is not prepended to the replaced value, then the first match will be lost.
|
||||
`${head} href="${fixMarkdownDocLinks(link, file.path)}"`
|
||||
);
|
||||
|
||||
// Finally, wrap the entire generated in a doc in a div with a specific class.
|
||||
return `<div class="docs-markdown">${content}</div>`;
|
||||
}
|
||||
|
||||
/** Fixes paths in the markdown files to work in the material-docs-io. */
|
||||
function fixMarkdownDocLinks(link: string, filePath: string): string {
|
||||
// As for now, only markdown links that are relative and inside of the guides/ directory
|
||||
// will be rewritten.
|
||||
if (!filePath.includes(path.normalize('guides/')) || link.startsWith('http')) {
|
||||
return link;
|
||||
}
|
||||
|
||||
let baseName = path.basename(link, path.extname(link));
|
||||
|
||||
// Temporary link the file to the /guide URL because that's the route where the
|
||||
// guides can be loaded in the Material docs.
|
||||
return `guide/${baseName}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function to be called with an HTML document as its context that aliases HTML tags by
|
||||
* adding a class consisting of a prefix + the tag name.
|
||||
* @param classPrefix The prefix to use for the alias class.
|
||||
*/
|
||||
function createTagNameAliaser(classPrefix: string) {
|
||||
return function(this: HTMLElement) {
|
||||
MARKDOWN_TAGS_TO_CLASS_ALIAS.forEach(tag => {
|
||||
Array.from(this.querySelectorAll(tag)).forEach(el => {
|
||||
el.classList.add(`${classPrefix}-${tag}`);
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user