Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,8 @@ jobs:
- run: node "$DOCS_TOOLING_DIRECTORY/scripts/check-docs-examples.mjs"
- run: npm --prefix "$DOCS_TOOLING_DIRECTORY" run test:docs-portal-links
- run: npm --prefix "$DOCS_TOOLING_DIRECTORY" run test:docs-identity-status
- name: Test selected presentation asset validation
run: python "$DOCS_TOOLING_DIRECTORY/scripts/check-docs-analytics.test.py"
- name: Verify Composer trust before requests
uses: durable-workflow/.github/.github/actions/verify-composer-trust@75587fc33ff40c34f32ef777293dad56bb6f48c7 # clean-trust
- run: bash "$DOCS_TOOLING_DIRECTORY/scripts/build-docs.sh"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ jobs:
- run: node "$DOCS_TOOLING_DIRECTORY/scripts/check-docs-examples.mjs"
- run: npm --prefix "$DOCS_TOOLING_DIRECTORY" run test:docs-portal-links
- run: npm --prefix "$DOCS_TOOLING_DIRECTORY" run test:docs-identity-status
- name: Test selected presentation asset validation
run: python "$DOCS_TOOLING_DIRECTORY/scripts/check-docs-analytics.test.py"
- name: Check repository-owned documentation links offline
uses: docker://lycheeverse/lychee@sha256:e2d19e57cf6ab037026f20b8e449a1f30d9d7f81eef4194763aab2eab20bd28d # 0.24.2
with:
Expand Down
5 changes: 3 additions & 2 deletions scripts/check-docs-analytics.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

$siteDirectory = rtrim($argv[1] ?? __DIR__.'/../build/site', '/\\');
$sourceDirectory = getenv('DOCS_SOURCE_DIRECTORY') ?: __DIR__.'/..';
$templateDirectory = getenv('DOCS_TEMPLATE_DIRECTORY') ?: $sourceDirectory.'/.phpdoc/template';
$runtimeSource = file_get_contents($sourceDirectory.'/.phpdoc/template/analytics/analytics.js');
if ($runtimeSource !== false && getenv('CLOUDFLARE_WEB_ANALYTICS_TOKEN')) {
$runtimeSource = str_replace('__CLOUDFLARE_WEB_ANALYTICS_TOKEN__', getenv('CLOUDFLARE_WEB_ANALYTICS_TOKEN'), $runtimeSource);
}
$runtime = file_get_contents($siteDirectory.'/analytics/analytics.js');
$referenceStyles = file_get_contents($sourceDirectory.'/.phpdoc/template/assets/api-reference.css');
$referenceRuntime = file_get_contents($sourceDirectory.'/.phpdoc/template/assets/api-reference.js');
$referenceStyles = file_get_contents($templateDirectory.'/assets/api-reference.css');
$referenceRuntime = file_get_contents($templateDirectory.'/assets/api-reference.js');

if ($runtimeSource === false || $runtime === false || $runtime !== $runtimeSource) {
throw new RuntimeException('Rendered analytics runtime is missing or stale.');
Expand Down
92 changes: 92 additions & 0 deletions scripts/check-docs-analytics.test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""Rendered assets follow the selected presentation; analytics stays SDK-owned."""

import os
from pathlib import Path
import subprocess
import tempfile
import unittest


ROOT = Path(__file__).resolve().parent.parent
CHECKER = ROOT / 'scripts/check-docs-analytics.php'
ANALYTICS = ROOT / '.phpdoc/template/analytics/analytics.js'
STYLES = '.dw-cloud-promotion__eyebrow { letter-spacing: 0; }'
PROMOTION = ('data-promotion-source="sdk-php-reference" '
'href="https://cloud.durable-workflow.com/early-access#source=sdk-php-reference"')


class RenderedAssetsTest(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
root = Path(self.temporary.name)
self.source = root / 'sdk'
self.template = self.source / '.phpdoc/template'
self.presentation = root / 'presentation/template'
self.site = root / 'site'
self.write(self.template / 'analytics/analytics.js', ANALYTICS.read_text())
self.write(self.site / 'analytics/analytics.js', ANALYTICS.read_text())
self.write(self.template / 'assets/api-reference.css', STYLES + '/* SDK */')
self.write(self.template / 'assets/api-reference.js', '// SDK runtime')
self.write(self.presentation / 'assets/api-reference.css', STYLES + '/* presentation */')
self.write(self.presentation / 'assets/api-reference.js', '// presentation runtime')
for name in ['index.html', 'api/index.html', 'api/classes/Client.html']:
assets = ('href="/assets/api-reference.css" '
'type="module" src="/assets/api-reference.js"') if name.startswith('api/') else 'href="/assets/portal.css"'
self.write(self.site / name, f'<html>{assets} {PROMOTION} type="module" src="/analytics/analytics.js"</html>')
self.environment = os.environ | {'DOCS_SOURCE_DIRECTORY': str(self.source)}
for key in ['DOCS_TEMPLATE_DIRECTORY', 'CLOUDFLARE_WEB_ANALYTICS_TOKEN']:
self.environment.pop(key, None)
self.render(self.template)

@staticmethod
def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text)

def render(self, template):
for name in ['api-reference.css', 'api-reference.js']:
self.write(self.site / 'assets' / name, (template / 'assets' / name).read_text())

def check(self, expected):
result = subprocess.run(['php', str(CHECKER), str(self.site)], env=self.environment,
capture_output=True, text=True, timeout=30)
self.assertEqual(result.returncode == 0, expected, result.stdout + result.stderr)
return result

def testUnchangedSdkTemplateRemainsTheDefault(self):
self.check(True)

def testDifferentPresentationAssetsRequireTheirExactSelectedTemplate(self):
self.render(self.presentation)
refused = self.check(False)
self.assertIn('styles are missing or stale', refused.stdout + refused.stderr)
self.environment['DOCS_TEMPLATE_DIRECTORY'] = str(self.presentation)
self.check(True)

def testChangedRenderedStylesOrRuntimeStillRefuse(self):
self.render(self.presentation)
self.environment['DOCS_TEMPLATE_DIRECTORY'] = str(self.presentation)
for name in ['api-reference.css', 'api-reference.js']:
with self.subTest(name=name):
self.render(self.presentation)
self.write(self.site / 'assets' / name, 'stale')
self.check(False)

def testMissingSelectedTemplateDoesNotFallBackToSdkAssets(self):
self.environment['DOCS_TEMPLATE_DIRECTORY'] = str(self.presentation / 'absent')
self.check(False)

def testAnalyticsStillUsesTheSelectedSdkSource(self):
self.render(self.presentation)
self.environment['DOCS_TEMPLATE_DIRECTORY'] = str(self.presentation)
self.write(self.presentation / 'analytics/analytics.js', 'unselected analytics')
self.check(True)
self.write(self.site / 'analytics/analytics.js', 'unselected analytics')
refused = self.check(False)
self.assertIn('analytics runtime is missing or stale', refused.stdout + refused.stderr)


if __name__ == '__main__':
unittest.main()
Loading