Skip to content

Commit

Permalink
docs(versions): provide version menu for navigating to versioned docs
Browse files Browse the repository at this point in the history
Refs angular#918 provides version menu (with customizable min-version cutoff)
that navigates to docs based on a simple string format.

This approach was based on that provided in the base angular.js repo,
and some of the code was ported from that repo.
  • Loading branch information
Adam Pearson committed Mar 13, 2015
1 parent 5fab400 commit 8d7ef39
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 4 deletions.
205 changes: 205 additions & 0 deletions config/version-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
'use strict';

var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var semver = require('semver');
var _ = require('lodash');

var currentPackage, previousVersions, cdnVersion, gitRepoInfo;


/**
* Load information about this project from the package.json
* @return {Object} The package information
*/
var getPackage = function() {
// Search up the folder hierarchy for the first package.json
var packageFolder = path.resolve('.');
while (!fs.existsSync(path.join(packageFolder, 'package.json'))) {
var parent = path.dirname(packageFolder);
if (parent === packageFolder) { break; }
packageFolder = parent;
}
return JSON.parse(fs.readFileSync(path.join(packageFolder,'package.json'), 'UTF-8'));
};


/**
* Parse the github URL for useful information
* @return {Object} An object containing the github owner and repository name
*/
var getGitRepoInfo = function() {
var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/;
var match = GITURL_REGEX.exec(currentPackage.repository.url);
var git = {
owner: match[1],
repo: match[2]
};
return git;
};



/**
* Extract the code name from the tagged commit's message - it should contain the text of the form:
* "codename(some-code-name)"
* @param {String} tagName Name of the tag to look in for the codename
* @return {String} The codename if found, otherwise null/undefined
*/
var getCodeName = function(tagName) {
var gitCatOutput = shell.exec('git cat-file -p ' + tagName, {silent:true}).output;
var tagMessage = gitCatOutput.match(/^.*codename.*$/mg)[0];
var codeName = tagMessage && tagMessage.match(/codename\((.*)\)/)[1];
if (!codeName) {
throw new Error("Could not extract release code name. The message of tag " + tagName +
" must match '*codename(some release name)*'");
}
return codeName;
};


/**
* Compute a build segment for the version, from the Jenkins build number and current commit SHA
* @return {String} The build segment of the version
*/
function getBuild() {
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
return 'sha.' + hash;
}


/**
* If the current commit is tagged as a version get that version
* @return {SemVer} The version or null
*/
var getTaggedVersion = function() {
var gitTagResult = shell.exec('git describe --exact-match', {silent:true});

if (gitTagResult.code === 0) {
var tag = gitTagResult.output.trim();
var version = semver.parse(tag);

if (version && semver.satisfies(version, currentPackage.branchVersion)) {
version.codeName = getCodeName(tag);
version.full = version.version;
version.branch = 'v' + currentPackage.branchPattern.replace('*', 'x');
return version;
}
}

return null;
};

/**
* Get a collection of all the previous versions sorted by semantic version
* @return {Array.<SemVer>} The collection of previous versions
*/
var getPreviousVersions = function() {
// always use the remote tags as the local clone might
// not contain all commits when cloned with git clone --depth=...
// Needed e.g. for Travis
var repo_url = currentPackage.repository.url;
var tagResults = shell.exec('git ls-remote --tags ' + repo_url,
{silent: true});

// default document location template
var docDefaultUrlTemplate = 'http://code.angularjs.org/material/:version/docs';
var docMinimumVersionRequirement = '>=0.8.0';

if (tagResults.code === 0) {
return _(tagResults.output.match(/v[0-9].*[0-9]$/mg))
.map(function(tag) {
var version = semver.parse(tag);
return version;
})
.filter()
.map(function(version) {
version.docsUrl = null;
if(semver.satisfies(version, docMinimumVersionRequirement)) {

version.docsUrl = docDefaultUrlTemplate.replace(":version", version.version)
}
return version;
})
.sort(semver.compare)
.value();
} else {
return [];
}
};

var getCdnVersion = function() {
return _(previousVersions)
.filter(function(tag) {
return semver.satisfies(tag, currentPackage.branchVersion);
})
.reverse()
.reduce(function(cdnVersion, version) {
if (!cdnVersion) {
// Note: need to use shell.exec and curl here
// as version-infos returns its result synchronously...
var cdnResult = shell.exec('curl https://ajax.googleapis.com/ajax/libs/angular_material/' + version + '/angular-material.min.js ' +
'--head --write-out "%{http_code}" -o /dev/null -silent',
{silent: true});
if (cdnResult.code === 0) {
var statusCode = cdnResult.output.trim();
if (statusCode === '200') {
cdnVersion = version;
}
}
}
return cdnVersion;
}, null);
};

/**
* Get the unstable snapshot version
* @return {SemVer} The snapshot version
*/
var getSnapshotVersion = function() {
var version = _(previousVersions)
.filter(function(tag) {
return semver.satisfies(tag, currentPackage.branchVersion);
})
.last();

if (!version) {
// a snapshot version before the first tag on the branch
version = semver(currentPackage.branchPattern.replace('*','0-beta.1'));
}

// We need to clone to ensure that we are not modifying another version
version = semver(version.raw);

var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER;
if (!version.prerelease || !version.prerelease.length) {
// last release was a non beta release. Increment the patch level to
// indicate the next release that we will be doing.
// E.g. last release was 1.3.0, then the snapshot will be
// 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!

// If the last release was a beta release we don't update the
// beta number by purpose, as otherwise the semver comparison
// does not work any more when the next beta is released.
// E.g. don't generate 1.3.0-beta.2.build.1
// as this is bigger than 1.3.0-beta.2 according to semver
version.patch++;
}
version.prerelease = jenkinsBuild ? ['build', jenkinsBuild] : ['local'];
version.build = getBuild();
version.codeName = 'snapshot';
version.isSnapshot = true;
version.format();
version.full = version.version + '+' + version.build;
version.branch = 'master';

return version;
};


exports.currentPackage = currentPackage = getPackage();
exports.gitRepoInfo = gitRepoInfo = getGitRepoInfo();
exports.previousVersions = previousVersions = getPreviousVersions();
exports.cdnVersion = cdnVersion = getCdnVersion();
exports.currentVersion = getTaggedVersion() || getSnapshotVersion();
14 changes: 14 additions & 0 deletions docs/app/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ code:not(.highlight) {
.docs-menu > li {
border-top: 1px solid rgba(0, 0, 0, 0.12);
}
.docs-menu > li:nth-child(-n+2) {
border-top: none;
}

.docs-menu .md-button {
border-radius: 0;
color: inherit;
Expand All @@ -176,6 +180,16 @@ code:not(.highlight) {
white-space: normal;
width: 100%;
}

.docs-menu md-select {
margin-top: .5em;
width: 100%;
}

.docs-menu md-select md-select-label {
justify-content: flex-end
}

.docs-menu a.md-button {
display: block;
}
Expand Down
27 changes: 25 additions & 2 deletions docs/app/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,18 +349,20 @@ function(SERVICES, COMPONENTS, DEMOS, PAGES, $location, $rootScope) {
'$scope',
'COMPONENTS',
'BUILDCONFIG',
'VERSIONCONFIG',
'$mdSidenav',
'$timeout',
'$mdDialog',
'menu',
'$location',
'$rootScope',
'$log',
function($scope, COMPONENTS, BUILDCONFIG, $mdSidenav, $timeout, $mdDialog, menu, $location, $rootScope, $log) {
function($scope, COMPONENTS, BUILDCONFIG, VERSIONCONFIG, $mdSidenav, $timeout, $mdDialog, menu, $location, $rootScope, $log) {
var self = this;

$scope.COMPONENTS = COMPONENTS;
$scope.BUILDCONFIG = BUILDCONFIG;
$scope.VERSIONCONFIG = VERSIONCONFIG
$scope.menu = menu;

$scope.path = path;
Expand All @@ -378,7 +380,6 @@ function($scope, COMPONENTS, BUILDCONFIG, $mdSidenav, $timeout, $mdDialog, menu,
this.toggleOpen = toggleOpen;
this.autoFocusContent = false;


var mainContentArea = document.querySelector("[role='main']");

// *********************
Expand Down Expand Up @@ -450,6 +451,28 @@ function($scope, COMPONENTS, BUILDCONFIG, $mdSidenav, $timeout, $mdDialog, menu,
}
}])

.controller('DocsVersionsCtrl', [
'$scope',
'$location',
'$window',
'VERSIONCONFIG',
function($scope, $location, $window,VERSIONCONFIG) {
$scope.version = VERSIONCONFIG.currentVersion;
$scope.versions = VERSIONCONFIG.previousVersions.reverse();
$scope.versions.unshift(VERSIONCONFIG.currentVersion);

$scope.availableDocumentationVersions = function(element) {
return element.docsUrl != null || element.isSnapshot;
};

$scope.jumpToDocsVersion = function(version) {
var currentPagePath = $location.path().replace(/\/$/, '');

$window.location = version.docsUrl + currentPagePath;
};

}])

.controller('HomeCtrl', [
'$scope',
'$rootScope',
Expand Down
2 changes: 1 addition & 1 deletion docs/config/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var _ = require('lodash');
var path = require('canonical-path');
var buildConfig = require('../../config/build.config');

var projectPath = path.resolve(__dirname, '../..');
var packagePath = __dirname;

Expand All @@ -15,6 +14,7 @@ module.exports = new Package('angular-md', [
.processor(require('./processors/componentsData'))
.processor(require('./processors/indexPage'))
.processor(require('./processors/buildConfig'))
.processor(require('./processors/versionConfig'))
.processor(require('./processors/content'))

.config(function(log, templateEngine, templateFinder) {
Expand Down
16 changes: 16 additions & 0 deletions docs/config/processors/versionConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var versionConfig = require("../../../config/version-info")
module.exports = function versionConfigProcessor(log) {
return {
$runBefore: ['rendering-docs'],
$runAfter: ['indexPageProcessor'],
$process: process
};

function process(docs) {
docs.push({
template: 'version-config.js',
outputPath: 'js/version-config.js',
versionConfig: versionConfig
});
}
}
5 changes: 5 additions & 0 deletions docs/config/template/index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ <h1 class="md-toolbar-tools">

<md-content flex role="navigation">
<ul class="docs-menu">
<li ng-controller="DocsVersionsCtrl">
<md-select ng-model="version" ng-change="jumpToDocsVersion(version)" placeholder="Version">
<md-option ng-value="v" ng-repeat="v in versions | filter: availableDocumentationVersions">v{{v.version}}</md-option>
</md-select>
</li>
<li ng-repeat="section in menu.sections" class="parent-list-item" ng-class="{'parentActive' : isSectionSelected(section)}">
<h2 class="menu-heading" ng-if="section.type === 'heading'" id="heading_{{ section.name | nospace }}">
{{section.name}}
Expand Down
1 change: 1 addition & 0 deletions docs/config/template/version-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DocsApp.constant('VERSIONCONFIG', {$ doc.versionConfig | json $});
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"name": "angular-material",
"version": "0.8.3",
"branchVersion": "0.8.3",
"branchPattern": "0.8.*",
"repository": {
"url": "git://github.com/angular/material.git"
"url": "https://github.com/angular/material.git"
},
"devDependencies": {
"canonical-path": "0.0.2",
Expand Down Expand Up @@ -41,6 +43,8 @@
"minimist": "^0.1.0",
"mkdirp": "^0.5.0",
"q": "^1.0.1",
"semver": "~4.0.3",
"shelljs": "~0.3.0",
"stream-series": "^0.1.1",
"through2": "^0.6.3"
}
Expand Down

0 comments on commit 8d7ef39

Please sign in to comment.