diff --git a/.github/actions/get-next-package-version.js b/.github/actions/get-next-package-version.js new file mode 100644 index 0000000000..8715d2b9d5 --- /dev/null +++ b/.github/actions/get-next-package-version.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node + +// This script is used in GitHub Actions to get the next version based on the current package.json version. +// It supports three types of versioning: nightly, hotfix, and monthly. + +const { parseArgs } = require('node:util'); +const fs = require('node:fs'); + +const args = process.argv; + +const options = { + 'package-json': { + type: 'string', + short: 'p', + }, + 'type': { + type: 'string', // nightly, hotfix, monthly + short: 't', + }, +}; + +const { values } = parseArgs({ + args, + options, + allowPositionals: true, +}); + +if (!values["package-json"]) { + console.error('Please specify the path to package.json using --package-json or -p option.'); + process.exit(1); +} + +try { + const packageJsonPath = values['package-json']; + + // Read and parse package.json + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + const currentVersion = packageJson.version; + + // Parse year and month from version (e.g. 25.5.1 -> year=2025, month=5) + const versionParts = currentVersion.split('.'); + const versionYear = parseInt(versionParts[0]); + const versionMonth = parseInt(versionParts[1]); + const versionHotfix = parseInt(versionParts[2]); + + // Create date and add 1 month + const versionDate = new Date(2000 + versionYear, versionMonth - 1, 1); // month is 0-indexed + const nextVersionMonthDate = new Date(versionDate.getFullYear(), versionDate.getMonth() + 1, 1); + + // Format back to YY.M format + const nextVersionYear = nextVersionMonthDate.getFullYear().toString().slice(-2); + const nextVersionMonth = nextVersionMonthDate.getMonth() + 1; // Convert back to 1-indexed + + // Get current date string + const currentDate = new Date().toISOString().split('T')[0].replaceAll('-', ''); + + switch (values.type) { + case 'nightly': { + const newVersion = `${nextVersionYear}.${nextVersionMonth}.0-nightly.${currentDate}`; + process.stdout.write(newVersion); // return the new version to stdout + process.exit(); + } + case 'hotfix': { + const bugfixVersion = `${versionYear}.${versionMonth}.${versionHotfix + 1}`; + process.stdout.write(bugfixVersion); // return the bugfix version to stdout + process.exit(); + } + case 'monthly': { + const stableVersion = `${nextVersionYear}.${nextVersionMonth}.0`; + process.stdout.write(stableVersion); // return the stable version to stdout + process.exit(); + } + default: + console.error('Invalid type specified. Use "nightly", "hotfix", or "monthly".'); + process.exit(1); + } +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/.github/workflows/publish-nightly-npm-packages.yml b/.github/workflows/publish-nightly-npm-packages.yml new file mode 100644 index 0000000000..47d922f1e5 --- /dev/null +++ b/.github/workflows/publish-nightly-npm-packages.yml @@ -0,0 +1,97 @@ +name: Publish nightly npm packages + +# Nightly npm packages are built daily +on: + push: + branches: + - master + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +jobs: + build-and-pack: + runs-on: ubuntu-latest + name: Build and pack npm packages + steps: + - uses: actions/checkout@v4 + + - name: Set up environment + uses: ./.github/actions/setup + + - name: Update package versions + run: | + # Get new nightly versions + NEW_WEB_VERSION=$(node ./.github/actions/get-next-package-version.js --package-json ./packages/desktop-client/package.json --type nightly) + NEW_SYNC_VERSION=$(node ./.github/actions/get-next-package-version.js --package-json ./packages/sync-server/package.json --type nightly) + NEW_API_VERSION=$(node ./.github/actions/get-next-package-version.js --package-json ./packages/api/package.json --type nightly) + + # Set package versions + npm version $NEW_WEB_VERSION --no-git-tag-version --workspace=@actual-app/web --no-workspaces-update + npm version $NEW_SYNC_VERSION --no-git-tag-version --workspace=@actual-app/sync-server --no-workspaces-update + npm version $NEW_API_VERSION --no-git-tag-version --workspace=@actual-app/api --no-workspaces-update + + - name: Yarn install + run: | + yarn install + + - name: Build Server & Web + run: yarn build:server + + - name: Pack the web and server packages + run: | + yarn workspace @actual-app/web pack --filename @actual-app/web.tgz + yarn workspace @actual-app/sync-server pack --filename @actual-app/sync-server.tgz + + - name: Build API + run: yarn build:api + + - name: Pack the api package + run: | + yarn workspace @actual-app/api pack --filename @actual-app/api.tgz + + - name: Upload package artifacts + uses: actions/upload-artifact@v4 + with: + name: npm-packages + path: | + packages/desktop-client/@actual-app/web.tgz + packages/sync-server/@actual-app/sync-server.tgz + packages/api/@actual-app/api.tgz + + publish: + runs-on: ubuntu-latest + name: Publish Nightly npm packages + needs: build-and-pack + permissions: + contents: read + packages: write + steps: + - name: Download the artifacts + uses: actions/download-artifact@v4 + with: + name: npm-packages + + - name: Setup node and npm registry + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: 'https://registry.npmjs.org' + + - name: Publish Web + run: | + npm publish desktop-client/@actual-app/web.tgz --access public --tag nightly + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish Sync-Server + run: | + npm publish sync-server/@actual-app/sync-server.tgz --access public --tag nightly + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish API + run: | + npm publish api/@actual-app/api.tgz --access public --tag nightly + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/upcoming-release-notes/5047.md b/upcoming-release-notes/5047.md new file mode 100644 index 0000000000..1db0ad00e2 --- /dev/null +++ b/upcoming-release-notes/5047.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MikesGlitch, matt-fidd] +--- + +Added a Git Workflow to publish edge NPM packages every night