From 9f01b63120591cae14729ff96261d66a7fd7e4eb Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Wed, 30 Oct 2024 15:50:45 +0100 Subject: [PATCH 1/3] feat: Add support for remote GitHub repository + working directory (#2) --- __tests__/git.test.ts | 4 +-- action.yml | 14 +++++++-- dist/index.js | 68 +++++++++++++++++++++++++++++++------------ src/git.ts | 21 +++++++++++-- src/main.ts | 64 +++++++++++++++++++++++++++------------- src/utils/cwd.ts | 8 +++++ 6 files changed, 133 insertions(+), 46 deletions(-) diff --git a/__tests__/git.test.ts b/__tests__/git.test.ts index 560c398..bd006bf 100644 --- a/__tests__/git.test.ts +++ b/__tests__/git.test.ts @@ -182,7 +182,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 () => { @@ -191,7 +191,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/action.yml b/action.yml index 67225ee..7ce6a5b 100644 --- a/action.yml +++ b/action.yml @@ -15,15 +15,23 @@ 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. required: false - repository: + owner: description: | - Repository name including owner (e.g. owner/repo). Default: Workflow triggered repository. + 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 - default: '' branch-name: description: | Branch to commit to. Default: Workflow triggered branch. diff --git a/dist/index.js b/dist/index.js index c12df09..42cfdd3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30023,6 +30023,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, @@ -30067,8 +30068,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]); }); } @@ -30445,41 +30453,51 @@ 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() { 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)(); - const inputRepository = (0, input_1.getInput)('repository'); + 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.warning('Pushing local and current branch to remote before proceeding'); + // Git commands + yield (0, git_1.switchBranch)(selectedBranch); yield (0, git_1.pushCurrentBranch)(); } - const repositoryParts = inputRepository ? inputRepository.split('/') : []; - if (repositoryParts.length && repositoryParts.length != 2) { - throw new errors_1.InputRepositoryInvalid(inputRepository); - } - const currentOwner = repositoryParts.length ? repositoryParts[0] : owner; - const currentRepository = repositoryParts.length ? repositoryParts[1] : repo; - const currentBranch = inputBranch ? inputBranch : branch; - const repository = yield core.group(`fetching repository info for owner: ${currentOwner}, repo: ${currentRepository}, 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)(currentOwner, currentRepository, 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); @@ -30487,10 +30505,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) + @@ -30512,7 +30536,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`); @@ -30646,6 +30670,7 @@ var __importStar = (this && this.__importStar) || (function () { 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() { @@ -30660,6 +30685,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/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 8731e3c..538c3f8 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, @@ -24,30 +25,43 @@ import { export async function run(): Promise { try { + core.info('Getting info from GH Worklfow context') const { owner, repo, branch } = getContext() - const inputRepository = getInput('repository') + + 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 selectedBranch = inputBranch ? inputBranch : branch + + core.debug('* owner') + const inputOwner = getInput('owner') + const selectedOwner = inputOwner ? inputOwner : owner + + core.debug('* repo') + const inputRepo = getInput('repo') + const selectedRepo = inputRepo ? inputRepo : repo - const repositoryParts = inputRepository ? inputRepository.split('/') : [] - if (repositoryParts.length && repositoryParts.length != 2) { - throw new InputRepositoryInvalid(inputRepository) + 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() } - const currentOwner = repositoryParts.length ? repositoryParts[0] : owner - const currentRepository = repositoryParts.length ? repositoryParts[1] : repo - const currentBranch = inputBranch ? inputBranch : branch const repository = await core.group( - `fetching repository info for owner: ${currentOwner}, repo: ${currentRepository}, branch: ${currentBranch}`, + `fetching repository info for owner: ${selectedOwner}, repo: ${selectedRepo}, branch: ${selectedBranch}`, async () => { const startTime = Date.now() const repositoryData = await getRepository( - currentOwner, - currentRepository, - currentBranch + selectedOwner, + selectedRepo, + selectedBranch ) const endTime = Date.now() core.debug(`time taken: ${(endTime - startTime).toString()} ms`) @@ -55,14 +69,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) @@ -71,12 +88,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 = @@ -103,7 +127,7 @@ export async function run(): Promise { commitMessage, { repositoryNameWithOwner: repository.nameWithOwner, - branchName: currentBranch, + branchName: selectedBranch, }, fileChanges ) 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 ecb196e368174201a2091a0ada4f80a567423bc9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:02:54 +0000 Subject: [PATCH 2/3] ci: update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d63eb0..8642797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,11 @@ All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines. --- -## [Unreleased](https://github.com/ryancyq/github-signed-commit/tree/HEAD) +## [1.3.0](https://github.com/ryancyq/github-signed-commit/compare/v1.2.0..v1.3.0) - 2024-10-30 + +### Features + +- Add support for remote GitHub repository + working directory ([#2](https://github.com/ryancyq/github-signed-commit/issues/2)) - ([2c19408](https://github.com/ryancyq/github-signed-commit/commit/2c19408618f096a6064093809288c28e3f4daaa1)) - Xavier Krantz ### Documentation From 5d85f5f027d01342eff841614fe2a17e7e06925c Mon Sep 17 00:00:00 2001 From: Xavier Krantz Date: Mon, 6 Jan 2025 17:17:38 +0100 Subject: [PATCH 3/3] feat: Add support for Tags push events (#3) * Update repo.ts Signed-off-by: Xavier Krantz * fix: missing ) * update repo.ts * fixup: build dist * fix: return "" on tags * chore(readme): Update inputs --------- Signed-off-by: Xavier Krantz Co-authored-by: Stessy Mougeot --- README.md | 7 ++++--- dist/index.js | 3 +++ package-lock.json | 19 +++++++++++++++++++ src/github/repo.ts | 2 ++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c1fa72..3ab61a3 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,9 @@ Note: The `GH_TOKEN` environment variable is **required** for GitHub API request | `files` | **YES** | Multi-line string of file paths to be committed, relative to the current workspace.| | `workspace` | **NO** | Directory containing files to be committed. **DEFAULT:** GitHub workspace directory (root of the repository). | | `commit-message` | **YES** | Commit message for the file changes. | -| `repository` | **NO** | Repository name including owner (e.g. owner/repo). **DEFAULT:** Workflow triggered repository | -| `branch-name` | **NO** | Branch to commit, it must already exist in the remote. **DEFAULT:** Workflow triggered branch | +| `owner` | **NO** | GitHub repository owner (user or organization), defaults to the repo invoking the action. | +| `repo` | **NO** | GitHub repository name, defaults to the repo invoking the action. | +| `branch-name` | **NO*** | Branch to commit, it must already exist in the remote. **DEFAULT:** Workflow triggered branch. **REQUIRED:** If triggered through `on tags`.| | `branch-push-force` | **NO** | `--force` flag when running `git push `. | | `tag` | **NO** | Push tag for the new/current commit. | | `tag-only-if-file-changes` | **NO** | Push tag for new commit only when file changes present. **DEFAULT:** true | @@ -80,4 +81,4 @@ Note: The `GH_TOKEN` environment variable is **required** for GitHub API request [coverage_badge]: https://codecov.io/gh/ryancyq/github-signed-commit/graph/badge.svg?token=KZTD2F2MN2 [coverage]: https://codecov.io/gh/ryancyq/github-signed-commit [maintainability_badge]: https://api.codeclimate.com/v1/badges/0de9dbec270ca85719c6/maintainability -[maintainability]: https://codeclimate.com/github/ryancyq/github-signed-commit/maintainability \ No newline at end of file +[maintainability]: https://codeclimate.com/github/ryancyq/github-signed-commit/maintainability diff --git a/dist/index.js b/dist/index.js index 42cfdd3..89cc785 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30387,6 +30387,9 @@ function resolveCurrentBranch(ref) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access return (_c = (_b = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.head) === null || _b === void 0 ? void 0 : _b.ref) !== null && _c !== void 0 ? _c : ''; } + else if (ref.startsWith('refs/tags/')) { + return ''; + } throw new Error(`Unsupported ref: ${ref}`); } function getContext() { diff --git a/package-lock.json b/package-lock.json index 5ac1151..5a4e174 100644 --- a/package-lock.json +++ b/package-lock.json @@ -632,9 +632,15 @@ } }, "node_modules/@eslint/plugin-kit": { +<<<<<<< HEAD "version": "0.2.7", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", +======= + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", +>>>>>>> db38b15 (feat: Add support for Tags push events (#3)) "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2126,6 +2132,11 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", +<<<<<<< HEAD +======= + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", +>>>>>>> db38b15 (feat: Add support for Tags push events (#3)) "dev": true, "license": "MIT", "dependencies": { @@ -4806,6 +4817,7 @@ "node": ">=4" } }, +<<<<<<< HEAD "node_modules/typedescriptor": { "version": "3.0.2", "dev": true, @@ -4816,6 +4828,13 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, +======= + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, +>>>>>>> db38b15 (feat: Add support for Tags push events (#3)) "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/src/github/repo.ts b/src/github/repo.ts index b54e7c3..4ab9b8f 100644 --- a/src/github/repo.ts +++ b/src/github/repo.ts @@ -6,6 +6,8 @@ function resolveCurrentBranch(ref: string): string { } else if (ref.startsWith('refs/pull/')) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access return github.context.payload.pull_request?.head?.ref ?? '' + } else if (ref.startsWith('refs/tags/')) { + return '' } throw new Error(`Unsupported ref: ${ref}`)