Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use composite actions to test examples automatically and easily #22

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
55 changes: 55 additions & 0 deletions .github/actions/app-test/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: 'Start and Test Node.js App'
description: 'Starts Node.js app, runs tests, and shuts it down'
inputs:
port:
description: 'Port on which the Node.js app is running'
required: true
path:
description: 'Path to test with the HTTP request'
required: false
default: ""
method:
description: 'HTTP method to use for the test (GET, POST, etc.)'
required: true
body:
description: 'Request body for POST method (optional)'
required: false
default: ""
working-directory:
description: 'Working directory of the Node.js app'
required: true
channel-access-token:
description: 'Channel access token'
required: true
channel-secret:
description: 'Channel secret'
required: true


runs:
using: 'composite'
steps:
- name: Start application
run: |
export CHANNEL_ACCESS_TOKEN=${{ inputs.channel-access-token }}
export CHANNEL_SECRET=${{ inputs.channel-secret }}
npm start &
shell: bash
working-directory: ${{ inputs.working-directory }}

- name: Wait for application to start
run: sleep 3
shell: bash

- name: Test application
run: |
if [ "${{ inputs.method }}" = "POST" ]; then
curl --fail -X POST -d '${{ inputs.body }}' http://localhost:${{ inputs.port }}/${{ inputs.path }} || exit 1
else
curl --fail -X ${{ inputs.method }} http://localhost:${{ inputs.port }}/${{ inputs.path }} || exit 1
fi
shell: bash

- name: Kill application
run: pkill node
shell: bash
35 changes: 35 additions & 0 deletions .github/actions/setup-and-build/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# .github/actions/setup-and-build/action.yml
name: 'Setup and Build'
description: 'Sets up Java, Node.js, installs dependencies, and builds the project'
inputs:
node-version:
description: 'Node.js version to setup'
required: true

runs:
using: 'composite'
steps:
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
architecture: x64

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'

- name: Install Dependency
run: npm ci
shell: bash

- name: Test generator
run: cd generator; mvn package; cd ..
shell: bash

- name: Generate code
run: python3 generate-code.py
shell: bash
99 changes: 74 additions & 25 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,100 @@ jobs:
node: [ '18', '20' ]
fail-fast: false

name: Node.js ${{ matrix.node }}
name: Node.js ${{ matrix.node }} - test

steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
architecture: x64
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Setup and Build
uses: ./.github/actions/setup-and-build
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- name: Install Dependency
run: npm ci
- name: Test generator
run: cd generator; mvn package; cd ..
- name: Generate code
run: |
python3 generate-code.py

- name: Test Project
run: export NODE_OPTIONS=--max-old-space-size=6144; npm test
- name: Test building apidocs
run: export NODE_OPTIONS=--openssl-legacy-provider; npm run apidocs
- name: Test building docs
run: export NODE_OPTIONS=--openssl-legacy-provider; npm run docs:build
- name: Test building examples (CJS)

- name: publint
run: npx publint
- name: validate package
run: npx @arethetypeswrong/cli $(npm pack)

example:
runs-on: ubuntu-latest
strategy:
matrix:
# https://nodejs.org/en/about/releases/
node: [ '18', '20' ]
fail-fast: false
name: Node.js ${{ matrix.node }} - example
steps:
- uses: actions/checkout@v4
with:
submodules: true
# TODO: Enable this again
# - name: Setup and Build
# uses: ./.github/actions/setup-and-build
# with:
# node-version: ${{ matrix.node }}
- name: Test building examples (JS + ESM)
run: |
cd examples/echo-bot-esm
npm run build-sdk
npm install
- name: Test Node.js App (echo-bot-esm)
uses: ./.github/actions/app-test
with:
port: '3000'
method: 'GET'
working-directory: examples/echo-bot-esm
channel-access-token: ${{ secrets.CHANNEL_ACCESS_TOKEN }}
channel-secret: ${{ secrets.CHANNEL_SECRET }}

- name: Test building examples (TS + CJS)
run: |
cd examples/echo-bot-ts-cjs
npm run build-sdk
npm install
npm run build
cd -
- name: Test building examples (ESM)
- name: Test Node.js App (echo-bot-ts-cjs)
uses: ./.github/actions/app-test
with:
port: '3000'
method: 'GET'
working-directory: examples/echo-bot-ts-cjs
channel-access-token: ${{ secrets.CHANNEL_ACCESS_TOKEN }}
channel-secret: ${{ secrets.CHANNEL_SECRET }}

- name: Test building examples (TS + ESM)
run: |
cd examples/echo-bot-ts-esm
npm run build-sdk
npm install
npm run build
cd -
- name: publint
run: npx publint
- name: validate package
run: npx @arethetypeswrong/cli $(npm pack)
- name: Test Node.js App (echo-bot-ts-esm)
uses: ./.github/actions/app-test
with:
port: '3000'
method: 'GET'
working-directory: examples/echo-bot-ts-esm
channel-access-token: ${{ secrets.CHANNEL_ACCESS_TOKEN }}
channel-secret: ${{ secrets.CHANNEL_SECRET }}

- name: Test building examples (JS + CJS)
run: |
cd examples/echo-bot
npm run build-sdk
npm install
- name: Test Node.js App (echo-bot)
uses: ./.github/actions/app-test
with:
port: '3000'
method: 'GET'
working-directory: examples/echo-bot
channel-access-token: ${{ secrets.CHANNEL_ACCESS_TOKEN }}
channel-secret: ${{ secrets.CHANNEL_SECRET }}
2 changes: 1 addition & 1 deletion docs/getting-started/requirements.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Requirements

* **Node.js** >= 18.
* It uses ES2015.
* It uses ES2022.
* [**npm**](https://www.npmjs.com/), preferably >=10

Other dependencies are installed via npm, and do not need to be pre-installed.
32 changes: 32 additions & 0 deletions examples/echo-bot-esm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Echo Bot (ESM)

An example LINE bot just to echo messages

## How to use

### Install deps

``` shell
$ npm build-sdk
$ npm install
```

### Configuration

``` shell
$ export CHANNEL_SECRET=YOUR_CHANNEL_SECRET
$ export CHANNEL_ACCESS_TOKEN=YOUR_CHANNEL_ACCESS_TOKEN
$ export PORT=1234
```

### Run

``` shell
$ node .
```

## Webhook URL

```
https://your.base.url/callback
```
71 changes: 71 additions & 0 deletions examples/echo-bot-esm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { messagingApi, middleware } from '@line/bot-sdk';
import express from 'express';

// create LINE SDK config from env variables
const config = {
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.CHANNEL_SECRET,
};

// create LINE SDK client
const client = new messagingApi.MessagingApiClient({
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN
});

// create Express app
// about Express itself: https://expressjs.com/
const app = express();

app.get(
'/',
async (_, res) => {
const botInfo = await client.getBotInfo()
if (botInfo.displayName.length < 2) {
return res.status(500).json({
status: 'failure',
message: 'api call failed',
});
} else {
return res.status(200).json({
status: 'success',
message: `${JSON.stringify(botInfo)}`,
});
}
}
);


// register a webhook handler with middleware
// about the middleware, please refer to doc
app.post('/callback', middleware(config), (req, res) => {
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result))
.catch((err) => {
console.error(err);
res.status(500).end();
});
});

// event handler
function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
// ignore non-text-message event
return Promise.resolve(null);
}

// create an echoing text message
const echo = { type: 'text', text: event.message.text };

// use reply API
return client.replyMessage({
replyToken: event.replyToken,
messages: [echo],
});
}

// listen on port
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`listening on ${port}`);
});
Loading