const core = require('@actions/core') const exec = require('@actions/exec') const assert = require('assert') const { GITHUB_REPOSITORY, GITHUB_REF, ENV } = process.env const branch = GITHUB_REF.replace('refs/heads/', '') module.exports = new (class Git { commandsRun = [] constructor() { const githubToken = core.getInput('github-token', { required: true }) // Make the Github token secret core.setSecret(githubToken) const gitUserName = core.getInput('git-user-name') const gitUserEmail = core.getInput('git-user-email') // if the env is dont-use-git then we mock exec as we are testing a workflow if (ENV === 'dont-use-git') { this.exec = (command) => { const fullCommand = `git ${command}` console.log(`Skipping "${fullCommand}" because of test env`) if (!fullCommand.includes('git remote set-url origin')) { this.commandsRun.push(fullCommand) } } } // Set config this.config('user.name', gitUserName) this.config('user.email', gitUserEmail) // Update the origin this.updateOrigin(`https://x-access-token:${githubToken}@github.com/${GITHUB_REPOSITORY}.git`) } /** * Executes the git command * * @param command * @return {Promise<>} */ exec = (command) => new Promise(async(resolve, reject) => { const exitCode = await exec.exec(`git ${command}`) if (exitCode === 0) { resolve() } else { reject(`Command "git ${command}" exited with code ${exitCode}.`) } }) /** * Set a git config prop * * @param prop * @param value * @return {Promise<>} */ config = (prop, value) => this.exec(`config ${prop} "${value}"`) /** * Add a file to commit * * @param file * @returns {*} */ add = (file) => this.exec(`add ${file}`) /** * Commit all changes * * @param message * * @return {Promise<>} */ commit = (message) => ( this.exec(`commit -m "${message}"`) ) /** * Pull the full history * * @return {Promise<>} */ pull = async() => { const args = ['pull'] // Check if the repo is unshallow if (await this.isShallow()) { args.push('--unshallow') } args.push('--tags') args.push(core.getInput('git-pull-method')) return this.exec(args.join(' ')) } /** * Push all changes * * @return {Promise<>} */ push = () => ( this.exec(`push origin ${branch} --follow-tags`) ) /** * Check if the repo is shallow * * @return {Promise<>} */ isShallow = async() => { const isShallow = await this.exec('rev-parse --is-shallow-repository') // isShallow does not return anything on local machine if (isShallow) { return isShallow.trim().replace('\n', '') === 'true' } else { return false } } /** * Updates the origin remote * * @param repo * @return {Promise<>} */ updateOrigin = (repo) => this.exec(`remote set-url origin ${repo}`) /** * Creates git tag * * @param tag * @return {Promise<>} */ createTag = (tag) => this.exec(`tag -a ${tag} -m "${tag}"`) /** * Validates the commands run */ testHistory = () => { if (ENV === 'dont-use-git') { const { EXPECTED_TAG, SKIPPED_COMMIT } = process.env const expectedCommands = [ 'git config user.name "Conventional Changelog Action"', 'git config user.email "conventional.changelog.action@github.com"', 'git rev-parse --is-shallow-repository', 'git pull --tags --ff-only', ] if (!SKIPPED_COMMIT) { expectedCommands.push('git add .') expectedCommands.push(`git commit -m "chore(release): ${EXPECTED_TAG}"`) } expectedCommands.push(`git tag -a ${EXPECTED_TAG} -m "${EXPECTED_TAG}"`) expectedCommands.push(`git push origin ${branch} --follow-tags`) assert.deepStrictEqual( this.commandsRun, expectedCommands, ) } } })()