Skip to content

Commit 37e1cd1

Browse files
committed
Adds npm_publish() macro.
This generates a binary which publishes the given package to NPM. It just merges the given directory with the root `.npmrc` file (which contains authentication information) and calls `npm publish`. Also made publish binaries for `rules_prerender` and `@rules_prerender/declarative_shadow_dom`. I tried to add a trap which deletes the staging directory after the binary has run, but I got permission errors and couldn't easily figure out what was going on. Fortunately `mktemp` still creates files under `$TMP`, so they should be cleaned up automatically, just a little less agressively than they could be.
1 parent f42c1ea commit 37e1cd1

5 files changed

Lines changed: 111 additions & 0 deletions

File tree

BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test")
66
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
77
load("@npm_rules_js//:defs.bzl", "npm_link_all_packages")
88
load("//tools:publish.bzl", "publish_files")
9+
load("//tools/publish:npm_publish.bzl", "npm_publish")
910
load("//tools/stamping:stamp_package.bzl", "stamp_package")
1011
load("//:index.bzl", "link_prerender_component", "prerender_component", "prerender_component_publish_files")
1112

13+
exports_files([".npmrc"], visibility = ["//visibility:public"])
14+
1215
ts_config(
1316
name = "tsconfig",
1417
src = "tsconfig.json",
@@ -41,6 +44,11 @@ npm_package(
4144
# See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276
4245
include_external_repositories = ["rules_prerender"],
4346
)
47+
npm_publish(
48+
name = "rules_prerender_pkg_publish",
49+
package = ":rules_prerender_pkg",
50+
npmrc = ".npmrc",
51+
)
4452
npm_link_package(
4553
name = "node_modules/rules_prerender",
4654
src = ":rules_prerender_pkg",

packages/rules_prerender/declarative_shadow_dom/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ load(
1010
load("//tools:jasmine.bzl", "jasmine_node_test")
1111
load("//tools:publish.bzl", "publish_files")
1212
load("//tools:typescript.bzl", "ts_project")
13+
load("//tools/publish:npm_publish.bzl", "npm_publish")
1314
load("//tools/stamping:stamp_package.bzl", "stamp_package")
1415

1516
publish_files(
@@ -37,6 +38,11 @@ npm_package(
3738
# See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276
3839
include_external_repositories = ["rules_prerender"],
3940
)
41+
npm_publish(
42+
name = "pkg_publish",
43+
package = ":pkg",
44+
npmrc = "//:.npmrc",
45+
)
4046

4147
prerender_component(
4248
name = "declarative_shadow_dom",

tools/publish/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
2+
3+
exports_files(["npm_publish.sh"], visibility = ["//visibility:public"])
4+
5+
bzl_library(
6+
name = "npm_publish",
7+
srcs = ["npm_publish.bzl"],
8+
)

tools/publish/npm_publish.bzl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
2+
load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo")
3+
load("@bazel_skylib//rules:build_test.bzl", "build_test")
4+
load("//common:label.bzl", "absolute", "file_path_of")
5+
6+
def npm_publish(name, package, npmrc, testonly = None, visibility = None):
7+
"""Publishes the given `npm_package()` to NPM.
8+
9+
Generates a binary which, when run, publishes the given package to NPM.
10+
Authentication information should be provided via `_authToken` in the
11+
provided `.npmrc` file. Also generates a test to make sure the binary builds
12+
successfully, since this it is very likely nothing else will depend on this.
13+
14+
Args:
15+
name: Name of this target.
16+
package: The `npm_package()` to publish.
17+
npmrc: The `.npmrc` file containing authentication information.
18+
testonly: https://bazel.build/reference/be/common-definitions#common-attributes
19+
visibility: https://bazel.build/reference/be/common-definitions#common-attributes
20+
"""
21+
# For some reason we need to `copy_to_bin()` for the directory to show up in
22+
# `sh_binary()` runfiles? TBH, I don't understand why this is necessary.
23+
package_bin = "%s_package" % name
24+
copy_to_bin(
25+
name = package_bin,
26+
srcs = [package],
27+
testonly = testonly,
28+
)
29+
30+
# Merge the `.npmrc` and package together, then run `npm publish`.
31+
# Authentication information should be in the `.npmrc`.
32+
native.sh_binary(
33+
name = name,
34+
srcs = [Label("//tools/publish:npm_publish.sh")],
35+
data = [package_bin, npmrc, "@pnpm//:pnpm"],
36+
args = [
37+
"rules_prerender/%s" % _normalize(file_path_of(absolute(package))),
38+
"rules_prerender/%s" % _normalize(file_path_of(absolute(npmrc))),
39+
"pnpm/pnpm.sh",
40+
],
41+
deps = ["@bazel_tools//tools/bash/runfiles"],
42+
testonly = testonly,
43+
visibility = visibility,
44+
)
45+
46+
# Always generate a test so the release process doesn't attempt to run
47+
# multiple publish binaries only to find that the second one fails to build.
48+
build_test(
49+
name = "%s_test" % name,
50+
targets = [":%s" % name],
51+
)
52+
53+
# Bash runfiles is very particular about file paths, extra `./` paths are not
54+
# allowed.
55+
def _normalize(path):
56+
normalized = path.replace("/./", "/")
57+
if normalized.startswith("./"):
58+
return normalized[2:]
59+
return normalized

tools/publish/npm_publish.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# --- begin runfiles.bash initialization v2 ---
2+
# Copy-pasted from the Bazel Bash runfiles library v2.
3+
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
4+
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
5+
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
6+
source "$0.runfiles/$f" 2>/dev/null || \
7+
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
8+
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
9+
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
10+
# --- end runfiles.bash initialization v2 ---
11+
12+
# Resolve arguments.
13+
readonly PACKAGE="$(rlocation ${1})"
14+
readonly NPMRC="$(rlocation ${2})"
15+
readonly NPM="$(rlocation ${3})"
16+
17+
# Make sure there isn't already an `.npmrc` file in the package.
18+
if [[ -f "${PACKAGE}/.npmrc" ]]; then
19+
echo ".npmrc already exists in `${PACKAGE}`, expected it not to." >&2
20+
exit 1
21+
fi
22+
23+
# Merge the package and the `.npmrc` in the temporary staging directory.
24+
readonly STAGING_DIRECTORY=$(mktemp -d)
25+
cp -r ${PACKAGE}/* "${STAGING_DIRECTORY}"
26+
cp "${NPMRC}" "${STAGING_DIRECTORY}/.npmrc"
27+
28+
# Publish to NPM. Use `--no-git-checks` to ignore the `.git/` state, which is
29+
# still discovered by NPM, even within a Bazel context.
30+
"${NPM}" publish "${STAGING_DIRECTORY}" --no-git-checks --access public

0 commit comments

Comments
 (0)