Skip to content

Release Pipeline

Release Pipeline #19

Workflow file for this run

name: Release Pipeline
permissions:
contents: read
on:
workflow_dispatch:
inputs:
package_name:
description: 'Package folder (Name of the package directory under packages/ folder. e.g., xrpl, ripple-address-codec)'
required: true
npmjs_dist_tag:
description: 'npm distribution tag(Read more https://docs.npmjs.com/adding-dist-tags-to-packages)'
default: 'latest'
concurrency:
group: release
cancel-in-progress: true
jobs:
get_version:
runs-on: ubuntu-latest
name: Get release version from package.json
outputs:
package_version: ${{ steps.get_version.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate inputs
run: |
set -euo pipefail
RELEASE_BRANCH="$(git branch --show-current || true)"
if [[ -z "$RELEASE_BRANCH" ]]; then
RELEASE_BRANCH="${{ github.ref_name }}"
fi
if [[ -z "$RELEASE_BRANCH" ]]; then
echo "❌ Unable to determine branch name." >&2
exit 1
fi
# Validate package_name
PKG_NAME="${{ github.event.inputs.package_name }}"
if ! [[ "$PKG_NAME" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
echo "❌ Invalid package_name '$PKG_NAME' (allowed: [a-z0-9-], must start with alnum)." >&2
exit 1
fi
# Guard against path traversal
if [[ "$PKG_NAME" == *".."* || "$PKG_NAME" == *"/"* ]]; then
echo "❌ package_name must be a single directory under packages/." >&2
exit 1
fi
if [[ ! "${RELEASE_BRANCH,,}" =~ ^release[-/] ]]; then
echo "❌ Release branch '$RELEASE_BRANCH' must start with 'release-' or 'release/'." >&2
exit 1
fi
if grep -R --exclude-dir=.git --exclude-dir=.github "artifactory.ops.ripple.com" .; then
echo "❌ Internal Artifactory URL found"
exit 1
else
echo "✅ No Internal Artifactory URL found"
fi
# validate dist tag
NPM_DIST_TAG="${{ github.event.inputs.npmjs_dist_tag }}"
# Empty → default to 'latest'
if [ -z "$NPM_DIST_TAG" ]; then
NPM_DIST_TAG="latest"
echo "ℹ️ npmjs_dist_tag empty → defaulting to 'latest'."
fi
# Must start with a lowercase letter; then [a-z0-9._-]; max 128 chars
if ! [[ "$NPM_DIST_TAG" =~ ^[a-z][a-z0-9._-]{0,127}$ ]]; then
echo "❌ Invalid npm dist-tag '$NPM_DIST_TAG'. Must start with a lowercase letter and contain only [a-z0-9._-], max 128 chars." >&2
exit 1
fi
# Disallow version-like prefixes (avoid semver/range confusion)
if [[ "$NPM_DIST_TAG" =~ ^v[0-9] || "$NPM_DIST_TAG" =~ ^[0-9] ]]; then
echo "❌ Invalid npm dist-tag '$NPM_DIST_TAG'. Must not start with 'v' + digit or a digit (e.g., 'v1', '1.2.3')." >&2
exit 1
fi
echo "✅ npmjs_dist_tag '$NPM_DIST_TAG' is valid."
- name: Get package version from package.json
id: get_version
run: |
set -euo pipefail
PACKAGE_NAME="${{ github.event.inputs.package_name }}"
PKG_JSON="packages/${PACKAGE_NAME}/package.json"
if [[ ! -f "$PKG_JSON" ]]; then
echo "package.json not found at $PKG_JSON. Check 'package_name' input." >&2
exit 1
fi
VERSION=$(jq -er .version "$PKG_JSON")
if [[ -z "$VERSION" || "$VERSION" == "null" ]]; then
echo "Version is empty or missing in $PKG_JSON" >&2
exit 1
fi
NPM_DIST_TAG="${{ github.event.inputs.npmjs_dist_tag }}"
if [ -z "$NPM_DIST_TAG" ]; then
NPM_DIST_TAG="latest"
fi
if [[ "$NPM_DIST_TAG" == "latest" ]] && ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "With npmjs_dist_tag 'latest', version must be of the form x.y.z. Found '$VERSION'." >&2
exit 1
fi
echo "PACKAGE_VERSION=$VERSION" >> "$GITHUB_ENV"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
run_faucet_test:
name: Run faucet tests ${{ needs.get_version.outputs.package_version }}
needs: [get_version]
uses: ./.github/workflows/faucet_test.yml
with:
git_ref: ${{ github.ref }}
secrets: inherit
run_tests:
name: Run unit/integration tests ${{ needs.get_version.outputs.package_version }}
permissions:
contents: read
id-token: write
pages: write
needs: [get_version]
uses: ./.github/workflows/nodejs.yml
with:
git_ref: ${{ github.ref }}
secrets: inherit
pre_release:
runs-on: ubuntu-latest
needs: [get_version, run_faucet_test, run_tests]
name: Pre Release Pipeline for ${{ needs.get_version.outputs.package_version }}
permissions:
issues: write
env:
PACKAGE_VERSION: "${{ needs.get_version.outputs.package_version }}"
PACKAGE_NAME: "${{ github.event.inputs.package_name }}"
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Build package
run: |
# dubugging info
npm i -g npm@11.6.0
npm --version
node --version
ls -l
pwd
#build
npm ci
npm run build
- name: Notify Slack if tests fail
if: failure()
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
run: |
MESSAGE="❌ Build failed for xrpl.js ${{ env.PACKAGE_VERSION }}. Check the logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg channel "#xrpl-js" \
--arg text "$MESSAGE" \
'{channel: $channel, text: $text}')"
- name: Install cyclonedx-npm
run: npm install -g @cyclonedx/cyclonedx-npm@4.0.2
- name: Generate CycloneDX SBOM
run: cyclonedx-npm --output-format json --output-file sbom.json
- name: Scan SBOM for vulnerabilities using Trivy
uses: aquasecurity/trivy-action@0.28.0
with:
scan-type: sbom
scan-ref: sbom.json
format: table
exit-code: 0
output: vuln-report.txt
severity: CRITICAL,HIGH
- name: Upload sbom to OWASP
run: |
curl -X POST \
-H "X-Api-Key: ${{ secrets.OWASP_TOKEN }}" \
-F "autoCreate=true" \
-F "projectName=xrpl-js" \
-F "projectVersion=${{ env.PACKAGE_VERSION }}" \
-F "bom=@sbom.json" \
https://owasp-dt-api.prod.ripplex.io/api/v1/bom
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
- name: Print scan report
run: cat vuln-report.txt
- name: Upload vulnerability report artifact
id: upload_vuln
uses: actions/upload-artifact@v4
with:
name: vulnerability-report
path: vuln-report.txt
- name: Build vuln artifact URL
id: vuln_art
run: |
echo "art_url=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.upload_vuln.outputs.artifact-id }}" >> "$GITHUB_OUTPUT"
- name: Check vulnerabilities in report
id: check_vulns
shell: bash
env:
REPORT_PATH: vuln-report.txt # change if different
run: |
set -euo pipefail
if grep -qE "CRITICAL|HIGH" "$REPORT_PATH"; then
echo "found=true" >> "$GITHUB_OUTPUT"
else
echo "found=false" >> "$GITHUB_OUTPUT"
fi
- name: Create GitHub Issue (links to report artifact)
if: steps.check_vulns.outputs.found == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
PKG_NAME: ${{ env.PACKAGE_NAME }}
PKG_VER: ${{ env.PACKAGE_VERSION }}
REL_BRANCH: ${{ github.ref_name }}
VULN_ART_URL: ${{ steps.vuln_art.outputs.art_url }}
LABELS: security
run: |
set -euo pipefail
TITLE="🔒 Security vulnerabilities in ${PKG_NAME}@${PKG_VER}"
: > issue_body.md
echo "The vulnerability scan has detected **CRITICAL/HIGH** vulnerabilities for \`${PKG_NAME}@${PKG_VER}\` on branch \`${REL_BRANCH}\`." >> issue_body.md
echo "" >> issue_body.md
echo "**Release Branch:** \`${REL_BRANCH}\`" >> issue_body.md
echo "**Package Version:** \`${PKG_VER}\`" >> issue_body.md
echo "" >> issue_body.md
echo "**Full vulnerability report:** ${VULN_ART_URL}" >> issue_body.md
echo "" >> issue_body.md
echo "Please review the report and take necessary action." >> issue_body.md
echo "" >> issue_body.md
echo "---" >> issue_body.md
echo "_This issue was automatically generated by the Release Pipeline._" >> issue_body.md
gh issue create --title "$TITLE" --body-file issue_body.md --label "$LABELS"
- name: Generate lerna.json for choosen the package
run: |
echo "🔧 Updating lerna.json to include only packages/${{ env.PACKAGE_NAME }}"
# Use jq to update the packages field safely
jq --arg pkg "packages/${{ env.PACKAGE_NAME }}" '.packages = [$pkg]' lerna.json > lerna.tmp.json && mv lerna.tmp.json lerna.json
echo "✅ lerna.json updated:"
cat lerna.json
- name: Pack tarball
run: |
set -euo pipefail
echo "Packaging ${{ env.PACKAGE_NAME }}"
find "packages/${{ env.PACKAGE_NAME }}" -maxdepth 1 -name '*.tgz' -delete || true
FULL_PACKAGE_NAME="$(jq -er '.name' packages/${{ env.PACKAGE_NAME }}/package.json)"
TARBALL=$(npx lerna exec --scope "$FULL_PACKAGE_NAME" -- npm pack --json | jq -r '.[0].filename')
echo "TARBALL=packages/${{ env.PACKAGE_NAME }}/${TARBALL}" >> "$GITHUB_ENV"
- name: Upload tarball as artifact
uses: actions/upload-artifact@v4
with:
name: npm-package-tarball
path: ${{ env.TARBALL }}
ask_for_dev_team_review:
runs-on: ubuntu-latest
needs: [get_version, run_faucet_test, run_tests, pre_release]
permissions:
pull-requests: write
name: Print Test/Security scan result and invite Dev team to review
env:
PACKAGE_VERSION: "${{ needs.get_version.outputs.package_version }}"
PACKAGE_NAME: "${{ github.event.inputs.package_name }}"
RELEASE_BRANCH: "${{ github.ref_name }}"
outputs:
reviewers_dev: ${{ steps.get_reviewers.outputs.reviewers_dev }}
reviewers_sec: ${{ steps.get_reviewers.outputs.reviewers_sec }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create PR from release branch to main (skips for rc/beta)
id: ensure_pr
if: ${{ github.event.inputs.npmjs_dist_tag == '' || github.event.inputs.npmjs_dist_tag == 'latest' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
RELEASE_BRANCH: ${{ github.ref_name }}
VERSION: ${{ needs.get_version.outputs.package_version }}
run: |
set -euo pipefail
echo "🔎 Checking if a PR already exists for $RELEASE_BRANCH → main…"
OWNER="${REPO%%/*}"
# Find existing OPEN PR: base=main, head=OWNER:RELEASE_BRANCH
PRS_JSON="$(gh api -H 'Accept: application/vnd.github+json' \
"/repos/$REPO/pulls?state=open&base=main&head=${OWNER}:${RELEASE_BRANCH}")"
PR_NUMBER="$(printf '%s' "$PRS_JSON" | jq -r '.[0].number // empty')"
PR_URL="$(printf '%s' "$PRS_JSON" | jq -r '.[0].html_url // empty')"
if [ -n "${PR_NUMBER:-}" ]; then
echo "ℹ️ Found existing PR: #$PR_NUMBER ($PR_URL)"
else
echo "📝 Creating PR for release $VERSION from $RELEASE_BRANCH → main"
CREATE_JSON="$(jq -n \
--arg title "Release $VERSION: $RELEASE_BRANCH → main" \
--arg head "$RELEASE_BRANCH" \
--arg base "main" \
--arg body "Automated PR for release **$VERSION** from **$RELEASE_BRANCH** → **main**. Workflow Run: https://github.com/$REPO/actions/runs/${{ github.run_id }}" \
'{title:$title, head:$head, base:$base, body:$body}')"
RESP="$(gh api -H 'Accept: application/vnd.github+json' \
--method POST /repos/$REPO/pulls --input <(printf '%s' "$CREATE_JSON"))"
PR_NUMBER="$(printf '%s' "$RESP" | jq -r '.number')"
PR_URL="$(printf '%s' "$RESP" | jq -r '.html_url')"
fi
# Expose as step outputs (use these in later steps)
echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
- name: Get reviewers
id: get_reviewers
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
ENV_DEV_NAME: first-review
ENV_SEC_NAME: official-release
PACKAGE_NAME: ${{ env.PACKAGE_NAME }}
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
NPMJS_DIST_TAG: ${{ github.event.inputs.npmjs_dist_tag }}
PR_URL: ${{ steps.ensure_pr.outputs.pr_url }}
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }}
run: |
set -euo pipefail
fetch_reviewers() {
local env_name="$1"
local env_json reviewers
env_json="$(curl -sSf \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$REPO/environments/$env_name")" || true
reviewers="$(printf '%s' "$env_json" | jq -r '
(.protection_rules // [])
| map(select(.type=="required_reviewers") | .reviewers // [])
| add // []
| map(
if .type=="User" then (.reviewer.login)
elif .type=="Team" then (.reviewer.slug)
else (.reviewer.login // .reviewer.slug // "unknown")
end
)
| unique
| join(", ")
')"
if [ -z "$reviewers" ] || [ "$reviewers" = "null" ]; then
reviewers="(no required reviewers configured)"
fi
printf '%s' "$reviewers"
}
# Get reviewer lists
REVIEWERS_DEV="$(fetch_reviewers "$ENV_DEV_NAME")"
REVIEWERS_SEC="$(fetch_reviewers "$ENV_SEC_NAME")"
# Output messages
echo "reviewers_dev=$REVIEWERS_DEV" >> "$GITHUB_OUTPUT"
echo "reviewers_sec=$REVIEWERS_SEC" >> "$GITHUB_OUTPUT"
- name: Release summary for review
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
REPO: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
ENV_NAME: official-release
PACKAGE_NAME: ${{ env.PACKAGE_NAME }}
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
NPMJS_DIST_TAG: ${{ github.event.inputs.npmjs_dist_tag }}
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
PR_URL: ${{ steps.ensure_pr.outputs.pr_url }}
run: |
set -euo pipefail
ARTIFACT_NAME="vulnerability-report"
COMMIT_SHA="$(git rev-parse --short HEAD)"
echo "Fetching artifact ID for ${ARTIFACT_NAME}..."
ARTIFACTS=$(curl -s -H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$REPO/actions/runs/$RUN_ID/artifacts")
ARTIFACT_ID=$(echo "$ARTIFACTS" | jq -r ".artifacts[] | select(.name == \"$ARTIFACT_NAME\") | .id")
if [ -z "${ARTIFACT_ID:-}" ]; then
echo "❌ Artifact not found."
exit 1
fi
echo "🔍 Please review the following details before proceeding:"
echo "📦 Package Name: $PACKAGE_NAME"
echo "🔖 Package Version: $PACKAGE_VERSION"
echo "🌿 Release Branch: $RELEASE_BRANCH"
echo "🔢 Commit SHA: $COMMIT_SHA"
echo "🔗 Vulnerabilities: https://github.com/$REPO/actions/runs/$RUN_ID/artifacts/$ARTIFACT_ID"
- name: Send Dev review message to Slack
if: always()
shell: bash
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
CHANNEL: "#xrpl-js"
EXECUTOR: ${{ github.triggering_actor || github.actor }}
PACKAGE_NAME: ${{ env.PACKAGE_NAME }}
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
DEV_REVIEWERS: ${{ steps.get_reviewers.outputs.reviewers_dev }}
PR_URL: ${{ steps.ensure_pr.outputs.pr_url }}
run: |
set -euo pipefail
MSG="${EXECUTOR} is releasing ${PACKAGE_NAME}@${PACKAGE_VERSION}. A member from the dev team (${DEV_REVIEWERS}) needs to take the following actions: \n1) Review the release artifacts and approve/reject the release. (${RUN_URL})"
if [ -n "${PR_URL:-}" ]; then
MSG="${MSG} \n2) Review the package update PR and provide two approvals. DO NOT MERGE — ${EXECUTOR} will verify the package on npm and merge the approved PR. (${PR_URL})"
fi
MSG=$(printf '%b' "$MSG")
# Post once
curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$(jq -n --arg channel "$CHANNEL" --arg text "$MSG" '{channel:$channel, text:$text}')" \
| jq -er '.ok' >/dev/null
first_review:
runs-on: ubuntu-latest
needs: [get_version, run_faucet_test, run_tests, pre_release, ask_for_dev_team_review]
name: First approval (dev team)
environment:
name: first-review
url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Awaiting approval
run: echo "Awaiting Dev team approval"
ask_for_sec_team_review:
runs-on: ubuntu-latest
needs: [get_version, run_faucet_test, run_tests, pre_release, ask_for_dev_team_review, first_review]
name: Invite sec team to review
steps:
- name: Send Sec team review request to Slack
shell: bash
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
CHANNEL: "#ripplex-security"
EXECUTOR: ${{ github.triggering_actor || github.actor }}
PACKAGE_NAME: ${{ needs.get_version.outputs.package_version && github.event.inputs.package_name }}
PACKAGE_VERSION: ${{ needs.get_version.outputs.package_version }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
SEC_REVIEWERS: ${{ needs.ask_for_dev_team_review.outputs.reviewers_sec }}
run: |
set -euo pipefail
MSG="${EXECUTOR} is releasing ${PACKAGE_NAME}@${PACKAGE_VERSION}. A member from the infosec team (${SEC_REVIEWERS}) needs to take the following action:\n Review the release artifacts and approve/reject the release. (${RUN_URL})"
MSG=$(printf '%b' "$MSG")
curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$(jq -n --arg channel "$CHANNEL" --arg text "$MSG" '{channel:$channel, text:$text}')" \
| jq -er '.ok' >/dev/null
release:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
needs: [get_version, run_faucet_test, run_tests, pre_release, ask_for_dev_team_review, first_review, ask_for_sec_team_review]
name: Release for ${{ needs.get_version.outputs.package_version }}
env:
PACKAGE_VERSION: "${{ needs.get_version.outputs.package_version }}"
PACKAGE_NAME: "${{ github.event.inputs.package_name }}"
environment:
name: official-release
url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Prevent second attempt
run: |
if (( ${GITHUB_RUN_ATTEMPT:-1} > 1 )); then
echo "❌ Workflow rerun (attempt ${GITHUB_RUN_ATTEMPT}). Second attempts are not allowed."
exit 1
fi
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: npm-package-tarball
path: dist
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org/'
- name: Publish to npm
run: |
cd dist
PKG=$(ls *.tgz)
echo $PKG
NPM_DIST_TAG="${{ github.event.inputs.npmjs_dist_tag }}"
if [ -z "$NPM_DIST_TAG" ]; then
NPM_DIST_TAG="latest"
fi
if [[ "$NPM_DIST_TAG" == "latest" ]] && ! [[ "${{ env.PACKAGE_VERSION }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "With npmjs_dist_tag 'latest', version must be of the form x.y.z. Found '${{ env.PACKAGE_VERSION }}'." >&2
exit 1
fi
npm i -g npm@11.6.0
npm publish "$PKG" --provenance --access public --registry=https://registry.npmjs.org/ --tag "$NPM_DIST_TAG"
- name: Ensure Git tag exists
id: create_tag
run: |
set -euo pipefail
TAG="${{ env.PACKAGE_NAME }}@${{ env.PACKAGE_VERSION }}"
git fetch --tags origin
if git rev-parse "$TAG" >/dev/null 2>&1 ; then
echo "❌ Tag $TAG already exists (not a draft). Failing."
exit 1
fi
echo "🔖 Tagging $TAG"
git tag -f "$TAG"
git push origin -f "$TAG"
echo "tag_name=$TAG" >> "$GITHUB_OUTPUT"
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: "${{ steps.create_tag.outputs.tag_name }}"
name: "${{ steps.create_tag.outputs.tag_name }}"
draft: false
generate_release_notes: true
prerelease: ${{ github.event.inputs.npmjs_dist_tag != '' && github.event.inputs.npmjs_dist_tag != 'latest' }}
make_latest: ${{ github.event.inputs.npmjs_dist_tag == '' || github.event.inputs.npmjs_dist_tag == 'latest' }}
- name: Notify Slack success (single-line)
if: success()
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
REPO: ${{ github.repository }}
PACKAGE_NAME: ${{ env.PACKAGE_NAME }}
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
TAG: ${{ steps.create_tag.outputs.tag_name }}
run: |
set -euo pipefail
# Build release URL from tag (URL-encoded to handle '@' etc.)
enc_tag="$(printf '%s' "$TAG" | jq -sRr @uri)"
RELEASE_URL="https://github.com/$REPO/releases/tag/$enc_tag"
text="${PACKAGE_NAME} ${PACKAGE_VERSION} has been succesfully released and published to npm.js. Release URL: ${RELEASE_URL}"
text="${text//\\n/ }"
curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$(jq -n --arg channel "#xrpl-js" --arg text "$text" '{channel:$channel, text:$text}')"
- name: Notify Slack if tests fail
if: failure()
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
run: |
MESSAGE="❌ Release failed for ${{ env.PACKAGE_NAME }}@${{ env.PACKAGE_VERSION }}. Check the logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg channel "#xrpl-js" \
--arg text "$MESSAGE" \
'{channel: $channel, text: $text}')"
generate-documentation:
name: Generate and Publish documentation for ${{ needs.get_version.outputs.package_version }}
if: ${{ github.event.inputs.npmjs_dist_tag == 'latest' }}
uses: ./.github/workflows/generate-documentation.yml
needs: [get_version, release]
with:
git_ref: ${{ github.ref_name }}
permissions:
contents: read
id-token: write
pages: write