Skip to content

Commit 9ff92cc

Browse files
committed
Allow for customizing the expected root URL of a docs site.
1 parent 6af0c3d commit 9ff92cc

File tree

9 files changed

+106
-67
lines changed

9 files changed

+106
-67
lines changed

addon/components/docs-header/version-selector/template.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<li data-test-id='version'>
1010
<a {{action 'changeVersion' version}} href='#' class='text-black no-underline flex items-center px-4 py-3 hover:bg-grey-lighter'>
1111
<span class='w-6 flex'>
12-
{{#if (eq version currentVersion)}}
12+
{{#if (eq version.name currentVersion.name)}}
1313
{{svg-jar 'check' height=16 width=16}}
1414
{{/if}}
1515
</span>

addon/services/project-version.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,9 @@ import { computed } from '@ember/object';
55
import { task } from 'ember-concurrency';
66

77
export default Service.extend({
8-
current: null,
9-
root: null,
10-
118
_loadAvailableVersions: task(function*() {
12-
let config = getOwner(this).resolveRegistration('config:environment');
13-
let rootURL = config.rootURL;
14-
let tag = config['ember-cli-addon-docs'].projectTag;
15-
let slash = rootURL.indexOf('/', 1);
16-
17-
// TODO deal with apps deployed to custom domains, so their pathnames don't have a leading
18-
// segmenet for the project name. This will impact this service and the 404 page.
19-
this.set('root', rootURL.slice(0, slash));
20-
let currentFromURL = rootURL.substring(slash + 1).replace(/\/$/, '');
21-
this.set('current', currentFromURL || 'latest'); // dev-time guard. Think of a better way?
22-
23-
let response = yield fetch(`${this.get('root')}/versions.json`);
24-
let json = yield response.ok ? response.json() : [{ name: 'latest', tag, sha: '12345', path: '/' }];
9+
let response = yield fetch(`${this.get('root')}versions.json`);
10+
let json = yield response.ok ? response.json() : { latest: this.get('currentVersion') };
2511

2612
this.set('versions', Object.keys(json).map(key => {
2713
let version = json[key];
@@ -32,19 +18,33 @@ export default Service.extend({
3218
}),
3319

3420
redirectTo(version) {
35-
window.location.href = `${this.get('root')}/${version.path || version}`;
21+
window.location.href = `${this.get('root')}${version.path}`;
3622
},
3723

3824
loadAvailableVersions() {
3925
return this.get('_loadAvailableVersions').perform();
4026
},
4127

42-
currentVersion: computed('versions.[]', function() {
43-
let versions = this.get('versions');
28+
root: computed('currentVersion.path', function() {
29+
let rootURL = getOwner(this).resolveRegistration('config:environment').rootURL;
30+
return rootURL.replace(`/${this.get('currentVersion.path')}/`, '/');
31+
}),
4432

45-
if (versions) {
46-
return versions.find(version => version.name === this.get('current'));
33+
currentVersion: computed(function() {
34+
let config = getOwner(this).resolveRegistration('config:environment')['ember-cli-addon-docs'];
35+
let currentVersion = config.deployVersion;
36+
37+
// In development, this token won't have been replaced replaced
38+
if (currentVersion === 'ADDON_DOCS_DEPLOY_VERSION') {
39+
currentVersion = {
40+
name: 'latest',
41+
tag: config.projectTag,
42+
path: '',
43+
sha: 'abcde'
44+
};
4745
}
46+
47+
return currentVersion;
4848
})
4949

5050
});

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ module.exports = {
5858
'ember-cli-addon-docs': {
5959
projectName: this.parent.pkg.name,
6060
projectTag: this.parent.pkg.version,
61-
projectHref: info && info.browse()
61+
projectHref: info && info.browse(),
62+
deployVersion: 'ADDON_DOCS_DEPLOY_VERSION'
6263
}
6364
};
6465

lib/config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
'use strict';
22

33
const gitRepoInfo = require('git-repo-info');
4+
const hostedGitInfo = require('hosted-git-info');
45
const semver = require('semver');
56

67
module.exports = class AddonDocsConfig {
7-
constructor() {
8+
constructor(project) {
9+
this.project = project;
810
this.repoInfo = gitRepoInfo();
911
}
1012

13+
getRootURL() {
14+
let repository = this.project.pkg.repository || '';
15+
let info = hostedGitInfo.fromUrl(repository.url || repository);
16+
return info && info.project || this.project.name();
17+
}
18+
1119
getVersionPath() {
1220
if ('ADDON_DOCS_VERSION_PATH' in process.env) {
1321
return process.env.ADDON_DOCS_VERSION_PATH;

lib/deploy/plugin.js

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ module.exports = class AddonDocsDeployPlugin {
3838
}
3939

4040
willUpload(context) {
41-
let relativeBuildDestination = this.userConfig.getVersionPath();
41+
let relativeBuildDestination = this._getVersionPath();
4242
let stagingDirectory = context.addonDocs.stagingDirectory;
4343
let fullBuildDestination = path.join(stagingDirectory, relativeBuildDestination);
4444

4545
return this._copyExistingFiles(context, relativeBuildDestination)
46-
.then(() => this._copyBuildOutput(context, fullBuildDestination))
46+
.then(() => this._copyBuildOutput(context, stagingDirectory, relativeBuildDestination))
4747
.then(() => this._verifyRootFiles(stagingDirectory))
4848
.then(() => this._updateVersionsManifest(stagingDirectory))
4949
.then(() => this._maybeUpdateLatest(context, stagingDirectory, fullBuildDestination))
@@ -54,27 +54,36 @@ module.exports = class AddonDocsDeployPlugin {
5454
quickTemp.remove(this, 'deployStagingDirectory');
5555
}
5656

57+
_getVersionPath(version) {
58+
return version || this.userConfig.getVersionPath();
59+
}
60+
5761
_verifyRootFiles(stagingDirectory) {
5862
let vendorDir = `${__dirname}/../../vendor/ember-cli-addon-docs`;
5963

60-
for (let file of ['index.html', '404.html']) {
61-
if (!fs.existsSync(`${stagingDirectory}/${file}`)) {
62-
fs.copySync(`${vendorDir}/${file}`, `${stagingDirectory}/${file}`);
63-
}
64+
if (!fs.existsSync(`${stagingDirectory}/index.html`)) {
65+
fs.copySync(`${vendorDir}/index.html`, `${stagingDirectory}/index.html`);
6466
}
67+
68+
let segmentCount = this._getRootURL().split('/').length + 1;
69+
let redirectContents = fs.readFileSync(`${vendorDir}/404.html`, 'utf-8');
70+
redirectContents = redirectContents.replace(/\bADDON_DOCS_SEGMENT_COUNT\b/g, segmentCount);
71+
fs.writeFileSync(`${stagingDirectory}/404.html`, redirectContents);
72+
}
73+
74+
_getRootURL() {
75+
return this.userConfig.getRootURL().replace(/^\/|\/$/g, '');
6576
}
6677

6778
_updateVersionsManifest(stagingDirectory) {
6879
let versionsFile = `${stagingDirectory}/versions.json`;
6980
let versions = fs.existsSync(versionsFile) ? fs.readJSONSync(versionsFile) : {};
70-
let path = this.userConfig.getVersionPath();
71-
let name = this.userConfig.getVersionName();
72-
let sha = this.userConfig.repoInfo.sha;
73-
let tag = this.userConfig.repoInfo.tag;
81+
let version = this._currentDeployVersion();
82+
83+
versions[version.name] = version;
7484

75-
versions[path] = { sha, tag, path, name };
7685
if (this.userConfig.shouldUpdateLatest()) {
77-
versions['latest'] = { sha, tag, path: 'latest', name: 'latest' };
86+
versions['latest'] = this._latestDeployVersion();
7887
}
7988

8089
fs.writeJSONSync(versionsFile, versions, { spaces: 2 });
@@ -94,32 +103,49 @@ module.exports = class AddonDocsDeployPlugin {
94103
return fs.copy(from, to, { filter });
95104
}
96105

97-
_copyBuildOutput(context, fullBuildDestination) {
106+
_copyBuildOutput(context, stagingDirectory, relativeBuildDestination) {
107+
let fullBuildDestination = `${stagingDirectory}/${relativeBuildDestination}`;
108+
let deployVersion = this._currentDeployVersion();
98109
return fs.copy(context.distDir, fullBuildDestination, { overwrite: true })
99-
.then(() => this._updateRootURL(context, fullBuildDestination));
110+
.then(() => this._updateIndexContents(context, stagingDirectory, relativeBuildDestination, deployVersion));
100111
}
101112

102113
_maybeUpdateLatest(context, stagingDirectory) {
103114
if (!this.userConfig.shouldUpdateLatest()) { return; }
104115

105-
let latestDir = path.join(stagingDirectory, 'latest');
106-
return fs.remove(latestDir)
107-
.then(() => fs.copy(context.distDir, latestDir))
108-
.then(() => this._updateRootURL(context, latestDir));
116+
let latestDir = this._getVersionPath('latest');
117+
let fullPath = path.join(stagingDirectory, latestDir);
118+
let deployVersion = this._latestDeployVersion();
119+
return fs.remove(fullPath)
120+
.then(() => fs.copy(context.distDir, fullPath))
121+
.then(() => this._updateIndexContents(context, stagingDirectory, latestDir, deployVersion));
109122
}
110123

111-
_updateRootURL(context, appRoot) {
112-
let indexPath = `${appRoot}/index.html`;
113-
let rootURL = `${this._projectName(context)}/${path.basename(appRoot)}`;
124+
_updateIndexContents(context, stagingDirectory, appRoot, deployVersion) {
125+
let indexPath = `${stagingDirectory}/${appRoot}/index.html`;
126+
let rootURL = [this._getRootURL(), appRoot].filter(Boolean).join('/');
114127
let contents = fs.readFileSync(indexPath, 'utf-8');
115-
let updated = contents.replace(/\bADDON_DOCS_ROOT_URL\b/g, rootURL);
128+
let encodedVersion = encodeURIComponent(JSON.stringify(deployVersion));
129+
let updated = contents.replace(/\/?ADDON_DOCS_ROOT_URL\/?/g, `/${rootURL}/`)
130+
.replace(/%22ADDON_DOCS_DEPLOY_VERSION%22/g, encodedVersion);
131+
116132
fs.writeFileSync(indexPath, updated);
117133
}
118134

119-
_projectName(context) {
120-
let repository = context.config.git.repo;
121-
let info = hostedGitInfo.fromUrl(repository);
122-
return info && info.project || context.project.name();
135+
_currentDeployVersion() {
136+
let path = this._getVersionPath();
137+
let name = this.userConfig.getVersionName();
138+
let sha = this.userConfig.repoInfo.sha;
139+
let tag = this.userConfig.repoInfo.tag;
140+
return { path, name, sha, tag };
141+
}
142+
143+
_latestDeployVersion() {
144+
let path = this._getVersionPath('latest');
145+
let name = 'latest';
146+
let sha = this.userConfig.repoInfo.sha;
147+
let tag = this.userConfig.repoInfo.tag;
148+
return { path, name, sha, tag };
123149
}
124150

125151
_inferRepoUrl(context) {

lib/utils/read-config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ module.exports = function readConfig(project) {
1414
}
1515
}
1616

17-
return new ConfigClass();
17+
return new ConfigClass(project);
1818
}

tests/acceptance/version-selector-test.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ module('Acceptance | Version selector test', function(hooks) {
88
setupMirage(hooks);
99

1010
test('if the current version is latest and latest has a tag, it displays the tag', async function(assert) {
11-
server.get('/versions.json', {
12-
"latest": {
13-
"sha": "53b73465d31925f26fd1f77881aefcaccce2915a",
14-
"tag": 'v0.1.0',
15-
"path": "latest",
16-
"name": "latest"
17-
},
11+
this.owner.lookup('service:project-version').set('currentVersion', {
12+
"sha": "53b73465d31925f26fd1f77881aefcaccce2915a",
13+
"tag": 'v0.1.0',
14+
"path": "latest",
15+
"name": "latest"
1816
});
1917

2018
await visit('/');
@@ -23,13 +21,11 @@ module('Acceptance | Version selector test', function(hooks) {
2321
});
2422

2523
test(`if the current version is latest and latest doesn't have a tag, it displays Latest`, async function(assert) {
26-
server.get('/versions.json', {
27-
"latest": {
28-
"sha": "53b73465d31925f26fd1f77881aefcaccce2915a",
29-
"tag": null,
30-
"path": "latest",
31-
"name": "latest"
32-
},
24+
this.owner.lookup('service:project-version').set('currentVersion', {
25+
"sha": "53b73465d31925f26fd1f77881aefcaccce2915a",
26+
"tag": null,
27+
"path": "latest",
28+
"name": "latest"
3329
});
3430

3531
await visit('/');

tests/dummy/app/pods/docs/deploying/template.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ This method returns a name for a given version of your documentation. By default
141141

142142
This method determines whether the `/latest` directory will also be updated with the current deploy. By default, this will return true for builds from a tagged commit where the tag is a [semver non-prerelease version]([node-semver](https://github.com/npm/node-semver), and false otherwise. You can explicitly set the `ADDON_DOCS_UPDATE_LATEST` environment variable to `true` or `false` to override this behavior.
143143

144+
### `getRootURL()`
145+
146+
This method determines the static path under which all deploys of your docs app expect to live. It defaults to the name of your project, which matches the typical GitHub Pages setup where your site lives at <u>https://**[user]**.github.io/**[project]**/...</u>.
147+
148+
If instead, however, you want to [set up a CNAME for your project](https://help.github.com/articles/using-a-custom-domain-with-github-pages/) and host it at e.g. <u>https://my-great-project.com</u>, you would override this method to return `''`, since there would be no static path at the beginning of the URL.
149+
150+
**Note**: if you change this configuration after you've already deployed copies of your docs site, you'll need to check out your `gh-pages` branch and find/replace your previous root URL in those copies in order for them to continue to function in their new location.
151+
144152
## Removing a Deployed Version
145153

146154
Deploying a version of your documentation does two things: it copies the `dist` directory of your built docs app into a particular place on your `gh-pages` branch, and it adds or updates an entry in the `versions.json` manifest in the root of that branch. To remove a version, then, you just need to undo those two things.

vendor/ember-cli-addon-docs/404.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
2323
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
2424
// Otherwise, leave segmentCount as 0.
25-
var segmentCount = 2;
25+
var segmentCount = ADDON_DOCS_SEGMENT_COUNT;
2626
var l = window.location;
2727
var segments = l.pathname.split('/');
2828

@@ -38,5 +38,5 @@
3838
}
3939
</script>
4040
</head>
41-
<body>The request page wasn't found.</body>
41+
<body>The requested page wasn't found.</body>
4242
</html>

0 commit comments

Comments
 (0)