|
3 | 3 | * SPDX-License-Identifier: Apache-2.0 |
4 | 4 | */ |
5 | 5 |
|
6 | | -import { CfnLspName, CfnLspServerEnvType } from './lspServerConfig' |
7 | | -import { |
8 | | - addWindows, |
9 | | - CfnManifest, |
10 | | - CfnTarget, |
11 | | - CfnLspVersion, |
12 | | - dedupeAndGetLatestVersions, |
13 | | - extractPlatformAndArch, |
14 | | - useOldLinuxVersion, |
15 | | - mapLegacyLinux, |
16 | | -} from './utils' |
| 6 | +import { CfnLspServerEnvType } from './lspServerConfig' |
| 7 | +import { CfnManifest, CfnLspVersion, useOldLinuxVersion, mapLegacyLinux } from './utils' |
17 | 8 | import { getLogger } from '../../../shared/logger/logger' |
18 | | -import { ToolkitError } from '../../../shared/errors' |
| 9 | + |
| 10 | +const ManifestUrl = |
| 11 | + 'https://raw.githubusercontent.com/aws-cloudformation/cloudformation-languageserver/refs/heads/main/assets/release-manifest.json' |
19 | 12 |
|
20 | 13 | export class GitHubManifestAdapter { |
21 | | - constructor( |
22 | | - private readonly repoOwner: string, |
23 | | - private readonly repoName: string, |
24 | | - readonly environment: CfnLspServerEnvType |
25 | | - ) {} |
| 14 | + private lastRawManifest?: string |
26 | 15 |
|
27 | | - async getManifest(): Promise<CfnManifest> { |
28 | | - let manifest: CfnManifest |
29 | | - try { |
30 | | - manifest = await this.getManifestJson() |
31 | | - } catch (err) { |
32 | | - getLogger('awsCfnLsp').error(ToolkitError.chain(err, 'Failed to get CloudFormation manifest')) |
33 | | - manifest = await this.getFromReleases() |
34 | | - } |
| 16 | + constructor(readonly environment: CfnLspServerEnvType) {} |
35 | 17 |
|
36 | | - getLogger('awsCfnLsp').info( |
37 | | - 'Candidate versions: %s', |
38 | | - manifest.versions |
39 | | - .map( |
40 | | - (v) => |
41 | | - `${v.serverVersion}[${v.targets |
42 | | - .sort() |
43 | | - .map((t) => `${t.platform}-${t.arch}-${t.nodejs}`) |
44 | | - .join(',')}]` |
45 | | - ) |
46 | | - .join(', ') |
47 | | - ) |
48 | | - |
49 | | - if (process.platform !== 'linux') { |
50 | | - return manifest |
51 | | - } |
| 18 | + getLastRawManifest(): string | undefined { |
| 19 | + return this.lastRawManifest |
| 20 | + } |
52 | 21 |
|
53 | | - const useFallbackLinux = useOldLinuxVersion() |
54 | | - if (!useFallbackLinux) { |
55 | | - return manifest |
| 22 | + async getManifest(): Promise<CfnManifest> { |
| 23 | + const response = await fetch(ManifestUrl) |
| 24 | + if (!response.ok) { |
| 25 | + throw new Error(`Manifest fetch failed: ${response.status}`) |
56 | 26 | } |
57 | 27 |
|
58 | | - getLogger('awsCfnLsp').info('In a legacy or sandbox Linux environment') |
59 | | - manifest.versions = mapLegacyLinux(manifest.versions) |
| 28 | + const rawText = await response.text() |
| 29 | + this.lastRawManifest = rawText |
| 30 | + const json = JSON.parse(rawText) as Record<string, unknown> |
60 | 31 |
|
61 | | - getLogger('awsCfnLsp').info( |
62 | | - 'Remapped candidate versions: %s', |
63 | | - manifest.versions |
64 | | - .map( |
65 | | - (v) => |
66 | | - `${v.serverVersion}[${v.targets |
67 | | - .sort() |
68 | | - .map((t) => `${t.platform}-${t.arch}-${t.nodejs}`) |
69 | | - .join(',')}]` |
70 | | - ) |
71 | | - .join(', ') |
72 | | - ) |
73 | | - return manifest |
74 | | - } |
| 32 | + const versions = json[this.environment] as CfnLspVersion[] | undefined |
| 33 | + const manifest: CfnManifest = { |
| 34 | + manifestSchemaVersion: json.manifestSchemaVersion as string, |
| 35 | + artifactId: json.artifactId as string, |
| 36 | + artifactDescription: json.artifactDescription as string, |
| 37 | + isManifestDeprecated: json.isManifestDeprecated as boolean, |
| 38 | + versions: versions ?? [], |
| 39 | + } |
75 | 40 |
|
76 | | - private async getFromReleases(): Promise<CfnManifest> { |
77 | | - const releases = await this.fetchGitHubReleases() |
78 | | - const envReleases = this.filterByEnvironment(releases) |
79 | | - const sortedReleases = envReleases.sort((a, b) => { |
80 | | - return b.tag_name.localeCompare(a.tag_name) |
81 | | - }) |
82 | | - const versions = dedupeAndGetLatestVersions(sortedReleases.map((release) => this.convertRelease(release))) |
83 | 41 | getLogger('awsCfnLsp').info( |
84 | 42 | 'Candidate versions: %s', |
85 | | - versions |
| 43 | + manifest.versions |
86 | 44 | .map((v) => `${v.serverVersion}[${v.targets.map((t) => `${t.platform}-${t.arch}`).join(',')}]`) |
87 | 45 | .join(', ') |
88 | 46 | ) |
89 | | - return { |
90 | | - manifestSchemaVersion: '1.0', |
91 | | - artifactId: CfnLspName, |
92 | | - artifactDescription: 'GitHub CloudFormation Language Server', |
93 | | - isManifestDeprecated: false, |
94 | | - versions: versions, |
95 | | - } |
96 | | - } |
97 | | - |
98 | | - private filterByEnvironment(releases: GitHubRelease[]): GitHubRelease[] { |
99 | | - return releases.filter((release) => { |
100 | | - const tag = release.tag_name |
101 | | - if (this.environment === 'alpha') { |
102 | | - return release.prerelease && tag.endsWith('-alpha') |
103 | | - } else if (this.environment === 'beta') { |
104 | | - return release.prerelease && tag.endsWith('-beta') |
105 | | - } else { |
106 | | - return !release.prerelease |
107 | | - } |
108 | | - }) |
109 | | - } |
110 | | - |
111 | | - private async fetchGitHubReleases(): Promise<GitHubRelease[]> { |
112 | | - const response = await fetch(`https://api.github.com/repos/${this.repoOwner}/${this.repoName}/releases`) |
113 | | - if (!response.ok) { |
114 | | - throw new Error(`GitHub API error: ${response.status}`) |
115 | | - } |
116 | | - return response.json() |
117 | | - } |
118 | | - |
119 | | - private convertRelease(release: GitHubRelease): CfnLspVersion { |
120 | | - return { |
121 | | - serverVersion: release.tag_name, |
122 | | - isDelisted: false, |
123 | | - targets: addWindows(this.extractTargets(release.assets)), |
124 | | - } |
125 | | - } |
126 | | - |
127 | | - private extractTargets(assets: GitHubAsset[]): CfnTarget[] { |
128 | | - return assets.map((asset) => { |
129 | | - const { arch, platform, nodejs } = extractPlatformAndArch(asset.name) |
130 | | - |
131 | | - return { |
132 | | - platform, |
133 | | - arch, |
134 | | - nodejs, |
135 | | - contents: [ |
136 | | - { |
137 | | - filename: asset.name, |
138 | | - url: asset.browser_download_url, |
139 | | - hashes: [], |
140 | | - bytes: asset.size, |
141 | | - }, |
142 | | - ], |
143 | | - } |
144 | | - }) |
145 | | - } |
146 | 47 |
|
147 | | - private async getManifestJson(): Promise<CfnManifest> { |
148 | | - const response = await fetch( |
149 | | - `https://raw.githubusercontent.com/${this.repoOwner}/${this.repoName}/refs/heads/main/assets/release-manifest.json` |
150 | | - ) |
151 | | - if (!response.ok) { |
152 | | - throw new Error(`GitHub API error: ${response.status}`) |
| 48 | + if (process.platform === 'linux' && useOldLinuxVersion()) { |
| 49 | + getLogger('awsCfnLsp').info('In a legacy or sandbox Linux environment') |
| 50 | + manifest.versions = mapLegacyLinux(manifest.versions) |
153 | 51 | } |
154 | 52 |
|
155 | | - const json = (await response.json()) as Record<string, unknown> |
156 | | - |
157 | | - return { |
158 | | - manifestSchemaVersion: json.manifestSchemaVersion as string, |
159 | | - artifactId: json.artifactId as string, |
160 | | - artifactDescription: json.artifactDescription as string, |
161 | | - isManifestDeprecated: json.isManifestDeprecated as boolean, |
162 | | - versions: json[this.environment] as CfnLspVersion[], |
163 | | - } |
| 53 | + return manifest |
164 | 54 | } |
165 | 55 | } |
166 | | - |
167 | | -/* eslint-disable @typescript-eslint/naming-convention */ |
168 | | -interface GitHubAsset { |
169 | | - url: string |
170 | | - browser_download_url: string |
171 | | - id: number |
172 | | - node_id: string |
173 | | - name: string |
174 | | - label: string | null |
175 | | - state: string |
176 | | - content_type: string |
177 | | - size: number |
178 | | - download_count: number |
179 | | - created_at: string |
180 | | - updated_at: string |
181 | | -} |
182 | | - |
183 | | -interface GitHubRelease { |
184 | | - url: string |
185 | | - html_url: string |
186 | | - assets_url: string |
187 | | - upload_url: string |
188 | | - tarball_url: string | null |
189 | | - zipball_url: string | null |
190 | | - id: number |
191 | | - node_id: string |
192 | | - tag_name: string |
193 | | - target_commitish: string |
194 | | - name: string | null |
195 | | - body: string | null |
196 | | - draft: boolean |
197 | | - prerelease: boolean |
198 | | - created_at: string // ISO 8601 date string |
199 | | - published_at: string | null // ISO 8601 date string |
200 | | - assets: GitHubAsset[] |
201 | | -} |
0 commit comments