@org-press/deploy-github-pages 0.9.12

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/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
6
+
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+ For the full license text, see: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
11
+
12
+ ---
13
+
14
+ Org-Press - Static site generator for org-mode files
15
+ Copyright (C) 2024-2026
16
+
17
+ This program is free software; you can redistribute it and/or modify
18
+ it under the terms of the GNU General Public License as published by
19
+ the Free Software Foundation; either version 2 of the License, or
20
+ (at your option) any later version.
21
+
22
+ This program is distributed in the hope that it will be useful,
23
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
+ GNU General Public License for more details.
26
+
27
+ You should have received a copy of the GNU General Public License
28
+ along with this program; if not, write to the Free Software
29
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @org-press/deploy-github-pages
2
+
3
+ GitHub Pages deploy adapter for [org-press](https://orgp.dev).
4
+
5
+ Deploys static sites to GitHub Pages by pushing to the `gh-pages` branch.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @org-press/deploy-github-pages
11
+ # or
12
+ pnpm add @org-press/deploy-github-pages
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Basic Usage
18
+
19
+ ```typescript
20
+ import { githubPagesAdapter } from '@org-press/deploy-github-pages';
21
+
22
+ export default defineConfig({
23
+ deploy: {
24
+ adapter: githubPagesAdapter({
25
+ repo: 'user/my-site',
26
+ }),
27
+ },
28
+ });
29
+ ```
30
+
31
+ ### With Custom Domain
32
+
33
+ ```typescript
34
+ import { githubPagesAdapter } from '@org-press/deploy-github-pages';
35
+
36
+ export default defineConfig({
37
+ deploy: {
38
+ adapter: githubPagesAdapter({
39
+ repo: 'user/my-site',
40
+ cname: 'mysite.com',
41
+ }),
42
+ },
43
+ });
44
+ ```
45
+
46
+ ### Full Configuration
47
+
48
+ ```typescript
49
+ import { githubPagesAdapter } from '@org-press/deploy-github-pages';
50
+
51
+ export default defineConfig({
52
+ deploy: {
53
+ adapter: githubPagesAdapter({
54
+ // GitHub repository (user/repo or org/repo format)
55
+ // If not specified, auto-detects from git remote
56
+ repo: 'user/my-site',
57
+
58
+ // Target branch (default: 'gh-pages')
59
+ branch: 'gh-pages',
60
+
61
+ // Custom domain for CNAME file
62
+ cname: 'mysite.com',
63
+
64
+ // Add .nojekyll file (default: true)
65
+ // Recommended for pre-built static sites
66
+ noJekyll: true,
67
+
68
+ // Commit message (default: 'Deploy to GitHub Pages')
69
+ message: 'Deploy docs from CI',
70
+
71
+ // Remote name (default: 'origin')
72
+ remote: 'origin',
73
+ }),
74
+ },
75
+ });
76
+ ```
77
+
78
+ ## Configuration Options
79
+
80
+ | Option | Type | Default | Description |
81
+ |--------|------|---------|-------------|
82
+ | `repo` | `string` | Auto-detected | GitHub repository in `user/repo` format |
83
+ | `branch` | `string` | `'gh-pages'` | Target branch for deployment |
84
+ | `cname` | `string` | - | Custom domain (creates CNAME file) |
85
+ | `noJekyll` | `boolean` | `true` | Add `.nojekyll` file to disable Jekyll |
86
+ | `message` | `string` | `'Deploy to GitHub Pages'` | Git commit message |
87
+ | `remote` | `string` | `'origin'` | Git remote name |
88
+
89
+ ## How It Works
90
+
91
+ The adapter deploys your site by:
92
+
93
+ 1. Adding a `.nojekyll` file (optional, recommended)
94
+ 2. Adding a `CNAME` file if a custom domain is configured
95
+ 3. Initializing a new git repository in your build output directory
96
+ 4. Committing all files
97
+ 5. Force pushing to the `gh-pages` branch on GitHub
98
+
99
+ This approach ensures a clean deployment each time without accumulating history.
100
+
101
+ ## Auto-Detection
102
+
103
+ If `repo` is not specified, the adapter attempts to auto-detect the repository from your git remote:
104
+
105
+ ```bash
106
+ # Supports both HTTPS and SSH remote URLs:
107
+ https://github.com/user/repo.git
108
+ git@github.com:user/repo.git
109
+ ```
110
+
111
+ ## Dry Run Mode
112
+
113
+ Test your deployment without actually pushing:
114
+
115
+ ```typescript
116
+ const result = await deploy({
117
+ adapter: githubPagesAdapter({ repo: 'user/repo' }),
118
+ dryRun: true,
119
+ });
120
+
121
+ console.log(result.url); // Predicted GitHub Pages URL
122
+ ```
123
+
124
+ ## GitHub Pages URL
125
+
126
+ The adapter returns the correct URL based on your repository:
127
+
128
+ - **User/Org pages** (`username.github.io`): `https://username.github.io`
129
+ - **Project pages** (`user/project`): `https://user.github.io/project`
130
+ - **Custom domain**: `https://your-domain.com`
131
+
132
+ ## Requirements
133
+
134
+ - Git must be installed and available in PATH
135
+ - Push access to the target repository
136
+ - For private repos, appropriate authentication (SSH key or token)
137
+
138
+ ## CI/CD Example
139
+
140
+ ### GitHub Actions
141
+
142
+ ```yaml
143
+ name: Deploy to GitHub Pages
144
+
145
+ on:
146
+ push:
147
+ branches: [main]
148
+
149
+ jobs:
150
+ deploy:
151
+ runs-on: ubuntu-latest
152
+ permissions:
153
+ contents: write
154
+ steps:
155
+ - uses: actions/checkout@v4
156
+
157
+ - uses: pnpm/action-setup@v2
158
+ with:
159
+ version: 8
160
+
161
+ - uses: actions/setup-node@v4
162
+ with:
163
+ node-version: 20
164
+ cache: 'pnpm'
165
+
166
+ - run: pnpm install
167
+ - run: pnpm build
168
+
169
+ - name: Deploy
170
+ run: pnpm deploy
171
+ env:
172
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
173
+ ```
174
+
175
+ ## License
176
+
177
+ GPL-2.0
package/dist/index.js ADDED
@@ -0,0 +1,235 @@
1
+ // src/adapter.ts
2
+ import { spawnSync } from "child_process";
3
+ import { writeFileSync, existsSync, rmSync } from "fs";
4
+ import { join } from "path";
5
+ var GitHubPagesAdapter = class {
6
+ name = "github-pages";
7
+ description = "Deploy to GitHub Pages";
8
+ config;
9
+ constructor(config = {}) {
10
+ this.config = config;
11
+ }
12
+ /**
13
+ * Validate adapter configuration
14
+ *
15
+ * Checks:
16
+ * - git is available in PATH
17
+ * - Repository format is valid (if specified)
18
+ */
19
+ async validate(adapterConfig) {
20
+ const errors = [];
21
+ const warnings = [];
22
+ const gitCheck = spawnSync("git", ["--version"], {
23
+ encoding: "utf-8",
24
+ timeout: 5e3
25
+ });
26
+ if (gitCheck.status !== 0) {
27
+ errors.push("git is not available in PATH");
28
+ }
29
+ const repo = adapterConfig.options.repo || this.config.repo;
30
+ if (repo) {
31
+ const repoPattern = /^[\w.-]+\/[\w.-]+$/;
32
+ if (!repoPattern.test(repo)) {
33
+ errors.push(
34
+ `Invalid repository format: "${repo}". Expected format: "user/repo" or "org/repo"`
35
+ );
36
+ }
37
+ }
38
+ const branch = adapterConfig.options.branch || this.config.branch || "gh-pages";
39
+ const branchPattern = /^[\w./-]+$/;
40
+ if (!branchPattern.test(branch)) {
41
+ errors.push(`Invalid branch name: "${branch}"`);
42
+ }
43
+ if (!repo) {
44
+ warnings.push(
45
+ "No repository specified. Will attempt to auto-detect from git remote."
46
+ );
47
+ }
48
+ return {
49
+ valid: errors.length === 0,
50
+ errors,
51
+ warnings
52
+ };
53
+ }
54
+ /**
55
+ * Execute deployment to GitHub Pages
56
+ *
57
+ * Initializes a git repository in the output directory,
58
+ * adds all files, and force pushes to the gh-pages branch.
59
+ */
60
+ async deploy(context) {
61
+ const { outDir, metadata, adapterConfig, dryRun, logger } = context;
62
+ const branch = adapterConfig.branch || this.config.branch || "gh-pages";
63
+ const cname = adapterConfig.cname ?? this.config.cname;
64
+ const noJekyll = adapterConfig.noJekyll ?? this.config.noJekyll ?? true;
65
+ const message = adapterConfig.message || this.config.message || "Deploy to GitHub Pages";
66
+ const remote = adapterConfig.remote || this.config.remote || "origin";
67
+ let repo = adapterConfig.repo || this.config.repo;
68
+ if (!repo) {
69
+ repo = this.autoDetectRepo();
70
+ if (!repo) {
71
+ return {
72
+ success: false,
73
+ error: "Could not auto-detect repository. Please specify repo in adapter config."
74
+ };
75
+ }
76
+ logger.info(`Auto-detected repository: ${repo}`);
77
+ }
78
+ logger.info(`Deploying to GitHub Pages: ${repo}`);
79
+ logger.info(`Branch: ${branch}`);
80
+ if (cname) {
81
+ logger.info(`Custom domain: ${cname}`);
82
+ }
83
+ if (dryRun) {
84
+ logger.info("Dry run mode - skipping actual deployment");
85
+ return {
86
+ success: true,
87
+ deploymentId: `dry-run-${Date.now()}`,
88
+ url: this.getPageUrl(repo, cname),
89
+ logs: ["Dry run completed successfully"]
90
+ };
91
+ }
92
+ try {
93
+ if (noJekyll) {
94
+ const nojekyllPath = join(outDir, ".nojekyll");
95
+ writeFileSync(nojekyllPath, "");
96
+ logger.debug("Added .nojekyll file");
97
+ }
98
+ if (cname) {
99
+ const cnamePath = join(outDir, "CNAME");
100
+ writeFileSync(cnamePath, cname);
101
+ logger.debug(`Added CNAME file: ${cname}`);
102
+ }
103
+ const gitDir = join(outDir, ".git");
104
+ if (existsSync(gitDir)) {
105
+ rmSync(gitDir, { recursive: true });
106
+ }
107
+ const initResult = this.runGit(["init"], outDir);
108
+ if (!initResult.success) {
109
+ return {
110
+ success: false,
111
+ error: `Failed to initialize git repository: ${initResult.error}`
112
+ };
113
+ }
114
+ logger.debug("Initialized git repository");
115
+ this.runGit(
116
+ ["config", "user.email", "github-pages-deploy@org-press"],
117
+ outDir
118
+ );
119
+ this.runGit(["config", "user.name", "org-press deploy"], outDir);
120
+ const addResult = this.runGit(["add", "-A"], outDir);
121
+ if (!addResult.success) {
122
+ return {
123
+ success: false,
124
+ error: `Failed to add files: ${addResult.error}`
125
+ };
126
+ }
127
+ logger.debug("Added all files to git");
128
+ const commitResult = this.runGit(
129
+ ["commit", "-m", message],
130
+ outDir
131
+ );
132
+ if (!commitResult.success) {
133
+ return {
134
+ success: false,
135
+ error: `Failed to create commit: ${commitResult.error}`
136
+ };
137
+ }
138
+ logger.debug("Created commit");
139
+ const remoteUrl = `https://github.com/${repo}.git`;
140
+ const remoteAddResult = this.runGit(
141
+ ["remote", "add", remote, remoteUrl],
142
+ outDir
143
+ );
144
+ if (!remoteAddResult.success) {
145
+ this.runGit(["remote", "set-url", remote, remoteUrl], outDir);
146
+ }
147
+ logger.debug(`Set remote ${remote} to ${remoteUrl}`);
148
+ logger.info(`Pushing to ${remote}/${branch}...`);
149
+ const pushResult = this.runGit(
150
+ ["push", "-f", remote, `HEAD:${branch}`],
151
+ outDir
152
+ );
153
+ if (!pushResult.success) {
154
+ return {
155
+ success: false,
156
+ error: `Failed to push to GitHub: ${pushResult.error}`,
157
+ logs: pushResult.output ? [pushResult.output] : void 0
158
+ };
159
+ }
160
+ logger.info("Successfully deployed to GitHub Pages!");
161
+ return {
162
+ success: true,
163
+ deploymentId: `${repo}@${branch}`,
164
+ url: this.getPageUrl(repo, cname),
165
+ logs: pushResult.output ? [pushResult.output] : void 0
166
+ };
167
+ } catch (err) {
168
+ const error = err instanceof Error ? err.message : String(err);
169
+ logger.error(`Deployment failed: ${error}`);
170
+ return {
171
+ success: false,
172
+ error: `Deployment failed: ${error}`
173
+ };
174
+ }
175
+ }
176
+ /**
177
+ * Auto-detect repository from git remote
178
+ */
179
+ autoDetectRepo() {
180
+ const result = spawnSync("git", ["remote", "get-url", "origin"], {
181
+ encoding: "utf-8",
182
+ timeout: 5e3
183
+ });
184
+ if (result.status !== 0 || !result.stdout) {
185
+ return void 0;
186
+ }
187
+ const url = result.stdout.trim();
188
+ const httpsMatch = url.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
189
+ if (httpsMatch) {
190
+ return `${httpsMatch[1]}/${httpsMatch[2]}`;
191
+ }
192
+ return void 0;
193
+ }
194
+ /**
195
+ * Get the GitHub Pages URL for the repository
196
+ */
197
+ getPageUrl(repo, cname) {
198
+ if (cname) {
199
+ return `https://${cname}`;
200
+ }
201
+ const [user, repoName] = repo.split("/");
202
+ if (repoName === `${user}.github.io`) {
203
+ return `https://${user}.github.io`;
204
+ }
205
+ return `https://${user}.github.io/${repoName}`;
206
+ }
207
+ /**
208
+ * Run a git command and return the result
209
+ */
210
+ runGit(args, cwd) {
211
+ const result = spawnSync("git", args, {
212
+ cwd,
213
+ encoding: "utf-8",
214
+ timeout: 6e4
215
+ });
216
+ if (result.status !== 0) {
217
+ return {
218
+ success: false,
219
+ output: result.stdout,
220
+ error: result.stderr || result.stdout || "Unknown git error"
221
+ };
222
+ }
223
+ return {
224
+ success: true,
225
+ output: result.stdout
226
+ };
227
+ }
228
+ };
229
+ function githubPagesAdapter(config = {}) {
230
+ return new GitHubPagesAdapter(config);
231
+ }
232
+ export {
233
+ GitHubPagesAdapter,
234
+ githubPagesAdapter
235
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@org-press/deploy-github-pages",
3
+ "version": "0.9.12",
4
+ "description": "GitHub Pages deploy adapter for org-press",
5
+ "license": "GPL-2.0",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "README.md"
19
+ ],
20
+ "peerDependencies": {
21
+ "@org-press/deploy": ">=0.9.0"
22
+ },
23
+ "devDependencies": {
24
+ "tsup": "^8.0.0",
25
+ "typescript": "~5.7.3",
26
+ "@types/node": "^20.0.0",
27
+ "vitest": "^3.1.4",
28
+ "@org-press/deploy": "0.9.12"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "homepage": "https://orgp.dev",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/org-press/org-press.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/org-press/org-press/issues"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "dev": "tsup --watch",
44
+ "test": "vitest",
45
+ "test:ci": "vitest --run",
46
+ "clean": "rm -rf dist"
47
+ }
48
+ }