Skip to content

Commit a547f3c

Browse files
authored
✨ Verified commits when using GH_INSTALLATION_TOKEN as authentication (#153)
1 parent ea27671 commit a547f3c

File tree

3 files changed

+290
-20
lines changed

3 files changed

+290
-20
lines changed

dist/index.js

+145-10
Original file line numberDiff line numberDiff line change
@@ -17464,6 +17464,7 @@ class Git {
1746417464
await this.clone()
1746517465
await this.setIdentity()
1746617466
await this.getBaseBranch()
17467+
await this.getLastCommitSha()
1746717468

1746817469
if (FORK) {
1746917470
const forkUrl = `https://${ GITHUB_TOKEN }@github.com/${ FORK }/${ this.repo.name }.git`
@@ -17501,13 +17502,11 @@ class Git {
1750117502
let email = GIT_EMAIL
1750217503

1750317504
if (email === undefined) {
17504-
if (IS_INSTALLATION_TOKEN) {
17505-
core.setFailed('When using an installation token you must provide GIT_EMAIL and GIT_USERNAME')
17506-
process.exit(1)
17505+
if (!IS_INSTALLATION_TOKEN) {
17506+
const { data } = await this.github.users.getAuthenticated()
17507+
email = data.email
17508+
username = data.login
1750717509
}
17508-
const { data } = await this.github.users.getAuthenticated()
17509-
email = data.email
17510-
username = data.login
1751117510
}
1751217511

1751317512
core.debug(`Setting git user to email: ${ email }, username: ${ username }`)
@@ -17528,7 +17527,7 @@ class Git {
1752817527
async createPrBranch() {
1752917528
const prefix = BRANCH_PREFIX.replace('SOURCE_REPO_NAME', GITHUB_REPOSITORY.split('/')[1])
1753017529

17531-
let newBranch = path.join(prefix, this.repo.branch)
17530+
let newBranch = path.join(prefix, this.repo.branch).replace(/\\/g, '/')
1753217531

1753317532
if (OVERWRITE_EXISTING_PR === false) {
1753417533
newBranch += `-${ Math.round((new Date()).getTime() / 1000) }`
@@ -17546,7 +17545,7 @@ class Git {
1754617545

1754717546
async add(file) {
1754817547
return execCmd(
17549-
`git add -f ${ file }`,
17548+
`git add -f "${ file }"`,
1755017549
this.workingDir
1755117550
)
1755217551
}
@@ -17595,6 +17594,21 @@ class Git {
1759517594
}
1759617595
}
1759717596

17597+
async getBlobContent(objectSha) {
17598+
return await execCmd(
17599+
`git show ${ objectSha }`,
17600+
this.workingDir,
17601+
false // Do not trim the result
17602+
)
17603+
}
17604+
17605+
async getLastCommitSha() {
17606+
this.lastCommitSha = await execCmd(
17607+
`git rev-parse HEAD`,
17608+
this.workingDir
17609+
)
17610+
}
17611+
1759817612
async changes(destination) { // gets array of git diffs for the destination, which either can be a file or a dict
1759917613
const output = await execCmd(
1760017614
`git diff HEAD ${ destination }`,
@@ -17623,6 +17637,96 @@ class Git {
1762317637
)
1762417638
}
1762517639

17640+
// Creates a tree object with all the blobs of each commit
17641+
async getTree(commitSha) {
17642+
const output = await execCmd(
17643+
`git ls-tree -r --full-tree ${ commitSha }`,
17644+
this.workingDir
17645+
)
17646+
17647+
const tree = []
17648+
for (const treeObject of output.split('\n')) {
17649+
const [ mode, type, sha ] = treeObject.split(/\s/)
17650+
const treeObjectPath = treeObject.split('\t')[1]
17651+
17652+
const treeEntry = {
17653+
mode,
17654+
type,
17655+
content: await this.getBlobContent(sha),
17656+
path: treeObjectPath
17657+
}
17658+
tree.push(treeEntry)
17659+
}
17660+
return tree
17661+
}
17662+
17663+
// Gets the commit list in chronological order
17664+
async getCommitsToPush() {
17665+
const output = await execCmd(
17666+
`git log --format=%H --reverse ${ this.baseBranch }..HEAD`,
17667+
this.workingDir
17668+
)
17669+
17670+
const commits = output.split('\n')
17671+
return commits
17672+
}
17673+
17674+
async getCommitMessage(commitSha) {
17675+
return await execCmd(
17676+
`git log -1 --format=%B ${ commitSha }`,
17677+
this.workingDir
17678+
)
17679+
}
17680+
17681+
// Returns an array of objects with the git tree and the commit, one entry for each pending commit to push
17682+
async getCommitsDataToPush() {
17683+
const commitsToPush = await this.getCommitsToPush()
17684+
17685+
const commitsData = []
17686+
for (const commitSha of commitsToPush) {
17687+
const commitData = {
17688+
commitMessage: await this.getCommitMessage(commitSha),
17689+
tree: await this.getTree(commitSha)
17690+
}
17691+
commitsData.push(commitData)
17692+
}
17693+
return commitsData
17694+
}
17695+
17696+
// A wrapper for running all the flow to generate all the pending commits using the GitHub API
17697+
async createGithubVerifiedCommits() {
17698+
const commitsData = await this.getCommitsDataToPush()
17699+
17700+
// Creates the PR branch if doesn't exists
17701+
try {
17702+
await this.github.git.createRef({
17703+
owner: this.repo.user,
17704+
repo: this.repo.name,
17705+
sha: this.lastCommitSha,
17706+
ref: 'refs/heads/' + this.prBranch
17707+
})
17708+
17709+
core.debug(`Created new branch ${ this.prBranch }`)
17710+
} catch (error) {
17711+
// If the branch exists ignores the error
17712+
if (error.message !== 'Reference already exists') throw error
17713+
}
17714+
17715+
for (const commitData of commitsData) {
17716+
await this.createGithubTreeAndCommit(commitData.tree, commitData.commitMessage)
17717+
}
17718+
17719+
core.debug(`Updating branch ${ this.prBranch } ref`)
17720+
await this.github.git.updateRef({
17721+
owner: this.repo.user,
17722+
repo: this.repo.name,
17723+
ref: `heads/${ this.prBranch }`,
17724+
sha: this.lastCommitSha,
17725+
force: true
17726+
})
17727+
core.debug(`Commit using GitHub API completed`)
17728+
}
17729+
1762617730
async status() {
1762717731
return execCmd(
1762817732
`git status`,
@@ -17637,6 +17741,9 @@ class Git {
1763717741
this.workingDir
1763817742
)
1763917743
}
17744+
if (IS_INSTALLATION_TOKEN) {
17745+
return await this.createGithubVerifiedCommits()
17746+
}
1764017747
return execCmd(
1764117748
`git push ${ this.gitUrl } --force`,
1764217749
this.workingDir
@@ -17738,6 +17845,32 @@ class Git {
1773817845
assignees: assignees
1773917846
})
1774017847
}
17848+
17849+
async createGithubTreeAndCommit(tree, commitMessage) {
17850+
core.debug(`Creating a GitHub tree`)
17851+
let treeSha
17852+
try {
17853+
const request = await this.github.git.createTree({
17854+
owner: this.repo.user,
17855+
repo: this.repo.name,
17856+
tree
17857+
})
17858+
treeSha = request.data.sha
17859+
} catch (error) {
17860+
error.message = `Cannot create a new GitHub Tree: ${ error.message }`
17861+
throw error
17862+
}
17863+
17864+
core.debug(`Creating a commit for the GitHub tree`)
17865+
const request = await this.github.git.createCommit({
17866+
owner: this.repo.user,
17867+
repo: this.repo.name,
17868+
message: commitMessage,
17869+
parents: [ this.lastCommitSha ],
17870+
tree: treeSha
17871+
})
17872+
this.lastCommitSha = request.data.sha
17873+
}
1774117874
}
1774217875

1774317876
module.exports = Git
@@ -17788,7 +17921,7 @@ const dedent = function(templateStrings, ...values) {
1778817921
return string
1778917922
}
1779017923

17791-
const execCmd = (command, workingDir) => {
17924+
const execCmd = (command, workingDir, trimResult = true) => {
1779217925
core.debug(`EXEC: "${ command }" IN ${ workingDir }`)
1779317926
return new Promise((resolve, reject) => {
1779417927
exec(
@@ -17797,7 +17930,9 @@ const execCmd = (command, workingDir) => {
1779717930
cwd: workingDir
1779817931
},
1779917932
function(error, stdout) {
17800-
error ? reject(error) : resolve(stdout.trim())
17933+
error ? reject(error) : resolve(
17934+
trimResult ? stdout.trim() : stdout
17935+
)
1780117936
}
1780217937
)
1780317938
})

0 commit comments

Comments
 (0)