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
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ updates:
directory: "/"
open-pull-requests-limit: 4
schedule:
interval: "daily"
interval: "weekly"

- package-ecosystem: "npm"
directory: "/"
open-pull-requests-limit: 4
schedule:
interval: "daily"
interval: "weekly"
17 changes: 17 additions & 0 deletions .github/scripts/clean_up_stream_table.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

aws kinesis delete-stream --stream-name $STREAM_NAME || true

# Reset the values of checkpoint, leaseCounter, ownerSwitchesSinceCheckpoint, and leaseOwner in DynamoDB table
echo "Resetting DDB table"
aws dynamodb update-item \
--table-name $APP_NAME \
--key '{"leaseKey": {"S": "shardId-000000000000"}}' \
--update-expression "SET checkpoint = :checkpoint, leaseCounter = :counter, ownerSwitchesSinceCheckpoint = :switches, leaseOwner = :owner" \
--expression-attribute-values '{
":checkpoint": {"S": "TRIM_HORIZON"},
":counter": {"N": "0"},
":switches": {"N": "0"},
":owner": {"S": "AVAILABLE"}
}' \
--return-values NONE
12 changes: 12 additions & 0 deletions .github/scripts/create_stream.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

for i in {1..10}; do
if aws kinesis create-stream --stream-name $STREAM_NAME --shard-count 1; then
break
else
echo "Stream creation failed, attempt $i/10. Waiting $((i * 3)) seconds..."
sleep $((i * 3))
fi
done
aws kinesis wait stream-exists --stream-name $STREAM_NAME
30 changes: 30 additions & 0 deletions .github/scripts/manipulate_properties.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash
set -e

# Manipulate sample.properties file that the KCL application pulls properties from (ex: streamName, applicationName)
# Depending on the OS, different properties need to be changed
if [[ "$RUNNER_OS" == "macOS" ]]; then
sed -i "" "s/streamName = .*/streamName = $STREAM_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "" "s/applicationName = .*/applicationName = $APP_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "" "s/#*idleTimeBetweenReadsInMillis.*/idleTimeBetweenReadsInMillis = 250/" samples/basic_sample/consumer/sample.properties
sed -i "" "s/stream : 'kclnodejssample'/stream : '$STREAM_NAME'/" samples/basic_sample/producer/config.js
sed -i "" "s/shards : 2/shards : 1/" samples/basic_sample/producer/config.js
elif [[ "$RUNNER_OS" == "Linux" ]]; then
sed -i "s/streamName = .*/streamName = $STREAM_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "s/applicationName = .*/applicationName = $APP_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "s/#*idleTimeBetweenReadsInMillis.*/idleTimeBetweenReadsInMillis = 250/" samples/basic_sample/consumer/sample.properties
sed -i "s/stream : 'kclnodejssample'/stream : '$STREAM_NAME'/" samples/basic_sample/producer/config.js
sed -i "s/shards : 2/shards : 1/" samples/basic_sample/producer/config.js
elif [[ "$RUNNER_OS" == "Windows" ]]; then
sed -i "s/streamName = .*/streamName = $STREAM_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "s/applicationName = .*/applicationName = $APP_NAME/" samples/basic_sample/consumer/sample.properties
sed -i "s/#*idleTimeBetweenReadsInMillis.*/idleTimeBetweenReadsInMillis = 250/" samples/basic_sample/consumer/sample.properties
sed -i "s/stream : 'kclnodejssample'/stream : '$STREAM_NAME'/" samples/basic_sample/producer/config.js
sed -i "s/shards : 2/shards : 1/" samples/basic_sample/producer/config.js
Comment on lines +6 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these all the same commands? Can we merge them all under one if statement so we don't repeat code?

else
echo "Unknown OS: $RUNNER_OS"
exit 1
fi

cat samples/basic_sample/consumer/sample.properties
cat samples/basic_sample/producer/config.js
16 changes: 16 additions & 0 deletions .github/scripts/put_words_to_stream.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
set -e

cd samples/basic_sample/producer
node sample_kinesis_producer_app.js

# Get records from stream to verify they exist before continuing
SHARD_ITERATOR=$(aws kinesis get-shard-iterator --stream-name $STREAM_NAME --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
INITIAL_RECORDS=$(aws kinesis get-records --shard-iterator $SHARD_ITERATOR)
RECORD_COUNT_BEFORE=$(echo $INITIAL_RECORDS | jq '.Records | length')

if [ "$RECORD_COUNT_BEFORE" -eq 0 ]; then
echo "No records found in stream. Test cannot proceed."
exit 1
fi
echo "Found $RECORD_COUNT_BEFORE records in stream before KCL start"
48 changes: 48 additions & 0 deletions .github/scripts/start_kcl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
set -e
set -o pipefail

# Reset the values of checkpoint, leaseCounter, ownerSwitchesSinceCheckpoint, and leaseOwner in DynamoDB table
echo "Resetting checkpoint for shardId-000000000000"
aws dynamodb update-item \
--table-name $APP_NAME \
--key '{"leaseKey": {"S": "shardId-000000000000"}}' \
--update-expression "SET checkpoint = :checkpoint, leaseCounter = :counter, ownerSwitchesSinceCheckpoint = :switches, leaseOwner = :owner" \
--expression-attribute-values '{
":checkpoint": {"S": "TRIM_HORIZON"},
":counter": {"N": "0"},
":switches": {"N": "0"},
":owner": {"S": "AVAILABLE"}
}' \
--return-values NONE

# Get records from stream to verify they exist before continuing
SHARD_ITERATOR=$(aws kinesis get-shard-iterator --stream-name $STREAM_NAME --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
INITIAL_RECORDS=$(aws kinesis get-records --shard-iterator $SHARD_ITERATOR)
RECORD_COUNT_BEFORE=$(echo $INITIAL_RECORDS | jq '.Records | length')

echo "Found $RECORD_COUNT_BEFORE records in stream before KCL start"

if [[ "$RUNNER_OS" == "macOS" ]]; then
brew install coreutils
cd samples/basic_sample/consumer
KCL_COMMAND="../../../bin/kcl-bootstrap --java /usr/bin/java -e -p ./sample.properties"
gtimeout 300 $KCL_COMMAND 2>&1 | tee kcl_output.log || [ $? -eq 124 ]
elif [[ "$RUNNER_OS" == "Linux" ]]; then
cd samples/basic_sample/consumer
KCL_COMMAND="../../../bin/kcl-bootstrap -e -p ./sample.properties"
timeout 300 $KCL_COMMAND 2>&1 | tee kcl_output.log || [ $? -eq 124 ]
elif [[ "$RUNNER_OS" == "Windows" ]]; then
cd samples/basic_sample/consumer
KCL_COMMAND="../../../bin/kcl-bootstrap -e -p ./sample.properties"
timeout 300 $KCL_COMMAND 2>&1 | tee kcl_output.log || [ $? -eq 124 ]
Comment on lines +31 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look to be the same commands, can we put an or in the if statement instead to reduce copy paste?

else
echo "Unknown OS: $RUNNER_OS"
exit 1
fi

echo "---------ERROR LOGS HERE-------"
grep -i error kcl_output.log || echo "No errors found in logs"



20 changes: 20 additions & 0 deletions .github/scripts/verify_kcl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash
set -e

LEASE_EXISTS=$(aws dynamodb scan --table-name $APP_NAME --select "COUNT" --query "Count" --output text || echo "0")
CHECKPOINT_EXISTS=$(aws dynamodb scan --table-name $APP_NAME --select "COUNT" --filter-expression "attribute_exists(checkpoint) AND checkpoint <> :trim_horizon" --expression-attribute-values '{":trim_horizon": {"S": "TRIM_HORIZON"}}' --query "Count" --output text || echo "0")

echo "Found $LEASE_EXISTS leases and $CHECKPOINT_EXISTS non-TRIM-HORIZON checkpoints in DynamoDB"

echo "Printing checkpoint values"
aws dynamodb scan --table-name $APP_NAME --projection-expression "leaseKey,checkpoint" --output json

if [ "$LEASE_EXISTS" -gt 0 ] && [ "$CHECKPOINT_EXISTS" -gt 0 ]; then
echo "Test passed: Found both leases and non-TRIM_HORIZON checkpoints in DDB (KCL is fully functional)"
exit 0
else
echo "Test failed: KCL not fully functional"
echo "Lease(s) found: $LEASE_EXISTS"
echo "non-TRIM_HORIZON checkpoint(s) found: $CHECKPOINT_EXISTS"
exit 1
fi
156 changes: 117 additions & 39 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,82 @@
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

name: Sample Run and Dependabot Auto-merge
name: Sample Run Tests and Dependabot
on:
push:
branches: [ master ]
pull_request_target:
branches: [ master ]
types: [opened, synchronize, reopened, labeled, unlabeled]

permissions:
id-token: write
contents: write
pull-requests: write
statuses: write
concurrency:
group: node.js.yml
cancel-in-progress: false

jobs:
# Evaluates if the sample tests should run. If the workflow is triggered by a push OR
# is triggered by a pull request without the 'skip-sample-tests' label, the sample tests should run.
# Otherwise, the sample tests will be skipped
check-if-should-run:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request_target' && !contains(github.event.pull_request.labels.*.name, 'skip-sample-tests')) }}
outputs:
should_run: 'true'
is_fork: ${{ github.event_name == 'pull_request_target' && (github.event.pull_request.head.repo.fork || github.event.pull_request.user.login == 'dependabot[bot]') }}
steps:
- run: echo "Evaluating workflow conditions"

# Workflow will pause and wait here if it is triggered by a fork PR. The workflow will continue to wait until
# an approved member of the environment 'manual_approval' allows the workflow to run
wait-for-approval:
needs: [ check-if-should-run ]
if: ${{ needs.check-if-should-run.outputs.is_fork == 'true' }}
runs-on: ubuntu-latest
environment: manual-approval
steps:
- run: echo "Fork PR approved by a team member."

# Sample run tests of the KCL
# Runs only if (check-if-should-run allows AND (the PR is not from a fork OR it has been approved to run))
sample-run:
timeout-minutes: 8
needs: [ check-if-should-run, wait-for-approval ]
permissions:
id-token: write
if: ${{ always() && needs.check-if-should-run.outputs.should_run == 'true' && (needs.check-if-should-run.outputs.is_fork != 'true' || needs.wait-for-approval.result == 'success') }}
timeout-minutes: 20
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash

# Initialize matrix based on PR labels (more-tests label runs more tests)
strategy:
fail-fast: false
matrix:
node-version: [ '18.x', '20.x', '21.x' ]
jdk-version: [ "8", "11", "17", "21", "24" ]
node-version: ${{ github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'more-tests') && fromJSON('["18.x", "21.x"]') || fromJSON('["18.x"]') }}
jdk-version: ${{ github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'more-tests') && fromJSON('["8", "11", "17", "21", "24"]') || fromJSON('["8", "11"]') }}
os: [ ubuntu-latest, macOS-latest, windows-latest ]

steps:
- name: Checkout working directory
# For pull_request_target, checkout PR head instead of merge commit
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}

- name: Validate os, node-version, and jdk-version
run: |
[[ "${{ matrix.os }}" =~ ^(ubuntu-latest|macOS-latest|windows-latest)$ ]] || exit 1
[[ "${{ matrix.node-version }}" =~ ^(18.x|21.x)$ ]] || exit 1
[[ "${{ matrix.jdk-version }}" =~ ^(8|11|17|21|24)$ ]] || exit 1

# Configure AWS Credentials. Role session name is unique to avoid OIDC errors when running multiple tests concurrently
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
role-to-assume: arn:aws:iam::751999266872:role/GitHubNodejs
role-session-name: myGitHubActionsNodejs
role-to-assume: ${{ secrets.AWS_ARN_GHA }}
role-session-name: GHA-${{ github.run_id }}-${{ matrix.node-version }}-${{ matrix.jdk-version }}-${{ matrix.os }}

- name: Set up JDK ${{ matrix.jdk-version }}
uses: actions/setup-java@v4
Expand All @@ -49,7 +89,6 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: npm clean install, build, and test
run: |
Expand All @@ -61,28 +100,74 @@ jobs:
run: |
npm install

- name: Running data producer
# Create unique identifiers for the stream name and application name
- name: Set up unique identifiers
run: |
cd samples/basic_sample/producer
node sample_kinesis_producer_app.js
STREAM_NAME="kclnodesample-${{ matrix.os }}-node${{ matrix.node-version }}-jdk${{ matrix.jdk-version }}"
APP_NAME="NodeKCLSample-${{ matrix.os }}-node${{ matrix.node-version }}-jdk${{ matrix.jdk-version }}"
echo "STREAM_NAME=$STREAM_NAME" >> $GITHUB_ENV
echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV

- name: Running KCL consumer (windows or ubuntu)
if: matrix.os != 'macOS-latest'
# Manipulate sample.properties file to use unique stream name and application name
- name: Manipulate sample.properties file
run: |
cd samples/basic_sample/consumer
timeout 45 ../../../bin/kcl-bootstrap -e -p ./sample.properties || status="$?"; if (( status == 124 )); then exit 0; else exit 1; fi; exit "$status"
chmod +x .github/scripts/manipulate_properties.sh
.github/scripts/manipulate_properties.sh
env:
RUNNER_OS: ${{ matrix.os }}
STREAM_NAME: ${{ env.STREAM_NAME }}
APP_NAME: ${{ env.APP_NAME }}

# Create kinesis stream with unique name and wait for it to exist
- name: Create and wait Kinesis stream
run: |
chmod +x .github/scripts/create_stream.sh
.github/scripts/create_stream.sh
env:
STREAM_NAME: ${{ env.STREAM_NAME }}

- name: Running KCL consumer (macOS)
if: matrix.os == 'macOS-latest'
# Put words to sample stream with unique name based on run ID
- name: Put words to sample stream
run: |
chmod +x .github/scripts/put_words_to_stream.sh
.github/scripts/put_words_to_stream.sh
env:
STREAM_NAME: ${{ env.STREAM_NAME }}

# Run sample KCL application
- name: Start KCL application
run: |
chmod +x .github/scripts/start_kcl.sh
.github/scripts/start_kcl.sh
env:
RUNNER_OS: ${{ matrix.os }}
STREAM_NAME: ${{ env.STREAM_NAME }}

# Check and verify results of KCL test
- name: Verify KCL Functionality
run: |
chmod +x .github/scripts/verify_kcl.sh
.github/scripts/verify_kcl.sh
env:
APP_NAME: ${{ env.APP_NAME }}

# Clean up all existing Streams and DDB tables
- name: Clean up Kinesis Stream and DynamoDB table
if: always()
run: |
brew install coreutils
cd samples/basic_sample/consumer
gtimeout 45 ../../../bin/kcl-bootstrap --java /usr/bin/java -e -p ./sample.properties || status="$?"; if (( status == 124 )); then exit 0; else exit 1; fi; exit "$status"
chmod +x .github/scripts/clean_up_stream_table.sh
.github/scripts/clean_up_stream_table.sh
env:
STREAM_NAME: ${{ env.STREAM_NAME }}
APP_NAME: ${{ env.APP_NAME }}

auto-merge-dependabot:
needs: [ sample-run ]
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]'
if: github.event.pull_request.user.login == 'dependabot[bot]'
permissions:
contents: read
pull-requests: write
steps:
- name: Fetch Dependabot metadata
id: metadata
Expand All @@ -91,16 +176,9 @@ jobs:
alert-lookup: true
github-token: "${{ secrets.GITHUB_TOKEN }}"

# - name: Approve PR
# if: steps.metadata.outputs.update-type != 'version-update:semver-major'
# run: gh pr review --approve "$PR_URL"
# env:
# PR_URL: ${{github.event.pull_request.html_url}}
# GH_TOKEN: ${{secrets.GITHUB_TOKEN}}

# - name: Enable auto-merge for Dependabot PRs
# if: steps.metadata.outputs.update-type != 'version-update:semver-major'
# run: gh pr merge --auto --merge "$PR_URL"
# env:
# PR_URL: ${{github.event.pull_request.html_url}}
# GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Approve PR
if: steps.metadata.outputs.update-type != 'version-update:semver-major'
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
Loading