Skip to content

Commit

Permalink
Adds npm_publish() macro.
Browse files Browse the repository at this point in the history
Refs #48.

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.
  • Loading branch information
dgp1130 committed Feb 13, 2023
1 parent f42c1ea commit 1dbd456
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 0 deletions.
8 changes: 8 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
load("@npm_rules_js//:defs.bzl", "npm_link_all_packages")
load("//tools:publish.bzl", "publish_files")
load("//tools/publish:npm_publish.bzl", "npm_publish")
load("//tools/stamping:stamp_package.bzl", "stamp_package")
load("//:index.bzl", "link_prerender_component", "prerender_component", "prerender_component_publish_files")

exports_files([".npmrc"], visibility = ["//visibility:public"])

ts_config(
name = "tsconfig",
src = "tsconfig.json",
Expand Down Expand Up @@ -41,6 +44,11 @@ npm_package(
# See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276
include_external_repositories = ["rules_prerender"],
)
npm_publish(
name = "rules_prerender_pkg_publish",
package = ":rules_prerender_pkg",
npmrc = ".npmrc",
)
npm_link_package(
name = "node_modules/rules_prerender",
src = ":rules_prerender_pkg",
Expand Down
6 changes: 6 additions & 0 deletions packages/rules_prerender/declarative_shadow_dom/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ load(
load("//tools:jasmine.bzl", "jasmine_node_test")
load("//tools:publish.bzl", "publish_files")
load("//tools:typescript.bzl", "ts_project")
load("//tools/publish:npm_publish.bzl", "npm_publish")
load("//tools/stamping:stamp_package.bzl", "stamp_package")

publish_files(
Expand Down Expand Up @@ -37,6 +38,11 @@ npm_package(
# See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276
include_external_repositories = ["rules_prerender"],
)
npm_publish(
name = "pkg_publish",
package = ":pkg",
npmrc = "//:.npmrc",
)

prerender_component(
name = "declarative_shadow_dom",
Expand Down
8 changes: 8 additions & 0 deletions tools/publish/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

exports_files(["npm_publish.sh"], visibility = ["//visibility:public"])

bzl_library(
name = "npm_publish",
srcs = ["npm_publish.bzl"],
)
59 changes: 59 additions & 0 deletions tools/publish/npm_publish.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//common:label.bzl", "absolute", "file_path_of")

def npm_publish(name, package, npmrc, testonly = None, visibility = None):
"""Publishes the given `npm_package()` to NPM.
Generates a binary which, when run, publishes the given package to NPM.
Authentication information should be provided via `_authToken` in the
provided `.npmrc` file. Also generates a test to make sure the binary builds
successfully, since this it is very likely nothing else will depend on this.
Args:
name: Name of this target.
package: The `npm_package()` to publish.
npmrc: The `.npmrc` file containing authentication information.
testonly: https://bazel.build/reference/be/common-definitions#common-attributes
visibility: https://bazel.build/reference/be/common-definitions#common-attributes
"""
# For some reason we need to `copy_to_bin()` for the directory to show up in
# `sh_binary()` runfiles? TBH, I don't understand why this is necessary.
package_bin = "%s_package" % name
copy_to_bin(
name = package_bin,
srcs = [package],
testonly = testonly,
)

# Merge the `.npmrc` and package together, then run `npm publish`.
# Authentication information should be in the `.npmrc`.
native.sh_binary(
name = name,
srcs = [Label("//tools/publish:npm_publish.sh")],
data = [package_bin, npmrc, "@pnpm//:pnpm"],
args = [
"rules_prerender/%s" % _normalize(file_path_of(absolute(package))),
"rules_prerender/%s" % _normalize(file_path_of(absolute(npmrc))),
"pnpm/pnpm.sh",
],
deps = ["@bazel_tools//tools/bash/runfiles"],
testonly = testonly,
visibility = visibility,
)

# Always generate a test so the release process doesn't attempt to run
# multiple publish binaries only to find that the second one fails to build.
build_test(
name = "%s_test" % name,
targets = [":%s" % name],
)

# Bash runfiles is very particular about file paths, extra `./` paths are not
# allowed.
def _normalize(path):
normalized = path.replace("/./", "/")
if normalized.startswith("./"):
return normalized[2:]
return normalized
30 changes: 30 additions & 0 deletions tools/publish/npm_publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# --- begin runfiles.bash initialization v2 ---
# Copy-pasted from the Bazel Bash runfiles library v2.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v2 ---

# Resolve arguments.
readonly PACKAGE="$(rlocation ${1})"
readonly NPMRC="$(rlocation ${2})"
readonly NPM="$(rlocation ${3})"

# Make sure there isn't already an `.npmrc` file in the package.
if [[ -f "${PACKAGE}/.npmrc" ]]; then
echo ".npmrc already exists in `${PACKAGE}`, expected it not to." >&2
exit 1
fi

# Merge the package and the `.npmrc` in the temporary staging directory.
readonly STAGING_DIRECTORY=$(mktemp -d)
cp -r ${PACKAGE}/* "${STAGING_DIRECTORY}"
cp "${NPMRC}" "${STAGING_DIRECTORY}/.npmrc"

# Publish to NPM. Use `--no-git-checks` to ignore the `.git/` state, which is
# still discovered by NPM, even within a Bazel context.
"${NPM}" publish "${STAGING_DIRECTORY}" --no-git-checks --access public

0 comments on commit 1dbd456

Please sign in to comment.