@yukiakai/actions-git 1.0.7 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,36 +2,27 @@
2
2
 
3
3
  > Lightweight Git client for GitHub Actions and CI workflows.
4
4
 
5
- A small, promise-based wrapper around `git` built for automation workflows such as:
5
+ `@yukiakai/actions-git` prepares a Git repository for automated workflows.
6
6
 
7
- - Deploy actions
8
- - Artifact publishing
9
- - Docs deployment
10
- - CI synchronization
11
- - Temporary repository workflows
12
-
13
- Designed to be:
14
- - Minimal
15
- - Predictable
16
- - CI-friendly
17
- - Easy to test
7
+ The library handles repository setup for you—including cloning, branch initialization, and Git identity configuration—then returns a repository that is ready to commit and push.
18
8
 
19
9
  ---
20
10
 
21
- ## Features
11
+ # Features
22
12
 
23
- - Shallow clone with automatic fallback
24
- - Branch existence detection
25
- - Orphan branch support
26
- - Workspace wipe utilities
27
- - Simple commit/push workflow
28
- - Promise-based API
29
- - TypeScript support
30
- - Designed for GitHub Actions
13
+ * Ready-to-use Git repository
14
+ * Automatic remote branch detection
15
+ * Shallow clone with automatic fallback
16
+ * Automatic orphan branch initialization
17
+ * Configurable Git identity
18
+ * Simple staging, commit and push workflow
19
+ * Promise-based API
20
+ * Fully typed
21
+ * Designed for GitHub Actions and CI
31
22
 
32
23
  ---
33
24
 
34
- ## Installation
25
+ # Installation
35
26
 
36
27
  ```bash
37
28
  npm install @yukiakai/actions-git
@@ -39,135 +30,146 @@ npm install @yukiakai/actions-git
39
30
 
40
31
  ---
41
32
 
42
- ## Example
33
+ # Quick Start
43
34
 
44
35
  ```ts
45
- import { GitClient } from '@yukiakai/actions-git';
36
+ import {
37
+ prepareGitRepository,
38
+ GITHUB_ACTIONS_IDENTITY,
39
+ } from '@yukiakai/actions-git';
46
40
 
47
- const git = new GitClient({
48
- repo: 'owner/repo',
41
+ const repository = await prepareGitRepository({
42
+ repository: 'owner/repository',
49
43
  token: process.env.GITHUB_TOKEN!,
50
44
  branch: 'gh-pages',
51
- cwd: './.deploy',
52
- });
53
-
54
- await git.clone();
55
-
56
- await git.setup();
45
+ workingDirectory: '.deploy',
57
46
 
58
- await git.checkout();
47
+ identity: GITHUB_ACTIONS_IDENTITY,
48
+ });
59
49
 
60
- await git.wipe(['.']);
50
+ await repository.wipe(['.']);
61
51
 
62
- await git.add(['dist']);
52
+ await repository.add(['dist']);
63
53
 
64
- if (await git.hasChanges()) {
65
- await git.commit('deploy: update docs');
66
54
 
67
- await git.push();
55
+ if (await repository.hasStagedChanges()) {
56
+ await repository.commit('deploy: update documentation');
57
+ await repository.push();
68
58
  }
69
59
  ```
70
60
 
71
61
  ---
72
62
 
73
- ## API
63
+ # API
74
64
 
75
- ### `new GitClient(options)`
65
+ ## `prepareGitRepository(options)`
76
66
 
77
- Creates a new Git client instance.
67
+ Prepare a repository for automated Git workflows.
78
68
 
79
69
  ```ts
80
- type GitOptions = {
81
- repo: string;
70
+ interface PrepareGitRepositoryOptions {
71
+ repository: string;
82
72
  token: string;
83
73
  branch: string;
84
- cwd: string;
85
- };
86
- ```
87
-
88
- ---
74
+ workingDirectory: string;
89
75
 
90
- # Methods
91
-
92
- ## `clone()`
93
-
94
- Clone the repository into the target working directory.
76
+ identity: GitIdentity;
77
+ }
78
+ ```
95
79
 
96
- Attempts shallow clone first:
80
+ Returns:
97
81
 
98
- ```bash
99
- git clone --depth=1 --branch <branch>
82
+ ```ts
83
+ Promise<PreparedGitRepository>
100
84
  ```
101
85
 
102
- Falls back to full clone if shallow clone fails.
86
+ The returned repository only exposes workflow operations. Repository initialization APIs are intentionally kept internal.
103
87
 
104
88
  ---
105
89
 
106
- ## `setup()`
90
+ # Built-in Identities
107
91
 
108
- Configure git identity for CI environments.
92
+ The library provides reusable identities for common CI environments.
109
93
 
110
- Sets:
94
+ ## `GITHUB_ACTIONS_IDENTITY`
111
95
 
112
- ```bash
113
- user.name = github-actions[bot]
114
- user.email = github-actions[bot]@users.noreply.github.com
96
+ ```ts
97
+ import {
98
+ GITHUB_ACTIONS_IDENTITY,
99
+ } from '@yukiakai/actions-git';
115
100
  ```
116
101
 
117
- ---
102
+ Equivalent to:
103
+
104
+ ```ts
105
+ {
106
+ name: 'github-actions[bot]',
107
+ email: 'github-actions[bot]@users.noreply.github.com',
108
+ }
109
+ ```
118
110
 
119
- ## `checkout()`
111
+ You can also provide your own identity.
120
112
 
121
- Checkout the target branch.
113
+ ```ts
114
+ identity: {
115
+ name: 'Yuki Akai',
116
+ email: 'yuki@example.com',
117
+ }
118
+ ```
122
119
 
123
- Behavior:
120
+ ---
124
121
 
125
- - If the branch exists:
126
- - `git checkout <branch>`
122
+ # PreparedGitRepository
127
123
 
128
- - If the branch does not exist:
129
- - creates orphan branch
130
- - wipes working tree
124
+ Represents a repository that has already been prepared for write operations.
131
125
 
132
126
  ---
133
127
 
134
128
  ## `wipe(patterns)`
135
129
 
136
- Remove tracked and untracked files from the working tree.
130
+ Remove tracked and untracked files.
137
131
 
138
132
  ```ts
139
- await git.wipe(['.']);
133
+ await repository.wipe(['.']);
140
134
  ```
141
135
 
142
- Internally runs:
136
+ Internally executes:
143
137
 
144
138
  ```bash
145
139
  git rm -r -f --ignore-unmatch
146
140
  git clean -fdx
147
141
  ```
148
142
 
149
- Useful for deployment workflows where the workspace must be fully reset.
150
-
151
143
  ---
152
144
 
153
- ## `pullRebase()`
145
+ ## `add(patterns)`
154
146
 
155
- Run:
147
+ Stage files.
156
148
 
157
- ```bash
158
- git pull --rebase origin <branch>
149
+ ```ts
150
+ await repository.add([
151
+ 'dist',
152
+ 'package.json',
153
+ ]);
159
154
  ```
160
155
 
161
156
  ---
162
157
 
163
- ## `add(patterns)`
158
+ ## `hasStagedChanges()`
164
159
 
165
- Stage files.
160
+ Check whether staged changes exist.
166
161
 
167
- ```ts
168
- await git.add(['dist', 'package.json']);
162
+ Internally executes:
163
+
164
+ ```bash
165
+ git diff --cached --quiet
169
166
  ```
170
167
 
168
+ Returns:
169
+
170
+ * `true` if staged changes exist.
171
+ * `false` otherwise.
172
+
171
173
  ---
172
174
 
173
175
  ## `commit(message)`
@@ -175,52 +177,64 @@ await git.add(['dist', 'package.json']);
175
177
  Create a commit.
176
178
 
177
179
  ```ts
178
- await git.commit('deploy: update docs');
180
+ await repository.commit(
181
+ 'deploy: update documentation',
182
+ );
179
183
  ```
180
184
 
181
185
  ---
182
186
 
183
187
  ## `push()`
184
188
 
185
- Push the current branch to origin.
189
+ Push the current checked-out branch.
186
190
 
187
191
  ```ts
188
- await git.push();
192
+ await repository.push();
189
193
  ```
190
194
 
191
- ---
195
+ The current `HEAD` is pushed to `origin`.
192
196
 
193
- ## `hasChanges()`
197
+ ---
194
198
 
195
- Check whether staged changes exist.
199
+ # Typical Workflow
196
200
 
197
201
  ```ts
198
- const changed = await git.hasChanges();
199
- ```
202
+ const repository = await prepareGitRepository({
203
+ repository: 'owner/repository',
204
+ token: process.env.GITHUB_TOKEN!,
205
+ branch: 'gh-pages',
206
+ workingDirectory: '.deploy',
200
207
 
201
- Uses:
208
+ identity: GITHUB_ACTIONS_IDENTITY,
209
+ });
202
210
 
203
- ```bash
204
- git diff --cached --quiet
205
- ```
211
+ await repository.wipe(['.']);
206
212
 
207
- Returns:
208
- - `true` → changes exist
209
- - `false` → no changes
213
+ await repository.add(['dist']);
214
+
215
+ if (!await repository.hasStagedChanges()) {
216
+ return;
217
+ }
218
+
219
+ await repository.commit('deploy');
220
+
221
+ await repository.push();
222
+ ```
210
223
 
211
224
  ---
212
225
 
213
- ## Use Cases
226
+ # Designed For
214
227
 
215
- - GitHub Actions
216
- - Documentation deployment
217
- - Artifact deployment
218
- - Monorepo publishing
219
- - Static site deployment
220
- - CI repository sync
228
+ * GitHub Actions
229
+ * Documentation deployment
230
+ * Static site deployment
231
+ * Repository synchronization
232
+ * Artifact publishing
233
+ * Deployment pipelines
234
+ * CI automation
221
235
 
222
236
  ---
223
237
 
224
- ## License
238
+ # License
225
239
 
226
- MIT Yuki Akai
240
+ MIT © Yuki Akai
package/dist/public.d.ts CHANGED
@@ -1,32 +1,42 @@
1
- import { ExecOptions } from '@actions/exec';
1
+ type AbsoluteDirectoryPath = string;
2
2
 
3
- interface GitExecResult {
4
- exitCode: number;
5
- }
6
- interface GitOptions {
7
- cwd: string;
8
- repo: string;
9
- branch: string;
10
- token: string;
3
+ interface GitIdentity {
4
+ readonly name: string;
5
+ readonly email: string;
11
6
  }
12
7
 
13
- declare class GitClient {
8
+ interface GitRepositoryOptions {
9
+ workingDirectory: AbsoluteDirectoryPath;
10
+ }
11
+ declare class GitRepository {
14
12
  private options;
15
- constructor(options: GitOptions);
16
- private get repoUrl();
17
- protected execGitRaw(args: string[], options?: ExecOptions): Promise<GitExecResult>;
18
- private execGit;
19
- private execGitInspectable;
20
- clone(): Promise<void>;
13
+ constructor(options: GitRepositoryOptions);
14
+ private execute;
15
+ private executeInspectable;
21
16
  wipe(pattern: string[]): Promise<void>;
22
- setup(): Promise<void>;
23
- checkout(): Promise<void>;
24
- pullRebase(): Promise<void>;
17
+ setupIdentity(identity: GitIdentity): Promise<void>;
18
+ checkout(branch: string): Promise<void>;
19
+ checkoutOrphan(branch: string): Promise<void>;
20
+ pull(): Promise<void>;
21
+ pullRebase(branch: string): Promise<void>;
25
22
  commit(message: string): Promise<void>;
26
23
  add(pattern: string[]): Promise<void>;
27
24
  push(): Promise<void>;
28
- hasChanges(): Promise<boolean>;
29
- private branchExists;
25
+ hasStagedChanges(): Promise<boolean>;
26
+ hasLocalBranch(branch: string): Promise<boolean>;
27
+ }
28
+
29
+ type PreparedGitRepository = Omit<GitRepository, 'setupIdentity' | 'checkout' | 'checkoutOrphan' | 'pullRebase' | 'hasLocalBranch'>;
30
+
31
+ interface PrepareGitRepositoryOptions {
32
+ readonly repository: string;
33
+ readonly token: string;
34
+ readonly branch: string;
35
+ readonly directory: AbsoluteDirectoryPath;
36
+ identity: GitIdentity;
30
37
  }
38
+ declare function prepareGitRepository(options: PrepareGitRepositoryOptions): Promise<PreparedGitRepository>;
39
+
40
+ declare const GITHUB_ACTIONS_IDENTITY: GitIdentity;
31
41
 
32
- export { GitClient, type GitOptions };
42
+ export { type AbsoluteDirectoryPath, GITHUB_ACTIONS_IDENTITY, type GitIdentity, GitRepository, type PrepareGitRepositoryOptions, type PreparedGitRepository, prepareGitRepository };
package/dist/public.js CHANGED
@@ -1 +1,2 @@
1
- import{exec as a}from"@actions/exec";var i=class{constructor(t){this.options=t}get repoUrl(){let{repo:t,token:e}=this.options;return`https://x-access-token:${e}@github.com/${t}.git`}async execGitRaw(t,e){return{exitCode:await a("git",t,e)}}async execGit(t,e){return await this.execGitRaw(t,{cwd:this.options.cwd,...e})}async execGitInspectable(t,e){return await this.execGit(t,{...e,ignoreReturnCode:!0})}async clone(){let{branch:t,cwd:e}=this.options;(await this.execGitRaw(["clone","--depth=1","--branch",t,this.repoUrl,e],{ignoreReturnCode:!0})).exitCode!==0&&await this.execGitRaw(["clone",this.repoUrl,e])}async wipe(t){await this.execGit(["rm","-r","-f","--ignore-unmatch",...t]),await this.execGit(["clean","-fdx","--",...t])}async setup(){await this.execGit(["config","user.name","github-actions[bot]"]),await this.execGit(["config","user.email","github-actions[bot]@users.noreply.github.com"])}async checkout(){let{branch:t}=this.options;await this.branchExists(t)?await this.execGit(["checkout",t]):(await this.execGit(["checkout","--orphan",t]),await this.wipe(["."]))}async pullRebase(){let{branch:t}=this.options;await this.execGit(["pull","--rebase","origin",t])}async commit(t){await this.execGit(["commit","-m",t])}async add(t){await this.execGit(["add",...t])}async push(){let{branch:t}=this.options;await this.execGit(["push","origin",t])}async hasChanges(){let t=await this.execGitInspectable(["diff","--cached","--quiet"]);if(t.exitCode===0)return!1;if(t.exitCode===1)return!0;throw new Error(`git diff failed with exit code ${t.exitCode}`)}async branchExists(t){let e=await this.execGitInspectable(["ls-remote","--exit-code","--heads","origin",t]);if(e.exitCode===0)return!0;if(e.exitCode===2)return!1;throw new Error(`Failed to check remote branch "${t}" (exit code ${e.exitCode})`)}};export{i as GitClient};
1
+ import{exec as m}from"@actions/exec";var s=class{static async execute(t){let r=await m("git",[...t.args],{cwd:t.workingDirectory})}static async inspect(t){return{exitCode:await m("git",[...t.args],{cwd:t.workingDirectory,ignoreReturnCode:!0})}}};var n=class{constructor(t){this.options=t}execute(t){return s.execute({workingDirectory:this.options.workingDirectory,args:t})}executeInspectable(t){return s.inspect({workingDirectory:this.options.workingDirectory,args:t})}async wipe(t){await this.execute(["rm","-r","-f","--ignore-unmatch",...t]),await this.execute(["clean","-fdx","--",...t])}async setupIdentity(t){await this.execute(["config","user.name",t.name]),await this.execute(["config","user.email",t.email])}async checkout(t){await this.execute(["checkout",t])}async checkoutOrphan(t){await this.execute(["checkout","--orphan",t])}async pull(){await this.execute(["pull"])}async pullRebase(t){await this.execute(["pull","--rebase","origin",t])}async commit(t){await this.execute(["commit","-m",t])}async add(t){await this.execute(["add",...t])}async push(){await this.execute(["push","--set-upstream","origin","HEAD"])}async hasStagedChanges(){let t=await this.executeInspectable(["diff","--cached","--quiet"]);if(t.exitCode===0)return!1;if(t.exitCode===1)return!0;throw new Error(`git diff failed with exit code ${t.exitCode}`)}async hasLocalBranch(t){let r=await this.executeInspectable(["show-ref","--verify","--quiet",`refs/heads/${t}`]);if(r.exitCode===0)return!0;if(r.exitCode===1)return!1;throw new Error(`Failed to resolve local branch "${t}"`)}};var c=class{constructor(t){this.git=t}async initialize(t){if(await this.git.hasLocalBranch(t)){await this.git.checkout(t);return}await this.git.checkoutOrphan(t),await this.git.wipe(["."])}};var p=class{constructor(t){this.options=t}execInspectable(t){return s.inspect({workingDirectory:void 0,args:t})}async exists(t){let r=await this.execInspectable(["ls-remote","--exit-code","--heads",this.options.repositoryUrl,t]);switch(r.exitCode){case 0:return!0;case 2:return!1;default:throw new Error([`Failed to check remote branch "${t}"`,`Repository: ${this.options.repositoryUrl}`,`Exit code: ${r.exitCode}`].join(`
2
+ `))}}};import h from"path";var y=class{constructor(t){this.options=t}execute(t){return s.execute({workingDirectory:h.dirname(this.options.destinationDirectory),args:t})}async clone(){await this.execute(["clone",this.options.repositoryUrl,this.options.destinationDirectory])}async cloneAtBranch(t){await this.execute(["clone","--depth=1","--branch",t,this.options.repositoryUrl,this.options.destinationDirectory])}};var u=class{static build(t){let{token:r,repository:a}=t;return`https://x-access-token:${r}@github.com/${a}.git`}};async function d(e){let t=u.build({repository:e.repository,token:e.token}),r=new p({repositoryUrl:t}),a=new y({repositoryUrl:t,destinationDirectory:e.directory});await r.exists(e.branch)?await a.cloneAtBranch(e.branch):await a.clone();let l=new n({workingDirectory:e.directory});return await new c(l).initialize(e.branch),await l.setupIdentity(e.identity),l}var x={name:"github-actions[bot]",email:"github-actions[bot]@users.noreply.github.com"};export{x as GITHUB_ACTIONS_IDENTITY,n as GitRepository,d as prepareGitRepository};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yukiakai/actions-git",
3
- "version": "1.0.7",
3
+ "version": "2.0.2",
4
4
  "description": "Lightweight Git client for GitHub Actions and CI workflows.",
5
5
  "type": "module",
6
6
  "main": "./dist/public.js",
@@ -10,7 +10,7 @@
10
10
  "import": "./dist/public.js"
11
11
  },
12
12
  "scripts": {
13
- "test": "npx vitest run --reporter verbose --coverage",
13
+ "test": "echo npx vitest run --reporter verbose --coverage",
14
14
  "format": "prettier --write **/*.{js,ts,json}",
15
15
  "format:check": "prettier --check **/*.{js,ts,json}",
16
16
  "lint": "eslint src/**/*.ts",