Skip to content

Commit 3d96ddd

Browse files
committed
add workflow & skeleton generator
1 parent 2f2544e commit 3d96ddd

File tree

3 files changed

+203
-3
lines changed

3 files changed

+203
-3
lines changed

.github/actions/verify-generated-files/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ runs:
1313
ext/tokenizer/tokenizer_data_gen.php
1414
build/gen_stub.php -f --generate-optimizer-info --verify
1515
ext/phar/makestub.php
16+
.github/scripts/download-bundled/make-workflow-file.php
1617
.github/scripts/test-directory-unchanged.sh .
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
declare(strict_types=1);
5+
6+
namespace Phpsrc\Ci\DownloadBundled;
7+
8+
$bundles = [
9+
new Bundle('PCRE2', ['ext/pcre/pcre2lib']),
10+
];
11+
12+
class Bundle
13+
{
14+
/**
15+
* @param list<string> $directories
16+
*/
17+
public function __construct(
18+
public string $name,
19+
public array $directories
20+
) {}
21+
22+
public function getNameForPath(): string
23+
{
24+
return preg_replace('~\W+~', '-', strtolower($this->name));
25+
}
26+
}
27+
28+
class Generator
29+
{
30+
/**
31+
* @param list<Bundle> $bundles
32+
*/
33+
public function __construct(
34+
public array $bundles
35+
) {}
36+
37+
protected function getRepoDirectory(): string
38+
{
39+
return dirname(__DIR__, 3);
40+
}
41+
42+
protected function indentString(string $value, int $levels, bool $inclFirstLine): string
43+
{
44+
return preg_replace(
45+
'~' . ($inclFirstLine ? '^|' : '') . '(?<=\n)~',
46+
str_repeat(' ', $levels),
47+
$value
48+
);
49+
}
50+
51+
/**
52+
* @param mixed $data
53+
*/
54+
protected function encodeYml($data): string
55+
{
56+
if (is_array($data)) {
57+
$isList = array_is_list($data);
58+
$resParts = [];
59+
foreach ($data as $k => $v) {
60+
$kEncoded = $isList
61+
? '-'
62+
: $this->encodeYml($k) . ':';
63+
$vEncoded = $this->encodeYml($v);
64+
65+
$resParts[] = $kEncoded
66+
. (!$isList && is_array($v) && $v !== [] ? "\n " : ' ')
67+
. (is_array($v) ? $this->indentString($vEncoded, 1, false) : $vEncoded);
68+
}
69+
70+
return implode("\n", $resParts);
71+
}
72+
73+
if (preg_match('~^(\w+|\$\{\{[^\}]+\}\})$~', $data)) {
74+
return $data;
75+
}
76+
77+
return strpos($data, "\n") !== false
78+
? '|' . "\n" . $this->indentString($data, 1, true)
79+
: '\'' . str_replace('\'', '\'\'', $data) . '\'';
80+
}
81+
82+
public function makeWorkflowFile(): void
83+
{
84+
$content = <<<'EOD'
85+
name: Verify Bundled Files
86+
87+
on:
88+
push:
89+
paths: &paths
90+
%paths%
91+
pull_request:
92+
paths: *paths
93+
schedule:
94+
- cron: "0 1 * * *"
95+
workflow_dispatch: ~
96+
97+
permissions:
98+
contents: read
99+
100+
jobs:
101+
VERIFY_BUNDLED_FILES:
102+
name: Verify Bundled Files
103+
runs-on: ubuntu-24.04
104+
steps:
105+
- name: git checkout
106+
uses: actions/checkout@v5
107+
108+
- name: Detect changed files
109+
uses: dorny/paths-filter@v3
110+
id: changes
111+
with:
112+
base: master
113+
filters: %filters%
114+
115+
%steps%
116+
117+
EOD;
118+
119+
$paths = [
120+
'.github/scripts/download-bundled/**',
121+
];
122+
foreach ($this->bundles as $bundle) {
123+
foreach ($this->makeDornyPathsFilterFilters($bundle) as $p) {
124+
if (str_starts_with($p, '.github/scripts/download-bundled/')) {
125+
continue;
126+
}
127+
128+
$paths[] = $p;
129+
}
130+
}
131+
$content = str_replace('%paths%', $this->indentString($this->encodeYml($paths), 3, false), $content);
132+
133+
$filters = [];
134+
foreach ($this->bundles as $bundle) {
135+
$filters[$bundle->getNameForPath()] = $this->makeDornyPathsFilterFilters($bundle);
136+
}
137+
$content = str_replace('%filters%', $this->indentString($this->encodeYml($this->encodeYml($filters)), 5, false), $content);
138+
139+
$steps = [];
140+
foreach ($this->bundles as $bundle) {
141+
$steps[] = [
142+
'name' => $bundle->name,
143+
'if' => '${{ !cancelled() && (steps.changes.outputs.' . $bundle->getNameForPath() . ' == \'true\' || github.event_name == \'schedule\' || github.event_name == \'workflow_dispatch\') }}',
144+
'run' => implode("\n", [
145+
'echo "::group::Download"',
146+
'.github/scripts/download-bundled/' . $bundle->getNameForPath() . '.sh',
147+
'echo "::endgroup::"',
148+
'echo "::group::Verify files"',
149+
...array_map(static fn ($v) => '.github/scripts/test-directory-unchanged.sh ' . escapeshellarg($v), $bundle->directories),
150+
'echo "::endgroup::"',
151+
]),
152+
];
153+
}
154+
$content = str_replace('%steps%', $this->indentString($this->encodeYml($steps), 3, false), $content);
155+
156+
file_put_contents($this->getRepoDirectory() . '/.github/workflows/verify-bundled-files.yml', $content);
157+
}
158+
159+
protected function makeDornyPathsFilterFilters(Bundle $bundle): array
160+
{
161+
return [
162+
'.github/scripts/download-bundled/' . $bundle->getNameForPath() . '.*',
163+
...array_map(static fn ($v) => $v . '/**', $bundle->directories),
164+
];
165+
}
166+
167+
public function makeDownloadScriptHeaders(): void
168+
{
169+
foreach ($this->bundles as $bundle) {
170+
$this->makeDownloadScriptHeader($bundle);
171+
}
172+
}
173+
174+
protected function makeDownloadScriptHeader(Bundle $bundle): void
175+
{
176+
$scriptPath = $this->getRepoDirectory() . '/.github/scripts/download-bundled/' . $bundle->getNameForPath() . '.sh';
177+
178+
$content = !file_exists($scriptPath)
179+
? "# TODO\n"
180+
: file_get_contents($scriptPath);
181+
182+
$header = <<<'EOD'
183+
#!/bin/sh
184+
set -ex
185+
cd "$(dirname "$0")/../../.."
186+
187+
188+
EOD;
189+
if (!str_starts_with($content, $header)) {
190+
$content = $header . $content;
191+
}
192+
193+
file_put_contents($scriptPath, $content);
194+
}
195+
}
196+
197+
$generator = new Generator($bundles);
198+
$generator->makeWorkflowFile();
199+
$generator->makeDownloadScriptHeaders();

.github/workflows/verify-bundled-files.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Verify Bundled Files
33
on:
44
push:
55
paths: &paths
6-
- '.github/scripts/download-bundled/pcre2.sh'
6+
- '.github/scripts/download-bundled/**'
77
- 'ext/pcre/pcre2lib/**'
88
pull_request:
99
paths: *paths
@@ -29,7 +29,7 @@ jobs:
2929
base: master
3030
filters: |
3131
pcre2:
32-
- '.github/scripts/download-bundled/pcre2.sh'
32+
- '.github/scripts/download-bundled/pcre2.*'
3333
- 'ext/pcre/pcre2lib/**'
3434
3535
- name: PCRE2
@@ -39,5 +39,5 @@ jobs:
3939
.github/scripts/download-bundled/pcre2.sh
4040
echo "::endgroup::"
4141
echo "::group::Verify files"
42-
.github/scripts/test-directory-unchanged.sh ext/pcre/pcre2lib
42+
.github/scripts/test-directory-unchanged.sh "ext/pcre/pcre2lib"
4343
echo "::endgroup::"

0 commit comments

Comments
 (0)