Skip to content

Commit 947ca46

Browse files
coopernetesclaude
andcommitted
docs: restructure contributing docs and improve E2E test infrastructure
Move developer resources (setup, building, testing, code quality) into CONTRIBUTING.md and refocus the website's contributing page on project governance (roles, voting, CLA). Slim down localgit/README.md to a summary now that CONTRIBUTING.md covers E2E setup in detail. Rename E2E test repositories from real project names to clearly fake names (test-owner/test-repo, e2e-org/sample-repo). Add fail-fast pre-flight checks in E2E setup to detect missing Docker infrastructure. Add Docker Hub login to CI workflow to avoid pull rate limits. Remove outdated Mocha/Chai testing page from docs site and fix plugin import paths. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 6fb63d0 commit 947ca46

File tree

11 files changed

+549
-1309
lines changed

11 files changed

+549
-1309
lines changed

CONTRIBUTING.md

Lines changed: 365 additions & 39 deletions
Large diffs are not rendered by default.

localgit/README.md

Lines changed: 52 additions & 772 deletions
Large diffs are not rendered by default.

localgit/init-repos.sh

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ set -e # Exit on any error
33

44
# Create the git repositories directories for multiple owners
55
BASE_DIR="${BASE_DIR:-"/var/git"}"
6-
OWNERS=("coopernetes" "finos")
6+
OWNERS=("test-owner" "e2e-org")
77
TEMP_DIR="/tmp/git-init"
88

99
# Create base directory and owner subdirectories
@@ -27,11 +27,11 @@ create_bare_repo() {
2727
local owner="$1"
2828
local repo_name="$2"
2929
local repo_dir="$BASE_DIR/$owner"
30-
30+
3131
echo "Creating $repo_name in $owner's directory..."
3232
cd "$repo_dir" || exit 1
3333
git init --bare --initial-branch=main "$repo_name"
34-
34+
3535
# Configure for HTTP access
3636
cd "$repo_dir/$repo_name" || exit 1
3737
git config http.receivepack true
@@ -47,23 +47,23 @@ add_content_to_repo() {
4747
local repo_name="$2"
4848
local repo_path="$BASE_DIR/$owner/$repo_name"
4949
local work_dir="$TEMP_DIR/${owner}-${repo_name%-.*}-work"
50-
50+
5151
echo "Adding content to $owner/$repo_name..."
5252
cd "$TEMP_DIR" || exit 1
5353
git clone "$repo_path" "$work_dir"
5454
cd "$work_dir" || exit 1
5555
}
5656

5757
# Create repositories with simple content
58-
echo "=== Creating coopernetes/test-repo.git ==="
59-
create_bare_repo "coopernetes" "test-repo.git"
60-
add_content_to_repo "coopernetes" "test-repo.git"
58+
echo "=== Creating test-owner/test-repo.git ==="
59+
create_bare_repo "test-owner" "test-repo.git"
60+
add_content_to_repo "test-owner" "test-repo.git"
6161

6262
# Create a simple README
6363
cat > README.md << 'EOF'
6464
# Test Repository
6565
66-
This is a test repository for the git proxy, simulating coopernetes/test-repo.
66+
A dummy repository used for GitProxy end-to-end testing.
6767
EOF
6868

6969
# Create a simple text file
@@ -75,29 +75,29 @@ git add .
7575
git commit -m "Initial commit with basic content"
7676
git push origin main
7777

78-
echo "=== Creating finos/git-proxy.git ==="
79-
create_bare_repo "finos" "git-proxy.git"
80-
add_content_to_repo "finos" "git-proxy.git"
78+
echo "=== Creating e2e-org/sample-repo.git ==="
79+
create_bare_repo "e2e-org" "sample-repo.git"
80+
add_content_to_repo "e2e-org" "sample-repo.git"
8181

8282
# Create a simple README
8383
cat > README.md << 'EOF'
84-
# Git Proxy
84+
# Sample Repository
8585
86-
This is a test instance of the FINOS Git Proxy project for isolated e2e testing.
86+
A dummy repository used for GitProxy end-to-end testing.
8787
EOF
8888

89-
# Create a simple package.json to simulate the real project structure
89+
# Create a simple package.json to simulate a project structure
9090
cat > package.json << 'EOF'
9191
{
92-
"name": "git-proxy",
92+
"name": "sample-repo",
9393
"version": "1.0.0",
94-
"description": "A proxy for Git operations",
94+
"description": "A sample project for e2e testing",
9595
"main": "index.js",
9696
"scripts": {
9797
"test": "echo \"Error: no test specified\" && exit 1"
9898
},
99-
"keywords": ["git", "proxy", "finos"],
100-
"author": "FINOS",
99+
"keywords": ["git", "proxy", "test"],
100+
"author": "Test",
101101
"license": "Apache-2.0"
102102
}
103103
EOF
@@ -146,4 +146,4 @@ done
146146

147147
echo "Successfully initialized Git repositories in $BASE_DIR"
148148
echo "Owners created: ${OWNERS[*]}"
149-
echo "Total repositories: $(find $BASE_DIR -name "*.git" -type d | wc -l)"
149+
echo "Total repositories: $(find $BASE_DIR -name "*.git" -type d | wc -l)"

test-e2e.proxy.config.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
},
1212
"authorisedList": [
1313
{
14-
"project": "coopernetes",
14+
"project": "test-owner",
1515
"name": "test-repo",
16-
"url": "https://git-server:8443/coopernetes/test-repo.git"
16+
"url": "https://git-server:8443/test-owner/test-repo.git"
1717
},
1818
{
19-
"project": "finos",
20-
"name": "git-proxy",
21-
"url": "https://git-server:8443/finos/git-proxy.git"
19+
"project": "e2e-org",
20+
"name": "sample-repo",
21+
"url": "https://git-server:8443/e2e-org/sample-repo.git"
2222
}
2323
],
2424
"sink": [

tests/e2e/fetch.test.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ describe('Git Proxy E2E - Repository Fetch Tests', () => {
3737

3838
describe('Repository fetching through git proxy', () => {
3939
it(
40-
'should successfully fetch coopernetes/test-repo through git proxy',
40+
'should successfully fetch test-owner/test-repo through git proxy',
4141
async () => {
4242
// Build URL with embedded credentials for reliable authentication
4343
const baseUrl = new URL(testConfig.gitProxyUrl);
4444
baseUrl.username = testConfig.gitUsername;
4545
baseUrl.password = testConfig.gitPassword;
46-
const repoUrl = `${baseUrl.toString()}/coopernetes/test-repo.git`;
46+
const repoUrl = `${baseUrl.toString()}/test-owner/test-repo.git`;
4747
const cloneDir: string = path.join(tempDir, 'test-repo-clone');
4848

4949
console.log(
50-
`[TEST] Cloning ${testConfig.gitProxyUrl}/coopernetes/test-repo.git to ${cloneDir}`,
50+
`[TEST] Cloning ${testConfig.gitProxyUrl}/test-owner/test-repo.git to ${cloneDir}`,
5151
);
5252

5353
try {
@@ -73,7 +73,7 @@ describe('Git Proxy E2E - Repository Fetch Tests', () => {
7373
const readmePath: string = path.join(cloneDir, 'README.md');
7474
expect(fs.existsSync(readmePath)).toBe(true);
7575

76-
console.log('[TEST] Successfully fetched and verified coopernetes/test-repo');
76+
console.log('[TEST] Successfully fetched and verified test-owner/test-repo');
7777
} catch (error) {
7878
console.error('[TEST] Failed to clone repository:', error);
7979
throw error;
@@ -83,16 +83,18 @@ describe('Git Proxy E2E - Repository Fetch Tests', () => {
8383
);
8484

8585
it(
86-
'should successfully fetch finos/git-proxy through git proxy',
86+
'should successfully fetch e2e-org/sample-repo through git proxy',
8787
async () => {
8888
// Build URL with embedded credentials for reliable authentication
8989
const baseUrl = new URL(testConfig.gitProxyUrl);
9090
baseUrl.username = testConfig.gitUsername;
9191
baseUrl.password = testConfig.gitPassword;
92-
const repoUrl = `${baseUrl.toString()}/finos/git-proxy.git`;
93-
const cloneDir: string = path.join(tempDir, 'git-proxy-clone');
92+
const repoUrl = `${baseUrl.toString()}/e2e-org/sample-repo.git`;
93+
const cloneDir: string = path.join(tempDir, 'sample-repo-clone');
9494

95-
console.log(`[TEST] Cloning ${testConfig.gitProxyUrl}/finos/git-proxy.git to ${cloneDir}`);
95+
console.log(
96+
`[TEST] Cloning ${testConfig.gitProxyUrl}/e2e-org/sample-repo.git to ${cloneDir}`,
97+
);
9698

9799
try {
98100
const gitCloneCommand: string = `git clone ${repoUrl} ${cloneDir}`;
@@ -120,7 +122,7 @@ describe('Git Proxy E2E - Repository Fetch Tests', () => {
120122
const readmePath: string = path.join(cloneDir, 'README.md');
121123
expect(fs.existsSync(readmePath)).toBe(true);
122124

123-
console.log('[TEST] Successfully fetched and verified finos/git-proxy');
125+
console.log('[TEST] Successfully fetched and verified e2e-org/sample-repo');
124126
} catch (error) {
125127
console.error('[TEST] Failed to clone repository:', error);
126128
throw error;

tests/e2e/push.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ describe('Git Proxy E2E - Repository Push Tests', () => {
268268
// Get the test-repo repository and add permissions
269269
const repos = await getRepos(adminCookie);
270270
const testRepo = repos.find(
271-
(r: any) => r.url === 'https://git-server:8443/coopernetes/test-repo.git',
271+
(r: any) => r.url === 'https://git-server:8443/test-owner/test-repo.git',
272272
);
273273

274274
if (testRepo && testRepo._id) {
@@ -299,11 +299,11 @@ describe('Git Proxy E2E - Repository Push Tests', () => {
299299
const baseUrl = new URL(testConfig.gitProxyUrl);
300300
baseUrl.username = testConfig.gitUsername;
301301
baseUrl.password = testConfig.gitPassword;
302-
const repoUrl = `${baseUrl.toString()}/coopernetes/test-repo.git`;
302+
const repoUrl = `${baseUrl.toString()}/test-owner/test-repo.git`;
303303
const cloneDir: string = path.join(tempDir, 'test-repo-push');
304304

305305
console.log(
306-
`[TEST] Testing push operation to ${testConfig.gitProxyUrl}/coopernetes/test-repo.git`,
306+
`[TEST] Testing push operation to ${testConfig.gitProxyUrl}/test-owner/test-repo.git`,
307307
);
308308

309309
try {
@@ -421,7 +421,7 @@ describe('Git Proxy E2E - Repository Push Tests', () => {
421421
const baseUrl = new URL(testConfig.gitProxyUrl);
422422
baseUrl.username = authorizedUser.username;
423423
baseUrl.password = authorizedUser.password;
424-
const repoUrl = `${baseUrl.toString()}/coopernetes/test-repo.git`;
424+
const repoUrl = `${baseUrl.toString()}/test-owner/test-repo.git`;
425425
const cloneDir: string = path.join(tempDir, 'test-repo-authorized-push');
426426

427427
console.log(`[TEST] Testing authorized push with user ${authorizedUser.username}`);
@@ -583,7 +583,7 @@ describe('Git Proxy E2E - Repository Push Tests', () => {
583583
const baseUrl = new URL(testConfig.gitProxyUrl);
584584
baseUrl.username = authorizedUser.username;
585585
baseUrl.password = authorizedUser.password;
586-
const repoUrl = `${baseUrl.toString()}/coopernetes/test-repo.git`;
586+
const repoUrl = `${baseUrl.toString()}/test-owner/test-repo.git`;
587587
const cloneDir: string = path.join(tempDir, 'test-repo-approved-push');
588588

589589
console.log(

tests/e2e/setup.ts

Lines changed: 48 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
*/
2020

2121
import { beforeAll } from 'vitest';
22+
import { execSync } from 'child_process';
2223

2324
// Environment configuration - can be overridden for different environments
2425
export const testConfig = {
2526
gitProxyUrl: process.env.GIT_PROXY_URL || 'http://localhost:8000/git-server:8443',
2627
gitProxyUiUrl: process.env.GIT_PROXY_UI_URL || 'http://localhost:8081',
28+
gitServerUrl: process.env.GIT_SERVER_URL || 'https://localhost:8443',
2729
timeout: parseInt(process.env.E2E_TIMEOUT || '30000'),
28-
maxRetries: parseInt(process.env.E2E_MAX_RETRIES || '30'),
29-
retryDelay: parseInt(process.env.E2E_RETRY_DELAY || '2000'),
3030
// Git credentials for authentication
3131
gitUsername: process.env.GIT_USERNAME || 'admin',
3232
gitPassword: process.env.GIT_PASSWORD || 'admin123',
@@ -39,96 +39,69 @@ export const testConfig = {
3939
: 'http://localhost:8000/'),
4040
};
4141

42+
const INFRA_HINT =
43+
'The E2E test infrastructure is not running. ' +
44+
'Start it with: docker compose up -d\n' +
45+
'See CONTRIBUTING.md for details.';
46+
4247
/**
43-
* Configures git credentials for authentication in a temporary directory
44-
* @param {string} tempDir - The temporary directory to configure git in
48+
* Verifies GitProxy is reachable by hitting its healthcheck endpoint.
49+
* Fails immediately instead of retrying — if the infrastructure isn't
50+
* running we want to fail fast with a helpful message.
4551
*/
46-
export function configureGitCredentials(tempDir: string): void {
47-
const { execSync } = require('child_process');
48-
52+
async function checkGitProxy(): Promise<void> {
53+
const healthUrl = `${testConfig.gitProxyUiUrl}/api/v1/healthcheck`;
4954
try {
50-
// Configure git credentials using URL rewriting
51-
const baseUrlParsed = new URL(testConfig.gitProxyBaseUrl);
52-
53-
// Initialize git if not already done
54-
try {
55-
execSync('git rev-parse --git-dir', { cwd: tempDir, encoding: 'utf8', stdio: 'pipe' });
56-
} catch {
57-
execSync('git init', { cwd: tempDir, encoding: 'utf8' });
58-
}
59-
60-
// Configure multiple URL patterns to catch all variations
61-
const patterns = [
62-
// Most important: the proxy server itself (this is what's asking for auth)
63-
{
64-
insteadOf: `${baseUrlParsed.protocol}//${baseUrlParsed.host}`,
65-
credUrl: `${baseUrlParsed.protocol}//${testConfig.gitUsername}:${testConfig.gitPassword}@${baseUrlParsed.host}`,
66-
},
67-
// Base URL with trailing slash
68-
{
69-
insteadOf: testConfig.gitProxyBaseUrl,
70-
credUrl: `${baseUrlParsed.protocol}//${testConfig.gitUsername}:${testConfig.gitPassword}@${baseUrlParsed.host}${baseUrlParsed.pathname}`,
71-
},
72-
// Base URL without trailing slash
73-
{
74-
insteadOf: testConfig.gitProxyBaseUrl.replace(/\/$/, ''),
75-
credUrl: `${baseUrlParsed.protocol}//${testConfig.gitUsername}:${testConfig.gitPassword}@${baseUrlParsed.host}`,
76-
},
77-
];
78-
79-
for (const pattern of patterns) {
80-
execSync(`git config url."${pattern.credUrl}".insteadOf "${pattern.insteadOf}"`, {
81-
cwd: tempDir,
82-
encoding: 'utf8',
83-
});
55+
const response = await fetch(healthUrl, {
56+
method: 'GET',
57+
signal: AbortSignal.timeout(5000),
58+
});
59+
if (response.ok || response.status < 500) {
60+
console.log(`GitProxy is reachable at ${testConfig.gitProxyUiUrl}`);
61+
return;
8462
}
85-
} catch (error) {
86-
console.error('Failed to configure git credentials:', error);
87-
throw error;
63+
throw new Error(`Healthcheck returned HTTP ${response.status}`);
64+
} catch (error: any) {
65+
throw new Error(`GitProxy is not reachable at ${healthUrl}.\n${INFRA_HINT}`);
8866
}
8967
}
9068

91-
export async function waitForService(
92-
url: string,
93-
maxAttempts?: number,
94-
delay?: number,
95-
): Promise<void> {
96-
const attempts = maxAttempts || testConfig.maxRetries;
97-
const retryDelay = delay || testConfig.retryDelay;
98-
99-
for (let i = 0; i < attempts; i++) {
100-
try {
101-
const response = await fetch(url, {
102-
method: 'GET',
103-
headers: { Accept: 'application/json' },
104-
});
105-
if (response.ok || response.status < 500) {
106-
console.log(`Service at ${url} is ready`);
107-
return;
108-
}
109-
} catch (error) {
110-
// Service not ready yet
111-
}
112-
113-
if (i < attempts - 1) {
114-
console.log(`Waiting for service at ${url}... (attempt ${i + 1}/${attempts})`);
115-
await new Promise((resolve) => setTimeout(resolve, retryDelay));
116-
}
69+
/**
70+
* Verifies the local git server is reachable by running `git ls-remote`
71+
* against a known test repository.
72+
*/
73+
function checkGitServer(): void {
74+
const repoUrl = `${testConfig.gitServerUrl}/test-owner/test-repo.git`;
75+
try {
76+
execSync(`git ls-remote ${repoUrl}`, {
77+
encoding: 'utf8',
78+
timeout: 10000,
79+
env: {
80+
...process.env,
81+
GIT_TERMINAL_PROMPT: '0',
82+
GIT_SSL_NO_VERIFY: '1',
83+
},
84+
stdio: 'pipe',
85+
});
86+
console.log(`Git server is reachable at ${testConfig.gitServerUrl}`);
87+
} catch (error: any) {
88+
throw new Error(`Git server is not reachable at ${repoUrl}.\n${INFRA_HINT}`);
11789
}
118-
119-
throw new Error(`Service at ${url} failed to become ready after ${attempts} attempts`);
12090
}
12191

12292
beforeAll(async () => {
12393
console.log('Setting up e2e test environment...');
12494
console.log(`Git Proxy URL: ${testConfig.gitProxyUrl}`);
12595
console.log(`Git Proxy UI URL: ${testConfig.gitProxyUiUrl}`);
96+
console.log(`Git Server URL: ${testConfig.gitServerUrl}`);
12697
console.log(`Git Username: ${testConfig.gitUsername}`);
12798
console.log(`Git Proxy Base URL: ${testConfig.gitProxyBaseUrl}`);
12899

129-
// Wait for the git proxy UI service to be ready
130-
// Note: Docker Compose should be started externally (e.g., in CI or manually)
131-
await waitForService(`${testConfig.gitProxyUiUrl}/api/v1/healthcheck`);
100+
// Pre-flight: verify both services are reachable before running any tests.
101+
// These checks fail fast so developers get a clear error instead of
102+
// waiting through retries when the Docker environment isn't running.
103+
await checkGitProxy();
104+
checkGitServer();
132105

133106
console.log('E2E test environment is ready');
134107
}, testConfig.timeout);

0 commit comments

Comments
 (0)