-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f075a8a
commit 364a0d5
Showing
4 changed files
with
258 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import { describe, it } from "https://deno.land/[email protected]/testing/bdd.ts"; | ||
import { | ||
assertEquals, | ||
assertMatch, | ||
assertNotEquals, | ||
} from "https://deno.land/[email protected]/assert/mod.ts"; | ||
import * as garn from "./mod.ts"; | ||
import { assertSuccess, runCommand, runExecutable } from "./testUtils.ts"; | ||
import outdent from "https://deno.land/x/[email protected]/mod.ts"; | ||
|
||
const project = garn | ||
.mkProject( | ||
{ | ||
description: "", | ||
defaultEnvironment: garn.emptyEnvironment, | ||
}, | ||
{ | ||
buildProject: garn.build`echo built > $out/artifact ; echo hidden > $out/.hidden`, | ||
}, | ||
) | ||
.add(garn.deployToGhPages((self) => self.buildProject)); | ||
|
||
const mkGitRepo = () => { | ||
const path = Deno.makeTempDirSync(); | ||
const run = (...args: Array<string>) => { | ||
const output = runCommand(new Deno.Command("git", { args, cwd: path })); | ||
assertSuccess(output); | ||
return output.stdout; | ||
}; | ||
run("init"); | ||
run("commit", "--allow-empty", "-m", "first commit"); | ||
return { run, path }; | ||
}; | ||
|
||
const ansiRegexp = "(?:\\x1b\\[[0-9;]+m)+"; | ||
|
||
describe("deployToGhPagesBranch", () => { | ||
it("allows to create a commit on a new 'gh-pages' branch", () => { | ||
const gitRepo = mkGitRepo(); | ||
const output = runExecutable(project.deployToGhPages, { | ||
cwd: gitRepo.path, | ||
}); | ||
assertSuccess(output); | ||
assertMatch( | ||
output.stderr, | ||
regexp` | ||
^ | ||
warning: creating lock file [^\\n]+\\n | ||
(?: | ||
this derivation will be built:\\n | ||
[^\\n]+\\n | ||
building[^\\n]+\\n | ||
)? | ||
Created commit to "gh-pages" branch, but it has not been pushed yet\\n | ||
Run ${ansiRegexp}git push <remote> gh-pages:gh-pages${ansiRegexp} to deploy\\n | ||
$ | ||
`, | ||
); | ||
gitRepo.run("checkout", "gh-pages"); | ||
assertEquals( | ||
Array.from(Deno.readDirSync(gitRepo.path)) | ||
.map((x) => x.name) | ||
.sort(), | ||
[".git", ".hidden", "artifact"], | ||
); | ||
assertEquals(Deno.readTextFileSync(`${gitRepo.path}/artifact`), "built\n"); | ||
assertMatch( | ||
gitRepo.run("log", "-n1", "--pretty=format:%s"), | ||
/^Deploy [0-9a-f]{7} to gh-pages$/, | ||
); | ||
assertEquals(gitRepo.run("status", "--short"), ""); | ||
}); | ||
|
||
it("allows to create a commit on an existing 'gh-pages' branch", () => { | ||
const gitRepo = mkGitRepo(); | ||
gitRepo.run("checkout", "--orphan", "gh-pages"); | ||
Deno.writeTextFileSync(`${gitRepo.path}/foo`, "some existing content"); | ||
Deno.writeTextFileSync(`${gitRepo.path}/.hidden`, "some hidden content"); | ||
gitRepo.run("add", "foo", ".hidden"); | ||
gitRepo.run("commit", "-m", "Add some files"); | ||
gitRepo.run("checkout", "master"); | ||
assertSuccess( | ||
runExecutable(project.deployToGhPages, { cwd: gitRepo.path }), | ||
); | ||
gitRepo.run("checkout", "gh-pages"); | ||
assertEquals( | ||
Array.from(Deno.readDirSync(gitRepo.path)) | ||
.map((x) => x.name) | ||
.sort(), | ||
[".git", ".hidden", "artifact"], | ||
); | ||
assertEquals(Deno.readTextFileSync(`${gitRepo.path}/artifact`), "built\n"); | ||
assertMatch( | ||
gitRepo.run("log", "--pretty=format:%s"), | ||
/^Deploy [0-9a-f]{7} to gh-pages\nAdd some files$/, | ||
); | ||
assertEquals(gitRepo.run("status", "--short"), ""); | ||
}); | ||
|
||
it("does not commit files from the source branch to the 'gh-pages' branch", () => { | ||
const gitRepo = mkGitRepo(); | ||
Deno.writeTextFileSync(`${gitRepo.path}/foo`, "some existing content"); | ||
Deno.writeTextFileSync(`${gitRepo.path}/.hidden`, "some hidden content"); | ||
gitRepo.run("add", "foo", ".hidden"); | ||
gitRepo.run("commit", "-m", "Add some files"); | ||
assertSuccess( | ||
runExecutable(project.deployToGhPages, { cwd: gitRepo.path }), | ||
); | ||
gitRepo.run("checkout", "gh-pages"); | ||
assertEquals( | ||
Array.from(Deno.readDirSync(gitRepo.path)) | ||
.map((x) => x.name) | ||
.sort(), | ||
[".git", ".hidden", "artifact"], | ||
); | ||
assertMatch( | ||
gitRepo.run("log", "--pretty=format:%s"), | ||
/^Deploy [0-9a-f]{7} to gh-pages$/, | ||
); | ||
}); | ||
|
||
it("does not affect working-tree changes", () => { | ||
const gitRepo = mkGitRepo(); | ||
Deno.writeTextFileSync(`${gitRepo.path}/foo`, "some existing content"); | ||
gitRepo.run("add", "foo"); | ||
gitRepo.run("commit", "-m", "Add foo"); | ||
Deno.writeTextFileSync(`${gitRepo.path}/foo`, "foo has been modified"); | ||
Deno.writeTextFileSync( | ||
`${gitRepo.path}/untracked`, | ||
"some untracked content", | ||
); | ||
assertSuccess( | ||
runExecutable(project.deployToGhPages, { cwd: gitRepo.path }), | ||
); | ||
assertEquals( | ||
Array.from(Deno.readDirSync(gitRepo.path)) | ||
.map((x) => x.name) | ||
.sort(), | ||
[".git", "foo", "untracked"], | ||
); | ||
}); | ||
|
||
it("throws an error if the gh-pages branch is already checked out", () => { | ||
const gitRepo = mkGitRepo(); | ||
gitRepo.run("checkout", "-b", "gh-pages"); | ||
const output = runExecutable(project.deployToGhPages, { | ||
cwd: gitRepo.path, | ||
}); | ||
assertNotEquals(output.exitCode, 0); | ||
assertMatch( | ||
output.stderr, | ||
regexp` | ||
^ | ||
warning: creating lock file [^\\n]+\\n | ||
${ansiRegexp}error: | ||
${ansiRegexp} deployToGhPages cannot run if gh-pages is currently checked out. Please change branches first.${ansiRegexp}\\n | ||
$ | ||
`, | ||
); | ||
}); | ||
}); | ||
|
||
function regexp(f: TemplateStringsArray, ...templates: Array<string>) { | ||
return new RegExp(outdent(f, ...templates).replaceAll("\n", "")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Executable } from "./executable.ts"; | ||
import { Package } from "./package.ts"; | ||
import { Plugin } from "./project.ts"; | ||
|
||
const ansiBold = "\\e[0;1m"; | ||
const ansiReset = "\\e[0m"; | ||
const ansiRedBold = "\\e[31;1m"; | ||
|
||
/** | ||
* A garn plugin that allows easy deployment of a package to GitHub pages. | ||
* | ||
* @param pkg - The `Package` whose artifacts will be committed to the | ||
* `gh-pages` branch. For convenience, this can also be a function that takes | ||
* in a refrence to the project and returns the `Package`. | ||
* | ||
* Example: | ||
* ```typescript | ||
* export const myProject = mkNpmProject({ ... }) | ||
* .addPackage("genStaticSite", "npm run build && mv dist/* $out") | ||
* .add(garn.deployToGhPages(project => project.genStaticSite)); | ||
* ``` | ||
* | ||
* Then running `garn run myProject.deployToGhPages` will create the `gh-pages` | ||
* branch for you if it doesn't already exist, and add a commit containing the | ||
* artifacts from the specified project (`genStaticSite` in the example above) | ||
* to the branch. | ||
* | ||
* At this point all you need to do to deploy is push the branch to GitHub with | ||
* `git push <remote> gh-pages:gh-pages` | ||
*/ | ||
export function deployToGhPages<T>( | ||
pkg: Package | ((t: T) => Package), | ||
): Plugin<{ deployToGhPages: Executable }, T> { | ||
return (p) => { | ||
if (p.defaultEnvironment == null) { | ||
throw new Error( | ||
`'deployToGhPages' can only be added to projects with a default environment`, | ||
); | ||
} | ||
return { | ||
deployToGhPages: p.defaultEnvironment!.shell` | ||
set -eu | ||
REPO_DIR=$(git rev-parse --show-toplevel) | ||
TMP_DIR=$(mktemp -d) | ||
TMP_SRC="$TMP_DIR/src" | ||
TMP_DST="$TMP_DIR/dst" | ||
VERSION_NAME=$(git describe --tags --dirty --always) | ||
function cleanup() { | ||
rm -rf "$TMP_DIR" | ||
} | ||
trap cleanup EXIT | ||
if [ "$(git rev-parse --abbrev-ref HEAD)" = gh-pages ]; then | ||
>&2 echo -e '${ansiRedBold}error:${ansiBold} deployToGhPages cannot run if gh-pages is currently checked out. Please change branches first.${ansiReset}' | ||
exit 1 | ||
fi | ||
git clone --quiet "$REPO_DIR" "$TMP_SRC" | ||
git -C "$TMP_SRC" checkout gh-pages 2>/dev/null || git -C "$TMP_SRC" checkout --quiet --orphan gh-pages | ||
cp -rv ${typeof pkg === "function" ? pkg(p) : pkg} "$TMP_DST" | ||
chmod +w "$TMP_DST" | ||
mv "$TMP_SRC/.git" "$TMP_DST" | ||
git -C "$TMP_DST" add . | ||
git -C "$TMP_DST" commit -m "Deploy $VERSION_NAME to gh-pages" | ||
git fetch --quiet "$TMP_DST" gh-pages:gh-pages | ||
>&2 echo -e 'Created commit to "gh-pages" branch, but it has not been pushed yet' | ||
>&2 echo -e 'Run ${ansiBold}git push <remote> gh-pages:gh-pages${ansiReset} to deploy' | ||
`, | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters