Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 29 additions & 33 deletions .github/workflows/release-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ jobs:
with:
fetch-depth: 0

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: lts/*

- name: 🔍 Check for unreleased commits
id: check
run: |
Expand All @@ -34,21 +38,26 @@ jobs:
echo "$COMMITS"
fi

- name: 🔢 Determine next version
if: steps.check.outputs.skip == 'false'
id: version
run: |
VERSION_JSON=$(node scripts/next-version.ts)
CURRENT_VERSION=$(echo "$VERSION_JSON" | jq -r .current)
NEXT_VERSION=$(echo "$VERSION_JSON" | jq -r .next)
FROM_REF=$(echo "$VERSION_JSON" | jq -r .from)
echo "current=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
echo "next=v${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
echo "from=$FROM_REF" >> "$GITHUB_OUTPUT"

- name: 📝 Generate changelog body
if: steps.check.outputs.skip == 'false'
id: changelog
env:
CURRENT_VERSION: ${{ steps.version.outputs.current }}
NEXT_VERSION: ${{ steps.version.outputs.next }}
FROM_REF: ${{ steps.version.outputs.from }}
run: |
# Get the latest tag, or use initial commit if no tags exist
LATEST_TAG=$(git describe --tags --abbrev=0 origin/release 2>/dev/null || echo "")

if [ -z "$LATEST_TAG" ]; then
FROM_REF=$(git rev-list --max-parents=0 HEAD)
CURRENT_VERSION="0.0.0"
else
FROM_REF="$LATEST_TAG"
CURRENT_VERSION="${LATEST_TAG#v}"
fi

# Categorize commits
FEATURES=""
FIXES=""
Expand All @@ -72,25 +81,12 @@ jobs:
fi
done <<< "$(git log "$FROM_REF"..origin/main --oneline --no-merges)"

# Determine next version
HAS_BREAKING=$(git log "$FROM_REF"..origin/main --format='%B' | grep -c 'BREAKING CHANGE\|!:' || true)
HAS_FEAT=$(git log "$FROM_REF"..origin/main --oneline --no-merges | grep -cE '^[a-f0-9]+ feat(\(|:)' || true)

IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"

if [ "$HAS_BREAKING" -gt 0 ] && [ "$MAJOR" -gt 0 ]; then
NEXT_VERSION="$((MAJOR + 1)).0.0"
elif [ "$HAS_FEAT" -gt 0 ]; then
NEXT_VERSION="${MAJOR}.$((MINOR + 1)).0"
else
NEXT_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
fi

echo "next_version=v${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
# Strip the leading 'v' for display
DISPLAY_NEXT="${NEXT_VERSION#v}"

# Build the PR body
BODY="This PR will deploy the following changes to production (\`npmx.dev\`).\n\n"
BODY="${BODY}**Next version: \`v${NEXT_VERSION}\`** (current: \`v${CURRENT_VERSION}\`)\n\n"
BODY="${BODY}**Next version: \`${NEXT_VERSION}\`** (current: \`v${CURRENT_VERSION}\`)\n\n"

if [ -n "$FEATURES" ]; then
BODY="${BODY}### Features\n\n${FEATURES}\n"
Expand All @@ -108,31 +104,31 @@ jobs:
BODY="${BODY}---\n\n"
BODY="${BODY}> Merging this PR will:\n"
BODY="${BODY}> - Deploy to \`npmx.dev\` via Vercel\n"
BODY="${BODY}> - Create a \`v${NEXT_VERSION}\` tag and GitHub Release\n"
BODY="${BODY}> - Publish \`npmx-connector@${NEXT_VERSION}\` to npm"
BODY="${BODY}> - Create a \`${NEXT_VERSION}\` tag and GitHub Release\n"
BODY="${BODY}> - Publish \`npmx-connector@${DISPLAY_NEXT}\` to npm"

# Write body to file, truncating if needed (GitHub limits PR body to 65536 chars)
echo -e "$BODY" > /tmp/pr-body.md
if [ "$(wc -c < /tmp/pr-body.md)" -gt 60000 ]; then
COMMIT_COUNT=$(git log "$FROM_REF"..origin/main --oneline --no-merges | wc -l)
COMPARE_URL="https://github.com/npmx-dev/npmx.dev/compare/${FROM_REF}...main"
TRUNCATED="This PR will deploy the following changes to production (\`npmx.dev\`).\n\n"
TRUNCATED="${TRUNCATED}**Next version: \`v${NEXT_VERSION}\`** (current: \`v${CURRENT_VERSION}\`)\n\n"
TRUNCATED="${TRUNCATED}**Next version: \`${NEXT_VERSION}\`** (current: \`v${CURRENT_VERSION}\`)\n\n"
TRUNCATED="${TRUNCATED}> **${COMMIT_COUNT} commits** are included in this release. The full changelog is too large to display here.\n>\n"
TRUNCATED="${TRUNCATED}> [View full diff on GitHub](${COMPARE_URL})\n\n"
TRUNCATED="${TRUNCATED}---\n\n"
TRUNCATED="${TRUNCATED}> Merging this PR will:\n"
TRUNCATED="${TRUNCATED}> - Deploy to \`npmx.dev\` via Vercel\n"
TRUNCATED="${TRUNCATED}> - Create a \`v${NEXT_VERSION}\` tag and GitHub Release\n"
TRUNCATED="${TRUNCATED}> - Publish \`npmx-connector@${NEXT_VERSION}\` to npm"
TRUNCATED="${TRUNCATED}> - Create a \`${NEXT_VERSION}\` tag and GitHub Release\n"
TRUNCATED="${TRUNCATED}> - Publish \`npmx-connector@${DISPLAY_NEXT}\` to npm"
echo -e "$TRUNCATED" > /tmp/pr-body.md
fi

- name: 🚀 Create or update release PR
if: steps.check.outputs.skip == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NEXT_VERSION: ${{ steps.changelog.outputs.next_version }}
NEXT_VERSION: ${{ steps.version.outputs.next }}
run: |
EXISTING_PR=$(gh pr list --base release --head main --state open --json number --jq '.[0].number')

Expand Down
47 changes: 9 additions & 38 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,18 @@ jobs:
with:
fetch-depth: 0

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: lts/*

- name: 🔢 Determine next version
id: version
run: |
# Get the latest tag on this branch
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

if [ -z "$LATEST_TAG" ]; then
CURRENT_VERSION="0.0.0"
FROM_REF=$(git rev-list --max-parents=0 HEAD)
else
CURRENT_VERSION="${LATEST_TAG#v}"
FROM_REF="$LATEST_TAG"
fi

# Analyze conventional commits since last tag
HAS_BREAKING=$(git log "${FROM_REF}..HEAD" --format='%B' | grep -c 'BREAKING CHANGE\|!:' || true)
HAS_FEAT=$(git log "${FROM_REF}..HEAD" --oneline --no-merges | grep -cE '^[a-f0-9]+ feat(\(|:)' || true)
HAS_FIX=$(git log "${FROM_REF}..HEAD" --oneline --no-merges | grep -cE '^[a-f0-9]+ fix(\(|:)' || true)

IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"

if [ "$HAS_BREAKING" -gt 0 ] && [ "$MAJOR" -gt 0 ]; then
NEXT_VERSION="$((MAJOR + 1)).0.0"
elif [ "$HAS_FEAT" -gt 0 ]; then
NEXT_VERSION="${MAJOR}.$((MINOR + 1)).0"
elif [ "$HAS_FIX" -gt 0 ]; then
NEXT_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
else
# Only chore/docs/ci commits — still bump patch
NEXT_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
fi

echo "current=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
echo "next=v${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
echo "from=$FROM_REF" >> "$GITHUB_OUTPUT"
echo "Bumping from v${CURRENT_VERSION} to v${NEXT_VERSION}"
VERSION_JSON=$(node scripts/next-version.ts)
echo "current=$(echo "$VERSION_JSON" | jq -r .current)" >> "$GITHUB_OUTPUT"
echo "next=v$(echo "$VERSION_JSON" | jq -r .next)" >> "$GITHUB_OUTPUT"
echo "from=$(echo "$VERSION_JSON" | jq -r .from)" >> "$GITHUB_OUTPUT"
echo "Bumping from v$(echo "$VERSION_JSON" | jq -r .current) to v$(echo "$VERSION_JSON" | jq -r .next)"

- name: 🔍 Check if tag already exists
id: check
Expand All @@ -82,11 +58,6 @@ jobs:
git tag -a "$VERSION" -m "Release $VERSION"
git push origin "$VERSION"

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
if: steps.check.outputs.skip == 'false'
with:
node-version: lts/*

- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # 4e1c8eafbd745f64b1ef30a7d7ed7965034c486c
if: steps.check.outputs.skip == 'false'
name: 🟧 Install pnpm
Expand Down
6 changes: 6 additions & 0 deletions app/assets/logos/oss-partners/blento.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/assets/logos/oss-partners/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import LogoLunaria from './lunaria.svg'
import LogoJsr from './jsr.svg'
import LogoIconify from './iconify.svg'
import LogoFloatingUi from './floating-ui-vue.svg'
import LogoBlento from './blento.svg'

// The list is used on the about page. To add, simply upload the logos nearby and add an entry here. Prefer SVGs.
// For logo src, specify a string or object with the light and dark theme variants.
Expand Down Expand Up @@ -195,4 +196,9 @@ export const OSS_PARTNERS = [
logo: LogoFloatingUi,
url: 'https://floating-ui.com/',
},
{
name: 'blento',
logo: LogoBlento,
url: 'https://blento.app/npmx.dev',
},
]
10 changes: 10 additions & 0 deletions app/components/global/BlogPostWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { BlogPostFrontmatter } from '#shared/schemas/blog'
import { generateBlogTID } from '#shared/utils/atproto'

const props = defineProps<{
frontmatter: BlogPostFrontmatter
Expand All @@ -14,6 +15,15 @@ useSeoMeta({
...(props.frontmatter.draft ? { robots: 'noindex, nofollow' } : {}),
})

useHead({
link: [
{
rel: 'site.standard.document',
href: `at://${NPMX_DEV_DID}/site.standard.document/${generateBlogTID(props.frontmatter.date, props.frontmatter.slug)}`,
},
],
})

defineOgImageComponent('BlogPost', {
title: props.frontmatter.title,
authors: props.frontmatter.authors,
Expand Down
6 changes: 6 additions & 0 deletions app/pages/blog/alpha-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ headline="Read more from the community"
authorHandle: 'patak.cat',
description: 'The story of the many people and communities that converged to build npmx together.'
},
{
url: 'https://www.freecodecamp.org/news/learning-to-enjoy-code-reviews-with-npmx/',
title: 'OSS Pull Request Therapy: Learning to Enjoy Code Reviews with npmx',
authorHandle: 'abbeyperini.dev',
description: 'For years, I thought Open Source Software (OSS) just wasn\'t for me. Curious about the hype I saw on Bluesky, I recently joined the npmx Discord server on a whim. My journey from lurker to contributor taught me a lot about OSS and gave me new confidence going into code reviews.'
},
{
url: 'https://graphieros.github.io/graphieros-blog/blog/2026/npmx.html',
title: 'vue-data-ui is on npmx npmx is on vue-data-ui',
Expand Down
21 changes: 13 additions & 8 deletions config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Git from 'simple-git'
import * as process from 'node:process'

import { version as packageVersion } from '../package.json'
import { getNextVersion } from '../scripts/next-version'

export { packageVersion as version }

Expand Down Expand Up @@ -44,13 +45,15 @@ export const gitBranch = process.env.BRANCH || process.env.VERCEL_GIT_COMMIT_REF
* Whether this is the canary environment (main.npmx.dev).
*
* Detected as any non-PR Vercel deploy from the `main` branch
* (which may receive `VERCEL_ENV === 'production'` or `'preview'`
* depending on the project's production branch configuration).
* (which may receive `VERCEL_ENV === 'production'`, `'preview'`, or a
* custom `'canary'` environment depending on the project configuration).
*
* @see {@link https://vercel.com/docs/environment-variables/system-environment-variables#VERCEL_ENV}
*/
export const isCanary =
(process.env.VERCEL_ENV === 'production' || process.env.VERCEL_ENV === 'preview') &&
(process.env.VERCEL_ENV === 'production' ||
process.env.VERCEL_ENV === 'preview' ||
process.env.VERCEL_ENV === 'canary') &&
gitBranch === 'main' &&
!isPR

Expand Down Expand Up @@ -157,15 +160,17 @@ export async function getFileLastUpdated(path: string) {
}

/**
* Resolves the current version from git tags, falling back to `package.json`.
* Resolves the **next** version by analysing conventional commits since the
* last reachable `v*` tag. Delegates to {@link getNextVersion} which is also
* used by the `release-tag` and `release-pr` GitHub Actions workflows so the
* version shown in the UI matches the tag that will be created *after* deploy.
*
* Uses `git describe --tags --abbrev=0 --match 'v*'` to find the most recent
* reachable release tag (e.g. `v0.1.0` -> `0.1.0`).
* Falls back to `package.json` when git is unavailable (e.g. shallow clone).
*/
export async function getVersion() {
try {
const tag = (await git.raw(['describe', '--tags', '--abbrev=0', '--match', 'v*'])).trim()
return tag.replace(/^v/, '')
const { next } = await getNextVersion()
return next
} catch {
return packageVersion
}
Expand Down
Loading
Loading