Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
98 changes: 98 additions & 0 deletions .github/workflows/self-hosted.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: AWS

on:
workflow_dispatch:
push:

jobs:
gather:
name: Gather Test Files
runs-on: ubuntu-latest
outputs:
test_files: ${{ steps.test_list.outputs.files }}
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Find all test files
id: test_list
run: |
FILES=$(ls ./testdriver/acceptance/*.yaml)
FILENAMES=$(basename -a $FILES)
FILES_JSON=$(echo "$FILENAMES" | jq -R -s -c 'split("\n")[:-1]')
echo "files=$FILES_JSON" >> $GITHUB_OUTPUT

test:
needs: gather
runs-on: ubuntu-latest
strategy:
matrix:
test: ${{ fromJson(needs.gather.outputs.test_files) }}
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
# only needed for `act`
# - name: Install AWS CLI
# run: |
# apt-get update
# apt-get install curl unzip -y
# curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
# unzip awscliv2.zip
# ./aws/install
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: NODE_ENV=production npm ci
- name: Setup AWS Instance
id: aws-setup
run: |
OUTPUT=$(./setup/aws/spawn-runner.sh | tee /dev/stderr) # Capture and display output
echo "$OUTPUT"
PUBLIC_IP=$(echo "$OUTPUT" | grep "PUBLIC_IP=" | cut -d'=' -f2)
INSTANCE_ID=$(echo "$OUTPUT" | grep "INSTANCE_ID=" | cut -d'=' -f2)
AWS_REGION=$(echo "$OUTPUT" | grep "AWS_REGION=" | cut -d'=' -f2)
echo "public-ip=$PUBLIC_IP" >> $GITHUB_OUTPUT
echo "instance-id=$INSTANCE_ID" >> $GITHUB_OUTPUT
echo "aws-region=$AWS_REGION" >> $GITHUB_OUTPUT
env:
FORCE_COLOR: 3
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-2
AWS_LAUNCH_TEMPLATE_ID: lt-00d02f31cfc602f27
AMI_ID: ami-085f872ca0cd80fed
- name: Run TestDriver
run: node bin/testdriverai.js run testdriver/acceptance/${{ matrix.test }} --ip="${{ steps.aws-setup.outputs.public-ip }}" --junit=out.xml
env:
TD_API_KEY: ${{ secrets.TD_API_KEY }}
TD_WEBSITE: https://testdriver-sandbox.vercel.app
TD_THIS_FILE: ${{ matrix.test }}
- name: Upload TestDriver AI CLI logs
if: always()
uses: actions/upload-artifact@v4
with:
name: testdriverai-cli-logs-${{ matrix.test }}
path: /tmp/testdriverai-cli-*.log
if-no-files-found: warn
retention-days: 30
- name: Upload test results as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.test }}
path: out.xml
retention-days: 30
- name: Shutdown AWS Instance
if: always()
run: aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ steps.aws-setup.outputs.aws-region }}
INSTANCE_ID: ${{ steps.aws-setup.outputs.instance-id }}
22 changes: 17 additions & 5 deletions agent/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class TestDriverAgent extends EventEmitter2 {
this.sandboxId = flags["sandbox-id"] || null;
this.sandboxAmi = flags["sandbox-ami"] || null;
this.sandboxInstance = flags["sandbox-instance"] || null;
this.ip = flags.ip || null;
this.workingDir = flags.workingDir || process.cwd();

// Resolve thisFile to absolute path with proper extension
Expand Down Expand Up @@ -1699,7 +1700,20 @@ ${regression}
const recentId = createNew ? null : this.getRecentSandboxId();

// Set sandbox ID for reconnection (only if not creating new and recent ID exists)
if (!createNew && recentId) {
if (this.ip) {
let instance = await this.sandbox.send({
type: "direct",
resolution: this.config.TD_RESOLUTION,
ci: this.config.CI,
ip: this.ip,
});

await this.renderSandbox(instance.instance, headless);
await this.newSession();
await this.runLifecycle("provision");

return;
} else if (!createNew && recentId) {
this.emitter.emit(
events.log.narration,
theme.dim(`using recent sandbox: ${recentId}`),
Expand All @@ -1710,10 +1724,8 @@ ${regression}
events.log.narration,
theme.dim(`no recent sandbox found, creating a new one.`),
);
}

// Only attempt to connect to existing sandbox if not in CI mode and not creating new
if (this.sandboxId && !this.config.CI && !createNew) {
} else if (this.sandboxId && !this.config.CI) {
// Only attempt to connect to existing sandbox if not in CI mode and not creating new
// Attempt to connect to known instance
this.emitter.emit(
events.log.narration,
Expand Down
8 changes: 8 additions & 0 deletions agent/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ function createCommandDefinitions(agent) {
"sandbox-instance": Flags.string({
description: "Specify EC2 instance type for sandbox (e.g., i3.metal)",
}),
ip: Flags.string({
description:
"Connect directly to a sandbox at the specified IP address",
}),
summary: Flags.string({
description: "Specify output file for summarize results",
}),
Expand Down Expand Up @@ -129,6 +133,10 @@ function createCommandDefinitions(agent) {
"sandbox-instance": Flags.string({
description: "Specify EC2 instance type for sandbox (e.g., i3.metal)",
}),
ip: Flags.string({
description:
"Connect directly to a sandbox at the specified IP address",
}),
summary: Flags.string({
description: "Specify output file for summarize results",
}),
Expand Down
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
}
]
},
"/getting-started/self-hosting",
"/getting-started/playwright",
"/getting-started/vscode"
]
Expand Down
Loading