Skip to content

Publish packages to GitHub Release #9

Publish packages to GitHub Release

Publish packages to GitHub Release #9

name: Publish packages to GitHub Release
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g. v1.2.3)"
required: true
type: string
title:
description: "Release title (optional). Defaults to the tag."
required: false
type: string
prerelease:
description: "Mark as prerelease?"
required: false
default: false
type: boolean
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
# Optional but recommended: ensure tag doesn't already exist
- name: Check if tag already exists
id: tagcheck
run: |
set -euo pipefail
TAG="${{ inputs.tag }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists locally."
fi
if git ls-remote --tags origin "$TAG" | grep -q "$TAG"; then
echo "Tag $TAG already exists on origin. Refusing to overwrite."
exit 1
fi
# Create and push the tag pointing to the current commit
- name: Create and push tag
run: |
set -euo pipefail
TAG="${{ inputs.tag }}"
git tag "$TAG"
git push origin "$TAG"
- name: Reclaim disk space
uses: AdityaGarg8/remove-unwanted-software@v5
with:
remove-dotnet: true
remove-haskell: true
remove-codeql: true
remove-docker-images: true
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: latest
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24.10.0"
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build packages
run: pnpm nx run-many -t build --projects="packages/*"
- name: Patch package.json monorepo deps to tarball URLs
env:
OLD_VER: "workspace:*"
TAG: "1.0.0-alpha.20"
BASE_URL: "https://github.com/nachooya/react-native-harness/releases/download"
SCOPE: "@react-native-harness/"
run: |
set -euo pipefail
node <<'NODE'
const fs = require("fs");
const path = require("path");
const OLD_VER = process.env.OLD_VER;
const TAG = process.env.TAG;
const BASE_URL = process.env.BASE_URL;
const SCOPE = process.env.SCOPE;
// Recursively find all package.json files (excluding node_modules/dist)
function findPackageJson(dir, out = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
const full = path.join(dir, entry.name);
if (entry.isDirectory()) findPackageJson(full, out);
else if (entry.isFile() && entry.name === "package.json") out.push(full);
}
return out;
}
function tarballUrl(pkgName) {
// pkgName is like "@react-native-harness/runtime"
const monorepoPackage = pkgName.startsWith(SCOPE)
? pkgName.slice(SCOPE.length)
: pkgName;
return `${BASE_URL}/${TAG}/react-native-harness-${monorepoPackage}-${TAG}.tgz`;
}
const files = findPackageJson(process.cwd());
let totalChanges = 0;
for (const file of files) {
const raw = fs.readFileSync(file, "utf8");
const pkg = JSON.parse(raw);
let changed = false;
// fields to patch
const depFields = [
"dependencies",
"devDependencies",
"peerDependencies",
"optionalDependencies",
];
for (const field of depFields) {
if (!pkg[field]) continue;
for (const [name, ver] of Object.entries(pkg[field])) {
if (ver === OLD_VER && name.startsWith(SCOPE)) {
pkg[field][name] = tarballUrl(name);
changed = true;
}
}
}
if (changed) {
fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + "\n");
console.log("Patched:", file);
totalChanges++;
}
}
console.log(`✅ Patched ${totalChanges} package.json files`);
NODE
- name: Create package tarballs
run: |
set -euo pipefail
mkdir -p dist
for pkg in ./packages/*; do
if [ -f "$pkg/package.json" ]; then
echo "Packing $pkg"
(cd "$pkg" && pnpm pack --pack-destination ../../dist)
fi
done
# Optional: generate checksums
- name: Generate checksums
run: |
set -euo pipefail
sha256sum dist/*.tgz > dist/checksums.txt
- name: Create GitHub Release and upload assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag }}
name: ${{ inputs.title || inputs.tag }}
prerelease: ${{ inputs.prerelease }}
generate_release_notes: true
files: |
dist/*.tgz
dist/checksums.txt