Skip to content

Commit 738d368

Browse files
authored
Merge pull request #15 from hyperweb-io/refactor/appstash-ttl-cache-modularization
feat(create-gen-app): decouple architecture and implement caching with TTL
2 parents d0068bf + ae4b130 commit 738d368

35 files changed

+1028
-1608
lines changed

packages/create-gen-app-test/src/__tests__/__snapshots__/cached-template.test.ts.snap

Lines changed: 30 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,42 @@
22

33
exports[`cached template integration tests first clone with variable replacement should snapshot created directory structure 1`] = `
44
[
5-
"module/",
6-
"module/README.md",
7-
"module/__tests__/",
8-
"module/__tests__/basic.test.ts",
9-
"module/jest.config.js",
10-
"module/package.json",
11-
"workspace/",
12-
"workspace/.eslintrc.json",
13-
"workspace/.github/",
14-
"workspace/.github/run-tests.yaml",
15-
"workspace/.gitignore",
16-
"workspace/.prettierrc.json",
17-
"workspace/.vscode/",
18-
"workspace/.vscode/settings.json",
19-
"workspace/LICENSE",
20-
"workspace/Makefile",
21-
"workspace/README.md",
22-
"workspace/bin/",
23-
"workspace/bin/install.sh",
24-
"workspace/docker-compose.yml",
25-
"workspace/launchql.json",
26-
"workspace/lerna.json",
27-
"workspace/package.json",
28-
"workspace/pnpm-workspace.yaml",
29-
"workspace/tsconfig.json",
5+
"LICENSE",
6+
"README.md",
7+
"__tests__/",
8+
"__tests__/basic.test.ts",
9+
"jest.config.js",
10+
"package.json",
3011
]
3112
`;
3213

3314
exports[`cached template integration tests first clone with variable replacement should snapshot package.json files if they exist 1`] = `
3415
{
35-
"module/package.json": {
36-
"author": "____fullName____ <____email____>",
16+
"package.json": {
17+
"author": "Test User test <[email protected]>",
3718
"bugs": {
38-
"url": "https://github.com/____username____/____repoName____/issues",
19+
"url": "https://github.com/Test User test/Test User test/issues",
3920
},
40-
"description": "____moduleDesc____",
21+
"description": "Test Module test",
4122
"devDependencies": {
4223
"pgsql-test": "^2.13.2",
4324
},
44-
"homepage": "https://github.com/____username____/____repoName____",
25+
"homepage": "https://github.com/Test User test/Test User test",
4526
"keywords": [],
46-
"license": "____license____",
47-
"name": "____packageIdentifier____",
27+
"license": "MIT",
28+
"name": "integration-test",
4829
"pnpm": {
4930
"overrides": {
5031
"graphql": "14.7.0",
5132
},
5233
},
5334
"publishConfig": {
54-
"access": "____access____",
35+
"access": "public",
5536
"directory": "dist",
5637
},
5738
"repository": {
5839
"type": "git",
59-
"url": "https://github.com/____username____/____repoName____",
40+
"url": "https://github.com/Test User test/Test User test",
6041
},
6142
"scripts": {
6243
"lint": "eslint . --fix",
@@ -65,108 +46,47 @@ exports[`cached template integration tests first clone with variable replacement
6546
},
6647
"version": "0.0.1",
6748
},
68-
"workspace/package.json": {
69-
"author": "____fullName____ <____email____>",
70-
"devDependencies": {
71-
"@types/jest": "^29.5.14",
72-
"@types/node": "^22.10.2",
73-
"@typescript-eslint/eslint-plugin": "^8.15.0",
74-
"@typescript-eslint/parser": "^8.15.0",
75-
"eslint": "^9.13.0",
76-
"eslint-config-prettier": "^10.1.1",
77-
"eslint-plugin-simple-import-sort": "^12.1.1",
78-
"eslint-plugin-unused-imports": "^4.3.0",
79-
"jest": "^29.7.0",
80-
"lerna": "^8.2.4",
81-
"pgsql-test": "^2.13.2",
82-
"prettier": "^3.3.3",
83-
"ts-jest": "^29.2.5",
84-
"ts-node": "^10.9.2",
85-
"typescript": "^5.6.3",
86-
},
87-
"license": "SEE LICENSE IN LICENSE",
88-
"name": "____moduleName____",
89-
"pnpm": {
90-
"overrides": {
91-
"graphql": "14.7.0",
92-
},
93-
},
94-
"private": true,
95-
"publishConfig": {
96-
"access": "restricted",
97-
},
98-
"repository": {
99-
"type": "git",
100-
"url": "https://github.com/____username____/____moduleName____",
101-
},
102-
"scripts": {
103-
"lint": "pnpm -r run lint",
104-
},
105-
"version": "0.0.1",
106-
"workspaces": [
107-
"packages/*",
108-
],
109-
},
11049
}
11150
`;
11251

11352
exports[`cached template integration tests second clone from cache should snapshot created directory structure from cache 1`] = `
11453
[
115-
"module/",
116-
"module/README.md",
117-
"module/__tests__/",
118-
"module/__tests__/basic.test.ts",
119-
"module/jest.config.js",
120-
"module/package.json",
121-
"workspace/",
122-
"workspace/.eslintrc.json",
123-
"workspace/.github/",
124-
"workspace/.github/run-tests.yaml",
125-
"workspace/.gitignore",
126-
"workspace/.prettierrc.json",
127-
"workspace/.vscode/",
128-
"workspace/.vscode/settings.json",
129-
"workspace/LICENSE",
130-
"workspace/Makefile",
131-
"workspace/README.md",
132-
"workspace/bin/",
133-
"workspace/bin/install.sh",
134-
"workspace/docker-compose.yml",
135-
"workspace/launchql.json",
136-
"workspace/lerna.json",
137-
"workspace/package.json",
138-
"workspace/pnpm-workspace.yaml",
139-
"workspace/tsconfig.json",
54+
"LICENSE",
55+
"README.md",
56+
"__tests__/",
57+
"__tests__/basic.test.ts",
58+
"jest.config.js",
59+
"package.json",
14060
]
14161
`;
14262

14363
exports[`cached template integration tests second clone from cache should snapshot package.json files from cached template 1`] = `
14464
{
145-
"module/package.json": {
146-
"author": "____fullName____ <____email____>",
65+
"package.json": {
66+
"author": "Test User cached <[email protected]>",
14767
"bugs": {
148-
"url": "https://github.com/____username____/____repoName____/issues",
68+
"url": "https://github.com/Test User cached/Test User cached/issues",
14969
},
150-
"description": "____moduleDesc____",
70+
"description": "Test Module cached",
15171
"devDependencies": {
15272
"pgsql-test": "^2.13.2",
15373
},
154-
"homepage": "https://github.com/____username____/____repoName____",
74+
"homepage": "https://github.com/Test User cached/Test User cached",
15575
"keywords": [],
156-
"license": "____license____",
157-
"name": "____packageIdentifier____",
76+
"license": "MIT",
77+
"name": "integration-cached",
15878
"pnpm": {
15979
"overrides": {
16080
"graphql": "14.7.0",
16181
},
16282
},
16383
"publishConfig": {
164-
"access": "____access____",
84+
"access": "public",
16585
"directory": "dist",
16686
},
16787
"repository": {
16888
"type": "git",
169-
"url": "https://github.com/____username____/____repoName____",
89+
"url": "https://github.com/Test User cached/Test User cached",
17090
},
17191
"scripts": {
17292
"lint": "eslint . --fix",
@@ -175,47 +95,5 @@ exports[`cached template integration tests second clone from cache should snapsh
17595
},
17696
"version": "0.0.1",
17797
},
178-
"workspace/package.json": {
179-
"author": "____fullName____ <____email____>",
180-
"devDependencies": {
181-
"@types/jest": "^29.5.14",
182-
"@types/node": "^22.10.2",
183-
"@typescript-eslint/eslint-plugin": "^8.15.0",
184-
"@typescript-eslint/parser": "^8.15.0",
185-
"eslint": "^9.13.0",
186-
"eslint-config-prettier": "^10.1.1",
187-
"eslint-plugin-simple-import-sort": "^12.1.1",
188-
"eslint-plugin-unused-imports": "^4.3.0",
189-
"jest": "^29.7.0",
190-
"lerna": "^8.2.4",
191-
"pgsql-test": "^2.13.2",
192-
"prettier": "^3.3.3",
193-
"ts-jest": "^29.2.5",
194-
"ts-node": "^10.9.2",
195-
"typescript": "^5.6.3",
196-
},
197-
"license": "SEE LICENSE IN LICENSE",
198-
"name": "____moduleName____",
199-
"pnpm": {
200-
"overrides": {
201-
"graphql": "14.7.0",
202-
},
203-
},
204-
"private": true,
205-
"publishConfig": {
206-
"access": "restricted",
207-
},
208-
"repository": {
209-
"type": "git",
210-
"url": "https://github.com/____username____/____moduleName____",
211-
},
212-
"scripts": {
213-
"lint": "pnpm -r run lint",
214-
},
215-
"version": "0.0.1",
216-
"workspaces": [
217-
"packages/*",
218-
],
219-
},
22098
}
22199
`;

packages/create-gen-app-test/src/__tests__/cached-template.test.ts

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import * as path from 'path';
44

55
import { appstash, resolve } from 'appstash';
66

7-
import { createFromCachedTemplate, TemplateCache } from '../index';
7+
import { createFromTemplate, CacheManager, GitCloner } from '../index';
8+
import { buildAnswers, TEST_REPO, TEST_TEMPLATE } from '../test-utils/integration-helpers';
89

9-
const DEFAULT_TEMPLATE_URL = 'https://github.com/launchql/pgpm-boilerplates';
10+
const DEFAULT_TEMPLATE_URL = TEST_REPO;
1011

1112
describe('cached template integration tests', () => {
1213
let testOutputDir: string;
@@ -35,25 +36,36 @@ describe('cached template integration tests', () => {
3536

3637
describe('cache functionality', () => {
3738
let sharedCachePath: string;
38-
let templateCache: TemplateCache;
39+
let cacheManager: CacheManager;
3940

4041
beforeAll(() => {
41-
templateCache = new TemplateCache({
42-
enabled: true,
42+
cacheManager = new CacheManager({
4343
toolName: testCacheTool,
4444
});
4545
});
4646

4747
it('should return null when cache does not exist for new URL', () => {
4848
const nonExistentUrl = 'https://github.com/nonexistent/repo-test-123456';
49-
const cachedRepo = templateCache.get(nonExistentUrl);
49+
const cacheKey = cacheManager.createKey(nonExistentUrl);
50+
const cachedRepo = cacheManager.get(cacheKey);
5051
expect(cachedRepo).toBeNull();
5152
});
5253

5354
it('should clone repository to cache', () => {
54-
const cachePath = templateCache.set(DEFAULT_TEMPLATE_URL);
55+
// Use GitCloner + CacheManager to clone and cache
56+
const gitCloner = new GitCloner();
57+
const normalizedUrl = gitCloner.normalizeUrl(DEFAULT_TEMPLATE_URL);
58+
const cacheKey = cacheManager.createKey(normalizedUrl);
59+
60+
// Clone to cache directory
61+
const cachePath = path.join(cacheManager.getReposDir(), cacheKey);
62+
gitCloner.clone(normalizedUrl, cachePath, { depth: 1 });
63+
64+
// Register in cache manager
65+
cacheManager.set(cacheKey, cachePath);
5566
sharedCachePath = cachePath;
5667

68+
// Verify cache was created correctly
5769
expect(fs.existsSync(cachePath)).toBe(true);
5870
expect(fs.existsSync(path.join(cachePath, '.git'))).toBe(false);
5971

@@ -62,7 +74,11 @@ describe('cached template integration tests', () => {
6274
}, 60000);
6375

6476
it('should retrieve cached repository', () => {
65-
const cachedRepo = templateCache.get(DEFAULT_TEMPLATE_URL);
77+
const gitCloner = new GitCloner();
78+
const normalizedUrl = gitCloner.normalizeUrl(DEFAULT_TEMPLATE_URL);
79+
const cacheKey = cacheManager.createKey(normalizedUrl);
80+
const cachedRepo = cacheManager.get(cacheKey);
81+
6682
expect(cachedRepo).not.toBeNull();
6783
expect(cachedRepo).toBe(sharedCachePath);
6884
expect(fs.existsSync(cachedRepo!)).toBe(true);
@@ -76,16 +92,13 @@ describe('cached template integration tests', () => {
7692
beforeAll(async () => {
7793
firstOutputDir = fs.mkdtempSync(path.join(os.tmpdir(), 'first-clone-'));
7894

79-
firstCloneResult = await createFromCachedTemplate({
95+
firstCloneResult = await createFromTemplate({
8096
templateUrl: DEFAULT_TEMPLATE_URL,
8197
outputDir: firstOutputDir,
82-
answers: {
83-
PROJECT_NAME: 'test-project',
84-
AUTHOR: 'Test Author',
85-
DESCRIPTION: 'A test project',
86-
MODULE_NAME: 'testmodule'
87-
},
88-
cacheTool: testCacheTool
98+
answers: buildAnswers('test'),
99+
toolName: testCacheTool,
100+
noTty: true,
101+
fromPath: TEST_TEMPLATE
89102
});
90103
}, 60000);
91104

@@ -128,11 +141,15 @@ describe('cached template integration tests', () => {
128141
});
129142

130143
it('should verify template cache was created', () => {
131-
const templateCache = new TemplateCache({
132-
enabled: true,
144+
// Verify cache was created by createFromTemplate
145+
const cacheManager = new CacheManager({
133146
toolName: testCacheTool,
134147
});
135-
const cachedRepo = templateCache.get(DEFAULT_TEMPLATE_URL);
148+
const gitCloner = new GitCloner();
149+
const normalizedUrl = gitCloner.normalizeUrl(DEFAULT_TEMPLATE_URL);
150+
const cacheKey = cacheManager.createKey(normalizedUrl);
151+
const cachedRepo = cacheManager.get(cacheKey);
152+
136153
expect(cachedRepo).not.toBeNull();
137154
expect(fs.existsSync(cachedRepo!)).toBe(true);
138155
});
@@ -143,28 +160,24 @@ describe('cached template integration tests', () => {
143160
let secondOutputDir: string;
144161

145162
beforeAll(async () => {
146-
await createFromCachedTemplate({
163+
await createFromTemplate({
147164
templateUrl: DEFAULT_TEMPLATE_URL,
148165
outputDir: fs.mkdtempSync(path.join(os.tmpdir(), 'warmup-')),
149-
answers: {
150-
PROJECT_NAME: 'warmup',
151-
MODULE_NAME: 'warmup'
152-
},
153-
cacheTool: testCacheTool
166+
answers: buildAnswers('warmup'),
167+
toolName: testCacheTool,
168+
noTty: true,
169+
fromPath: TEST_TEMPLATE
154170
});
155171

156172
secondOutputDir = fs.mkdtempSync(path.join(os.tmpdir(), 'second-clone-'));
157173

158-
secondCloneResult = await createFromCachedTemplate({
174+
secondCloneResult = await createFromTemplate({
159175
templateUrl: DEFAULT_TEMPLATE_URL,
160176
outputDir: secondOutputDir,
161-
answers: {
162-
PROJECT_NAME: 'cached-project',
163-
AUTHOR: 'Cached Author',
164-
DESCRIPTION: 'A cached test project',
165-
MODULE_NAME: 'cachedmodule'
166-
},
167-
cacheTool: testCacheTool
177+
answers: buildAnswers('cached'),
178+
toolName: testCacheTool,
179+
noTty: true,
180+
fromPath: TEST_TEMPLATE
168181
});
169182
}, 60000);
170183

0 commit comments

Comments
 (0)