Skip to content

Commit b127b6e

Browse files
authored
Prepare docs and release v1.0.0 (#12)
* Add individual modules to package exports * Import getOctokit from root of package * Clean up interfaces & arguments * Add initial documentation * Add changeset * Bump version * Additional docs improvements
1 parent 0f8c582 commit b127b6e

13 files changed

+398
-96
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @s0/ghcommit
22

3+
## 1.0.0
4+
5+
### Major Changes
6+
7+
- be55175: First major release
8+
39
## 0.1.0
410

511
### Minor Changes

README.md

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# `@s0/ghcommit`
2+
3+
[![View on NPM](https://badgen.net/npm/v/@s0/ghcommit)](https://www.npmjs.com/package/@s0/ghcommit)
4+
5+
NPM / TypeScript package to commit changes GitHub repositories using the GraphQL API.
6+
7+
## Why?
8+
9+
If you or your organisation has strict requirements
10+
around requiring signed commits (i.e. via Branch Protection or Repo Rulesets), then this can make integrating CI workflows or applications that are designed to make changes to your repos quite difficult. This is because you will need to manage your own GPG keys, assign them to machine accounts (which also means it doesn't work with GitHub Apps), and securely manage and rotate them.
11+
12+
Instead of doing this, if you use the GitHub API to make changes to files (such as what happens when making changes to files directly in the web UI), then GitHub's internal GPG key is used, and commits are all signed and associated with the user of the access token that was used.
13+
14+
(And this also works with GitHub Apps too, including the GitHub Actions app).
15+
16+
![](docs/verified.png)
17+
18+
This library has primarily been designed for use in custom Node GitHub Actions, but can be used in any Node.js or JavaScript project that needs to directly modify files in GitHub repositories.
19+
20+
## Usage
21+
22+
### Installation
23+
24+
Install using your favourite package manager:
25+
26+
```
27+
pnpm install @s0/ghcommit
28+
```
29+
30+
### Usage in github actions
31+
32+
All functions in this library that interact with the GitHub API require an octokit client that can execute GraphQL. If you are writing code that is designed to be run from within a GitHub Action, this can be done using the `@actions.github` library:
33+
34+
```ts
35+
import { getOctokit } from "@actions/github";
36+
37+
const octokit = getOctokit(process.env.GITHUB_TOKEN);
38+
```
39+
40+
### Importing specific modules
41+
42+
To allow for you to produce smaller bundle sizes, the functionality exposed in this package is grouped into specific modules that only import the packages required for their use. We recommend that you import from the specific modules rather than the root of the package.
43+
44+
## API
45+
46+
All the functions below accept a single object as its argument, and share the following base arguments:
47+
48+
<!-- TODO: point to some generated docs instead of including a code snippet -->
49+
50+
```ts
51+
{
52+
octokit: GitHubClient;
53+
owner: string;
54+
repository: string;
55+
branch: string;
56+
/**
57+
* Push the commit even if the branch exists and does not match what was
58+
* specified as the base.
59+
*/
60+
force?: boolean;
61+
/**
62+
* The commit message
63+
*/
64+
message: CommitMessage;
65+
log?: Logger;
66+
}
67+
```
68+
69+
### `commitChangesFromRepo`
70+
71+
This function will take an existing repository on your filesystem (defaulting to the current working directory). This function is good to use if you're usually working within the context of a git repository, such as after running `@actions/checkout` in github actions.
72+
73+
In addition to `CommitFilesBasedArgs`, this function has the following arguments:
74+
75+
```ts
76+
{
77+
/**
78+
* The root of the repository.
79+
*
80+
* @default process.cwd()
81+
*/
82+
repoDirectory?: string;
83+
}
84+
```
85+
86+
Example:
87+
88+
```ts
89+
import { getOctokit } from "@actions/github";
90+
import { commitChangesFromRepo } from "@s0/ghcommit/git";
91+
92+
const octokit = getOctokit(process.env.GITHUB_TOKEN);
93+
94+
// Commit & push the files from the current directory
95+
// e.g. if you're just using @ations/checkout
96+
await commitChangesFromRepo({
97+
octokit,
98+
owner: "my-org",
99+
repository: "my-repo",
100+
branch: "new-branch-to-create",
101+
message: {
102+
headline: "[chore] do something",
103+
},
104+
});
105+
106+
// Commit & push the files from ta specific directory
107+
// where we've cloned a repo, and made changes to files
108+
await commitChangesFromRepo({
109+
octokit,
110+
owner: "my-org",
111+
repository: "my-repo",
112+
branch: "another-new-branch-to-create",
113+
message: {
114+
headline: "[chore] do something else",
115+
},
116+
repoDirectory: "/tmp/some-repo",
117+
});
118+
```
119+
120+
### `commitFilesFromDirectory`
121+
122+
This function will add or delete specific files from a repository's branch based on files found on the local filesystem. This is good to use when there are specific files that need to be updated on a branch, or if many changes may have been made locally, but only some files need to be pushed.
123+
124+
In addition to `CommitFilesBasedArgs`, this function has the following arguments:
125+
126+
```ts
127+
{
128+
/**
129+
* The current branch, tag or commit that the new branch should be based on.
130+
*/
131+
base: GitBase;
132+
/**
133+
* The directory to consider the root of the repository when calculating
134+
* file paths
135+
*/
136+
workingDirectory?: string;
137+
/**
138+
* The file paths, relative to {@link workingDirectory},
139+
* to add or delete from the branch on GitHub.
140+
*/
141+
fileChanges: {
142+
/** File paths, relative to {@link workingDirectory}, to remove from the repo. */
143+
additions?: string[];
144+
/** File paths, relative to the repository root, to remove from the repo. */
145+
deletions?: string[];
146+
};
147+
}
148+
```
149+
150+
Example:
151+
152+
```ts
153+
import { getOctokit } from "@actions/github";
154+
import { commitFilesFromDirectory } from "@s0/ghcommit/fs";
155+
156+
const octokit = getOctokit(process.env.GITHUB_TOKEN);
157+
158+
// Commit the changes to package.json and package-lock.json
159+
// based on the main branch
160+
await commitFilesFromDirectory({
161+
octokit,
162+
owner: "my-org",
163+
repository: "my-repo",
164+
branch: "new-branch-to-create",
165+
message: {
166+
headline: "[chore] do something",
167+
},
168+
base: {
169+
branch: "main",
170+
},
171+
workingDirectory: "foo/bar",
172+
fileChanges: {
173+
additions: ["package-lock.json", "package.json"],
174+
},
175+
});
176+
177+
// Push just the index.html file to a new branch called docs, based off the tag v1.0.0
178+
await commitFilesFromDirectory({
179+
octokit,
180+
owner: "my-org",
181+
repository: "my-repo",
182+
branch: "docs",
183+
message: {
184+
headline: "[chore] do something",
185+
},
186+
force: true, // Overwrite any existing branch
187+
base: {
188+
tag: "v1.0.0",
189+
},
190+
workingDirectory: "some-dir",
191+
fileChanges: {
192+
additions: ["index.html"],
193+
},
194+
});
195+
```
196+
197+
### `commitFilesFromBuffers`
198+
199+
This function will add or delete specific files from a repository's branch based on Node.js `Buffers` that can be any binary data in memory. This is useful for when you want to make changes to a repository / branch without cloning a repo or interacting with a filesystem.
200+
201+
In addition to `CommitFilesBasedArgs`, this function has the following arguments:
202+
203+
```ts
204+
{
205+
/**
206+
* The current branch, tag or commit that the new branch should be based on.
207+
*/
208+
base: GitBase;
209+
/**
210+
* The file changes, relative to the repository root, to make to the specified branch.
211+
*/
212+
fileChanges: {
213+
additions?: Array<{
214+
path: string;
215+
contents: Buffer;
216+
}>;
217+
deletions?: string[];
218+
};
219+
}
220+
```
221+
222+
Example:
223+
224+
```ts
225+
import { getOctokit } from "@actions/github";
226+
import { commitFilesFromBuffers } from "@s0/ghcommit/node";
227+
228+
const octokit = getOctokit(process.env.GITHUB_TOKEN);
229+
230+
// Add a file called hello-world
231+
await commitFilesFromBuffers({
232+
octokit,
233+
owner: "my-org",
234+
repository: "my-repo",
235+
branch: "new-branch-to-create",
236+
message: {
237+
headline: "[chore] do something",
238+
},
239+
base: {
240+
branch: "main",
241+
},
242+
fileChanges: {
243+
additions: [
244+
{
245+
path: "hello/world.txt",
246+
contents: Buffer.alloc(1024, "Hello, world!"),
247+
},
248+
],
249+
},
250+
});
251+
```
252+
253+
## Other Tools / Alternatives
254+
255+
- [planetscale/ghcommit](https://github.com/planetscale/ghcommit) - Go library for committing to GitHub using graphql
256+
- [planetscale/ghcommit-action](https://github.com/planetscale/ghcommit-action) - GitHub Action to detect file changes and commit using the above library

docs/verified.png

28 KB
Loading

package.json

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@s0/ghcommit",
3-
"version": "0.1.0",
3+
"version": "1.0.0",
44
"private": false,
55
"description": "Directly change files on github using the github API, to support GPG signing",
66
"keywords": [
@@ -23,6 +23,26 @@
2323
"import": "./dist/index.mjs",
2424
"require": "./dist/index.js",
2525
"types": "./dist/index.d.ts"
26+
},
27+
"./core": {
28+
"import": "./dist/core.mjs",
29+
"require": "./dist/core.js",
30+
"types": "./dist/core.d.ts"
31+
},
32+
"./fs": {
33+
"import": "./dist/fs.mjs",
34+
"require": "./dist/fs.js",
35+
"types": "./dist/fs.d.ts"
36+
},
37+
"./git": {
38+
"import": "./dist/git.mjs",
39+
"require": "./dist/git.js",
40+
"types": "./dist/git.d.ts"
41+
},
42+
"./node": {
43+
"import": "./dist/node.mjs",
44+
"require": "./dist/node.js",
45+
"types": "./dist/node.d.ts"
2646
}
2747
},
2848
"scripts": {

src/core.ts

+5-43
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,18 @@
1-
import type {
2-
CommitMessage,
3-
FileChanges,
4-
} from "./github/graphql/generated/types.js";
51
import {
62
createCommitOnBranchQuery,
73
createRefMutation,
84
getRepositoryMetadata,
9-
GitHubClient,
105
updateRefMutation,
116
} from "./github/graphql/queries.js";
127
import type {
138
CreateCommitOnBranchMutationVariables,
149
GetRepositoryMetadataQuery,
1510
} from "./github/graphql/generated/operations.js";
16-
import type { Logger } from "./logging.js";
17-
18-
export type CommitFilesResult = {
19-
refId: string | null;
20-
};
21-
22-
export type GitBase =
23-
| {
24-
branch: string;
25-
}
26-
| {
27-
tag: string;
28-
}
29-
| {
30-
commit: string;
31-
};
32-
33-
export type CommitFilesFromBase64Args = {
34-
octokit: GitHubClient;
35-
owner: string;
36-
repository: string;
37-
branch: string;
38-
/**
39-
* The current branch, tag or commit that the new branch should be based on.
40-
*/
41-
base: GitBase;
42-
/**
43-
* Push the commit even if the branch exists and does not match what was
44-
* specified as the base.
45-
*/
46-
force?: boolean;
47-
/**
48-
* The commit message
49-
*/
50-
message: CommitMessage;
51-
fileChanges: FileChanges;
52-
log?: Logger;
53-
};
11+
import {
12+
CommitFilesFromBase64Args,
13+
CommitFilesResult,
14+
GitBase,
15+
} from "./interface.js";
5416

5517
const getBaseRef = (base: GitBase): string => {
5618
if ("branch" in base) {

src/fs.ts

+4-16
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
11
import { promises as fs } from "fs";
22
import * as path from "path";
33
import type { FileAddition } from "./github/graphql/generated/types.js";
4-
import { CommitFilesFromBase64Args, CommitFilesResult } from "./core.js";
54
import { commitFilesFromBuffers } from "./node.js";
6-
7-
export type CommitFilesFromDirectoryArgs = Omit<
8-
CommitFilesFromBase64Args,
9-
"fileChanges"
10-
> & {
11-
/**
12-
* The directory to consider the root of the repository when calculating
13-
* file paths
14-
*/
15-
workingDirectory?: string;
16-
fileChanges: {
17-
additions?: string[];
18-
deletions?: string[];
19-
};
20-
};
5+
import {
6+
CommitFilesFromDirectoryArgs,
7+
CommitFilesResult,
8+
} from "./interface.js";
219

2210
export const commitFilesFromDirectory = async ({
2311
workingDirectory = process.cwd(),

0 commit comments

Comments
 (0)