Skip to content
Open
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
278 changes: 278 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: ["**"]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Typecheck
run: npm run typecheck

- name: Build
run: npm run build

- name: Run tests
run: npm test

publish-dev:
needs: test
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
pull-requests: write
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://npm.pkg.github.com'
scope: '@open-game-system'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Generate dev version
id: version
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
MAJOR_VERSION=$(node -p "require('./package.json').version.split('.')[0]")
DATE=$(date +'%Y%m%d')

# Get PR number
PR_NUMBER=$(echo $GITHUB_REF | sed -n 's/refs\/pull\/\([0-9]*\)\/merge/\1/p')

# Configure npm to use GitHub registry for version check
echo "Configuring npm to use GitHub registry for @open-game-system..."
echo "@open-game-system:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc

# Get published versions to find highest patch
echo "Checking GitHub registry for existing versions..."
NPM_VERSIONS=$(npm view ${PACKAGE_NAME} versions --registry https://npm.pkg.github.com/ 2>/dev/null || echo "[]")

# Find highest patch for this PR today
VERSION_PREFIX="${MAJOR_VERSION}.${DATE}"
HIGHEST_PATCH=-1
if [[ "$NPM_VERSIONS" != "[]" ]]; then
HIGHEST_PATCH=$(echo "$NPM_VERSIONS" | jq -r --arg prefix "$VERSION_PREFIX" --arg pr "$PR_NUMBER" '
map(select(test("^" + $prefix + "\\\\.[0-9]+-pr" + $pr + "$"))) |
map(capture("^" + $prefix + "\\\\.(\\\\d+)-pr" + $pr + "$")[0] | tonumber) |
max // -1
')
fi

# Increment patch number
NEXT_PATCH=$((HIGHEST_PATCH + 1))

# Create version: MAJOR.DATE.PATCH-prN
DEV_VERSION="${MAJOR_VERSION}.${DATE}.${NEXT_PATCH}-pr${PR_NUMBER}"

echo "Generated dev version: ${PACKAGE_NAME}@${DEV_VERSION}"
echo "DEV_VERSION=${DEV_VERSION}" >> $GITHUB_OUTPUT
echo "PACKAGE_NAME=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
env:
GITHUB_REF: ${{ github.ref }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Update version in package.json
run: |
npm version ${{ steps.version.outputs.DEV_VERSION }} --no-git-tag-version --allow-same-version

# Add GitHub registry config
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
if (!pkg.publishConfig) pkg.publishConfig = {};
pkg.publishConfig.registry = 'https://npm.pkg.github.com/';
pkg.publishConfig.access = 'public';
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n');
"

- name: Publish to GitHub Packages
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
MAX_RETRIES=5
RETRY_COUNT=0
VERSION=${{ steps.version.outputs.DEV_VERSION }}
OUTPUT_FILE="npm_publish_output.log"

echo "Initial version to try: ${VERSION}"

while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
echo "--- Attempt ${RETRY_COUNT} --- Trying to publish ${VERSION} ---"
npm publish --tag dev > "$OUTPUT_FILE" 2>&1
ERROR_CODE=$?

if [ $ERROR_CODE -eq 0 ]; then
echo "Successfully published ${VERSION}"
cat "$OUTPUT_FILE"
break
fi

echo "Publish failed with exit code ${ERROR_CODE}. Retrying with next patch."
cat "$OUTPUT_FILE"

# Increment patch version
CURRENT_PATCH=$(echo $VERSION | sed -n 's/.*\.\([0-9]\+\)-pr.*/\1/p')
if [ -z "$CURRENT_PATCH" ]; then
echo "Error: Could not extract patch number from version ${VERSION}. Cannot retry."
exit 1
fi
NEXT_PATCH=$((CURRENT_PATCH + 1))
VERSION=$(echo $VERSION | sed "s/\.[0-9]\+-pr/\.${NEXT_PATCH}-pr/")

echo "Incrementing version for retry: ${VERSION}"
npm version $VERSION --no-git-tag-version --allow-same-version >> "$OUTPUT_FILE" 2>&1
RETRY_COUNT=$((RETRY_COUNT + 1))
done

if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "Failed to publish after ${MAX_RETRIES} retries."
cat "$OUTPUT_FILE"
exit 1
fi

- name: Comment on PR
uses: actions/github-script@v7
if: success()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.issue.number;
const version = '${{ steps.version.outputs.DEV_VERSION }}';
const packageName = '${{ steps.version.outputs.PACKAGE_NAME }}';

github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: `📦 Dev version published: \`${packageName}@${version}\`\n\nInstall via GitHub Packages (ensure .npmrc is configured):\n\`\`\`bash\nnpm install ${packageName}@${version}\n\`\`\``
});

publish-production:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
scope: '@open-game-system'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Generate production version
id: version
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
MAJOR_VERSION=$(node -p "require('./package.json').version.split('.')[0]")
DATE=$(date +'%Y%m%d')

echo "Checking npm for existing versions of ${PACKAGE_NAME} with prefix ${MAJOR_VERSION}.${DATE}..."

# Get published versions, handle errors/empty results
NPM_VERSIONS=$(npm view ${PACKAGE_NAME} versions --json 2>/dev/null || echo "[]")

# Find highest patch for today
HIGHEST_PATCH=-1
if [[ "$NPM_VERSIONS" != "[]" && "$NPM_VERSIONS" != *error* ]]; then
PATTERN="${MAJOR_VERSION}.${DATE}."
HIGHEST_PATCH=$(echo "$NPM_VERSIONS" | jq -c --arg pattern "$PATTERN" 'map(select(startswith($pattern))) | map(split(".")[2] | tonumber) | max // -1')
fi

# Calculate next patch version
NEXT_PATCH=$((HIGHEST_PATCH + 1))
NEW_VERSION="${MAJOR_VERSION}.${DATE}.${NEXT_PATCH}"

echo "Generated production version: ${PACKAGE_NAME}@${NEW_VERSION}"
echo "NEW_VERSION=${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "PACKAGE_NAME=${PACKAGE_NAME}" >> $GITHUB_OUTPUT

- name: Update version in package.json
run: |
npm version ${{ steps.version.outputs.NEW_VERSION }} --no-git-tag-version --allow-same-version

# Ensure public access for npm
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
if (!pkg.publishConfig) pkg.publishConfig = {};
pkg.publishConfig.access = 'public';
delete pkg.publishConfig.registry;
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n');
"

- name: Publish to npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
# Diagnostic logging
echo "=== NPM PUBLISH ==="
echo "Package: $(node -p "require('./package.json').name")"
echo "Version: $(node -p "require('./package.json').version")"
echo "Registry: $(npm config get registry)"

npm cache clean --force
npm publish --access public || {
echo "Standard publish failed, trying with --tag latest"
npm publish --access public --tag latest
}

- name: Commit version bump
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'

CURRENT_VERSION=$(node -p "require('./package.json').version")
LATEST_VERSION=$(npm view $(node -p "require('./package.json').name") version 2>/dev/null || echo "0.0.0")

echo "Current version: ${CURRENT_VERSION}, Latest published: ${LATEST_VERSION}"

if [ "${CURRENT_VERSION}" != "$(node -p "require('./package.json').version" 2>/dev/null)" ] || git diff --quiet package.json; then
echo "No version change to commit"
else
git add package.json
git commit -m "ci: bump version to ${CURRENT_VERSION} [skip ci]"
git push origin main
echo "Version bump committed"
fi
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
*.tsbuildinfo
Loading
Loading