@@ -105,115 +105,116 @@ jobs:
105105 SPRING_RELEASE : ${{ inputs.spring-release }}
106106 PROJECTS_FILTER : ${{ inputs.projects }}
107107 run : |
108- python3 - << 'PYEOF'
109- import json, os, re, subprocess, sys
108+ node - << 'JSEOF'
109+ const { execFileSync } = require('child_process');
110+ const fs = require('fs');
110111
111- projects_json = subprocess.run(
112- ['gh', 'api', 'repos/spring-cloud/spring-cloud-github-actions/contents/config/projects.json',
113- '-X', 'GET', '-f', 'ref=main', '--jq', '.content'],
114- capture_output=True, text=True, check=True).stdout.strip()
115- decode = subprocess.run(['base64', '-d'], input=projects_json,
116- capture_output=True, text=True, check=True)
117- projects = json.loads(decode.stdout)
112+ // Fetch projects.json from the main branch
113+ const b64 = execFileSync('gh', [
114+ 'api', 'repos/spring-cloud/spring-cloud-github-actions/contents/config/projects.json',
115+ '-X', 'GET', '-f', 'ref=main', '--jq', '.content'
116+ ], { encoding: 'utf8' }).trim();
117+ const projects = JSON.parse(Buffer.from(b64, 'base64').toString('utf8'));
118118
119- defaults = projects.get(' defaults', {})
119+ const defaults = projects.defaults || {};
120120
121- projects_filter_raw = os.environ.get('PROJECTS_FILTER', '').strip()
122- projects_filter = {p.strip() for p in projects_filter_raw.split(',') if p.strip()} if projects_filter_raw else set()
121+ const projectsFilterRaw = (process.env.PROJECTS_FILTER || '').trim();
122+ const projectsFilter = projectsFilterRaw
123+ ? new Set(projectsFilterRaw.split(',').map(p => p.trim()).filter(Boolean))
124+ : new Set();
123125
124- def get_jdks(project_key, type_key, branch):
125- proj = projects.get(project_key, {})
126- type_cfg = proj.get(type_key, {})
127- jdkmap = type_cfg.get('jdkVersions', {})
128- if branch in jdkmap:
129- return jdkmap[branch]
130- if 'default' in jdkmap:
131- return jdkmap['default']
132- def_jdkmap = defaults.get(type_key, {}).get('jdkVersions', {})
133- if branch in def_jdkmap:
134- return def_jdkmap[branch]
135- return def_jdkmap.get('default', ['17', '21', '25'])
126+ function getJdks(projectKey, typeKey, branch) {
127+ const typeCfg = (projects[projectKey] || {})[typeKey] || {};
128+ const jdkmap = typeCfg.jdkVersions || {};
129+ if (jdkmap[branch]) return jdkmap[branch];
130+ if (jdkmap['default']) return jdkmap['default'];
131+ const defJdkmap = (defaults[typeKey] || {}).jdkVersions || {};
132+ if (defJdkmap[branch]) return defJdkmap[branch];
133+ return defJdkmap['default'] || ['17', '21', '25'];
134+ }
136135
137- def primary_jdk(jdks):
138- return '8' if '8' in jdks else '17'
136+ function primaryJdk(jdks) {
137+ return jdks.includes('8') ? '8' : '17';
138+ }
139139
140- entries = []
141- seen = set()
140+ const entries = [];
141+ const seen = new Set();
142142
143- def add_entry(repo, branch, type_key, project_key, jdk_lookup_branch=None):
144- key = (repo, branch)
145- if key in seen:
146- return
147- seen.add(key)
148- jdks = get_jdks(project_key, type_key, jdk_lookup_branch or branch)
149- entries.append({
150- 'repo': repo,
151- 'branch': branch,
152- 'primary_jdk': primary_jdk(jdks),
153- })
143+ function addEntry(repo, branch, typeKey, projectKey, jdkLookupBranch) {
144+ const key = `${repo}@${branch}`;
145+ if (seen.has(key)) return;
146+ seen.add(key);
147+ const jdks = getJdks(projectKey, typeKey, jdkLookupBranch || branch);
148+ entries.push({ repo, branch, primary_jdk: primaryJdk(jdks) });
149+ }
154150
155- for project_key, config in projects.items():
156- if project_key == 'defaults':
157- continue
158- if projects_filter and project_key not in projects_filter:
159- continue
160- for type_key in ('oss', 'commercial'):
161- type_cfg = config.get(type_key)
162- if not type_cfg:
163- continue
164- repo = (f'spring-cloud/{project_key}-commercial'
165- if type_key == 'commercial'
166- else f'spring-cloud/{project_key}')
167- for branch in type_cfg.get('branches', {}).get('scheduled', []):
168- add_entry(repo, branch, type_key, project_key)
151+ // Build entries from projects.json
152+ for (const [projectKey, config] of Object.entries(projects)) {
153+ if (projectKey === 'defaults') continue;
154+ if (projectsFilter.size > 0 && !projectsFilter.has(projectKey)) continue;
155+ for (const typeKey of ['oss', 'commercial']) {
156+ const typeCfg = config[typeKey];
157+ if (!typeCfg) continue;
158+ const repo = typeKey === 'commercial'
159+ ? `spring-cloud/${projectKey}-commercial`
160+ : `spring-cloud/${projectKey}`;
161+ for (const branch of (typeCfg.branches || {}).scheduled || []) {
162+ addEntry(repo, branch, typeKey, projectKey);
163+ }
164+ }
165+ }
169166
170- spring_release = os.environ.get('SPRING_RELEASE', '').strip()
171- if spring_release:
172- result = subprocess.run(
173- ['gh', 'api', 'repos/spring-io/release-train/contents/README.adoc',
174- '-X', 'GET', '-f', f'ref={spring_release}', '--jq', '.content'],
175- capture_output=True, text=True)
176- if result.returncode != 0:
177- print(f'Warning: could not fetch README.adoc for spring release {spring_release}: '
178- f'{result.stderr.strip()}', file=sys.stderr)
179- else:
180- decode = subprocess.run(['base64', '-d'],
181- input=result.stdout.strip(),
182- capture_output=True, text=True)
183- current_repo = None
184- current_project_key = None
185- for line in decode.stdout.splitlines():
186- if re.match(r'^== ', line):
187- if 'Spring Cloud' not in line:
188- current_repo = None
189- current_project_key = None
190- continue
191- m = re.search(
192- r'\*\*Releasing from:\*\* https://github\.com/spring-cloud/([^\[]+)\[',
193- line)
194- if m:
195- repo_name = m.group(1).strip().rstrip('/')
196- current_repo = f'spring-cloud/{repo_name}'
197- current_project_key = repo_name.replace('-commercial', '')
198- continue
199- if current_repo:
200- vm = re.search(r'=== .+ (\d+\.\d+(?:\.\d+(?:\.\d+)?)?)\s*$', line)
201- if vm:
202- version = vm.group(1)
203- parts = version.split('.')
204- parent_branch = '.'.join(parts[:-1]) + '.x'
205- if projects_filter and current_project_key not in projects_filter:
206- continue
207- add_entry(current_repo, f'release/{version}',
208- 'commercial', current_project_key,
209- jdk_lookup_branch=parent_branch)
167+ // Optionally add release/[version] branches from the Spring release train README
168+ const springRelease = (process.env.SPRING_RELEASE || '').trim();
169+ if (springRelease) {
170+ let readmeB64;
171+ try {
172+ readmeB64 = execFileSync('gh', [
173+ 'api', 'repos/spring-io/release-train/contents/README.adoc',
174+ '-X', 'GET', '-f', `ref=${springRelease}`, '--jq', '.content'
175+ ], { encoding: 'utf8' }).trim();
176+ } catch (err) {
177+ console.error(`Warning: could not fetch README.adoc for spring release ${springRelease}: ${err.message}`);
178+ }
179+ if (readmeB64) {
180+ const content = Buffer.from(readmeB64, 'base64').toString('utf8');
181+ let currentRepo = null;
182+ let currentProjectKey = null;
183+ for (const line of content.split('\n')) {
184+ if (/^== /.test(line)) {
185+ if (!line.includes('Spring Cloud')) {
186+ currentRepo = null;
187+ currentProjectKey = null;
188+ }
189+ continue;
190+ }
191+ const releasingMatch = line.match(
192+ /\*\*Releasing from:\*\* https:\/\/github\.com\/spring-cloud\/([^\[]+)\[/
193+ );
194+ if (releasingMatch) {
195+ const repoName = releasingMatch[1].trim().replace(/\/$/, '');
196+ currentRepo = `spring-cloud/${repoName}`;
197+ currentProjectKey = repoName.replace(/-commercial$/, '');
198+ continue;
199+ }
200+ if (currentRepo) {
201+ const versionMatch = line.match(/=== .+ (\d+\.\d+(?:\.\d+(?:\.\d+)?)?)\s*$/);
202+ if (versionMatch) {
203+ const version = versionMatch[1];
204+ const parts = version.split('.');
205+ const parentBranch = parts.slice(0, -1).join('.') + '.x';
206+ if (projectsFilter.size > 0 && !projectsFilter.has(currentProjectKey)) continue;
207+ addEntry(currentRepo, `release/${version}`, 'commercial', currentProjectKey, parentBranch);
208+ }
209+ }
210+ }
211+ }
212+ }
210213
211- matrix = {'include': entries}
212- matrix_json = json.dumps(matrix, separators=(',', ':'))
213- with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
214- f.write(f'matrix={matrix_json}\n')
215- print(f'Matrix built: {len(entries)} entries')
216- PYEOF
214+ const matrix = { include: entries };
215+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix=${JSON.stringify(matrix)}\n`);
216+ console.log(`Matrix built: ${entries.length} entries`);
217+ JSEOF
217218
218219 generate :
219220 name : " Generate — ${{ matrix.repo }}@${{ matrix.branch }}"
0 commit comments