@embrace-ai/infra-api-schema-sync 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/src/dispatch-update.d.ts +34 -0
- package/dist/src/dispatch-update.d.ts.map +1 -0
- package/dist/src/dispatch-update.js +224 -0
- package/dist/src/dispatch-update.js.map +1 -0
- package/dist/src/fetch-schema.d.ts +6 -0
- package/dist/src/fetch-schema.d.ts.map +1 -0
- package/dist/src/fetch-schema.js +43 -0
- package/dist/src/fetch-schema.js.map +1 -0
- package/dist/src/generate-schema-url.d.ts +8 -0
- package/dist/src/generate-schema-url.d.ts.map +1 -0
- package/dist/src/generate-schema-url.js +108 -0
- package/dist/src/generate-schema-url.js.map +1 -0
- package/dist/src/generate-summary.d.ts +4 -0
- package/dist/src/generate-summary.d.ts.map +1 -0
- package/dist/src/generate-summary.js +47 -0
- package/dist/src/generate-summary.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +62 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/validate-schema.d.ts +7 -0
- package/dist/src/validate-schema.d.ts.map +1 -0
- package/dist/src/validate-schema.js +115 -0
- package/dist/src/validate-schema.js.map +1 -0
- package/dist/vitest.config.js +3 -5
- package/dist/vitest.config.js.map +1 -1
- package/package.json +3 -2
- package/src/generate-schema-url.js +22 -8
- package/templates/workflows/emit-schema-update.yml +13 -14
- package/templates/workflows/graphql-schema-validate.yml +11 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.2](https://github.com/Embrace-AI/infra-api-schema-sync/compare/v1.0.1...v1.0.2) (2025-10-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **cli:** use process.stderr for logs, and output logs to file ([#13](https://github.com/Embrace-AI/infra-api-schema-sync/issues/13)) ([84b30d0](https://github.com/Embrace-AI/infra-api-schema-sync/commit/84b30d05cc922912edf34c3c1f3e50f5cbc65644))
|
|
9
|
+
|
|
10
|
+
## [1.0.1](https://github.com/Embrace-AI/infra-api-schema-sync/compare/v1.0.0...v1.0.1) (2025-06-19)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **workflows:** use pnpm exec in workflows, use correct build path in package.json for cli tool ([#8](https://github.com/Embrace-AI/infra-api-schema-sync/issues/8)) ([5b8daf3](https://github.com/Embrace-AI/infra-api-schema-sync/commit/5b8daf305dc8c868cf1766c1b4b4b5d86503b282))
|
|
16
|
+
|
|
3
17
|
## 1.0.0 (2025-06-19)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function dispatchUpdate(options: {
|
|
2
|
+
schemaUrl: string;
|
|
3
|
+
sourceRepo: string;
|
|
4
|
+
commit: string;
|
|
5
|
+
branch: string;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
token: string;
|
|
8
|
+
orgName: string;
|
|
9
|
+
repoFilter: string;
|
|
10
|
+
dryRun: boolean;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
success: number;
|
|
13
|
+
errors: number;
|
|
14
|
+
total: number;
|
|
15
|
+
dryRun?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
success: number;
|
|
18
|
+
errors: number;
|
|
19
|
+
total: number;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
export function dispatchUpdateCommand(opts: any): Promise<{
|
|
23
|
+
success: number;
|
|
24
|
+
errors: number;
|
|
25
|
+
total: number;
|
|
26
|
+
dryRun?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
success: number;
|
|
29
|
+
errors: number;
|
|
30
|
+
total: number;
|
|
31
|
+
dryRun: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
export default dispatchUpdateCommand;
|
|
34
|
+
//# sourceMappingURL=dispatch-update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-update.d.ts","sourceRoot":"","sources":["../../src/dispatch-update.js"],"names":[],"mappings":"AAeO,wCAVJ;IAAwB,SAAS,EAAzB,MAAM;IACU,UAAU,EAA1B,MAAM;IACU,MAAM,EAAtB,MAAM;IACU,MAAM,EAAtB,MAAM;IACU,SAAS,EAAzB,MAAM;IACU,KAAK,EAArB,MAAM;IACU,OAAO,EAAvB,MAAM;IACU,UAAU,EAA1B,MAAM;IACW,MAAM,EAAvB,OAAO;CACjB;;;;;;;;;;GA4LA;AA2DM;;;;;;;;;;GAyDN"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
export const dispatchUpdate = async (options) => {
|
|
3
|
+
try {
|
|
4
|
+
const { schemaUrl, sourceRepo, commit, branch, timestamp, token, orgName, repoFilter = ".*", dryRun = false, } = options;
|
|
5
|
+
console.log("📡 Starting schema update dispatch...");
|
|
6
|
+
console.log(`🌐 Schema URL: ${schemaUrl}`);
|
|
7
|
+
console.log(`📁 Source Repository: ${sourceRepo}`);
|
|
8
|
+
console.log(`🔍 Organization: ${orgName}`);
|
|
9
|
+
console.log(`🎯 Repository Filter: ${repoFilter}`);
|
|
10
|
+
if (dryRun) {
|
|
11
|
+
console.log("DRY RUN MODE - No actual dispatches will be sent");
|
|
12
|
+
}
|
|
13
|
+
const fetchAllRepos = async () => {
|
|
14
|
+
let page = 1;
|
|
15
|
+
const perPage = 100;
|
|
16
|
+
let allRepos = "";
|
|
17
|
+
while (true) {
|
|
18
|
+
console.log(`Fetching repos page ${page}...`);
|
|
19
|
+
const response = await fetch(`https://api.github.com/orgs/${orgName}/repos?page=${page}&per_page=${perPage}&type=all`, {
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${token}`,
|
|
22
|
+
Accept: "application/vnd.github.v3+json",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const errorData = await response.json();
|
|
27
|
+
throw new Error(`GitHub API error: ${errorData.message || response.statusText}`);
|
|
28
|
+
}
|
|
29
|
+
const repos = await response.json();
|
|
30
|
+
if (!repos || repos.length === 0) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
const repoNames = repos.map((repo) => repo.full_name).join("\n");
|
|
34
|
+
allRepos += `${repoNames}\n`;
|
|
35
|
+
if (repos.length < perPage) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
page++;
|
|
39
|
+
}
|
|
40
|
+
return allRepos;
|
|
41
|
+
};
|
|
42
|
+
console.log("🔍 Fetching all organization repositories...");
|
|
43
|
+
let allRepos;
|
|
44
|
+
if (dryRun && (token === "fake-token" || token.startsWith("fake"))) {
|
|
45
|
+
console.log("DRY RUN: Using simulated repositories");
|
|
46
|
+
allRepos = `${orgName}/repo1\n${orgName}/repo2\n${orgName}/frontend\n${sourceRepo}\n`;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
allRepos = await fetchAllRepos();
|
|
50
|
+
}
|
|
51
|
+
let filteredRepos;
|
|
52
|
+
if (repoFilter !== ".*") {
|
|
53
|
+
console.log(`🔍 Filtering repositories with pattern: ${repoFilter}`);
|
|
54
|
+
const repoList = allRepos.split("\n").filter((repo) => repo.trim());
|
|
55
|
+
const regex = new RegExp(repoFilter);
|
|
56
|
+
filteredRepos = repoList.filter((repo) => regex.test(repo)).join("\n");
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
filteredRepos = allRepos;
|
|
60
|
+
}
|
|
61
|
+
const targetRepos = filteredRepos
|
|
62
|
+
.split("\n")
|
|
63
|
+
.filter((repo) => repo.trim() && repo !== sourceRepo)
|
|
64
|
+
.filter((repo) => repo.length > 0);
|
|
65
|
+
if (targetRepos.length === 0) {
|
|
66
|
+
console.log("⚠️ No target repositories found to notify");
|
|
67
|
+
return { success: 0, errors: 0, total: 0 };
|
|
68
|
+
}
|
|
69
|
+
console.log(`Found ${targetRepos.length} repositories to notify:`);
|
|
70
|
+
targetRepos.forEach((repo) => console.log(` - ${repo}`));
|
|
71
|
+
console.log("");
|
|
72
|
+
if (dryRun) {
|
|
73
|
+
console.log("DRY RUN: Would dispatch to the above repositories");
|
|
74
|
+
return {
|
|
75
|
+
success: targetRepos.length,
|
|
76
|
+
errors: 0,
|
|
77
|
+
total: targetRepos.length,
|
|
78
|
+
dryRun: true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
let successCount = 0;
|
|
82
|
+
let errorCount = 0;
|
|
83
|
+
for (const repo of targetRepos) {
|
|
84
|
+
if (repo.trim()) {
|
|
85
|
+
console.log(`📡 Dispatching to repository: ${repo}`);
|
|
86
|
+
try {
|
|
87
|
+
const dispatchResponse = await fetch(`https://api.github.com/repos/${repo}/dispatches`, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: {
|
|
90
|
+
Authorization: `Bearer ${token}`,
|
|
91
|
+
Accept: "application/vnd.github.v3+json",
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify({
|
|
95
|
+
event_type: "graphql-schema-updated",
|
|
96
|
+
client_payload: {
|
|
97
|
+
schemaUrl,
|
|
98
|
+
sourceRepo,
|
|
99
|
+
commit,
|
|
100
|
+
branch,
|
|
101
|
+
timestamp,
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
if (dispatchResponse.status === 204) {
|
|
106
|
+
console.log(" ✅ Success");
|
|
107
|
+
successCount++;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.log(` ❌ Failed (HTTP ${dispatchResponse.status})`);
|
|
111
|
+
errorCount++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
console.log(` ❌ Failed: ${error.message}`);
|
|
116
|
+
errorCount++;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
console.log("");
|
|
121
|
+
console.log("📊 Dispatch Summary:");
|
|
122
|
+
console.log(` ✅ Successful: ${successCount}`);
|
|
123
|
+
console.log(` ❌ Failed: ${errorCount}`);
|
|
124
|
+
console.log(` 📋 Total: ${successCount + errorCount}`);
|
|
125
|
+
if (errorCount > 0) {
|
|
126
|
+
console.log("⚠️ Some dispatches failed. Check repository permissions and workflow file presence.");
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
success: successCount,
|
|
130
|
+
errors: errorCount,
|
|
131
|
+
total: successCount + errorCount,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
console.error(`❌ Failed to dispatch schema updates: ${error.message}`);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const detectValues = () => {
|
|
140
|
+
const sourceRepo = process.env.GITHUB_REPOSITORY || detectRepositoryFromGit();
|
|
141
|
+
const commit = process.env.GITHUB_SHA || detectCommitFromGit();
|
|
142
|
+
const branch = process.env.GITHUB_REF_NAME || detectBranchFromGit();
|
|
143
|
+
const orgName = process.env.GITHUB_REPOSITORY_OWNER || sourceRepo?.split("/")[0];
|
|
144
|
+
const timestamp = new Date().toISOString();
|
|
145
|
+
return { sourceRepo, commit, branch, orgName, timestamp };
|
|
146
|
+
};
|
|
147
|
+
const detectRepositoryFromGit = () => {
|
|
148
|
+
try {
|
|
149
|
+
const remoteUrl = execSync("git config --get remote.origin.url", {
|
|
150
|
+
encoding: "utf8",
|
|
151
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
152
|
+
}).trim();
|
|
153
|
+
const match = remoteUrl.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
154
|
+
return match ? match[1] : null;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.warn("Failed to detect repository from git:", error.message);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const detectCommitFromGit = () => {
|
|
162
|
+
try {
|
|
163
|
+
return execSync("git rev-parse HEAD", {
|
|
164
|
+
encoding: "utf8",
|
|
165
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
166
|
+
}).trim();
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.warn("Failed to detect commit from git:", error.message);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const detectBranchFromGit = () => {
|
|
174
|
+
try {
|
|
175
|
+
return execSync("git rev-parse --abbrev-ref HEAD", {
|
|
176
|
+
encoding: "utf8",
|
|
177
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
178
|
+
}).trim();
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.warn("Failed to detect branch from git:", error.message);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
export const dispatchUpdateCommand = async (opts) => {
|
|
186
|
+
const { schemaUrl, sourceRepo: providedSourceRepo, commit: providedCommit, branch: providedBranch, token, orgName: providedOrgName, repoFilter, dryRun, } = opts;
|
|
187
|
+
const detected = detectValues();
|
|
188
|
+
const sourceRepo = providedSourceRepo || detected.sourceRepo;
|
|
189
|
+
const commit = providedCommit || detected.commit;
|
|
190
|
+
const branch = providedBranch || detected.branch;
|
|
191
|
+
const orgName = providedOrgName || detected.orgName;
|
|
192
|
+
const timestamp = detected.timestamp;
|
|
193
|
+
if (!schemaUrl) {
|
|
194
|
+
throw new Error("Schema URL is required (--schema-url)");
|
|
195
|
+
}
|
|
196
|
+
if (!token) {
|
|
197
|
+
throw new Error("GitHub token is required (--token)");
|
|
198
|
+
}
|
|
199
|
+
if (!sourceRepo) {
|
|
200
|
+
throw new Error("Source repository could not be detected. Please provide --source-repo");
|
|
201
|
+
}
|
|
202
|
+
if (!orgName) {
|
|
203
|
+
throw new Error("Organization name could not be detected. Please provide --org-name");
|
|
204
|
+
}
|
|
205
|
+
console.log("🔧 Preparing schema update dispatch...");
|
|
206
|
+
console.log(`📁 Source Repository: ${sourceRepo}`);
|
|
207
|
+
console.log(`🏷️ Commit: ${commit || "not detected"}`);
|
|
208
|
+
console.log(`🌿 Branch: ${branch || "not detected"}`);
|
|
209
|
+
console.log(`🏢 Organization: ${orgName}`);
|
|
210
|
+
console.log(`⏰ Timestamp: ${timestamp}`);
|
|
211
|
+
return dispatchUpdate({
|
|
212
|
+
schemaUrl,
|
|
213
|
+
sourceRepo,
|
|
214
|
+
commit,
|
|
215
|
+
branch,
|
|
216
|
+
timestamp,
|
|
217
|
+
token,
|
|
218
|
+
orgName,
|
|
219
|
+
repoFilter,
|
|
220
|
+
dryRun,
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
export default dispatchUpdateCommand;
|
|
224
|
+
//# sourceMappingURL=dispatch-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-update.js","sourceRoot":"","sources":["../../src/dispatch-update.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-schema.d.ts","sourceRoot":"","sources":["../../src/fetch-schema.js"],"names":[],"mappings":"AAKO;;;kBAwDN"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import fse from "fs-extra";
|
|
3
|
+
import { buildClientSchema, getIntrospectionQuery, printSchema } from "graphql";
|
|
4
|
+
import path from "path";
|
|
5
|
+
export const fetchSchema = async ({ url, output }) => {
|
|
6
|
+
try {
|
|
7
|
+
console.log(`🔄 Fetching GraphQL schema from ${url}...`);
|
|
8
|
+
const introspectionQuery = getIntrospectionQuery();
|
|
9
|
+
const response = await fetch(url, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: {
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
Accept: "application/json",
|
|
14
|
+
},
|
|
15
|
+
body: JSON.stringify({
|
|
16
|
+
query: introspectionQuery,
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
21
|
+
}
|
|
22
|
+
const result = await response.json();
|
|
23
|
+
if (result.errors) {
|
|
24
|
+
throw new Error(`GraphQL errors: ${result.errors.map((e) => e.message).join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
if (!result.data) {
|
|
27
|
+
throw new Error("No data returned from introspection query");
|
|
28
|
+
}
|
|
29
|
+
const schema = buildClientSchema(result.data);
|
|
30
|
+
const schemaSDL = printSchema(schema);
|
|
31
|
+
const outputDir = path.dirname(output);
|
|
32
|
+
fse.ensureDirSync(outputDir);
|
|
33
|
+
fs.writeFileSync(output, schemaSDL, "utf8");
|
|
34
|
+
console.log(`✅ Schema successfully saved to ${output}`);
|
|
35
|
+
console.log(`📊 Schema contains ${Object.keys(schema.getTypeMap()).length} types`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`❌ Failed to fetch schema: ${error.message}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export default fetchSchema;
|
|
43
|
+
//# sourceMappingURL=fetch-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-schema.js","sourceRoot":"","sources":["../../src/fetch-schema.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;IACnD,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,mCAAmC,GAAG,KAAK,CAAC,CAAC;QAGzD,MAAM,kBAAkB,GAAG,qBAAqB,EAAE,CAAC;QAGnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,kBAAkB;aAC1B,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAErC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAGD,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAG9C,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAGtC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAG7B,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAE5C,OAAO,CAAC,GAAG,CAAC,kCAAkC,MAAM,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CACT,sBAAsB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,MAAM,QAAQ,CACtE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAGF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function buildSchemaUrl({ stage, service, repo }: {
|
|
2
|
+
stage: string;
|
|
3
|
+
service: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
}): string;
|
|
6
|
+
export function generateSchemaUrl(opts: any): string;
|
|
7
|
+
export default generateSchemaUrl;
|
|
8
|
+
//# sourceMappingURL=generate-schema-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-schema-url.d.ts","sourceRoot":"","sources":["../../src/generate-schema-url.js"],"names":[],"mappings":"AAYO,yDALJ;IAAwB,KAAK,EAArB,MAAM;IACU,OAAO,EAAvB,MAAM;IACU,IAAI,EAApB,MAAM;CACd,GAAU,MAAM,CAwBlB;AAkGM,qDA2CN"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
export const buildSchemaUrl = ({ stage = "dev", service, repo }) => {
|
|
5
|
+
if (!repo) {
|
|
6
|
+
repo = detectRepositoryName();
|
|
7
|
+
}
|
|
8
|
+
if (!service) {
|
|
9
|
+
service = extractServiceName(repo);
|
|
10
|
+
}
|
|
11
|
+
if (service === "embrace" ||
|
|
12
|
+
repo === "embrace" ||
|
|
13
|
+
repo.endsWith("/embrace")) {
|
|
14
|
+
return buildEmbraceUrl(stage);
|
|
15
|
+
}
|
|
16
|
+
return buildServiceUrl(service, stage);
|
|
17
|
+
};
|
|
18
|
+
const buildEmbraceUrl = (stage) => {
|
|
19
|
+
switch (stage) {
|
|
20
|
+
case "dev":
|
|
21
|
+
return "https://api.dev.embrace.ai/v2/graphql/schema";
|
|
22
|
+
default:
|
|
23
|
+
if (stage.startsWith("pr-")) {
|
|
24
|
+
return `https://api.${stage}.dev.embrace.ai/v2/graphql/schema`;
|
|
25
|
+
}
|
|
26
|
+
return "https://api.dev.embrace.ai/v2/graphql/schema";
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const buildServiceUrl = (service, stage) => {
|
|
30
|
+
switch (stage) {
|
|
31
|
+
case "prod":
|
|
32
|
+
return `https://api.${service}.services.embrace.ai/graphql/schema`;
|
|
33
|
+
case "dev":
|
|
34
|
+
return `https://api.${service}.services.dev.embrace.ai/graphql/schema`;
|
|
35
|
+
default:
|
|
36
|
+
if (stage.startsWith("pr-")) {
|
|
37
|
+
return `https://api.${service}.${stage}.services.dev.embrace.ai/graphql/schema`;
|
|
38
|
+
}
|
|
39
|
+
return `https://api.${service}.services.dev.embrace.ai/graphql/schema`;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const detectRepositoryName = () => {
|
|
43
|
+
try {
|
|
44
|
+
const remoteUrl = execSync("git config --get remote.origin.url", {
|
|
45
|
+
encoding: "utf8",
|
|
46
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
47
|
+
}).trim();
|
|
48
|
+
const match = remoteUrl.match(/[/:]([^/]+?)(?:\.git)?$/);
|
|
49
|
+
if (match) {
|
|
50
|
+
return match[1];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.warn("⚠️ Could not detect repository from git, using directory name: ", error.message);
|
|
55
|
+
}
|
|
56
|
+
return path.basename(process.cwd());
|
|
57
|
+
};
|
|
58
|
+
const extractServiceName = (repo) => {
|
|
59
|
+
let serviceName = repo
|
|
60
|
+
.replace(/^(api-|service-|microservice-|ms-)/, "")
|
|
61
|
+
.replace(/(-api|-service|-microservice|-ms)$/, "")
|
|
62
|
+
.replace(/^embrace-/, "");
|
|
63
|
+
if (serviceName === "embrace" || serviceName === "") {
|
|
64
|
+
return "embrace";
|
|
65
|
+
}
|
|
66
|
+
return serviceName;
|
|
67
|
+
};
|
|
68
|
+
export const generateSchemaUrl = (opts) => {
|
|
69
|
+
try {
|
|
70
|
+
const { stage, service, repo } = opts;
|
|
71
|
+
const detectedRepo = repo || detectRepositoryName();
|
|
72
|
+
const detectedService = service || extractServiceName(detectedRepo);
|
|
73
|
+
const url = buildSchemaUrl({
|
|
74
|
+
stage,
|
|
75
|
+
service: detectedService,
|
|
76
|
+
repo: detectedRepo,
|
|
77
|
+
});
|
|
78
|
+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
79
|
+
if (summaryPath) {
|
|
80
|
+
const md = [
|
|
81
|
+
"### Schema URL Generation",
|
|
82
|
+
"",
|
|
83
|
+
`- Repository: ${detectedRepo}`,
|
|
84
|
+
`- Service: ${detectedService}`,
|
|
85
|
+
`- Stage: ${stage}`,
|
|
86
|
+
`- URL: ${url}`,
|
|
87
|
+
"",
|
|
88
|
+
].join("\n");
|
|
89
|
+
try {
|
|
90
|
+
fs.appendFileSync(summaryPath, md);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
console.warn("Failed to write summary:", e.message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
process.stderr.write("::notice::Generated schema URL\n");
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write(url);
|
|
100
|
+
return url;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error(`❌ Failed to generate schema URL: ${error.message}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export default generateSchemaUrl;
|
|
108
|
+
//# sourceMappingURL=generate-schema-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-schema-url.js","sourceRoot":"","sources":["../../src/generate-schema-url.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-summary.d.ts","sourceRoot":"","sources":["../../src/generate-summary.js"],"names":[],"mappings":"AAEO,+DA2BN;AAGM,iDAeN"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
export const generateSummaryFromReport = (report) => {
|
|
3
|
+
if (!report || report.length === 0) {
|
|
4
|
+
return "No GraphQL validation errors found.";
|
|
5
|
+
}
|
|
6
|
+
let output = "## 🚨 GraphQL Schema Validation Issues\n\n";
|
|
7
|
+
const grouped = report.reduce((acc, issue) => {
|
|
8
|
+
const file = issue.location?.file || "Unknown file";
|
|
9
|
+
if (!acc[file]) {
|
|
10
|
+
acc[file] = [];
|
|
11
|
+
}
|
|
12
|
+
acc[file].push(issue);
|
|
13
|
+
return acc;
|
|
14
|
+
}, {});
|
|
15
|
+
for (const [file, issues] of Object.entries(grouped)) {
|
|
16
|
+
output += `### \`${file}\`\n`;
|
|
17
|
+
issues.forEach(({ message, location, operation }) => {
|
|
18
|
+
const line = location?.line || "?";
|
|
19
|
+
output += `- ❌ \`${operation || "Unknown Operation"}\`: ${message} (line ${line})\n`;
|
|
20
|
+
});
|
|
21
|
+
output += "\n";
|
|
22
|
+
}
|
|
23
|
+
return output;
|
|
24
|
+
};
|
|
25
|
+
export const generateSummary = (opts) => {
|
|
26
|
+
const reportPath = opts.report;
|
|
27
|
+
const outputPath = opts.output;
|
|
28
|
+
const raw = fs.readFileSync(reportPath, "utf-8");
|
|
29
|
+
const report = JSON.parse(raw);
|
|
30
|
+
const summary = generateSummaryFromReport(report);
|
|
31
|
+
if (outputPath) {
|
|
32
|
+
fs.writeFileSync(outputPath, summary, "utf-8");
|
|
33
|
+
console.log(`✅ Summary written to ${outputPath}`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log(summary);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (process.argv[1] && process.argv[1].endsWith("generate-summary.js")) {
|
|
40
|
+
const reportPath = process.argv[2] || "report.json";
|
|
41
|
+
const raw = fs.readFileSync(reportPath, "utf-8");
|
|
42
|
+
const report = JSON.parse(raw);
|
|
43
|
+
const summary = generateSummaryFromReport(report);
|
|
44
|
+
console.log(summary);
|
|
45
|
+
}
|
|
46
|
+
export default generateSummary;
|
|
47
|
+
//# sourceMappingURL=generate-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-summary.js","sourceRoot":"","sources":["../../src/generate-summary.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,EAAE;IAClD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,qCAAqC,CAAC;IAC/C,CAAC;IAED,IAAI,MAAM,GAAG,4CAA4C,CAAC;IAG1D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,cAAc,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACjB,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,SAAS,IAAI,MAAM,CAAC;QAC9B,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE;YAClD,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC;YACnC,MAAM,IAAI,SAAS,SAAS,IAAI,mBAAmB,OAAO,OAAO,UAAU,IAAI,KAAK,CAAC;QACvF,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,EAAE;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAE/B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/B,MAAM,OAAO,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAElD,IAAI,UAAU,EAAE,CAAC;QACf,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC;AAGF,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;IACvE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC;IACpD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/B,MAAM,OAAO,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAGD,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
const program = new Command();
|
|
4
|
+
program
|
|
5
|
+
.name("api-tool")
|
|
6
|
+
.description("CLI for API schema management")
|
|
7
|
+
.version("0.1.0");
|
|
8
|
+
program
|
|
9
|
+
.command("fetch")
|
|
10
|
+
.description("Fetch GraphQL schema from a URL")
|
|
11
|
+
.requiredOption("--url <url>", "Schema URL")
|
|
12
|
+
.requiredOption("--output <file>", "Output file path")
|
|
13
|
+
.action(async (opts) => {
|
|
14
|
+
const { default: fetchSchema } = await import("./fetch-schema.js");
|
|
15
|
+
return fetchSchema(opts);
|
|
16
|
+
});
|
|
17
|
+
program
|
|
18
|
+
.command("validate")
|
|
19
|
+
.description("Validate queries against schema")
|
|
20
|
+
.requiredOption("--schema <file>", "Schema file path")
|
|
21
|
+
.requiredOption("--queries <glob>", "Glob pattern to GraphQL query files")
|
|
22
|
+
.requiredOption("--output <file>", "JSON report output")
|
|
23
|
+
.action(async (opts) => {
|
|
24
|
+
const { default: validateSchema } = await import("./validate-schema.js");
|
|
25
|
+
return validateSchema(opts);
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command("summarize")
|
|
29
|
+
.description("Generate markdown from a validation report")
|
|
30
|
+
.requiredOption("--report <file>", "Validation JSON report")
|
|
31
|
+
.requiredOption("--output <file>", "Markdown file path")
|
|
32
|
+
.action(async (opts) => {
|
|
33
|
+
const { default: generateSummary } = await import("./generate-summary.js");
|
|
34
|
+
return generateSummary(opts);
|
|
35
|
+
});
|
|
36
|
+
program
|
|
37
|
+
.command("generate-schema-url")
|
|
38
|
+
.description("Generate dynamic schema URL based on repository and stage")
|
|
39
|
+
.option("--stage <stage>", "Deployment stage (dev, prod, pr-*)", "dev")
|
|
40
|
+
.option("--service <service>", "Service name (auto-detected from repo if not provided)")
|
|
41
|
+
.option("--repo <repo>", "Repository name (auto-detected from git if not provided)")
|
|
42
|
+
.action(async (opts) => {
|
|
43
|
+
const { default: generateSchemaUrl } = await import("./generate-schema-url.js");
|
|
44
|
+
return generateSchemaUrl(opts);
|
|
45
|
+
});
|
|
46
|
+
program
|
|
47
|
+
.command("dispatch-update")
|
|
48
|
+
.description("Dispatch schema update events to organization repositories")
|
|
49
|
+
.requiredOption("--schema-url <url>", "Schema URL to dispatch")
|
|
50
|
+
.requiredOption("--token <token>", "GitHub token for API access")
|
|
51
|
+
.option("--source-repo <repo>", "Source repository (auto-detected if not provided)")
|
|
52
|
+
.option("--commit <sha>", "Git commit SHA (auto-detected if not provided)")
|
|
53
|
+
.option("--branch <branch>", "Git branch name (auto-detected if not provided)")
|
|
54
|
+
.option("--org-name <org>", "GitHub organization name (auto-detected if not provided)")
|
|
55
|
+
.option("--repo-filter <pattern>", "Regex pattern to filter repositories", ".*")
|
|
56
|
+
.option("--dry-run", "Show what would be dispatched without sending", false)
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
const { default: dispatchUpdate } = await import("./dispatch-update.js");
|
|
59
|
+
return dispatchUpdate(opts);
|
|
60
|
+
});
|
|
61
|
+
program.parse();
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-schema.d.ts","sourceRoot":"","sources":["../../src/validate-schema.js"],"names":[],"mappings":"AAMO;;;;kBAuGN"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { validate } from "@graphql-inspector/core";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import fse from "fs-extra";
|
|
4
|
+
import { buildSchema } from "graphql";
|
|
5
|
+
import path from "path";
|
|
6
|
+
export const validateSchema = async ({ schema, queries, output }) => {
|
|
7
|
+
try {
|
|
8
|
+
console.log(`🔄 Validating GraphQL queries against schema...`);
|
|
9
|
+
console.log(`📄 Schema: ${schema}`);
|
|
10
|
+
console.log(`🔍 Queries: ${queries}`);
|
|
11
|
+
if (!fs.existsSync(schema)) {
|
|
12
|
+
throw new Error(`Schema file not found: ${schema}`);
|
|
13
|
+
}
|
|
14
|
+
const outputDir = path.dirname(output);
|
|
15
|
+
fse.ensureDirSync(outputDir);
|
|
16
|
+
const schemaContent = fs.readFileSync(schema, "utf8");
|
|
17
|
+
const graphqlSchema = buildSchema(schemaContent);
|
|
18
|
+
const queryFiles = findFiles(queries);
|
|
19
|
+
if (queryFiles.length === 0) {
|
|
20
|
+
console.log(`⚠️ No query files found matching pattern: ${queries}`);
|
|
21
|
+
}
|
|
22
|
+
const sources = queryFiles.map((filePath) => ({
|
|
23
|
+
name: filePath,
|
|
24
|
+
body: fs.readFileSync(filePath, "utf8"),
|
|
25
|
+
location: filePath,
|
|
26
|
+
}));
|
|
27
|
+
console.log(`🚀 Validating ${sources.length} query file(s) against schema...`);
|
|
28
|
+
const invalidDocuments = validate(graphqlSchema, sources, {
|
|
29
|
+
strictDeprecated: false,
|
|
30
|
+
strictFragments: true,
|
|
31
|
+
apollo: false,
|
|
32
|
+
});
|
|
33
|
+
const validationReport = [];
|
|
34
|
+
for (const doc of invalidDocuments) {
|
|
35
|
+
for (const error of doc.errors) {
|
|
36
|
+
validationReport.push({
|
|
37
|
+
message: error.message,
|
|
38
|
+
location: {
|
|
39
|
+
file: doc.source.name,
|
|
40
|
+
line: error.locations?.[0]?.line || 1,
|
|
41
|
+
column: error.locations?.[0]?.column || 1,
|
|
42
|
+
},
|
|
43
|
+
operation: "validation",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
for (const deprecated of doc.deprecated) {
|
|
47
|
+
validationReport.push({
|
|
48
|
+
message: `Deprecated: ${deprecated.message}`,
|
|
49
|
+
location: {
|
|
50
|
+
file: doc.source.name,
|
|
51
|
+
line: deprecated.locations?.[0]?.line || 1,
|
|
52
|
+
column: deprecated.locations?.[0]?.column || 1,
|
|
53
|
+
},
|
|
54
|
+
operation: "deprecated",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
fs.writeFileSync(output, JSON.stringify(validationReport, null, 2), "utf8");
|
|
59
|
+
const errorCount = validationReport.length;
|
|
60
|
+
if (errorCount === 0) {
|
|
61
|
+
console.log(`✅ Validation completed successfully - no issues found`);
|
|
62
|
+
console.log(`📊 Report saved to ${output}`);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(`⚠️ Validation completed with ${errorCount} issue(s) found`);
|
|
66
|
+
console.log(`📊 Report saved to ${output}`);
|
|
67
|
+
const fileGroups = validationReport.reduce((acc, issue) => {
|
|
68
|
+
const file = issue.location?.file || "Unknown file";
|
|
69
|
+
acc[file] = (acc[file] || 0) + 1;
|
|
70
|
+
return acc;
|
|
71
|
+
}, {});
|
|
72
|
+
console.log(`📋 Issues by file:`);
|
|
73
|
+
Object.entries(fileGroups).forEach(([file, count]) => {
|
|
74
|
+
console.log(` ${file}: ${count} issue(s)`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(`❌ Validation failed: ${error.message}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const findFiles = (pattern) => {
|
|
84
|
+
if (fs.existsSync(pattern) && fs.statSync(pattern).isFile()) {
|
|
85
|
+
return [pattern];
|
|
86
|
+
}
|
|
87
|
+
const files = [];
|
|
88
|
+
if (pattern.includes("*")) {
|
|
89
|
+
const dir = pattern.includes("/") ? path.dirname(pattern) : ".";
|
|
90
|
+
const searchDir = fs.existsSync(dir) ? dir : ".";
|
|
91
|
+
const searchDirectory = (dirPath, recursive = false) => {
|
|
92
|
+
const entries = fs.readdirSync(dirPath);
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
const fullPath = path.join(dirPath, entry);
|
|
95
|
+
const stat = fs.statSync(fullPath);
|
|
96
|
+
if (stat.isDirectory() && recursive) {
|
|
97
|
+
searchDirectory(fullPath, true);
|
|
98
|
+
}
|
|
99
|
+
else if (stat.isFile() && entry.endsWith(".graphql")) {
|
|
100
|
+
files.push(fullPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const recursive = pattern.includes("**");
|
|
105
|
+
searchDirectory(searchDir, recursive);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
if (fs.existsSync(pattern)) {
|
|
109
|
+
files.push(pattern);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return files;
|
|
113
|
+
};
|
|
114
|
+
export default validateSchema;
|
|
115
|
+
//# sourceMappingURL=validate-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-schema.js","sourceRoot":"","sources":["../../src/validate-schema.js"],"names":[],"mappings":"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"}
|
package/dist/vitest.config.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const config_1 = require("vitest/config");
|
|
4
|
-
exports.default = (0, config_1.defineConfig)({
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
export default defineConfig({
|
|
5
3
|
test: {
|
|
6
4
|
exclude: [
|
|
7
5
|
"**/node_modules/**",
|
|
@@ -11,7 +9,7 @@ exports.default = (0, config_1.defineConfig)({
|
|
|
11
9
|
],
|
|
12
10
|
chaiConfig: { truncateThreshold: 200 },
|
|
13
11
|
maxConcurrency: 20,
|
|
14
|
-
testTimeout: 20 * 1000,
|
|
12
|
+
testTimeout: 20 * 1000,
|
|
15
13
|
coverage: {
|
|
16
14
|
enabled: false,
|
|
17
15
|
exclude: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.config.js","sourceRoot":"","sources":["../vitest.config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vitest.config.js","sourceRoot":"","sources":["../vitest.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,eAAe,YAAY,CAAC;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE;YACP,oBAAoB;YACpB,YAAY;YACZ,qCAAqC;YACrC,sFAAsF;SACvF;QACD,UAAU,EAAE,EAAE,iBAAiB,EAAE,GAAG,EAAE;QACtC,cAAc,EAAE,EAAE;QAClB,WAAW,EAAE,EAAE,GAAG,IAAI;QACtB,QAAQ,EAAE;YACR,OAAO,EAAE,KAAK;YACd,OAAO,EAAE;gBACP,aAAa;gBACb,YAAY;gBACZ,oBAAoB;gBACpB,oBAAoB;aACrB;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAC3B;KACF;IACD,OAAO,EAAE;QACP,gBAAgB,EAAE,IAAI;KACvB;CACF,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execSync } from "child_process";
|
|
2
|
-
import
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Generate a dynamic GraphQL schema URL based on repository and deployment stage
|
|
@@ -133,23 +134,36 @@ export const generateSchemaUrl = (opts) => {
|
|
|
133
134
|
try {
|
|
134
135
|
const { stage, service, repo } = opts;
|
|
135
136
|
|
|
136
|
-
console.log("🔧 Generating schema URL...");
|
|
137
|
-
|
|
138
137
|
// Detect values if not provided
|
|
139
138
|
const detectedRepo = repo || detectRepositoryName();
|
|
140
139
|
const detectedService = service || extractServiceName(detectedRepo);
|
|
141
140
|
|
|
142
|
-
console.log(`📁 Repository: ${detectedRepo}`);
|
|
143
|
-
console.log(`🏷️ Service: ${detectedService}`);
|
|
144
|
-
console.log(`🚀 Stage: ${stage}`);
|
|
145
|
-
|
|
146
141
|
const url = buildSchemaUrl({
|
|
147
142
|
stage,
|
|
148
143
|
service: detectedService,
|
|
149
144
|
repo: detectedRepo,
|
|
150
145
|
});
|
|
151
146
|
|
|
152
|
-
|
|
147
|
+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
148
|
+
if (summaryPath) {
|
|
149
|
+
const md = [
|
|
150
|
+
"### Schema URL Generation",
|
|
151
|
+
"",
|
|
152
|
+
`- Repository: ${detectedRepo}`,
|
|
153
|
+
`- Service: ${detectedService}`,
|
|
154
|
+
`- Stage: ${stage}`,
|
|
155
|
+
`- URL: ${url}`,
|
|
156
|
+
"",
|
|
157
|
+
].join("\n");
|
|
158
|
+
try {
|
|
159
|
+
fs.appendFileSync(summaryPath, md);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
console.warn("Failed to write summary:", e.message);
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
// Optional: Create a GitHub Actions notice without using console.*
|
|
165
|
+
process.stderr.write("::notice::Generated schema URL\n");
|
|
166
|
+
}
|
|
153
167
|
|
|
154
168
|
// Output just the URL for easy consumption by scripts
|
|
155
169
|
process.stdout.write(url);
|
|
@@ -6,7 +6,8 @@ on:
|
|
|
6
6
|
branches:
|
|
7
7
|
- main
|
|
8
8
|
paths:
|
|
9
|
-
-
|
|
9
|
+
- "**/*schema.ts"
|
|
10
|
+
workflow_dispatch: {}
|
|
10
11
|
|
|
11
12
|
env:
|
|
12
13
|
# Configure these environment variables for your setup
|
|
@@ -15,12 +16,12 @@ env:
|
|
|
15
16
|
# SCHEMA_URL: "https://api.dev.embrace.ai/v2/graphql/schema"
|
|
16
17
|
|
|
17
18
|
# Deployment stage - determines the environment URL pattern
|
|
18
|
-
DEPLOYMENT_STAGE: "dev"
|
|
19
|
+
DEPLOYMENT_STAGE: "dev" # Options: dev, prod, pr-* (e.g., pr-123)
|
|
19
20
|
# Optional: Override service name (auto-detected from repository name if not set)
|
|
20
21
|
# SERVICE_NAME: "your-service-name"
|
|
21
22
|
|
|
22
23
|
# Optional: Filter repositories by name pattern (regex)
|
|
23
|
-
REPO_FILTER: ".*"
|
|
24
|
+
REPO_FILTER: ".*" # Default: all repos. Example: "^(frontend|mobile|web)-.*" for specific patterns
|
|
24
25
|
permissions:
|
|
25
26
|
id-token: write
|
|
26
27
|
contents: read
|
|
@@ -40,40 +41,38 @@ jobs:
|
|
|
40
41
|
uses: actions/setup-node@v4
|
|
41
42
|
with:
|
|
42
43
|
node-version: 22.16.0
|
|
43
|
-
cache:
|
|
44
|
+
cache: "pnpm"
|
|
44
45
|
- name: Setup NPM
|
|
45
46
|
env:
|
|
46
47
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
47
48
|
run: pnpm config set //registry.npmjs.org/:_authToken "${NPM_TOKEN}"
|
|
48
|
-
- name: Install dependencies
|
|
49
|
-
run: pnpm i --frozen-lockfile
|
|
50
49
|
|
|
51
50
|
- name: Install GraphQL schema sync tool
|
|
52
|
-
|
|
51
|
+
# Update below to use the version you want
|
|
52
|
+
run: pnpm install -w @embrace-ai/infra-api-schema-sync@latest
|
|
53
|
+
|
|
53
54
|
# Generate dynamic schema URL based on repository and stage
|
|
54
55
|
- name: Generate schema URL
|
|
55
56
|
id: schema-url
|
|
57
|
+
if: ${{ env.SCHEMA_URL == '' || env.SCHEMA_URL == null }}
|
|
56
58
|
run: |
|
|
57
59
|
# Generate URL using the CLI tool
|
|
58
60
|
if [ -n "$SERVICE_NAME" ]; then
|
|
59
|
-
SCHEMA_URL=$(
|
|
61
|
+
SCHEMA_URL=$(pnpm exec api-tool generate-schema-url --stage "$DEPLOYMENT_STAGE" --service "$SERVICE_NAME")
|
|
60
62
|
else
|
|
61
|
-
SCHEMA_URL=$(
|
|
63
|
+
SCHEMA_URL=$(pnpm exec api-tool generate-schema-url --stage "$DEPLOYMENT_STAGE")
|
|
62
64
|
fi
|
|
63
65
|
|
|
64
66
|
# Set as output for use in later steps
|
|
65
67
|
echo "url=$SCHEMA_URL" >> $GITHUB_OUTPUT
|
|
66
68
|
echo "🌐 Generated schema URL: $SCHEMA_URL"
|
|
67
69
|
|
|
68
|
-
|
|
69
70
|
# Fetch all organization repositories and dispatch to each
|
|
70
71
|
- name: Dispatch schema update events to all org repositories
|
|
71
72
|
env:
|
|
72
|
-
|
|
73
|
-
# Use the dynamically generated schema URL
|
|
74
|
-
SCHEMA_URL: ${{ steps.schema-url.outputs.url }}
|
|
73
|
+
SCHEMA_URL: ${{ env.SCHEMA_URL || steps.schema-url.outputs.url }}
|
|
75
74
|
run: |
|
|
76
|
-
|
|
75
|
+
pnpm exec api-tool dispatch-update \
|
|
77
76
|
--schema-url "$SCHEMA_URL" \
|
|
78
77
|
--token "${{ secrets.GITHUB_TOKEN }}" \
|
|
79
78
|
--source-repo "${{ github.repository }}" \
|
|
@@ -4,7 +4,7 @@ name: Validate GraphQL Schema Updates
|
|
|
4
4
|
on:
|
|
5
5
|
repository_dispatch:
|
|
6
6
|
types: [graphql-schema-updated]
|
|
7
|
-
|
|
7
|
+
workflow_dispatch: {}
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
validate-schema:
|
|
@@ -20,18 +20,16 @@ jobs:
|
|
|
20
20
|
uses: actions/setup-node@v4
|
|
21
21
|
with:
|
|
22
22
|
node-version: 22.16.0
|
|
23
|
-
cache:
|
|
23
|
+
cache: "pnpm"
|
|
24
24
|
|
|
25
25
|
- name: Setup NPM
|
|
26
26
|
env:
|
|
27
27
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
28
28
|
run: pnpm config set //registry.npmjs.org/:_authToken "${NPM_TOKEN}"
|
|
29
29
|
|
|
30
|
-
- name: Install dependencies
|
|
31
|
-
run: pnpm i --frozen-lockfile
|
|
32
|
-
|
|
33
30
|
- name: Install GraphQL schema sync tool
|
|
34
|
-
|
|
31
|
+
# Update line below to use the version you want
|
|
32
|
+
run: pnpm install -w @embrace-ai/infra-api-schema-sync@latest
|
|
35
33
|
|
|
36
34
|
- name: Configure aws credentials
|
|
37
35
|
uses: aws-actions/configure-aws-credentials@v4.2.1
|
|
@@ -48,18 +46,18 @@ jobs:
|
|
|
48
46
|
echo "Timestamp: ${{ github.event.client_payload.timestamp }}"
|
|
49
47
|
|
|
50
48
|
- name: Fetch updated schema
|
|
51
|
-
run:
|
|
49
|
+
run: pnpm exec api-tool fetch --url ${{ github.event.client_payload.schemaUrl }} --output new-schema.graphql
|
|
52
50
|
|
|
53
51
|
- name: Validate queries against new schema
|
|
54
52
|
id: validate
|
|
55
|
-
run:
|
|
53
|
+
run: pnpm exec api-tool validate --schema new-schema.graphql --queries 'src/**/*.graphql' --output report.json
|
|
56
54
|
|
|
57
55
|
- name: Check for issues
|
|
58
56
|
id: check-issues
|
|
59
57
|
run: |
|
|
60
|
-
if [ -s report.json ] && [ "$(jq '
|
|
58
|
+
if [ -s report.json ] && [ "$(jq 'length' report.json)" -gt 0 ]; then
|
|
61
59
|
echo "has_issues=true" >> $GITHUB_OUTPUT
|
|
62
|
-
echo "issue_count=$(jq '
|
|
60
|
+
echo "issue_count=$(jq 'length' report.json)" >> $GITHUB_OUTPUT
|
|
63
61
|
else
|
|
64
62
|
echo "has_issues=false" >> $GITHUB_OUTPUT
|
|
65
63
|
echo "issue_count=0" >> $GITHUB_OUTPUT
|
|
@@ -68,7 +66,7 @@ jobs:
|
|
|
68
66
|
- name: Generate summary
|
|
69
67
|
id: gen-summary
|
|
70
68
|
if: steps.check-issues.outputs.has_issues == 'true'
|
|
71
|
-
run:
|
|
69
|
+
run: pnpm exec api-tool summarize --report report.json --output GRAPHQL_ISSUES.md && echo "summary=$(cat GRAPHQL_ISSUES.md)" >> $GITHUB_OUTPUT
|
|
72
70
|
|
|
73
71
|
- name: Commit and create PR with issues
|
|
74
72
|
uses: peter-evans/create-pull-request@v6
|
|
@@ -87,14 +85,10 @@ jobs:
|
|
|
87
85
|
|
|
88
86
|
---
|
|
89
87
|
## ${{ steps.check-issues.outputs.has_issues == 'true' && 'Detected Issues' || '🎉 No Issues Found' }}
|
|
90
|
-
${{
|
|
91
|
-
steps.check-issues.outputs.has_issues == 'true'
|
|
92
|
-
? steps.gen-summary.outputs.summary
|
|
93
|
-
: 'The updated schema is compatible with your existing GraphQL queries. No changes are required.'
|
|
94
|
-
}}
|
|
88
|
+
${{ steps.check-issues.outputs.has_issues == 'true' && steps.gen-summary.outputs.summary || 'The updated schema is compatible with your existing GraphQL queries' }}
|
|
95
89
|
|
|
96
90
|
## Next Steps
|
|
97
|
-
1. Review
|
|
91
|
+
1. Review any compatibility issues above
|
|
98
92
|
2. Update your GraphQL queries to match the new schema
|
|
99
93
|
3. Test your changes thoroughly
|
|
100
94
|
4. Merge this PR once all issues are resolved
|