Skip to content

Commit 5abdddf

Browse files
authored
Merge pull request #81 from apify/feature/convert-relative-image-paths-to-absolute-in-repo-readme
Convert relative URLs to absolute in git READMEs
2 parents d3945d0 + 40aebf3 commit 5abdddf

File tree

4 files changed

+208
-2
lines changed

4 files changed

+208
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
0.5.1 / 2020/10/27
2+
==================
3+
- Added function to convert relative URL paths in git README files to absolute paths
4+
15
0.5.0 / 2020/10/02
26
==================
37
- Removed unused `getPublicCrawlerNiceUrl` function and its unlicensed dependency `slugg`.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apify-shared",
3-
"version": "0.5.0",
3+
"version": "0.5.1",
44
"description": "Tools and constants shared across Apify projects.",
55
"main": "build/index.js",
66
"keywords": [
@@ -47,7 +47,8 @@
4747
"moment": "^2.27.0",
4848
"request": "^2.88.0",
4949
"underscore": "^1.9.1",
50-
"url": "^0.11.0"
50+
"url": "^0.11.0",
51+
"git-url-parse": "^11.2.0"
5152
},
5253
"devDependencies": {
5354
"@apify/eslint-config": "0.0.3",

src/git.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import gitUrlParse from 'git-url-parse';
2+
3+
4+
/**
5+
* This replaces all relative image paths (starting with './') in markdown readme
6+
* by appropriate absolute paths so they can be correctly rendered on the website.
7+
* At the moment, the conversion works for 3 major repo systems, namely Github, Gitlab and Bitbucket and
8+
* also works if the user opted to use custom branch for deploying their actor to Apify.
9+
* @param {Object} args
10+
* @param {string} args.readme whole readme file stored as a single string
11+
* @param {string} args.gitRepoUrl e.g. git@github.com:AUTHOR_NAME/REPO_NAME.git
12+
* @param {string} args.gitBranchName branch name associated with the actor build to which this readme corresponds
13+
* @return {string} updated readme
14+
*/
15+
export const convertRelativeImagePathsToAbsoluteInReadme = ({ readme, gitRepoUrl, gitBranchName }) => {
16+
const parsedRepoUrl = gitUrlParse(gitRepoUrl);
17+
18+
// Can't use parsedRepoUrl.full_name on it's own as Bitbucket adds irrelevant path suffix to the end of it
19+
const repoNameParts = parsedRepoUrl.full_name.split('/');
20+
const repoFullName = `${repoNameParts[0]}/${repoNameParts[1]}`;
21+
22+
// When user wants to specify a different branch during actor addition, they need
23+
// to add #branchName to the end of git URL. Hence it ends up under 'hash' key here.
24+
// Otherwise, we try to use the branch name from the build object. It should exist for all builds since roughly mid October 2020.
25+
// Prior to that, all default branches were 'master', hence we default to that as a backup.
26+
const branchName = parsedRepoUrl.hash || gitBranchName || 'master';
27+
28+
// Images in markdown have syntax ![alt text](image url)
29+
const relativeImageMarkdownRegex = /(!\[.*?\])\(\.\/(.*?)\)/g;
30+
31+
// HTML image references of type <img src="..." /> can be also embedded in markdown (e.g. in HTML table)
32+
// We provide 2 regular expression for cases where src attribute is wrapped in double or single quotes
33+
const relativeImageHtmlRegexWithDoubleQuotes = /(<img.*?src=")\.\/(.*?)(".*?\/>)/g;
34+
const relativeImageHtmlRegexWithSingleQuotes = /(<img.*?src=')\.\/(.*?)('.*?\/>)/g;
35+
36+
let urlPrefix = null;
37+
if (parsedRepoUrl.resource === 'github.com') {
38+
urlPrefix = `https://raw.githubusercontent.com/${repoFullName}/${branchName}`;
39+
} else if (parsedRepoUrl.resource === 'gitlab.com') {
40+
urlPrefix = `https://gitlab.com/${repoFullName}/-/raw/${branchName}`;
41+
} else if (parsedRepoUrl.resource === 'bitbucket.org') {
42+
// Note: bytebucket is raw content serving service by Bitbucket
43+
urlPrefix = `https://bytebucket.org/${repoFullName}/raw/${branchName}`;
44+
}
45+
46+
return urlPrefix
47+
? readme
48+
.replace(relativeImageMarkdownRegex, `$1(${urlPrefix}/$2)`)
49+
.replace(relativeImageHtmlRegexWithDoubleQuotes, `$1${urlPrefix}/$2$3`)
50+
.replace(relativeImageHtmlRegexWithSingleQuotes, `$1${urlPrefix}/$2$3`)
51+
: readme;
52+
};

test/git.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* eslint-disable */
2+
3+
import { expect } from 'chai';
4+
5+
import { convertRelativeImagePathsToAbsoluteInReadme } from '../src/git';
6+
7+
describe('convertRelativeImagePathsToAbsoluteInReadme()', () => {
8+
it('works correctly for Github repo with explicit branch name', () => {
9+
const testMarkdown = `
10+
# Heading
11+
![img1](http://www.apify-awesome-test-image.com)
12+
![img2](./relative-path-to-img.jpg)
13+
`;
14+
const expectedResult = `
15+
# Heading
16+
![img1](http://www.apify-awesome-test-image.com)
17+
![img2](https://raw.githubusercontent.com/apify/test-repo/main/relative-path-to-img.jpg)
18+
`;
19+
20+
expect(convertRelativeImagePathsToAbsoluteInReadme({
21+
readme: testMarkdown,
22+
gitRepoUrl: 'git@github.com:apify/test-repo.git',
23+
gitBranchName: 'main',
24+
})).to.eql(expectedResult)
25+
});
26+
27+
it('works correctly for Bitbucket repo with explicit branch name', () => {
28+
const testMarkdown = `
29+
# Heading
30+
![img1](http://www.apify-awesome-test-image.com)
31+
![img2](./relative-path-to-img.jpg)
32+
`;
33+
const expectedResult = `
34+
# Heading
35+
![img1](http://www.apify-awesome-test-image.com)
36+
![img2](https://bytebucket.org/apify/test-repo/raw/main/relative-path-to-img.jpg)
37+
`;
38+
expect(convertRelativeImagePathsToAbsoluteInReadme({
39+
readme: testMarkdown,
40+
gitRepoUrl: 'git@bitbucket.org:apify/test-repo.git',
41+
gitBranchName: 'main',
42+
})).to.eql(expectedResult)
43+
});
44+
45+
it('works correctly for Gitlab repo with explicit branch name', () => {
46+
const testMarkdown = `
47+
# Heading
48+
![img1](http://www.apify-awesome-test-image.com)
49+
![img2](./relative-path-to-img.jpg)
50+
`;
51+
const expectedResult = `
52+
# Heading
53+
![img1](http://www.apify-awesome-test-image.com)
54+
![img2](https://gitlab.com/apify/test-repo/-/raw/main/relative-path-to-img.jpg)
55+
`;
56+
57+
expect(convertRelativeImagePathsToAbsoluteInReadme({
58+
readme: testMarkdown,
59+
gitRepoUrl: 'git@gitlab.com:apify/test-repo.git',
60+
gitBranchName: 'main',
61+
})).to.eql(expectedResult)
62+
});
63+
64+
it('works correctly for Github repo with branch name in hash', () => {
65+
const testMarkdown = `
66+
# Heading
67+
![img1](http://www.apify-awesome-test-image.com)
68+
![img2](./relative-path-to-img.jpg)
69+
`;
70+
const expectedResult = `
71+
# Heading
72+
![img1](http://www.apify-awesome-test-image.com)
73+
![img2](https://raw.githubusercontent.com/apify/test-repo/my-awesome-branch/relative-path-to-img.jpg)
74+
`;
75+
76+
expect(convertRelativeImagePathsToAbsoluteInReadme({
77+
readme: testMarkdown,
78+
gitRepoUrl: 'git@github.com:apify/test-repo.git#my-awesome-branch',
79+
})).to.eql(expectedResult)
80+
});
81+
82+
it('works correctly for Github repo without explicit branch name', () => {
83+
const testMarkdown = `
84+
# Heading
85+
![img1](http://www.apify-awesome-test-image.com)
86+
![img2](./relative-path-to-img.jpg)
87+
`;
88+
const expectedResult = `
89+
# Heading
90+
![img1](http://www.apify-awesome-test-image.com)
91+
![img2](https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg)
92+
`;
93+
94+
expect(convertRelativeImagePathsToAbsoluteInReadme({
95+
readme: testMarkdown,
96+
gitRepoUrl: 'git@github.com:apify/test-repo.git',
97+
})).to.eql(expectedResult)
98+
});
99+
100+
it('works correctly for Github repo with explicit branch name and <img src=... /> tags', () => {
101+
const testMarkdown = `
102+
# Heading
103+
![img1](http://www.apify-awesome-test-image.com)
104+
![img2](./relative-path-to-img.jpg)
105+
<img src='./relative-path-to-img.jpg' />
106+
<img src='./relative-path-to-img.jpg' alt='Some alt text'/>
107+
<img alt='Some alt text' src='./relative-path-to-img.jpg' />
108+
<img alt='Some alt text' src='./relative-path-to-img.jpg' width="500"/>
109+
<img src="./relative-path-to-img.jpg" />
110+
<img src="./relative-path-to-img.jpg" alt="Some alt text"/>
111+
<img alt="Some alt text" src="./relative-path-to-img.jpg" />
112+
<img alt="Some alt text" src="./relative-path-to-img.jpg" width="500"/>
113+
`;
114+
const expectedResult = `
115+
# Heading
116+
![img1](http://www.apify-awesome-test-image.com)
117+
![img2](https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg)
118+
<img src='https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg' />
119+
<img src='https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg' alt='Some alt text'/>
120+
<img alt='Some alt text' src='https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg' />
121+
<img alt='Some alt text' src='https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg' width="500"/>
122+
<img src="https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg" />
123+
<img src="https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg" alt="Some alt text"/>
124+
<img alt="Some alt text" src="https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg" />
125+
<img alt="Some alt text" src="https://raw.githubusercontent.com/apify/test-repo/master/relative-path-to-img.jpg" width="500"/>
126+
`;
127+
console.log(convertRelativeImagePathsToAbsoluteInReadme({
128+
readme: testMarkdown,
129+
gitRepoUrl: 'git@github.com:apify/test-repo.git',
130+
}));
131+
expect(convertRelativeImagePathsToAbsoluteInReadme({
132+
readme: testMarkdown,
133+
gitRepoUrl: 'git@github.com:apify/test-repo.git',
134+
})).to.eql(expectedResult)
135+
});
136+
137+
it('works correctly for unknown repo', () => {
138+
const testMarkdown = `
139+
# Heading
140+
![img1](http://www.apify-awesome-test-image.com)
141+
![img2](./relative-path-to-img.jpg)
142+
`;
143+
expect(convertRelativeImagePathsToAbsoluteInReadme({
144+
readme: testMarkdown,
145+
gitRepoUrl: 'git@some-unknown-git-site.com:apify/test-repo.git',
146+
})).to.eql(testMarkdown)
147+
});
148+
149+
});

0 commit comments

Comments
 (0)