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
19 changes: 19 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@ version: 2
updates:
- package-ecosystem: npm
directory: "/"
target-branch: staging
schedule:
interval: monthly
open-pull-requests-limit: 10
versioning-strategy: increase-if-necessary
groups:
dev-dependencies:
dependency-type: development
update-types: [ "minor", "patch" ]
ignore:
# mocha 12 needs Node 20.19+ while CI still tests Node 18, and eslint 9+ needs a new config format
- dependency-name: "mocha"
update-types: [ "version-update:semver-major" ]
- dependency-name: "eslint"
update-types: [ "version-update:semver-major" ]
- package-ecosystem: github-actions
directory: "/"
target-branch: staging
schedule:
interval: monthly
groups:
github-actions:
patterns: [ "*" ]
58 changes: 58 additions & 0 deletions .github/scripts/check_release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Release check run by CI before publishing: the version in package.json, the SDK_VERSION constants in lib and the
* first CHANGELOG heading must all name the same version. With "--notes" it prints that version's CHANGELOG section
* instead, which becomes the GitHub release notes.
* usage: node .github/scripts/check_release.js [--notes]
*/
var fs = require("fs");
var path = require("path");

var root = path.resolve(__dirname, "../..");

/**
* Reads a file of the repository
* @param {String} file - path relative to the repository root
* @returns {String} file content
*/
function read(file) {
return fs.readFileSync(path.join(root, file), "utf8");
}

/**
* Splits the CHANGELOG into its "## " sections
* @returns {Array<{heading: String, body: String}>} sections in file order
*/
function changelogSections() {
return read("CHANGELOG.md").split(/^## /m).slice(1).map((section) => {
var lines = section.split("\n");
return { heading: lines[0].trim(), body: lines.slice(1).join("\n").trim() };
});
}

var { version } = JSON.parse(read("package.json"));
var sections = changelogSections();

if (process.argv.indexOf("--notes") !== -1) {
process.stdout.write(`${sections.length ? sections[0].body : ""}\n`);
}
else {
var problems = [];
var heading = sections.length ? sections[0].heading : "(none)";
if (heading !== version) {
problems.push(`the first CHANGELOG heading is "${heading}", rename it to "${version}"`);
}
["lib/countly.js", "lib/countly-bulk.js"].forEach((file) => {
var match = /SDK_VERSION = "([^"]+)"/.exec(read(file));
var found = match ? match[1] : "(none)";
if (found !== version) {
problems.push(`${file} has SDK_VERSION "${found}", set it to "${version}"`);
}
});
if (problems.length) {
process.stderr.write(`Release check failed for ${version}:\n- ${problems.join("\n- ")}\n`);
process.exitCode = 1;
}
else {
process.stdout.write(`Release check passed for ${version}\n`);
}
}
23 changes: 4 additions & 19 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 +39,18 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
with:
languages: ${{ matrix.language }}
build-mode: none
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
162 changes: 150 additions & 12 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,76 @@ on:
pull_request:
branches: [ master, staging ]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build:

runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
# mocha 11 requires Node 18.18+, 24 is the active LTS
node: [18, 20, 22, 24]
fail-fast: false
matrix:
# the test suite needs Node 18.18+ (mocha 11), the compat job covers the older supported versions
os: [ ubuntu-latest ]
node: [ 18, 20, 22, 24, 26 ]
include:
- os: windows-latest
node: 24
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
- name: Lint and test
if: matrix.os == 'ubuntu-latest' && matrix.node != 24
run: npm test
- name: Lint and test with coverage
if: matrix.os == 'ubuntu-latest' && matrix.node == 24
run: npm run coverage
- name: Upload the coverage report
if: matrix.os == 'ubuntu-latest' && matrix.node == 24
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: coverage-report
path: coverage/
# lint runs on Linux only, as Windows checkouts can have CRLF line endings that the lint rules reject
- name: Test
if: matrix.os == 'windows-latest'
run: npm test --ignore-scripts

compat:
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
node: [ 10, 12, 14, 16 ]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: ${{ matrix.node }}
# the SDK has no dependencies, so the check runs without installing packages
- run: node test/compat/compat_check.js

deploy:
runs-on: ubuntu-latest
needs: build
needs: [ build, compat ]
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js 24.x
uses: actions/setup-node@v4
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
cache: 'npm'
Expand All @@ -48,3 +88,101 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash generateDocs.sh

version:
runs-on: ubuntu-latest
needs: [ build, compat ]
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
outputs:
version: ${{ steps.version.outputs.version }}
new: ${{ steps.version.outputs.new }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js 24
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
package-manager-cache: false
- name: Check whether this version is on npm already
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
STATUS=0
PUBLISHED=$(npm view "countly-sdk-nodejs@$VERSION" version 2> npm-view-error.txt) || STATUS=$?
if [ "$STATUS" -eq 0 ] && [ "$PUBLISHED" = "$VERSION" ]; then
echo "new=false" >> "$GITHUB_OUTPUT"
echo "::notice::$VERSION is on npm already, nothing to release"
elif [ "$STATUS" -eq 0 ] || grep -q E404 npm-view-error.txt; then
echo "new=true" >> "$GITHUB_OUTPUT"
else
cat npm-view-error.txt
echo "::error::Could not check whether $VERSION is on npm"
exit 1
fi
- name: Check that package.json, the code and the CHANGELOG name the same version
if: steps.version.outputs.new == 'true'
run: node .github/scripts/check_release.js

release:
runs-on: ubuntu-latest
needs: version
if: needs.version.outputs.new == 'true'
# the npm environment holds the approval step, and npm's trusted publisher setting names it
environment: npm
permissions:
contents: write
id-token: write
outputs:
created: ${{ steps.release.outputs.created }}
url: ${{ steps.release.outputs.url }}
notes: ${{ steps.release.outputs.notes }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Node.js 24
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
registry-url: https://registry.npmjs.org
package-manager-cache: false
- name: Publish to npm
env:
VERSION: ${{ needs.version.outputs.version }}
run: |
if [ "$(npm view "countly-sdk-nodejs@$VERSION" version 2> /dev/null)" = "$VERSION" ]; then
echo "::notice::$VERSION is on npm already, publishing is skipped"
else
npm publish
fi
- name: Create the GitHub release
id: release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.version.outputs.version }}
run: |
node .github/scripts/check_release.js --notes > release-notes.md
if gh release view "$VERSION" > /dev/null 2>&1; then
echo "::notice::The GitHub release $VERSION exists already, so it is not created again and no notice is sent"
echo "created=false" >> "$GITHUB_OUTPUT"
else
gh release create "$VERSION" --title "Countly NodeJS SDK $VERSION" --notes-file release-notes.md --target "$GITHUB_SHA"
echo "created=true" >> "$GITHUB_OUTPUT"
fi
URL=$(gh release view "$VERSION" --json url --jq .url)
echo "url=$URL" >> "$GITHUB_OUTPUT"
{
echo "notes<<RELEASE_NOTES_END"
cat release-notes.md
echo "RELEASE_NOTES_END"
} >> "$GITHUB_OUTPUT"

# a release created with the workflow token does not start other workflows, so the notice is called directly
notify:
needs: [ version, release ]
if: needs.release.outputs.created == 'true'
uses: ./.github/workflows/release_notice.yml
with:
tag_name: ${{ needs.version.outputs.version }}
html_url: ${{ needs.release.outputs.url }}
body: ${{ needs.release.outputs.notes }}
secrets: inherit
59 changes: 43 additions & 16 deletions .github/workflows/release_notice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,64 @@ on:
release:
types: [published]
workflow_dispatch:
inputs:
tag_name:
description: "Version to announce, for example 26.1.0"
type: string
required: false
html_url:
description: "Link to the GitHub release"
type: string
required: false
body:
description: "Release notes"
type: string
required: false
workflow_call:
inputs:
tag_name:
type: string
required: true
html_url:
type: string
required: true
body:
type: string
required: false
default: ""
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
# To check the github context
- name: Dump Github context
env:
GITHUB_CONTEXT: ${{ toJSON(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Send custom JSON data to Slack workflow
id: slack
uses: slackapi/slack-github-action@v1.23.0
uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
with:
webhook: ${{ secrets.SLACK_RELEASE }}
webhook-type: webhook-trigger
# errors, retries and payload-delimiter keep the behaviour of v1: the step fails on an error, posts once and sends every value as text
errors: true
retries: 0
payload-delimiter: "."
# This data can be any valid JSON from a previous step in the GitHub Action
payload: |
{
"repository": "${{ github.repository }}",
"tag_name": "${{ github.event.release.tag_name }}",
"tag_name": "${{ inputs.tag_name || github.event.release.tag_name }}",
"actor": "${{ github.actor }}",
"body": ${{ toJSON(github.event.release.body) }},
"html_url": "${{ github.event.release.html_url }}"
"body": ${{ toJSON(inputs.body || github.event.release.body) }},
"html_url": "${{ inputs.html_url || github.event.release.html_url }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_RELEASE }}
- name: Send custom JSON data to Discord
uses: sarisia/actions-status-discord@v1.13.0
if: ${{ !cancelled() }}
uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1.16.0
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
nodetail: true
title: New ${{ github.repository }} version ${{ github.event.release.tag_name }} published by ${{ github.actor }}
title: New ${{ github.repository }} version ${{ inputs.tag_name || github.event.release.tag_name }} published by ${{ github.actor }}
description: |
Release URL: ${{ github.event.release.html_url }}
Click [here](https://github.com/Countly/countly-server/blob/master/CHANGELOG.md) to view the change log.
`${{ github.event.release.body }}`
Release URL: ${{ inputs.html_url || github.event.release.html_url }}
Click [here](https://github.com/${{ github.repository }}/blob/master/CHANGELOG.md) to view the change log.
`${{ inputs.body || github.event.release.body }}`
Loading
Loading