From af9b7c519823d6fea16347776b560327fe47b1bb Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Tue, 22 Oct 2024 13:21:59 +0200 Subject: [PATCH 1/6] feat: Add support for remote GitHub owner and repo - Update default values for `commit-message`, `owner`, `repo`, `branch-name`, `branch-push-force`, and `tag-only-if-file-changes` - Add logging for getting info from context and setting branch according to input and context in `main.ts` - Update repository info fetching message with input owner and repo in `main.ts` --- action.yml | 14 +++++++++++--- src/main.ts | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index d3c9df1..0bebd00 100644 --- a/action.yml +++ b/action.yml @@ -14,16 +14,24 @@ inputs: description: | Directory containing files to be committed. Default: GitHub workspace directory (root of repository). required: false - default: '' + default: "" commit-message: 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. required: false - default: '' + default: "" branch-push-force: description: | --force flag when running git push . @@ -33,7 +41,7 @@ inputs: description: | Push tag for the new/current commit. required: false - default: '' + default: "" tag-only-if-file-changes: description: | Push tag for new commit only when file changes present. diff --git a/src/main.ts b/src/main.ts index 4014982..d70534c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,18 +23,28 @@ import { export async function run(): Promise { try { + core.info('Getting info from context') const { owner, repo, branch } = getContext() + + core.debug('Setting branch according to input and context') const inputBranch = getInput('branch-name') if (inputBranch && inputBranch !== branch) { await switchBranch(inputBranch) await pushCurrentBranch() } const currentBranch = inputBranch ? inputBranch : branch + + const inputOwner = getInput('owner') + const currentOwner = inputOwner ? inputOwner : owner + + const inputRepo = getInput('repo') + const currentRepo = inputRepo ? inputRepo : repo + const repository = await core.group( - `fetching repository info for owner: ${owner}, repo: ${repo}, branch: ${currentBranch}`, + `fetching repository info for owner: ${currentOwner}, repo: ${currentRepo}, branch: ${currentBranch}`, async () => { const startTime = Date.now() - const repositoryData = await getRepository(owner, repo, currentBranch) + const repositoryData = await getRepository(currentOwner, currentRepo, currentBranch) const endTime = Date.now() core.debug(`time taken: ${(endTime - startTime).toString()} ms`) return repositoryData From 756aef5d9653ff355fbeaa14c504faf5afe0264e Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Fri, 25 Oct 2024 11:53:56 +0200 Subject: [PATCH 2/6] Fixup: prettier --- action.yml | 6 +++--- src/main.ts | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index 0bebd00..690b6d8 100644 --- a/action.yml +++ b/action.yml @@ -14,7 +14,7 @@ inputs: description: | Directory containing files to be committed. Default: GitHub workspace directory (root of repository). required: false - default: "" + default: '' commit-message: description: | Commit message for the file changes. @@ -31,7 +31,7 @@ inputs: description: | Branch to commit to. Default: Workflow triggered branch. required: false - default: "" + default: '' branch-push-force: description: | --force flag when running git push . @@ -41,7 +41,7 @@ inputs: description: | Push tag for the new/current commit. required: false - default: "" + default: '' tag-only-if-file-changes: description: | Push tag for new commit only when file changes present. diff --git a/src/main.ts b/src/main.ts index d70534c..5d9bbf7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -44,7 +44,11 @@ export async function run(): Promise { `fetching repository info for owner: ${currentOwner}, repo: ${currentRepo}, branch: ${currentBranch}`, async () => { const startTime = Date.now() - const repositoryData = await getRepository(currentOwner, currentRepo, currentBranch) + const repositoryData = await getRepository( + currentOwner, + currentRepo, + currentBranch + ) const endTime = Date.now() core.debug(`time taken: ${(endTime - startTime).toString()} ms`) return repositoryData From ef960487345977a26523ba45bac87331a600083c Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Fri, 25 Oct 2024 11:56:07 +0200 Subject: [PATCH 3/6] Fixup: Build Ts --- dist/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index 258dd67..bfc7690 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30387,16 +30387,22 @@ function run() { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; try { + core.info('Getting info from context'); const { owner, repo, branch } = (0, repo_1.getContext)(); + core.debug('Setting branch according to input and context'); const inputBranch = (0, input_1.getInput)('branch-name'); if (inputBranch && inputBranch !== branch) { yield (0, git_1.switchBranch)(inputBranch); 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 inputOwner = (0, input_1.getInput)('owner'); + const currentOwner = inputOwner ? inputOwner : owner; + const inputRepo = (0, input_1.getInput)('repo'); + const currentRepo = inputRepo ? inputRepo : repo; + const repository = yield core.group(`fetching repository info for owner: ${currentOwner}, repo: ${currentRepo}, branch: ${currentBranch}`, () => __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)(currentOwner, currentRepo, currentBranch); const endTime = Date.now(); core.debug(`time taken: ${(endTime - startTime).toString()} ms`); return repositoryData; From 19f59fe4970e4b924ec1ad96b7b4227cb6b41c37 Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Tue, 29 Oct 2024 23:03:50 +0100 Subject: [PATCH 4/6] Improve logging --- dist/index.js | 38 ++++++++++++++++++++++++-------------- src/main.ts | 45 +++++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/dist/index.js b/dist/index.js index bfc7690..f8455f5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30387,34 +30387,44 @@ function run() { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; try { - core.info('Getting info from context'); + core.info('Getting info from GH Worklfow context'); const { owner, repo, branch } = (0, repo_1.getContext)(); - core.debug('Setting branch according to input and context'); + 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); - yield (0, git_1.pushCurrentBranch)(); - } - const currentBranch = inputBranch ? inputBranch : branch; + const selectedBranch = inputBranch ? inputBranch : branch; + core.debug('* owner'); const inputOwner = (0, input_1.getInput)('owner'); - const currentOwner = inputOwner ? inputOwner : owner; + const selectedOwner = inputOwner ? inputOwner : owner; + core.debug('* repo'); const inputRepo = (0, input_1.getInput)('repo'); - const currentRepo = inputRepo ? inputRepo : repo; - const repository = yield core.group(`fetching repository info for owner: ${currentOwner}, repo: ${currentRepo}, branch: ${currentBranch}`, () => __awaiter(this, void 0, void 0, function* () { + const selectedRepo = inputRepo ? inputRepo : repo; + core.warning('Pushing local and current branch to remote before proceeding'); + if (selectedOwner == owner && + selectedRepo == repo && + selectedBranch !== branch) { + // Git commands + yield (0, git_1.switchBranch)(selectedBranch); + yield (0, git_1.pushCurrentBranch)(); + } + 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)(currentOwner, currentRepo, 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); @@ -30447,7 +30457,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`); diff --git a/src/main.ts b/src/main.ts index 5d9bbf7..3a4099a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,31 +23,41 @@ import { export async function run(): Promise { try { - core.info('Getting info from context') + core.info('Getting info from GH Worklfow context') const { owner, repo, branch } = getContext() - core.debug('Setting branch according to input and context') + core.info('Setting variables according to inputs and context') + core.debug('* branch') const inputBranch = getInput('branch-name') - if (inputBranch && inputBranch !== branch) { - await switchBranch(inputBranch) - await pushCurrentBranch() - } - const currentBranch = inputBranch ? inputBranch : branch + const selectedBranch = inputBranch ? inputBranch : branch + core.debug('* owner') const inputOwner = getInput('owner') - const currentOwner = inputOwner ? inputOwner : owner + const selectedOwner = inputOwner ? inputOwner : owner + core.debug('* repo') const inputRepo = getInput('repo') - const currentRepo = inputRepo ? inputRepo : repo + const selectedRepo = inputRepo ? inputRepo : repo + + core.warning('Pushing local and current branch to remote before proceeding') + if ( + selectedOwner == owner && + selectedRepo == repo && + selectedBranch !== branch + ) { + // Git commands + await switchBranch(selectedBranch) + await pushCurrentBranch() + } const repository = await core.group( - `fetching repository info for owner: ${currentOwner}, repo: ${currentRepo}, branch: ${currentBranch}`, + `fetching repository info for owner: ${selectedOwner}, repo: ${selectedRepo}, branch: ${selectedBranch}`, async () => { const startTime = Date.now() const repositoryData = await getRepository( - currentOwner, - currentRepo, - currentBranch + selectedOwner, + selectedRepo, + selectedBranch ) const endTime = Date.now() core.debug(`time taken: ${(endTime - startTime).toString()} ms`) @@ -55,14 +65,17 @@ export async function run(): Promise { } ) + core.info('Checking remote branches') if (!repository.ref) { - if (inputBranch && currentBranch == inputBranch) { + if (inputBranch) { throw new InputBranchNotFound(inputBranch) } else { - throw new BranchNotFound(currentBranch) + throw new BranchNotFound(branch) } } + core.info('Processing to create signed commit') + core.debug('Get last (current?) commit') const currentCommit = repository.ref.target.history?.nodes?.[0] if (!currentCommit) { throw new BranchCommitNotFound(repository.ref.name) @@ -103,7 +116,7 @@ export async function run(): Promise { commitMessage, { repositoryNameWithOwner: repository.nameWithOwner, - branchName: currentBranch, + branchName: selectedBranch, }, fileChanges ) From 2198d9f92bac01aabdb469a826f26d7ac7c7b7df Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Tue, 29 Oct 2024 23:33:19 +0100 Subject: [PATCH 5/6] Add support for 'workdir' input field --- action.yml | 5 +++++ dist/index.js | 19 +++++++++++++++++-- src/main.ts | 12 ++++++++++-- src/utils/cwd.ts | 8 ++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index 690b6d8..7ce6a5b 100644 --- a/action.yml +++ b/action.yml @@ -15,6 +15,11 @@ inputs: Directory containing files to be committed. Default: GitHub workspace directory (root of repository). required: false default: '' + workdir: + description: | + Directory where the action should run. Default: GitHub workspace directory (root of repository from where the GH Workflow is triggered). + required: false + default: '' commit-message: description: | Commit message for the file changes. diff --git a/dist/index.js b/dist/index.js index f8455f5..7e4864a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30381,6 +30381,7 @@ const core = __importStar(__nccwpck_require__(7484)); const graphql_1 = __nccwpck_require__(1422); const repo_1 = __nccwpck_require__(1839); const git_1 = __nccwpck_require__(1243); +const cwd_1 = __nccwpck_require__(9827); const input_1 = __nccwpck_require__(7797); const errors_1 = __nccwpck_require__(3916); function run() { @@ -30432,10 +30433,16 @@ function run() { let createdCommit; const filePaths = core.getMultilineInput('files'); if (filePaths.length <= 0) { - core.debug('skip file commit, empty files input'); + core.notice('skip file commit, empty files input'); } else { - core.debug(`proceed with file commit, input: ${JSON.stringify(filePaths)}`); + core.debug(`Proceed with file commit, input: ${JSON.stringify(filePaths)}`); + const workdir = (0, cwd_1.getWorkdir)(); + const cwd = (0, cwd_1.getCwd)(); + if (cwd !== workdir) { + core.notice('Changing working directory to Workdir: ' + workdir); + process.chdir(workdir); + } yield (0, git_1.addFileChanges)(filePaths); 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) + @@ -30581,6 +30588,7 @@ var __importStar = (this && this.__importStar) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getCwd = getCwd; exports.getWorkspace = getWorkspace; +exports.getWorkdir = getWorkdir; const core = __importStar(__nccwpck_require__(7484)); const input_1 = __nccwpck_require__(7797); function getCwd() { @@ -30595,6 +30603,13 @@ function getWorkspace() { core.debug(`workspace: ${workspace}`); return workspace; } +function getWorkdir() { + const workdir = (0, input_1.getInput)('workdir', { + default: process.env.GITHUB_WORKSPACE, + }); + core.debug(`workdir: ${workdir}`); + return workdir; +} /***/ }), diff --git a/src/main.ts b/src/main.ts index 3a4099a..86101bc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,6 +13,7 @@ import { pushCurrentBranch, switchBranch, } from './git' +import { getCwd, getWorkdir } from './utils/cwd' import { getInput } from './utils/input' import { NoFileChanges, @@ -84,12 +85,19 @@ export async function run(): Promise { let createdCommit: Commit | undefined const filePaths = core.getMultilineInput('files') if (filePaths.length <= 0) { - core.debug('skip file commit, empty files input') + core.notice('skip file commit, empty files input') } else { core.debug( - `proceed with file commit, input: ${JSON.stringify(filePaths)}` + `Proceed with file commit, input: ${JSON.stringify(filePaths)}` ) + const workdir = getWorkdir() + const cwd = getCwd() + if (cwd !== workdir) { + core.notice('Changing working directory to Workdir: ' + workdir) + process.chdir(workdir) + } + await addFileChanges(filePaths) const fileChanges = await getFileChanges() const fileCount = diff --git a/src/utils/cwd.ts b/src/utils/cwd.ts index ea9f338..cd3a798 100644 --- a/src/utils/cwd.ts +++ b/src/utils/cwd.ts @@ -14,3 +14,11 @@ export function getWorkspace() { core.debug(`workspace: ${workspace}`) return workspace } + +export function getWorkdir() { + const workdir = getInput('workdir', { + default: process.env.GITHUB_WORKSPACE, + }) + core.debug(`workdir: ${workdir}`) + return workdir +} From c7c93e3ffc4f55bff63b6613e865dc038c7fb51e Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Wed, 30 Oct 2024 00:42:03 +0100 Subject: [PATCH 6/6] feat: Update the 'addFileChanges' function --- __tests__/git.test.ts | 4 ++-- dist/index.js | 12 ++++++++++-- src/git.ts | 21 ++++++++++++++++++--- src/main.ts | 4 +++- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/__tests__/git.test.ts b/__tests__/git.test.ts index 4182e9b..6d3eae0 100644 --- a/__tests__/git.test.ts +++ b/__tests__/git.test.ts @@ -181,7 +181,7 @@ describe('Git CLI', () => { describe('git add', () => { beforeEach(() => { - jest.spyOn(cwd, 'getWorkspace').mockReturnValue('/test-workspace') + jest.spyOn(cwd, 'getWorkspace').mockReturnValue('test-workspace/') }) it('should ensure file paths are within curent working directory', async () => { @@ -190,7 +190,7 @@ describe('Git CLI', () => { await addFileChanges(['*.ts', '~/.bashrc']) expect(execMock).toHaveBeenCalledWith( 'git', - ['add', '--', '/test-workspace/*.ts', '/test-workspace/~/.bashrc'], + ['add', '--', 'test-workspace/*.ts', 'test-workspace/~/.bashrc'], expect.objectContaining({ listeners: { stdline: expect.anything(), errline: expect.anything() }, }) diff --git a/dist/index.js b/dist/index.js index 7e4864a..d0daefb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -29989,6 +29989,7 @@ function execGit(args) { const debugOutput = []; const warningOutput = []; const errorOutput = []; + core.debug('execGit() - args: ' + JSON.stringify(args)); yield (0, exec_1.exec)('git', args, { silent: true, ignoreReturnCode: true, @@ -30033,8 +30034,15 @@ function pushCurrentBranch() { } function addFileChanges(globPatterns) { return __awaiter(this, void 0, void 0, function* () { + const cwd = (0, cwd_1.getCwd)(); const workspace = (0, cwd_1.getWorkspace)(); - const workspacePaths = globPatterns.map((p) => (0, node_path_1.join)(workspace, p)); + const resolvedWorkspace = (0, node_path_1.resolve)(workspace); + core.debug('addFileChanges() - resolvedWorkspace: ' + JSON.stringify(resolvedWorkspace)); + let workspacePaths = globPatterns; + if (resolvedWorkspace.includes(cwd)) { + core.notice('addFileChanges() - "workspace" is a subdirectory, updating globPatterns'); + workspacePaths = globPatterns.map((p) => (0, node_path_1.join)((0, node_path_1.relative)(cwd, resolvedWorkspace), p)); + } yield execGit(['add', '--', ...workspacePaths]); }); } @@ -30400,10 +30408,10 @@ function run() { core.debug('* repo'); const inputRepo = (0, input_1.getInput)('repo'); const selectedRepo = inputRepo ? inputRepo : repo; - core.warning('Pushing local and current branch to remote before proceeding'); if (selectedOwner == owner && selectedRepo == repo && selectedBranch !== branch) { + core.warning('Pushing local and current branch to remote before proceeding'); // Git commands yield (0, git_1.switchBranch)(selectedBranch); yield (0, git_1.pushCurrentBranch)(); diff --git a/src/git.ts b/src/git.ts index 64f2efa..258030f 100644 --- a/src/git.ts +++ b/src/git.ts @@ -1,19 +1,20 @@ import * as core from '@actions/core' import { exec } from '@actions/exec' -import { join } from 'node:path' +import { join, relative, resolve } from 'node:path' import { FileChanges, FileAddition, FileDeletion, } from '@octokit/graphql-schema' -import { getWorkspace } from './utils/cwd' +import { getCwd, getWorkspace } from './utils/cwd' async function execGit(args: string[]) { const debugOutput: string[] = [] const warningOutput: string[] = [] const errorOutput: string[] = [] + core.debug('execGit() - args: ' + JSON.stringify(args)) await exec('git', args, { silent: true, ignoreReturnCode: true, @@ -53,8 +54,22 @@ export async function pushCurrentBranch() { } export async function addFileChanges(globPatterns: string[]) { + const cwd = getCwd() const workspace = getWorkspace() - const workspacePaths = globPatterns.map((p) => join(workspace, p)) + const resolvedWorkspace = resolve(workspace) + core.debug( + 'addFileChanges() - resolvedWorkspace: ' + JSON.stringify(resolvedWorkspace) + ) + + let workspacePaths = globPatterns + if (resolvedWorkspace.includes(cwd)) { + core.notice( + 'addFileChanges() - "workspace" is a subdirectory, updating globPatterns' + ) + workspacePaths = globPatterns.map((p) => + join(relative(cwd, resolvedWorkspace), p) + ) + } await execGit(['add', '--', ...workspacePaths]) } diff --git a/src/main.ts b/src/main.ts index 86101bc..454a85d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -40,12 +40,14 @@ export async function run(): Promise { const inputRepo = getInput('repo') const selectedRepo = inputRepo ? inputRepo : repo - core.warning('Pushing local and current branch to remote before proceeding') if ( selectedOwner == owner && selectedRepo == repo && selectedBranch !== branch ) { + core.warning( + 'Pushing local and current branch to remote before proceeding' + ) // Git commands await switchBranch(selectedBranch) await pushCurrentBranch()