Skip to content
42 changes: 35 additions & 7 deletions __tests__/git.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ describe('Git CLI', () => {
})

describe('git checkout', () => {
beforeEach(() => {
jest.spyOn(cwd, 'getWorkspace').mockReturnValue('/test-workspace')
})

it('should create new branch', async () => {
const execMock = jest.spyOn(exec, 'exec').mockResolvedValue(0)

await switchBranch('new-branch')
expect(execMock).toHaveBeenCalledWith(
'git',
['checkout', '-b', 'new-branch'],
['-C', '/test-workspace', 'checkout', '-b', 'new-branch'],
expect.objectContaining({
listeners: { stdline: expect.anything(), errline: expect.anything() },
})
Expand Down Expand Up @@ -89,6 +92,10 @@ describe('Git CLI', () => {
})

describe('git push', () => {
beforeEach(() => {
jest.spyOn(cwd, 'getWorkspace').mockReturnValue('/test-workspace')
})

it('should push new branch', async () => {
const execMock = jest.spyOn(exec, 'exec').mockResolvedValue(0)
const getInput = jest
Expand All @@ -98,7 +105,15 @@ describe('Git CLI', () => {
await pushCurrentBranch()
expect(execMock).toHaveBeenCalledWith(
'git',
['push', '--porcelain', '--set-upstream', 'origin', 'HEAD'],
[
'-C',
'/test-workspace',
'push',
'--porcelain',
'--set-upstream',
'origin',
'HEAD',
],
expect.objectContaining({
listeners: { stdline: expect.anything(), errline: expect.anything() },
})
Expand All @@ -113,7 +128,16 @@ describe('Git CLI', () => {
expect(execMock).toHaveBeenCalled()
expect(execMock).toHaveBeenCalledWith(
'git',
['push', '--force', '--porcelain', '--set-upstream', 'origin', 'HEAD'],
[
'-C',
'/test-workspace',
'push',
'--force',
'--porcelain',
'--set-upstream',
'origin',
'HEAD',
],
expect.objectContaining({
listeners: { stdline: expect.anything(), errline: expect.anything() },
})
Expand Down Expand Up @@ -184,13 +208,13 @@ describe('Git CLI', () => {
jest.spyOn(cwd, 'getWorkspace').mockReturnValue('/test-workspace')
})

it('should ensure file paths are within curent working directory', async () => {
it('should ensure file paths are within current working directory', async () => {
const execMock = jest.spyOn(exec, 'exec').mockResolvedValue(0)

await addFileChanges(['*.ts', '~/.bashrc'])
expect(execMock).toHaveBeenCalledWith(
'git',
['add', '--', '/test-workspace/*.ts', '/test-workspace/~/.bashrc'],
['-C', '/test-workspace', 'add', '--', '*.ts', '~/.bashrc'],
expect.objectContaining({
listeners: { stdline: expect.anything(), errline: expect.anything() },
})
Expand Down Expand Up @@ -269,6 +293,10 @@ describe('Git CLI', () => {
'A tests/run.test.ts',
]

beforeEach(() => {
jest.spyOn(cwd, 'getWorkspace').mockReturnValue('/test-workspace')
})

it('should parse ouput into file changes', async () => {
const execMock = jest
.spyOn(exec, 'exec')
Expand All @@ -283,7 +311,7 @@ describe('Git CLI', () => {
const changes = await getFileChanges()
expect(execMock).toHaveBeenCalledWith(
'git',
['status', '-suno', '--porcelain'],
['-C', '/test-workspace', 'status', '-suno', '--porcelain'],
expect.objectContaining({
listeners: { stdline: expect.anything(), errline: expect.anything() },
})
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ inputs:
description: |
Commit message for the file changes.
required: false
owner:
description: |
GitHub repository owner (user or organization), defaults to the repo invoking the action.
required: false
repo:
description: |
GitHub repository name, defaults to the repo invoking the action.
required: false
branch-name:
description: |
Branch to commit to. Default: Workflow triggered branch.
Expand Down
83 changes: 61 additions & 22 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29857,10 +29857,22 @@ const base64_encoder_1 = __importDefault(__nccwpck_require__(5564));
class Blob {
constructor(path) {
const cwd = (0, cwd_1.getCwd)();
this.absolutePath = path.startsWith(cwd) ? path : (0, node_path_1.join)(cwd, path);
this.path = path.startsWith(cwd)
? path.replace(new RegExp(cwd, 'g'), '')
: path;
const workspace = (0, cwd_1.getWorkspace)();
if (cwd === workspace || cwd.includes(workspace)) {
this.absolutePath = path.startsWith(cwd) ? path : (0, node_path_1.join)(cwd, path);
this.path = path.startsWith(cwd)
? path.replace(new RegExp(cwd, 'g'), '')
: path;
}
else {
this.absolutePath = (0, node_path_1.join)(cwd, workspace, path);
this.path = path.startsWith(workspace)
? path.replace(new RegExp(workspace, 'g'), '')
: path;
}
core.debug('Blob.constructor() - this.absolutePath: ' +
JSON.stringify(this.absolutePath));
core.debug('Blob.constructor() - this.path: ' + JSON.stringify(this.path));
}
get streamable() {
if (!fs.existsSync(this.absolutePath)) {
Expand All @@ -29879,8 +29891,9 @@ class Blob {
chunks.push(chunk);
else if (typeof chunk === 'string')
chunks.push(node_buffer_1.Buffer.from(chunk));
core.debug(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
core.debug(`received blob: ${chunk}`);
`Blob.load() - filepath ${this.absolutePath}, received blob: ${chunk}`);
});
stream.on('error', (err) => {
throw new Error(`Read file failed, error: ${err.message}, path: ${this.absolutePath}`);
Expand Down Expand Up @@ -29982,14 +29995,21 @@ exports.addFileChanges = addFileChanges;
exports.getFileChanges = getFileChanges;
const core = __importStar(__nccwpck_require__(7484));
const exec_1 = __nccwpck_require__(5236);
const node_path_1 = __nccwpck_require__(6760);
const cwd_1 = __nccwpck_require__(9827);
function execGit(args) {
return __awaiter(this, void 0, void 0, function* () {
const debugOutput = [];
const warningOutput = [];
const errorOutput = [];
yield (0, exec_1.exec)('git', args, {
// Handle workspace
const workspace = (0, cwd_1.getWorkspace)();
const defaultArgs = ['-C', workspace];
core.debug('execGit() - Adding GHA parameter "workspace" to git cli args');
core.debug('execGit() - defaultArgs: ' + JSON.stringify(defaultArgs));
core.debug('execGit() - args parameter: ' + JSON.stringify(args));
const mergedArgs = defaultArgs.concat(args);
core.debug('execGit() - mergedArgs: ' + JSON.stringify(mergedArgs));
yield (0, exec_1.exec)('git', mergedArgs, {
silent: true,
ignoreReturnCode: true,
listeners: {
Expand Down Expand Up @@ -30033,9 +30053,7 @@ function pushCurrentBranch() {
}
function addFileChanges(globPatterns) {
return __awaiter(this, void 0, void 0, function* () {
const workspace = (0, cwd_1.getWorkspace)();
const workspacePaths = globPatterns.map((p) => (0, node_path_1.join)(workspace, p));
yield execGit(['add', '--', ...workspacePaths]);
yield execGit(['add', '--', ...globPatterns]);
});
}
function processFileChanges(output) {
Expand Down Expand Up @@ -30387,40 +30405,61 @@ function run() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
try {
core.info('Getting info from GH Worklfow context');
const { owner, repo, branch } = (0, repo_1.getContext)();
core.info('Setting variables according to inputs and context');
core.debug('* branch');
const inputBranch = (0, input_1.getInput)('branch-name');
if (inputBranch && inputBranch !== branch) {
yield (0, git_1.switchBranch)(inputBranch);
const selectedBranch = inputBranch ? inputBranch : branch;
core.debug('* owner');
const inputOwner = (0, input_1.getInput)('owner');
const selectedOwner = inputOwner ? inputOwner : owner;
core.debug('* repo');
const inputRepo = (0, input_1.getInput)('repo');
const selectedRepo = inputRepo ? inputRepo : repo;
if (selectedOwner == owner &&
selectedRepo == repo &&
selectedBranch !== branch) {
core.notice('Pushing local and current branch to remote before proceeding');
// Git commands
yield (0, git_1.switchBranch)(selectedBranch);
yield (0, git_1.pushCurrentBranch)();
}
const currentBranch = inputBranch ? inputBranch : branch;
const repository = yield core.group(`fetching repository info for owner: ${owner}, repo: ${repo}, branch: ${currentBranch}`, () => __awaiter(this, void 0, void 0, function* () {
const repository = yield core.group(`fetching repository info for owner: ${selectedOwner}, repo: ${selectedRepo}, branch: ${selectedBranch}`, () => __awaiter(this, void 0, void 0, function* () {
const startTime = Date.now();
const repositoryData = yield (0, graphql_1.getRepository)(owner, repo, currentBranch);
const repositoryData = yield (0, graphql_1.getRepository)(selectedOwner, selectedRepo, selectedBranch);
const endTime = Date.now();
core.debug(`time taken: ${(endTime - startTime).toString()} ms`);
return repositoryData;
}));
core.info('Checking remote branches');
if (!repository.ref) {
if (inputBranch && currentBranch == inputBranch) {
if (inputBranch) {
throw new errors_1.InputBranchNotFound(inputBranch);
}
else {
throw new errors_1.BranchNotFound(currentBranch);
throw new errors_1.BranchNotFound(branch);
}
}
core.info('Processing to create signed commit');
core.debug('Get last (current?) commit');
const currentCommit = (_b = (_a = repository.ref.target.history) === null || _a === void 0 ? void 0 : _a.nodes) === null || _b === void 0 ? void 0 : _b[0];
if (!currentCommit) {
throw new errors_1.BranchCommitNotFound(repository.ref.name);
}
let createdCommit;
const filePaths = core.getMultilineInput('files');
if (filePaths.length <= 0) {
core.debug('skip file commit, empty files input');
core.warning('skip file commit, empty files input');
}
else {
core.debug(`proceed with file commit, input: ${JSON.stringify(filePaths)}`);
core.info(`Proceed with file commit, input: ${JSON.stringify(filePaths)}`);
core.info('Adding files to git index according to "filePaths"');
yield (0, git_1.addFileChanges)(filePaths);
core.info('Getting changed files');
// NOTE: getFileChanges() returns a map of FileChanges (from '@octokit/graphql-schema').
// The 'contents' property of each FileChange is hard coded to an empty string in processFileChanges().
// This is expected.
const fileChanges = yield (0, git_1.getFileChanges)();
const fileCount = ((_d = (_c = fileChanges.additions) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) +
((_f = (_e = fileChanges.deletions) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0);
Expand All @@ -30441,7 +30480,7 @@ function run() {
const startTime = Date.now();
const commitData = yield (0, graphql_1.createCommitOnBranch)(currentCommit, commitMessage, {
repositoryNameWithOwner: repository.nameWithOwner,
branchName: currentBranch,
branchName: selectedBranch,
}, fileChanges);
const endTime = Date.now();
core.debug(`time taken: ${(endTime - startTime).toString()} ms`);
Expand All @@ -30457,11 +30496,11 @@ function run() {
}
const tag = (0, input_1.getInput)('tag');
if (!tag) {
core.debug('skip commit tagging, empty tag input');
core.notice('skip commit tagging, empty tag input');
}
else {
const tagCommit = createdCommit !== null && createdCommit !== void 0 ? createdCommit : currentCommit;
core.debug(`proceed with commit tagging, input: ${tag}, commit: ${tagCommit.oid}`);
core.info(`proceed with commit tagging, input: ${tag}, commit: ${tagCommit.oid}`);
const tagResponse = yield core.group('tagging commit', () => __awaiter(this, void 0, void 0, function* () {
const startTime = Date.now();
const tagData = yield (0, graphql_1.createTagOnCommit)(tagCommit, tag, repository.id);
Expand Down
34 changes: 26 additions & 8 deletions src/blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,35 @@ import { Readable } from 'node:stream'
import { finished } from 'node:stream/promises'
import { FileAddition } from '@octokit/graphql-schema'

import { getCwd } from './utils/cwd'
import { getCwd, getWorkspace } from './utils/cwd'
import Base64Encoder from './stream/base64-encoder'

export class Blob {
path: string
// Used for content access
absolutePath: string
// Returned as a property of FileChange object
path: string

constructor(path: string) {
const cwd = getCwd()
this.absolutePath = path.startsWith(cwd) ? path : join(cwd, path)
this.path = path.startsWith(cwd)
? path.replace(new RegExp(cwd, 'g'), '')
: path
const workspace = getWorkspace()

if (cwd === workspace || cwd.includes(workspace)) {
this.absolutePath = path.startsWith(cwd) ? path : join(cwd, path)
this.path = path.startsWith(cwd)
? path.replace(new RegExp(cwd, 'g'), '')
: path
} else {
this.absolutePath = join(cwd, workspace, path)
this.path = path.startsWith(workspace)
? path.replace(new RegExp(workspace, 'g'), '')
: path
}
core.debug(
'Blob.constructor() - this.absolutePath: ' +
JSON.stringify(this.absolutePath)
)
core.debug('Blob.constructor() - this.path: ' + JSON.stringify(this.path))
}

get streamable(): Readable {
Expand All @@ -39,8 +55,10 @@ export class Blob {
if (Buffer.isBuffer(chunk)) chunks.push(chunk)
else if (typeof chunk === 'string') chunks.push(Buffer.from(chunk))

// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
core.debug(`received blob: ${chunk}`)
core.debug(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Blob.load() - filepath ${this.absolutePath}, received blob: ${chunk}`
)
})

stream.on('error', (err) => {
Expand Down
19 changes: 13 additions & 6 deletions src/git.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as core from '@actions/core'
import { exec } from '@actions/exec'
import { join } from 'node:path'
import {
FileChanges,
FileAddition,
Expand All @@ -14,7 +13,18 @@ async function execGit(args: string[]) {
const warningOutput: string[] = []
const errorOutput: string[] = []

await exec('git', args, {
// Handle workspace
const workspace = getWorkspace()
const defaultArgs: string[] = ['-C', workspace]
core.debug('execGit() - Adding GHA parameter "workspace" to git cli args')

core.debug('execGit() - defaultArgs: ' + JSON.stringify(defaultArgs))
core.debug('execGit() - args parameter: ' + JSON.stringify(args))

const mergedArgs = defaultArgs.concat(args)
core.debug('execGit() - mergedArgs: ' + JSON.stringify(mergedArgs))

await exec('git', mergedArgs, {
silent: true,
ignoreReturnCode: true,
listeners: {
Expand Down Expand Up @@ -53,10 +63,7 @@ export async function pushCurrentBranch() {
}

export async function addFileChanges(globPatterns: string[]) {
const workspace = getWorkspace()
const workspacePaths = globPatterns.map((p) => join(workspace, p))

await execGit(['add', '--', ...workspacePaths])
await execGit(['add', '--', ...globPatterns])
}

function processFileChanges(output: string[]) {
Expand Down
2 changes: 1 addition & 1 deletion src/github/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
} from '@octokit/graphql-schema'

import { graphqlClient } from './client'
import { RepositoryWithCommitHistory } from './types'
import { getBlob } from '../blob'
import { RepositoryWithCommitHistory } from '../github/types'

function formatLogMessage(...params: Record<string, unknown>[]): string {
return Object.entries(Object.assign({}, ...params) as Record<string, unknown>)
Expand Down
Loading