Skip to content

Commit

Permalink
feat: add pnpm support
Browse files Browse the repository at this point in the history
  • Loading branch information
hulkoba authored and Realtin committed Jun 26, 2019
1 parent b577d0d commit e6ee360
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 36 deletions.
2 changes: 1 addition & 1 deletion content/initial-pr.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ There is a collection of [frequently asked questions](https://greenkeeper.io/faq
// needs to handle files as an array of arrays!
function hasLockFileText (files) {
if (!files) return
const lockFiles = ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'].filter((key) => {
const lockFiles = ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock', 'pnpm-lock.yaml'].filter((key) => {
if (_.isArray(files[key]) && files[key].length) {
return true
}
Expand Down
1 change: 1 addition & 0 deletions jobs/github-event/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module.exports = async function (data) {
'package.json',
'package-lock.json',
'npm-shrinkwrap.json',
'pnpm-lock.yaml',
'yarn.lock',
'greenkeeper.json'
]
Expand Down
13 changes: 8 additions & 5 deletions lib/create-branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,20 @@ module.exports = async (
oldVersion: transform.oldVersion
}
})

log.info('starting lockfile update', { lockfilePath, versions })

const oldLockfile = await getGithubFile(ghqueue, { path: lockfilePath, owner, repo: repoName, sha: branch }, log)
const oldLockfileContent = Buffer.from(oldLockfile.content, 'base64').toString()

const isNpm = lockfilePath.includes('package-lock.json')
try {
const { tokens, 'token-audits': tokenAudits } = await dbs() // eslint-disable-line

/*
This is the structure of the tokens 'model'
_id: `${accountId}
tokens: {
${repoId}: {
tokens: {
${repoId}: {
npm: ${token},
github: ${token}
}
Expand All @@ -141,7 +141,6 @@ module.exports = async (
if (repositoryTokens) {
execTokens = JSON.stringify(repositoryTokens.tokens[repoDoc._id])
const datetime = new Date().toISOString().substr(0, 19).replace(/[^0-9]/g, '')

// write audit log entry to 'token-audits' db
// log entry type: 'read'
try {
Expand All @@ -154,7 +153,11 @@ module.exports = async (
}
}

const { ok, contents, error } = await getNewLockfile({ packageJson: commit.content, lock: oldLockfileContent, isNpm, repositoryTokens: execTokens })
let type = 'npm'
if (lockfilePath.includes('pnpm-lock.yaml')) type = 'pnpm'
if (lockfilePath.includes('yarn.lock')) type = 'yarn'

const { ok, contents, error } = await getNewLockfile({ packageJson: commit.content, lock: oldLockfileContent, type, repositoryTokens: execTokens })
if (ok) {
// !ok means the old and new lockfile are the same, so we don’t make a commit
log.info(`new lockfile contents for ${lockfilePath} received`)
Expand Down
2 changes: 2 additions & 0 deletions lib/get-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const fileList = [
'package.json',
'package-lock.json',
'npm-shrinkwrap.json',
'pnpm-lock.yaml',
'yarn.lock'
]

Expand Down Expand Up @@ -92,6 +93,7 @@ function addRelatedLockfilePaths (files) {
files.map(path => {
relatedLockfilePaths.push(path.replace('package.json', 'package-lock.json'))
relatedLockfilePaths.push(path.replace('package.json', 'yarn.lock'))
relatedLockfilePaths.push(path.replace('package.json', 'pnpm-lock.yaml'))
relatedLockfilePaths.push(path.replace('package.json', 'npm-shrinkwrap.json'))
})
return relatedLockfilePaths
Expand Down
3 changes: 1 addition & 2 deletions lib/lockfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ async function findNextServer () {
})
return sortedServers[0]
}
async function getNewLockfile ({ packageJson, lock, isNpm, repositoryTokens }) {
async function getNewLockfile ({ packageJson, lock, type, repositoryTokens }) {
const logs = dbs.getLogsDb()
const log = Log({
logsDb: logs,
accountId: 'lockfile',
repoSlug: null,
context: 'lockfile'
})
const type = isNpm ? 'npm' : 'yarn'
const nextServer = await findNextServer()
jobCountByServer[nextServer] = jobCountByServer[nextServer] ? jobCountByServer[nextServer] + 1 : 1
return promiseRetry((retry, number) => {
Expand Down
3 changes: 2 additions & 1 deletion lib/repository-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ async function updateRepoDoc ({ installationId, doc, filePaths, log }) {
'package.json': [],
'package-lock.json': [],
'yarn.lock': [],
'npm-shrinkwrap.json': []
'npm-shrinkwrap.json': [],
'pnpm-lock.yaml': []
}
let filePathsFromConfig = []

Expand Down
11 changes: 10 additions & 1 deletion test/lib/__snapshots__/create-branch.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`create branch with lockfiles change one file (package.json) and generate its lockfile (old syntax) 1`] = `
exports[`create branch with lockfiles change a package.json and generate its lockfile for pnpm 1`] = `
Object {
"lock": "{\\"devDependencies\\":{\\"jest\\":\\"1.1.1\\"}}",
"packageJson": "{\\"devDependencies\\":{\\"jest\\":\\"1.2.0\\"}}",
"repositoryTokens": "",
"type": "pnpm",
}
`;

exports[`create branch with lockfiles change one file (package.json) and generate its lockfile 1`] = `
Object {
"lock": "{\\"devDependencies\\":{\\"jest\\":\\"1.1.1\\"}}",
"packageJson": "{\\"devDependencies\\":{\\"jest\\":\\"1.2.0\\"}}",
Expand Down
181 changes: 165 additions & 16 deletions test/lib/create-branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -768,8 +768,8 @@ describe('create branch', async () => {
})
})

describe('create branch with lockfiles', async () => {
test('change one file (package.json) and generate its lockfile (old syntax)', async () => {
describe('create branch with lockfiles', () => {
test('change one file (package.json) and generate its lockfile', async () => {
const packageFileContents = { devDependencies: {
'jest': '1.1.1'
} }
Expand Down Expand Up @@ -889,10 +889,11 @@ describe('create branch with lockfiles', async () => {
fullName: 'finnp/one-lockfile-old-syntax',
private: false,
files: {
'package.json': true,
'package-lock.json': true,
'npm-shrinkwrap.json': false,
'yarn.lock': false
'package.json': ['package.json'],
'package-lock.json': ['package-lock.json'],
'npm-shrinkwrap.json': [],
'yarn.lock': [],
'pnpm-lock.yaml': []
},
packages: {
'package.json': {
Expand Down Expand Up @@ -1112,7 +1113,8 @@ describe('create branch with lockfiles', async () => {
'package.json': ['package.json', 'frontend/package.json'],
'package-lock.json': ['package-lock.json', 'frontend/package-lock.json'],
'npm-shrinkwrap.json': [],
'yarn.lock': []
'yarn.lock': [],
'pnpm-lock.yaml': []
},
packages: {
'package.json': {
Expand All @@ -1133,6 +1135,150 @@ describe('create branch with lockfiles', async () => {
expect(gitHubNock.isDone()).toBeTruthy()
})

test('change a package.json and generate its lockfile for pnpm', async () => {
const packageFileContents = { devDependencies: {
'jest': '1.1.1'
} }
const updatedPackageFileContents = { devDependencies: {
'jest': '1.2.0'
} }
const gitHubNock = nock('https://api.github.com')
.post('/app/installations/123/access_tokens')
.optionally()
.reply(200, {
token: 'secret'
})
.get('/rate_limit')
.optionally()
.reply(200)
.get('/repos/owner/repo/contents/package.json')
.query({ ref: 'master' })
.reply(200, {
type: 'file',
content: Buffer.from(JSON.stringify(packageFileContents)).toString('base64')
})
.get('/repos/owner/repo/contents/pnpm-lock.yaml')
.reply(200, {
type: 'file',
path: 'pnpm-lock.yaml',
name: 'pnpm-lock.yaml',
content: Buffer.from(JSON.stringify(packageFileContents)).toString('base64')
})
.get('/repos/owner/repo/git/refs/heads/master')
.reply(200, {
object: {
sha: '123abc'
}
})
// First tree and commit for package.json
.post('/repos/owner/repo/git/trees', {
tree: [
{
path: 'package.json',
content: JSON.stringify(updatedPackageFileContents),
mode: '100644',
type: 'blob'
}
],
base_tree: '123abc'
})
.reply(201, {
sha: 'def456'
})
.post('/repos/owner/repo/git/commits', {
message: 'new commit',
tree: 'def456',
parents: ['123abc']
})
.reply(201, {
sha: '789beef'
})
// Second tree and commit for pnpm-lock.yaml
.post('/repos/owner/repo/git/trees', {
tree: [
{
path: 'pnpm-lock.yaml',
content: '{"devDependencies":{"jest": {"version": "1.2.0"}}}',
mode: '100644',
type: 'blob'
}
],
base_tree: '789beef'
})
.reply(201, {
sha: 'lol999'
})
.post('/repos/owner/repo/git/commits', {
message: 'Updated lockfile pnpm-lock.yaml, yay',
tree: 'lol999',
parents: ['789beef']
})
.reply(201, {
sha: 'finalsha123'
})
.post('/repos/owner/repo/git/refs', {
ref: 'refs/heads/testBranch',
sha: 'finalsha123'
})
.reply(201)

nock('http://localhost:1234')
.post('/', (body) => {
expect(body.packageJson).toEqual(JSON.stringify(updatedPackageFileContents))
expect(body.type).toEqual('pnpm')
expect(typeof body.packageJson).toBe('string')
expect(typeof body.lock).toBe('string')
expect(body).toMatchSnapshot()
return true
})
.reply(200, () => {
return {
ok: true,
contents: '{"devDependencies":{"jest": {"version": "1.2.0"}}}'
}
})

const sha = await createBranch({
installationId: 123,
owner: 'owner',
repoName: 'repo',
branch: 'master',
newBranch: 'testBranch',
transforms: [
{
path: 'package.json',
transform: oldPkg => JSON.stringify(updatedPackageFileContents),
message: 'new commit'
}
],
processLockfiles: true,
commitMessageTemplates: { 'lockfileUpdate': 'Updated lockfile ${lockfilePath}, yay' }, // eslint-disable-line no-template-curly-in-string
repoDoc: {
_id: 'one-lockfile-pnpm',
accountId: '124',
fullName: 'finnp/one-lockfile-pnpm',
private: false,
files: {
'package.json': ['package.json'],
'package-lock.json': [],
'npm-shrinkwrap.json': [],
'yarn.lock': [],
'pnpm-lock.yaml': ['pnpm-lock.yaml']
},
packages: {
'package.json': {
devDependencies: {
'jest': '1.0.0'
}
}
}
}
})

expect(sha).toEqual('finalsha123')
expect(gitHubNock.isDone()).toBeTruthy()
})

test('don’t generate the same lockfile multiple times', async () => {
// multiple commits to the same package file should only result in a single lockfile update,
// meaning a single exec server request and a single github tree update plus commit
Expand Down Expand Up @@ -1296,7 +1442,8 @@ describe('create branch with lockfiles', async () => {
'package.json': ['package.json'],
'package-lock.json': ['package-lock.json'],
'npm-shrinkwrap.json': [],
'yarn.lock': []
'yarn.lock': [],
'pnpm-lock.yaml': []
},
packages: {
'package.json': {
Expand Down Expand Up @@ -1407,10 +1554,11 @@ describe('create branch with lockfiles', async () => {
fullName: 'finnp/one-lockfile-old-syntax',
private: false,
files: {
'package.json': true,
'package-lock.json': true,
'npm-shrinkwrap.json': false,
'yarn.lock': false
'package.json': ['package.json'],
'package-lock.json': ['package-lock.json'],
'npm-shrinkwrap.json': [],
'yarn.lock': [],
'pnpm-lock.yaml': []
},
packages: {
'package.json': {
Expand Down Expand Up @@ -1559,10 +1707,11 @@ describe('create branch with lockfiles', async () => {
fullName: 'finnp/one-lockfile-with-token',
private: false,
files: {
'package.json': true,
'package-lock.json': true,
'npm-shrinkwrap.json': false,
'yarn.lock': false
'package.json': ['package.json'],
'package-lock.json': ['package-lock.json'],
'npm-shrinkwrap.json': [],
'yarn.lock': [],
'pnpm-lock.yaml': []
},
packages: {
'package.json': {
Expand Down
8 changes: 4 additions & 4 deletions test/lib/get-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ test('getFiles: with no fileList provided', async () => {
const files = await getFiles({ installationId: '123', fullName: 'owner/repo', log })

// returns an Object with the 4 standard files
expect(Object.keys(files)).toHaveLength(4)
expect(Object.keys(files)).toHaveLength(5)
})

test('getFiles: 2 package.json files', async () => {
Expand Down Expand Up @@ -66,8 +66,8 @@ test('getFiles: 2 package.json files', async () => {
]

const files = await getFiles({ installationId: '123', fullName: 'owner/repo', files: fileList, log })
// returns an Object with the 4 file types
expect(Object.keys(files)).toHaveLength(4)
// returns an Object with the 5 file types
expect(Object.keys(files)).toHaveLength(5)
// The Object has 2 files at the `package.json` key
expect(files['package.json']).toHaveLength(2)
expect(files['package.json'][0].path).toEqual('package.json')
Expand Down Expand Up @@ -104,7 +104,7 @@ test('getFiles: 2 package.json files but one is not found on github', async () =

const files = await getFiles({ installationId: '123', fullName: 'owner/repo', files: fileList, log })

expect(Object.keys(files)).toHaveLength(4)
expect(Object.keys(files)).toHaveLength(5)
// returns an Object with the key `package.json`
expect(files['package.json']).toBeDefined()
// The Object has 2 files at the `package.json` key
Expand Down
Loading

0 comments on commit e6ee360

Please sign in to comment.