惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
博客园 - 三生石上(FineUI控件)
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
腾讯CDC
酷 壳 – CoolShell
酷 壳 – CoolShell
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Jina AI
Jina AI
爱范儿
爱范儿
博客园 - 【当耐特】
雷峰网
雷峰网
S
SegmentFault 最新的问题
美团技术团队
Blog — PlanetScale
Blog — PlanetScale
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
J
Java Code Geeks

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
gitrelease.mjs file in Nango codebase.
Ramu Narasinga · 2026-06-02 · via DEV Community

Ramu Narasinga

In this article, we review gitrelease.mjs file in Nango codebase. You will learn:

  1. gitrelease.mjs file

  2. publish workflow

gitrelease.mjs file

gitrelease.mjs. is defined in the scripts folder and is defined as shown below:

#!/usr/bin/env zx
import { $, echo } from 'zx';

const { GITHUB_TOKEN } = process.env;
const nextVersion = process.argv[3];
const branch = process.argv[4] || 'master';
const nextTag = `v${nextVersion}`;

echo`Publishing ${nextVersion} on branch ${branch}`;

await $`git config --global user.email "contact@nango.dev"`;
await $`git config --global user.name "Release Bot"`;

const tagExists = await $`git tag -l ${nextTag}`;
if (tagExists.stdout !== '') {
    echo`Tag ${nextTag} already exists`;
    process.exit(1);
}

const releaseMessage = `chore(release): ${nextVersion}`;

echo`Checkout out branch`;
await $`git fetch origin ${branch}`;
await $`git switch ${branch}`;

echo`Generating changelog`;
await $`npx git-cliff -o CHANGELOG.md -t ${nextTag}`;

echo`Adding file`;
await $`git add -A package.json package-lock.json packages/**/package.json CHANGELOG.md packages/**/lib/version.ts`;

echo`Creating commit`;
await $`git commit --allow-empty --author="Release Bot <contact@nango.dev>" -m ${releaseMessage} `;

echo`Creating tag`;
await $`git tag -a ${nextTag} HEAD -m ${releaseMessage}`;

echo`Pushing`;
// Rebase on latest to handle commits that landed on ${branch} during publish
await $`git fetch origin ${branch}`;
await $`git rebase origin/${branch}`;
// Push branch and tag separately - tag intentionally points to the pre-rebase commit
await $`git push origin HEAD:refs/heads/${branch}`;
await $`git push origin ${nextTag}`;

echo`Commit pushed, publishing release...`;
// Push GitHub release
const releaseNotes = await $`npx git-cliff --latest --strip header footer`;
const releaseData = JSON.stringify({
    name: nextTag,
    tag_name: nextTag,
    body: releaseNotes.stdout
});

try {
    await $`curl --silent --fail --show-error -H "Authorization: Bearer ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/NangoHQ/nango/releases -d ${releaseData}`;
} catch (err) {
    console.log(err, releaseData);
    process.exit(1);
}

echo`✅ Done`;

Enter fullscreen mode Exit fullscreen mode

You can follow the echo statements to understand what is happening in the code:

  1. Check out branch

  2. Generating changelog

  3. Adding file

  4. Creating commit

  5. Creating tag

  6. Pushing

  7. Commit pushed, publishing release.

I wrote a separate article about what git-cliff is.

publish workflow

It is a common practice to define scripts and run them in the GitHub workflows. nango/.github/workflows/publish.yaml is defined as below:

name: '[Release] NPM publish'
run-name: '[Release] NPM publish ${{ inputs.version }}'

on:
    workflow_dispatch:
        inputs:
            version:
                type: string
                description: 'Version to publish'
                required: true
                default: '0.0.0'

permissions:
    contents: write
    id-token: write

jobs:
    npm-publish:
        if: github.ref == 'refs/heads/master'
        runs-on: ubuntu-latest
        steps:
            - uses: actions/create-github-app-token@v2
              id: create_github_app_token
              with:
                  app-id: ${{ secrets.GH_APP_PUSHER_ID }}
                  private-key: ${{ secrets.GH_APP_PUSHER_PRIVATE_KEY }}

            - uses: actions/checkout@v4
              with:
                  token: ${{ steps.create_github_app_token.outputs.token }}
                  fetch-depth: 0

            - uses: actions/setup-node@v4
              with:
                  cache: 'npm'
                  node-version-file: '.nvmrc'
                  registry-url: 'https://registry.npmjs.org'

            - name: Update npm to latest
              run: npm install -g npm@11.5.1

            - name: Install dependencies
              run: npm ci

            - name: Publish npm packages
              shell: bash
              run: |
                  npx zx ./scripts/publish.mjs --version="${{ inputs.version }}"

            - name: Publish release
              env:
                  GITHUB_TOKEN: ${{ steps.create_github_app_token.outputs.token }}
              run: |
                  npx zx ./scripts/gitrelease.mjs "${{ inputs.version }}" "${{ github.head_ref || github.ref_name }}"

Enter fullscreen mode Exit fullscreen mode

In the run: section, you will see that this script is invoked using the command:

npx zx ./scripts/gitrelease.mjs "${{ inputs.version }}" "${{ github.head_ref || github.ref_name }}"

Enter fullscreen mode Exit fullscreen mode

About me:

Hey, my name is ramunarasinga. Email: ramunarasinga@gmail.com

Tired of AI slop?

I spent 3+ years studying OSS codebases and wrote 350+ articles on what makes them production-grade. I built

Get started for free — thinkthroo.com

References:

  1. nango/scripts/gitrelease.mjs.

  2. nango/.github/workflows/publish.yaml#L54.

  3. git-cliff.org/docs/.