-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
1,832 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
name: Checks | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
- development | ||
pull_request: | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
preflight: | ||
if: ${{ github.event.pull_request.head.ref != 'main' && github.event.pull_request.head.ref != 'development' }} | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [18.x, 20.x, 21.x] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- name: Load node modules cache | ||
id: modules-cache | ||
uses: actions/cache@v4 | ||
timeout-minutes: 5 | ||
continue-on-error: true | ||
with: | ||
path: | | ||
**/node_modules | ||
key: ${{ runner.OS }}-modules-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: | | ||
${{ runner.OS }}-modules-${{ matrix.node-version }}- | ||
- name: install modules | ||
run: | | ||
npm install --no-audit --force --loglevel=error --no-update-notifier | ||
linting: | ||
needs: preflight | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: latest | ||
- name: Load node modules cache | ||
id: modules-cache | ||
uses: actions/cache/restore@v4 | ||
timeout-minutes: 5 | ||
continue-on-error: false | ||
with: | ||
fail-on-cache-miss: true | ||
path: | | ||
**/node_modules | ||
key: ${{ runner.OS }}-modules-20.x-${{ hashFiles('**/package-lock.json') }} | ||
- name: linting | ||
run: | | ||
npm run build | ||
npm run lint | ||
typecheck: | ||
needs: preflight | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: latest | ||
- name: Load node modules cache | ||
id: modules-cache | ||
uses: actions/cache/restore@v4 | ||
timeout-minutes: 5 | ||
continue-on-error: false | ||
with: | ||
fail-on-cache-miss: true | ||
path: | | ||
**/node_modules | ||
key: ${{ runner.OS }}-modules-20.x-${{ hashFiles('**/package-lock.json') }} | ||
- name: typecheck | ||
run: | | ||
npm run build | ||
npm run type-check | ||
unit-tests: | ||
needs: preflight | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [18.x, 20.x, 21.x] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- name: Load node modules cache | ||
id: modules-cache | ||
uses: actions/cache/restore@v4 | ||
timeout-minutes: 5 | ||
continue-on-error: false | ||
with: | ||
fail-on-cache-miss: true | ||
path: | | ||
**/node_modules | ||
key: ${{ runner.OS }}-modules-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} | ||
- name: unit testing | ||
run: | | ||
npm run build | ||
npm test -- --coverage run | ||
- name: Upload coverage reports to Codecov | ||
uses: codecov/codecov-action@v4 | ||
env: | ||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | ||
|
||
build: | ||
needs: preflight | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [18.x, 20.x, 21.x] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- name: Load node modules cache | ||
id: modules-cache | ||
uses: actions/cache/restore@v4 | ||
timeout-minutes: 5 | ||
continue-on-error: false | ||
with: | ||
fail-on-cache-miss: true | ||
path: | | ||
**/node_modules | ||
key: ${{ runner.OS }}-modules-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} | ||
- name: build package | ||
run: | | ||
npm run build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
/tmp | ||
dist | ||
node_modules | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
/* eslint-disable no-restricted-syntax */ | ||
/* eslint-disable no-await-in-loop */ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import { describe, it, expect, afterAll, vi } from 'vitest' | ||
import temp from 'temp' | ||
import executeCommand from '../src/utils/executeCommand.js' | ||
import { add, update, commit, remove } from '../src/commands.js' | ||
import { createConfig, parseConfig } from '../src/config' | ||
import latestHash from '../src/utils/git/latestHash.js' | ||
|
||
const exists = async (file: string) => fs.promises.access(file) | ||
.then(() => true) | ||
.catch(() => false) | ||
|
||
async function setupGit( | ||
gitFiles: Record<string, string>, | ||
dependencies: { | ||
repo?: string, | ||
hash?: string, | ||
remotePath: string, | ||
localPath: string, | ||
}[] = [], | ||
) { | ||
await executeCommand('git config --global user.email "[email protected]"') | ||
await executeCommand('git config --global user.name "Test User"') | ||
|
||
const testFolder = temp.mkdirSync() | ||
const gitFolder = temp.mkdirSync() | ||
|
||
await executeCommand('git init', { cwd: gitFolder }) | ||
await executeCommand('git config receive.denyCurrentBranch ignore', { cwd: gitFolder }) | ||
for (const [file, content] of Object.entries(gitFiles)) { | ||
await fs.promises.writeFile(path.join(gitFolder, file), content) | ||
} | ||
|
||
await executeCommand('git add .', { cwd: gitFolder }) | ||
await executeCommand('git commit -m "initial commit"', { cwd: gitFolder }) | ||
const hash = await latestHash(gitFolder) | ||
|
||
await fs.promises.writeFile( | ||
path.join(testFolder, 'blend.yml'), | ||
createConfig({ | ||
dependencies: dependencies.map(dep => ({ | ||
repo: dep.repo ?? gitFolder, | ||
hash: dep.hash ?? hash, | ||
remotePath: dep.remotePath, | ||
localPath: dep.localPath, | ||
})), | ||
}), | ||
) | ||
await expect(exists(path.join(testFolder, 'blend.yml'))).resolves.toBe(true) | ||
|
||
vi.spyOn(process, 'cwd').mockReturnValue(testFolder) | ||
if (dependencies.length > 0) await update() | ||
for (const dep of dependencies) { | ||
const localPath = path.join(testFolder, dep.localPath) | ||
await expect(exists(localPath)).resolves.toBe(true) | ||
} | ||
|
||
return { testFolder, gitFolder } | ||
} | ||
|
||
describe('blend cli', () => { | ||
describe('add', () => { | ||
it('should add a dependency', async () => { | ||
const { testFolder, gitFolder } = await setupGit({ 'test.txt': 'test' }) | ||
await expect(add(gitFolder, 'test.txt')).resolves.not.toThrow() | ||
await expect(exists(path.join(testFolder, 'test.txt'))).resolves.toBe(true) | ||
|
||
await expect(exists(path.join(testFolder, 'blend.yml'))).resolves.toBe(true) | ||
const config = parseConfig(await fs.promises.readFile( | ||
path.join(testFolder, 'blend.yml'), | ||
'utf-8', | ||
)) | ||
expect(config).toMatchObject({ | ||
dependencies: [{ | ||
repo: gitFolder, | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}], | ||
}) | ||
}) | ||
|
||
it('should add a dependency with a local path', async () => { | ||
const { testFolder, gitFolder } = await setupGit({ 'test.txt': 'test' }) | ||
|
||
await expect(add(gitFolder, 'test.txt', 'test2.txt')).resolves.not.toThrow() | ||
await expect(exists(path.join(testFolder, 'test2.txt'))).resolves.toBe(true) | ||
|
||
await expect(exists(path.join(testFolder, 'blend.yml'))).resolves.toBe(true) | ||
const config = parseConfig(await fs.promises.readFile( | ||
path.join(testFolder, 'blend.yml'), | ||
'utf-8', | ||
)) | ||
expect(config).toMatchObject({ | ||
dependencies: [{ | ||
repo: gitFolder, | ||
remotePath: 'test.txt', | ||
localPath: 'test2.txt', | ||
}], | ||
}) | ||
}) | ||
|
||
it('should add a dependency with a branch', async () => { | ||
const { testFolder, gitFolder } = await setupGit({ 'test.txt': 'test' }) | ||
|
||
await expect(add(`${gitFolder}#main`, 'test.txt', 'test3.txt')).resolves.not.toThrow() | ||
Check failure on line 108 in __tests__/cli.spec.ts
|
||
await expect(exists(path.join(testFolder, 'test3.txt'))).resolves.toBe(true) | ||
|
||
await expect(exists(path.join(testFolder, 'blend.yml'))).resolves.toBe(true) | ||
const config = parseConfig(await fs.promises.readFile( | ||
path.join(testFolder, 'blend.yml'), | ||
'utf-8', | ||
)) | ||
expect(config).toMatchObject({ | ||
dependencies: [{ | ||
repo: `${gitFolder}#main`, | ||
remotePath: 'test.txt', | ||
localPath: 'test3.txt', | ||
}], | ||
}) | ||
}) | ||
|
||
it('should fail if the local path already exists', async () => { | ||
const { gitFolder } = await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(add(gitFolder, 'test.txt')).rejects.toThrowError() | ||
}) | ||
|
||
it('should fail if the repository does not exist', async () => { | ||
await setupGit({ 'test.txt': 'test' }) | ||
await expect(add('/tmp/does-not-exist', 'test.txt')).rejects.toThrowError() | ||
}) | ||
|
||
it('should fail if the remote path does not exist', async () => { | ||
const { gitFolder } = await setupGit({ 'test.txt': 'test' }) | ||
await expect(add(gitFolder, 'does-not-exist')).rejects.toThrowError() | ||
}) | ||
}) | ||
|
||
describe('update', () => { | ||
it('should update all dependencies', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(update()).resolves.not.toThrow() | ||
}) | ||
|
||
it('should fail if there are no dependencies', async () => { | ||
await setupGit({ 'test.txt': 'test' }) | ||
await expect(update()).rejects.toThrowError() | ||
}) | ||
}) | ||
|
||
describe('commit', () => { | ||
it('should fail if the dependency has no changes', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(commit('test.txt', 'commit message')).rejects.toThrowError() | ||
}) | ||
|
||
it('should fail if the commit message is empty', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(commit('test.txt', '')).rejects.toThrowError() | ||
}) | ||
|
||
it('should commit a dependency', async () => { | ||
const { testFolder } = await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await fs.promises.writeFile(path.join(testFolder, 'test.txt'), 'test2') | ||
console.log('TestFolder', testFolder) | ||
await expect(commit('test.txt', 'commit message')).resolves.not.toThrow() | ||
}) | ||
|
||
it('should fail if the dependency does not exist', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(commit('does-not-exist', 'commit message')).rejects.toThrowError() | ||
}) | ||
}) | ||
|
||
describe('remove', () => { | ||
it('should remove a dependency', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(remove('test.txt')).resolves.not.toThrow() | ||
}) | ||
|
||
it('should fail if the dependency does not exist', async () => { | ||
await setupGit({ 'test.txt': 'test' }, [{ | ||
remotePath: 'test.txt', | ||
localPath: 'test.txt', | ||
}]) | ||
await expect(remove('does-not-exist')).rejects.toThrowError() | ||
}) | ||
}) | ||
|
||
afterAll(() => { | ||
temp.cleanupSync() | ||
}) | ||
}) |
Oops, something went wrong.