Skip to content

Commit 1f8f7df

Browse files
authored
[FEATURE] Pre rendering scripts and GitHub workflow (#4)
A GitHub action will now run pre-rendering scripts and push changes to `main` whenever changes are pushed to the `contrib` branch. These commands can also be run with `make`. `docs` should still be the main argument for rendering documentation locally. * `cleanup-docs`: Restores the Documentation folder from Documentation-BACKUP-temp * `docs`: Prepare, generate, and clean up docs. * `expand-tags`: Expands tags into Markdown * `generate-tos`: Generates table of contents in all Index.md files * `help`: Displays this list of targets with descriptions * `index-files`: Indexes all files and links in files.json * `expand-links`: Expands shorthand links * `render-docs`: Render docs base on Documentation directory * `stage-docs`: Make a backup of the Documentation directory in Documentation-BACKUP-temp * `test-docs`: Test the documentation rendering Also implements a search-replace for shorthand links to only a file's file name. Since each step-by-step guide should have a unique title, it follows that a file name based on the title should also be unique. This allows us to link to a file by only its name, and we don't have to think about the folder structure.
1 parent dacfa2c commit 1f8f7df

File tree

9 files changed

+387
-4
lines changed

9 files changed

+387
-4
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Prepare for rendering and push to main
2+
3+
on:
4+
push:
5+
branches:
6+
- contrib
7+
workflow_dispatch:
8+
9+
jobs:
10+
prepare-and-push:
11+
if: github.repository_owner == 'TYPO3-documentation'
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
with:
17+
token: ${{ secrets.GITHUB_TOKEN }}
18+
ref: contrib
19+
20+
- name: Setup PHP
21+
uses: shivammathur/setup-php@v2
22+
with:
23+
php-version: '8.3'
24+
25+
- name: Index files
26+
run: php bin/index-files
27+
28+
- name: Expand shorthand links
29+
run: php bin/expand-tags
30+
31+
- name: Generate table of contents
32+
run: php bin/generate-tos
33+
34+
- name: Expand tags
35+
run: php bin/expand-tags
36+
37+
- name: Configure Git
38+
run: |
39+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
40+
git config --global user.name "github-actions[bot]"
41+
42+
- name: Commit and push changes
43+
run: |
44+
git fetch origin main
45+
git checkout main
46+
git add .
47+
git commit -m "Pre-render: $(git show -s --format='%s')"
48+
git push origin main --force
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
.webprj
2828
/_make
2929
/Documentation-GENERATED-temp/
30+
/Documentation-BACKUP-temp/
3031
ehthumbs.db
3132
composer.lock
3233
nbproject

Documentation/20BuildingWebsites/10ContentManagement/20CreateCustomContentElements/CustomizeAContentElementTemplate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Customize a content element template
22

3-
<!-- #TYPO3v13 #Beginner #ContentElements #Frontend #Fluid @mabolek -->
3+
<!-- #TYPO3v13 #Beginner #ContentElements #Frontend #Templating @mabolek -->
44

55
TYPO3 is modular by design and organizes content on a page as blocks, called content elements. You can customize how content elements are displayed on your website by overriding the default template.
66

Documentation/guides.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
project-home="https://github.com/TYPO3-Documentation/TYPO3CMS-Guide-StepByStep"
1818
project-repository="https://github.com/TYPO3-Documentation/TYPO3CMS-Guide-StepByStep"
1919
project-issues="https://github.com/TYPO3-Documentation/TYPO3CMS-Guide-StepByStep/issues"
20-
edit-on-github-branch="main"
20+
edit-on-github-branch="contrib"
2121
edit-on-github="TYPO3-Documentation/TYPO3CMS-Guide-StepByStep"
2222
interlink-shortcode="typo3/guide-step-by-step"
2323
typo3-core-preferred="stable"

Makefile

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ help: ## Displays this list of targets with descriptions
44
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'
55

66
.PHONY: docs
7-
docs: ## Generate projects documentation (from "Documentation" directory)
7+
docs: prepare-docs render-docs restore-docs ## Prepare, generate, and clean up docs.
8+
9+
.PHONY: render-docs
10+
render-docs: ## Render docs base on Documentation directory
811
mkdir -p Documentation-GENERATED-temp
912

1013
docker run --rm --pull always -v "$(shell pwd)":/project -t ghcr.io/typo3-documentation/render-guides:latest --config=Documentation
@@ -13,4 +16,33 @@ docs: ## Generate projects documentation (from "Documentation" directory)
1316
test-docs: ## Test the documentation rendering
1417
mkdir -p Documentation-GENERATED-temp
1518

16-
docker run --rm --pull always -v "$(shell pwd)":/project -t ghcr.io/typo3-documentation/render-guides:latest --config=Documentation --no-progress --fail-on-log
19+
docker run --rm --pull always -v "$(shell pwd)":/project -t ghcr.io/typo3-documentation/render-guides:latest --config=Documentation --no-progress --fail-on-log
20+
21+
.PHONY: stage-docs
22+
stage-docs: ## Make a backup of the Documentation directory in Documentation-BACKUP-temp
23+
cp -r Documentation Documentation-BACKUP-temp
24+
25+
.PHONY: index-files
26+
index-files: ## Indexes all files and links in files.json
27+
docker run --rm -v "$(shell pwd)":/app php:8.3-cli php app/bin/index-files
28+
29+
.PHONY: expand-links
30+
expand-links: ## Expands shorthand links
31+
docker run --rm -v "$(shell pwd)":/app php:8.3-cli php app/bin/expand-links
32+
33+
.PHONY: generate-tos
34+
generate-tos: ## Generates table of contents in all Index.md files
35+
docker run --rm -v "$(shell pwd)":/app php:8.3-cli php app/bin/generate-tos
36+
37+
.PHONY: expand-tags
38+
expand-tags: ## Expands tags into Markdown
39+
docker run --rm -v "$(shell pwd)":/app php:8.3-cli php app/bin/expand-tags
40+
41+
.PHONY: prepare-docs ## Prepares files for rendering: Backing up, generating TOS, expanding tags, etc.
42+
prepare-docs: stage-docs index-files expand-links generate-tos expand-tags
43+
44+
.PHONY: restore-docs
45+
restore-docs: ## Restores the Documentation folder from Documentation-BACKUP-temp
46+
rm -rf Documentation
47+
cp -r Documentation-BACKUP-temp Documentation
48+
rm -rf Documentation-BACKUP-temp

bin/expand-links

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env php
2+
<?php
3+
const SEARCH_PATH = __DIR__ . '/../Documentation/';
4+
5+
$files = json_decode(file_get_contents(SEARCH_PATH . 'files.json'), true);
6+
7+
foreach (array_values($files) as $file) {
8+
if (
9+
$file['path'] === 'Index.md' // Ignore the project root index file
10+
|| basename($file['path']) === 'Index.md'
11+
|| !$file['exists']
12+
) {
13+
continue;
14+
}
15+
16+
$matchedFile = null;
17+
18+
foreach ($file['outgoingLinks'] as $outgoingLink) {
19+
if (str_contains($outgoingLink['unexpandedUrl'], '/')) {
20+
continue;
21+
}
22+
23+
if ($matchedFile === null) {
24+
25+
$matchingFiles = array_values(array_filter(
26+
array_keys($files),
27+
function ($entry) use ($outgoingLink) {
28+
return str_ends_with($entry, '/' . $outgoingLink['unexpandedUrl']);
29+
}
30+
));
31+
32+
if ($matchingFiles === [] || count($matchingFiles) > 1) {
33+
continue;
34+
}
35+
36+
$matchedFile = $matchingFiles[0];
37+
}
38+
39+
$replaceLinkString = '[' . $outgoingLink['text'] . ']'
40+
. '(/' . $matchedFile
41+
. ($outgoingLink['title'] ? ' "' . $outgoingLink['title'] . '"' : '')
42+
. ')';
43+
44+
file_put_contents(
45+
SEARCH_PATH . $file['path'],
46+
str_replace(
47+
$outgoingLink['match'],
48+
$replaceLinkString,
49+
file_get_contents(SEARCH_PATH . $file['path'])
50+
)
51+
);
52+
53+
unset($files[$outgoingLink['url']]);
54+
}
55+
}
56+
57+
file_put_contents(SEARCH_PATH . 'files.json', json_encode($files));

bin/expand-tags

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env php
2+
<?php
3+
const SEARCH_PATH = __DIR__ . '/../Documentation/';
4+
5+
$tagsToFiles = [];
6+
7+
foreach (json_decode(file_get_contents(SEARCH_PATH . 'files.json'), true) as $file) {
8+
if (basename($file['path']) === 'Index.md' || !$file['exists']) {
9+
continue;
10+
}
11+
12+
$content = file_get_contents(SEARCH_PATH . $file['path']);
13+
14+
if (preg_match('/<!--(.*)-->/', $content, $matches)) {
15+
$comment = $matches[0];
16+
17+
$expandedTagLine = '';
18+
19+
$typo3Versions = [];
20+
$tags = [];
21+
$authors = [];
22+
23+
foreach (preg_split('/\s+/', $matches[1], -1, PREG_SPLIT_NO_EMPTY) as $tag) {
24+
$tagValue = substr($tag, 1);
25+
26+
// Skip if the value contains non-alphanumerical characters
27+
if (preg_match('/[^A-Za-z0-9]/', $tagValue)) {
28+
continue;
29+
}
30+
31+
if (preg_match('/#TYPO3v\d\d/', $tag)) {
32+
$typo3Versions[] = $tagValue;
33+
} elseif ($tag[0] === '#') {
34+
$tags[] = $tagValue;
35+
} elseif ($tag[0] === '@') {
36+
$authors[] = $tagValue;
37+
}
38+
}
39+
40+
if ($typo3Versions !== []) {
41+
$expandedTagLine .= ' **Tested in:**';
42+
43+
foreach ($typo3Versions as $typo3Version) {
44+
$tagsToFiles[$typo3Version][] = [$file['path'], $file['title']];
45+
46+
$expandedTagLine .= ' [' . $typo3Version . '](/Tags/' . $typo3Version . '.md)';
47+
}
48+
}
49+
50+
if ($tags !== []) {
51+
$expandedTagLine .= ' **Categories:**';
52+
53+
foreach ($tags as $tag) {
54+
$tagsToFiles[$tag][] = [$file['path'], $file['title']];
55+
56+
$expandedTagLine .= ' [' . $tag . '](/Tags/' . $tag . '.md)';
57+
}
58+
}
59+
60+
if ($authors !== []) {
61+
$expandedTagLine .= ' **Author:**';
62+
63+
foreach ($authors as $author) {
64+
$expandedTagLine .= ' [@' . $author . '](https://my.typo3.org/u/' . $author . ')';
65+
}
66+
}
67+
68+
file_put_contents(SEARCH_PATH . $file['path'], str_replace($comment, $expandedTagLine, $content));
69+
}
70+
}
71+
72+
if (!file_exists(SEARCH_PATH . '/Tags')) {
73+
mkdir(SEARCH_PATH . '/Tags');
74+
}
75+
76+
foreach ($tagsToFiles as $tag => $files) {
77+
$content = '# ' . $tag . PHP_EOL . PHP_EOL;
78+
79+
foreach ($files as [$filePath, $fileTitle]) {
80+
$content .= '* [' . $fileTitle . '](/' . $filePath . ')' . PHP_EOL;
81+
}
82+
83+
file_put_contents(SEARCH_PATH . '/Tags/' . $tag . '.md', $content);
84+
}

bin/generate-tos

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env php
2+
<?php
3+
const SEARCH_PATH = __DIR__ . '/../Documentation/';
4+
5+
$files = json_decode(file_get_contents(SEARCH_PATH . 'files.json'), true);
6+
7+
foreach ($files as $file) {
8+
if (
9+
$file['path'] === 'Index.md' // Ignore the project root index file
10+
|| str_contains($file['path'], '80GuidesRegistry/')
11+
|| str_contains($file['path'], '90Contribute/')
12+
|| basename($file['path']) !== 'Index.md'
13+
|| !$file['exists']
14+
) {
15+
continue;
16+
}
17+
18+
$topics = [];
19+
$guides = [];
20+
21+
$dirname = dirname($file['path']);
22+
23+
foreach ($files as $fileToCompare) {
24+
if ($fileToCompare['path'] === $file['path']) {
25+
continue;
26+
}
27+
28+
$compareDirname = dirname($fileToCompare['path']);
29+
30+
if ($compareDirname === $dirname) {
31+
$guides[] = $fileToCompare;
32+
} elseif (
33+
str_starts_with($compareDirname, $dirname)
34+
&& !str_contains(trim(str_replace($dirname, '', $compareDirname), '/'), '/')
35+
&& basename($fileToCompare['path']) === 'Index.md'
36+
) {
37+
$topics[] = $fileToCompare;
38+
}
39+
}
40+
41+
$content = '# ' . $file['title'] . "\n\n";
42+
43+
foreach ($topics as $topic) {
44+
$content .= '* [' . $topic['title'] . '](/' . $topic['path'] . ')' . "\n";
45+
}
46+
47+
if ($guides !== []) {
48+
$content .= "\n\n" . '## Guides' . "\n\n";
49+
}
50+
51+
foreach ($guides as $guide) {
52+
if ($guide['exists']) {
53+
$content .= '* [' . $guide['title'] . '](/' . $guide['path'] . ')' . "\n";
54+
} else {
55+
$url = 'https://github.com/TYPO3-Documentation/TYPO3CMS-Guide-StepByStep/new/contrib/Documentation/'
56+
. dirname($guide['path']) . '?'
57+
. 'filename=' . urlencode(basename($guide['path']))
58+
. '&value=' . urlencode('Copy content the template from: https://raw.githubusercontent.com/TYPO3-Documentation/TYPO3CMS-Guide-StepByStep/refs/heads/contrib/Documentation/90Contribute/10Template/Index.md');
59+
60+
$content .= '* ' . $guide['title'] . ' [CREATE](' . $url . ')' . "\n";
61+
}
62+
}
63+
64+
if ($topics === [] && $guides === []) {
65+
$content .= '> [!NOTE]' . "\n";
66+
$content .= '> There are no guides here yet.' . "\n";
67+
}
68+
69+
file_put_contents(SEARCH_PATH . $file['path'], $content);
70+
}

0 commit comments

Comments
 (0)