WIP: A simple cli for daily tangled use cases and AI integration. This is for my personal use right now, but happy if others get mileage from it! :)
at main 148 lines 5.4 kB view raw
1import { describe, expect, it } from 'vitest'; 2import { isTangledRemote, parseTangledRemote } from '../../src/utils/git.js'; 3 4describe('Git Utilities', () => { 5 describe('isTangledRemote', () => { 6 it('should detect SSH tangled remotes', () => { 7 expect(isTangledRemote('git@tangled.org:did:plc:abc123/repo.git')).toBe(true); 8 expect(isTangledRemote('ssh://git@tangled.org/did:plc:abc123/repo.git')).toBe(true); 9 }); 10 11 it('should detect HTTPS tangled remotes', () => { 12 expect(isTangledRemote('https://tangled.org/markbennett.ca/tangled-cli')).toBe(true); 13 expect(isTangledRemote('https://tangled.org/user.bsky.social/repo')).toBe(true); 14 }); 15 16 it('should reject non-tangled remotes', () => { 17 expect(isTangledRemote('git@github.com:user/repo.git')).toBe(false); 18 expect(isTangledRemote('https://github.com/user/repo')).toBe(false); 19 expect(isTangledRemote('https://gitlab.com/user/repo')).toBe(false); 20 expect(isTangledRemote('')).toBe(false); 21 }); 22 }); 23 24 describe('parseTangledRemote', () => { 25 describe('SSH URLs with DIDs', () => { 26 it('should parse git@tangled.org:did:plc:xxx/repo.git format', () => { 27 const result = parseTangledRemote( 28 'git@tangled.org:did:plc:b2mcbcamkwyznc5fkplwlxbf/tangled-cli.git' 29 ); 30 expect(result).toEqual({ 31 owner: 'did:plc:b2mcbcamkwyznc5fkplwlxbf', 32 ownerType: 'did', 33 name: 'tangled-cli', 34 protocol: 'ssh', 35 }); 36 }); 37 38 it('should parse ssh://git@tangled.org/did:plc:xxx/repo.git format', () => { 39 const result = parseTangledRemote( 40 'ssh://git@tangled.org/did:plc:b2mcbcamkwyznc5fkplwlxbf/tangled-cli.git' 41 ); 42 expect(result).toEqual({ 43 owner: 'did:plc:b2mcbcamkwyznc5fkplwlxbf', 44 ownerType: 'did', 45 name: 'tangled-cli', 46 protocol: 'ssh', 47 }); 48 }); 49 50 it('should handle SSH URLs without .git extension', () => { 51 const result = parseTangledRemote('git@tangled.org:did:plc:abc123/repo'); 52 expect(result).toEqual({ 53 owner: 'did:plc:abc123', 54 ownerType: 'did', 55 name: 'repo', 56 protocol: 'ssh', 57 }); 58 }); 59 }); 60 61 describe('SSH URLs with handles', () => { 62 it('should parse SSH URL with handle instead of DID', () => { 63 const result = parseTangledRemote('git@tangled.org:markbennett.ca/tangled-cli.git'); 64 expect(result).toEqual({ 65 owner: 'markbennett.ca', 66 ownerType: 'handle', 67 name: 'tangled-cli', 68 protocol: 'ssh', 69 }); 70 }); 71 }); 72 73 describe('HTTPS URLs with handles', () => { 74 it('should parse https://tangled.org/handle/repo format', () => { 75 const result = parseTangledRemote('https://tangled.org/markbennett.ca/tangled-cli'); 76 expect(result).toEqual({ 77 owner: 'markbennett.ca', 78 ownerType: 'handle', 79 name: 'tangled-cli', 80 protocol: 'https', 81 }); 82 }); 83 84 it('should parse HTTPS with user.bsky.social handle', () => { 85 const result = parseTangledRemote('https://tangled.org/user.bsky.social/repo'); 86 expect(result).toEqual({ 87 owner: 'user.bsky.social', 88 ownerType: 'handle', 89 name: 'repo', 90 protocol: 'https', 91 }); 92 }); 93 94 it('should handle HTTPS URLs without .git extension', () => { 95 const result = parseTangledRemote('https://tangled.org/markbennett.ca/repo'); 96 expect(result?.name).toBe('repo'); 97 }); 98 }); 99 100 describe('HTTPS URLs with DIDs', () => { 101 it('should parse HTTPS URL with DID instead of handle', () => { 102 const result = parseTangledRemote( 103 'https://tangled.org/did:plc:b2mcbcamkwyznc5fkplwlxbf/repo' 104 ); 105 expect(result).toEqual({ 106 owner: 'did:plc:b2mcbcamkwyznc5fkplwlxbf', 107 ownerType: 'did', 108 name: 'repo', 109 protocol: 'https', 110 }); 111 }); 112 }); 113 114 describe('edge cases', () => { 115 it('should handle trailing slashes', () => { 116 const result = parseTangledRemote('https://tangled.org/markbennett.ca/repo/'); 117 expect(result?.name).toBe('repo'); 118 }); 119 120 it('should handle .git extension in various positions', () => { 121 const result1 = parseTangledRemote('git@tangled.org:did:plc:abc123/repo.git'); 122 const result2 = parseTangledRemote('https://tangled.org/markbennett.ca/repo.git'); 123 expect(result1?.name).toBe('repo'); 124 expect(result2?.name).toBe('repo'); 125 }); 126 127 it('should return null for invalid DID format', () => { 128 const result = parseTangledRemote('git@tangled.org:did:plc:INVALID/repo.git'); 129 expect(result).toBeNull(); 130 }); 131 132 it('should return null for invalid handle format', () => { 133 const result = parseTangledRemote('https://tangled.org/invalid/repo'); 134 expect(result).toBeNull(); 135 }); 136 137 it('should return null for missing repo name', () => { 138 const result = parseTangledRemote('git@tangled.org:did:plc:abc123'); 139 expect(result).toBeNull(); 140 }); 141 142 it('should return null for non-tangled URLs', () => { 143 expect(parseTangledRemote('git@github.com:user/repo.git')).toBeNull(); 144 expect(parseTangledRemote('https://github.com/user/repo')).toBeNull(); 145 }); 146 }); 147 }); 148});