gatsby-attainlabs-cms 1.0.0
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/README.md +29 -0
- package/gatsby-node.js +148 -0
- package/package.json +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# gatsby-attain-labs-cms
|
|
2
|
+
|
|
3
|
+
A Gatsby plugin that downloads and syncs `index.tsx` components from the **Attain Labs CMS** hosted in Azure Repos into your Gatsby project at build time.
|
|
4
|
+
|
|
5
|
+
This is especially useful for keeping brand-specific and global CMS blocks up to date across Gatsby projects without manual copying.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install gatsby-attain-labs-cms
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
In your gatsby-config.js, configure the plugin with the brand you want to sync:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
{
|
|
23
|
+
resolve: "gatsby-attain-labs-cms",
|
|
24
|
+
options: {
|
|
25
|
+
// Select one: 'LendDirect', 'Cash Money', or 'Heights Finance'
|
|
26
|
+
brand: "LendDirect",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
```
|
package/gatsby-node.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import https from "https";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import "dotenv/config";
|
|
5
|
+
// Load PAT from env instead of hardcoding (fallback to old const for now but warn)
|
|
6
|
+
|
|
7
|
+
export const onPreInit = async (_, pluginOptions) => {
|
|
8
|
+
const { brand, azureBranch } = pluginOptions;
|
|
9
|
+
|
|
10
|
+
const pat = process.env.GATSBY_PERSONAL_ACCESS_TOKEN;
|
|
11
|
+
|
|
12
|
+
const brands = {
|
|
13
|
+
LendDirect: "lenddirect",
|
|
14
|
+
"Cash Money": "cashmoney",
|
|
15
|
+
"Heights Finance": "heightsfinance",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const org = "CuroFinTech";
|
|
19
|
+
const project = "Marketing";
|
|
20
|
+
const repo = "Attain Labs";
|
|
21
|
+
const branch = azureBranch || "feature/adding-puck-for-visual-code-editing";
|
|
22
|
+
|
|
23
|
+
// List of folders to download from
|
|
24
|
+
const targets = [
|
|
25
|
+
{
|
|
26
|
+
repoPath: `/apps/cms/src/cms/components/editor/templates/visual-block-editor/components/brands/${brands[brand]}`,
|
|
27
|
+
localBasePath: path.resolve("./src/cms/components/brand"),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
repoPath:
|
|
31
|
+
"/apps/cms/src/cms/components/editor/templates/visual-block-editor/components/global/blocks",
|
|
32
|
+
localBasePath: path.resolve("./src/cms/components/global"),
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const options = {
|
|
37
|
+
headers: {
|
|
38
|
+
Authorization: `Basic ${Buffer.from(`:${pat}`).toString("base64")}`,
|
|
39
|
+
"User-Agent": "component-transfer-script",
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Loop through targets
|
|
44
|
+
targets.forEach(({ repoPath, localBasePath }) => {
|
|
45
|
+
const listUrl = `https://dev.azure.com/${org}/${project}/_apis/git/repositories/${encodeURIComponent(
|
|
46
|
+
repo
|
|
47
|
+
)}/items?scopePath=${encodeURIComponent(
|
|
48
|
+
repoPath
|
|
49
|
+
)}&recursionLevel=full&includeContentMetadata=true&versionDescriptor.version=${encodeURIComponent(
|
|
50
|
+
branch
|
|
51
|
+
)}&versionDescriptor.versionType=branch&api-version=7.0`;
|
|
52
|
+
|
|
53
|
+
https
|
|
54
|
+
.get(listUrl, options, (res) => {
|
|
55
|
+
let data = "";
|
|
56
|
+
res.on("data", (chunk) => (data += chunk));
|
|
57
|
+
res.on("end", () => {
|
|
58
|
+
if (res.statusCode !== 200) {
|
|
59
|
+
console.error(
|
|
60
|
+
`Failed to list items for ${repoPath}: ${res.statusCode} ${res.statusMessage}`
|
|
61
|
+
);
|
|
62
|
+
console.error(data);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const result = JSON.parse(data);
|
|
67
|
+
const posix = path.posix;
|
|
68
|
+
|
|
69
|
+
// Keep only index.tsx files
|
|
70
|
+
const items = (result.value || []).filter(
|
|
71
|
+
(i) =>
|
|
72
|
+
!i.isFolder &&
|
|
73
|
+
i.gitObjectType === "blob" &&
|
|
74
|
+
posix.basename(i.path) === "index.tsx"
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
console.log(`Found ${items.length} index.tsx files in ${repoPath}`);
|
|
78
|
+
items.forEach((item) =>
|
|
79
|
+
downloadFile(item.path, repoPath, localBasePath)
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
})
|
|
83
|
+
.on("error", (err) => {
|
|
84
|
+
console.error("Request error:", err.message);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Download a single file preserving folder structure under localBasePath
|
|
89
|
+
function downloadFile(filePath, repoPath, localBasePath) {
|
|
90
|
+
const fileUrl = `https://dev.azure.com/${org}/${project}/_apis/git/repositories/${encodeURIComponent(
|
|
91
|
+
repo
|
|
92
|
+
)}/items?path=${encodeURIComponent(
|
|
93
|
+
filePath
|
|
94
|
+
)}&versionDescriptor.version=${encodeURIComponent(
|
|
95
|
+
branch
|
|
96
|
+
)}&versionDescriptor.versionType=branch&api-version=7.0&download=true`;
|
|
97
|
+
|
|
98
|
+
const posix = path.posix;
|
|
99
|
+
const relativePath = posix.relative(repoPath, filePath); // structure under repoPath
|
|
100
|
+
const destFile = path.join(localBasePath, ...relativePath.split("/"));
|
|
101
|
+
const destDir = path.dirname(destFile);
|
|
102
|
+
|
|
103
|
+
if (!fs.existsSync(destDir)) {
|
|
104
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
105
|
+
console.log(`📂 Created directory: ${destDir}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const doRequest = (url) => {
|
|
109
|
+
https
|
|
110
|
+
.get(url, options, (res) => {
|
|
111
|
+
if (
|
|
112
|
+
res.statusCode &&
|
|
113
|
+
res.statusCode >= 300 &&
|
|
114
|
+
res.statusCode < 400 &&
|
|
115
|
+
res.headers.location
|
|
116
|
+
) {
|
|
117
|
+
return doRequest(res.headers.location);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (res.statusCode !== 200) {
|
|
121
|
+
console.error(
|
|
122
|
+
`Failed to download ${filePath}: ${res.statusCode} ${res.statusMessage}`
|
|
123
|
+
);
|
|
124
|
+
res.resume();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const tmpFile = destFile + ".part";
|
|
129
|
+
const fileStream = fs.createWriteStream(tmpFile);
|
|
130
|
+
|
|
131
|
+
res.pipe(fileStream);
|
|
132
|
+
fileStream.on("finish", () => {
|
|
133
|
+
fileStream.close(() => {
|
|
134
|
+
fs.renameSync(tmpFile, destFile);
|
|
135
|
+
console.log(`✅ Downloaded ${destFile}`);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
})
|
|
139
|
+
.on("error", (err) => {
|
|
140
|
+
console.error("Request error:", err.message);
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
doRequest(fileUrl);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
onPreInit({}, { brand: "LendDirect" }); // For testing purposes, remove when done
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gatsby-attainlabs-cms",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "gatsby-node.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"author": "Anthony Barrera",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"description": "A Gatsby plugin that downloads and syncs `index.tsx` components from the **Attain Labs CMS** hosted in Azure Repos into your Gatsby project at build time.",
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"gatsby": "^5.0.0 || ^4.0.0"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"dotenv": "^17.2.1"
|
|
17
|
+
}
|
|
18
|
+
}
|