Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c8b03a427 | |||
| 92225d30c5 | |||
| 3630ba6618 | |||
| 6a03bb8e1b | |||
| 3139f541e4 | |||
| c5b9c7cfc4 | |||
| 7a14716481 | |||
| 087709f4c7 | |||
| ff81db8bb7 | |||
| bfd948fd3c | |||
| 260b563913 | |||
| 5fef548cee |
+101
-26
@@ -1,4 +1,4 @@
|
||||
name: Publish
|
||||
name: Publish & Release
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -8,57 +8,132 @@ on:
|
||||
- "package.json"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
version: latest
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "pnpm"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
- name: Get package version
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(npm pkg get version | tr -d '"')
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
# Extract major version (e.g., "0" from "0.0.1")
|
||||
MAJOR_VERSION=$(echo $VERSION | cut -d. -f1)
|
||||
echo "major_tag=v$MAJOR_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "📦 Package version: $VERSION"
|
||||
|
||||
- name: Check if tag already exists
|
||||
id: check_tag
|
||||
run: |
|
||||
if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "⚠️ Tag ${{ steps.version.outputs.tag }} already exists - skipping release"
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "✅ Tag ${{ steps.version.outputs.tag }} does not exist - will create release"
|
||||
fi
|
||||
|
||||
- name: Verify built files are up to date
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
run: |
|
||||
# Check if there are any uncommitted changes
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "❌ Error: There are uncommitted changes. Built files should be committed via pre-commit hook."
|
||||
git status
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ All built files are up to date"
|
||||
|
||||
- name: Build for npm with zshy
|
||||
run: |
|
||||
cd action
|
||||
pnpm build:npm
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
run: pnpm build:npm
|
||||
|
||||
- name: Get version from package.json
|
||||
id: get_version
|
||||
- name: Create and push tags
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
run: |
|
||||
cd action
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Publishing version: $VERSION"
|
||||
# Create specific version tag
|
||||
git tag ${{ steps.version.outputs.tag }}
|
||||
git push origin ${{ steps.version.outputs.tag }}
|
||||
|
||||
# Create/update major version tag (moving tag)
|
||||
git tag -f ${{ steps.version.outputs.major_tag }}
|
||||
git push origin ${{ steps.version.outputs.major_tag }} --force
|
||||
|
||||
echo "🏷️ Created tags: ${{ steps.version.outputs.tag }} and ${{ steps.version.outputs.major_tag }}"
|
||||
|
||||
- name: Create GitHub Release
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: v${{ steps.get_version.outputs.version }}
|
||||
release_name: "@pullfrog/action v${{ steps.get_version.outputs.version }}"
|
||||
tag_name: ${{ steps.version.outputs.tag }}
|
||||
release_name: "${{ steps.version.outputs.tag }}"
|
||||
body: |
|
||||
## 📦 @pullfrog/action ${{ steps.version.outputs.version }}
|
||||
|
||||
### Usage in GitHub Actions
|
||||
|
||||
```yaml
|
||||
- uses: pullfrog/action@${{ steps.version.outputs.major_tag }}
|
||||
```
|
||||
|
||||
### Installation via npm
|
||||
|
||||
```bash
|
||||
npm install @pullfrog/action@${{ steps.version.outputs.version }}
|
||||
```
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Publish to npm
|
||||
# - name: Publish to npm
|
||||
# if: steps.check_tag.outputs.exists == 'false'
|
||||
# run: npm publish --access public
|
||||
# env:
|
||||
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Summary
|
||||
if: always()
|
||||
run: |
|
||||
cd action
|
||||
npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
echo "## 📊 Publish Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
if [[ "${{ steps.check_tag.outputs.exists }}" == "true" ]]; then
|
||||
echo "⚠️ Version ${{ steps.version.outputs.version }} already exists - no action taken" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "✅ Successfully published version ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 🏷️ Tags Created" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- \`${{ steps.version.outputs.tag }}\` (specific version)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- \`${{ steps.version.outputs.major_tag }}\` (major version, auto-updating)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 📦 Published to" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- GitHub Release: [View Release](https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.tag }})" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- npm Registry: [@pullfrog/action@${{ steps.version.outputs.version }}](https://www.npmjs.com/package/@pullfrog/action/v/${{ steps.version.outputs.version }})" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
name: Auto-tag Action Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'package.json'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
auto-tag:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Get package version
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
# Extract major version (e.g., "0" from "0.0.1")
|
||||
MAJOR_VERSION=$(echo $VERSION | cut -d. -f1)
|
||||
echo "major_tag=v$MAJOR_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check if tag already exists
|
||||
id: check_tag
|
||||
run: |
|
||||
if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "Tag ${{ steps.version.outputs.tag }} already exists"
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Tag ${{ steps.version.outputs.tag }} does not exist"
|
||||
fi
|
||||
|
||||
- name: Verify built files are up to date
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
run: |
|
||||
# Check if there are any uncommitted changes (built files should already be committed via pre-commit hook)
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "❌ Error: There are uncommitted changes. Built files should be committed via pre-commit hook."
|
||||
git status
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ All built files are up to date"
|
||||
|
||||
- name: Create and push tags
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
run: |
|
||||
# Create specific version tag
|
||||
git tag ${{ steps.version.outputs.tag }}
|
||||
git push origin ${{ steps.version.outputs.tag }}
|
||||
|
||||
# Create/update major version tag (moving tag)
|
||||
git tag -f ${{ steps.version.outputs.major_tag }}
|
||||
git push origin ${{ steps.version.outputs.major_tag }} --force
|
||||
|
||||
- name: Create GitHub Release
|
||||
if: steps.check_tag.outputs.exists == 'false'
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.tag }}
|
||||
release_name: ${{ steps.version.outputs.tag }}
|
||||
body: |
|
||||
Automated release for action version ${{ steps.version.outputs.version }}
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: pullfrog/pullfrog@${{ steps.version.outputs.major_tag }}
|
||||
with:
|
||||
message: "Your message here"
|
||||
```
|
||||
|
||||
Or use the specific version:
|
||||
```yaml
|
||||
- uses: pullfrog/pullfrog@${{ steps.version.outputs.tag }}
|
||||
with:
|
||||
message: "Your message here"
|
||||
```
|
||||
draft: false
|
||||
prerelease: false
|
||||
+1
-1
@@ -3,4 +3,4 @@ echo "🔨 Building action..."
|
||||
npm run build
|
||||
|
||||
# Add the built files to the commit
|
||||
git add index.cjs entry.cjs
|
||||
git add entry.cjs
|
||||
|
||||
@@ -55,6 +55,14 @@ pnpm dev # Watch mode
|
||||
|
||||
The action is bundled into `entry.cjs` with all dependencies included, eliminating runtime dependency on node_modules.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Create `.env` in `/action`:
|
||||
|
||||
```bash
|
||||
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Claude API key
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
- **entry.cjs**: Bundled action entry point (self-contained)
|
||||
|
||||
@@ -10,6 +10,12 @@ inputs:
|
||||
anthropic_api_key:
|
||||
description: "Anthropic API key for Claude Code authentication"
|
||||
required: false
|
||||
github_token:
|
||||
description: "GitHub token for repository access"
|
||||
required: false
|
||||
github_installation_token:
|
||||
description: "GitHub App installation token"
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "node20"
|
||||
|
||||
+13
-9
@@ -59,7 +59,10 @@ export class ClaudeAgent implements Agent {
|
||||
],
|
||||
env: { ANTHROPIC_API_KEY: this.apiKey },
|
||||
timeout: 120000, // 2 minute timeout
|
||||
onStdout: (chunk) => process.stdout.write(chunk),
|
||||
onStdout: (chunk) => {
|
||||
// no logs
|
||||
// process.stdout.write(chunk)
|
||||
},
|
||||
onStderr: (chunk) => process.stderr.write(chunk),
|
||||
});
|
||||
|
||||
@@ -364,14 +367,15 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
||||
|
||||
case "result":
|
||||
if (parsedChunk.subtype === "success") {
|
||||
if (parsedChunk.result) {
|
||||
core.info(
|
||||
boxString(parsedChunk.result.trim(), {
|
||||
title: "🤖 Claude Code",
|
||||
maxWidth: 70,
|
||||
}),
|
||||
);
|
||||
}
|
||||
// Claude already prints something almost identical to this, so skip for now
|
||||
// if (parsedChunk.result) {
|
||||
// core.info(
|
||||
// boxString(parsedChunk.result.trim(), {
|
||||
// title: "🤖 Claude Code",
|
||||
// maxWidth: 70,
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
|
||||
core.info(
|
||||
tableString([
|
||||
|
||||
@@ -7,43 +7,55 @@
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import { main } from "./main";
|
||||
import { setupGitHubInstallationToken } from "./utils";
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
// Get inputs from GitHub Actions
|
||||
const prompt = core.getInput("prompt", { required: true });
|
||||
const anthropicApiKey = core.getInput("anthropic_api_key", {
|
||||
required: true,
|
||||
});
|
||||
|
||||
if (!anthropicApiKey) {
|
||||
throw new Error("anthropic_api_key is required");
|
||||
}
|
||||
const anthropicApiKey = core.getInput("anthropic_api_key");
|
||||
|
||||
if (!prompt) {
|
||||
throw new Error("prompt is required");
|
||||
}
|
||||
|
||||
// Create params object
|
||||
const params = {
|
||||
// Create params object with new structure
|
||||
const inputs: any = {
|
||||
prompt,
|
||||
anthropicApiKey,
|
||||
anthropic_api_key: anthropicApiKey,
|
||||
};
|
||||
|
||||
// Add optional properties only if they exist
|
||||
const githubToken = core.getInput("github_token") || process.env.GITHUB_TOKEN;
|
||||
if (githubToken) {
|
||||
inputs.github_token = githubToken;
|
||||
}
|
||||
|
||||
const githubInstallationToken =
|
||||
core.getInput("github_installation_token") || process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
if (githubInstallationToken) {
|
||||
inputs.github_installation_token = githubInstallationToken;
|
||||
} else {
|
||||
// Setup GitHub installation token
|
||||
await setupGitHubInstallationToken();
|
||||
}
|
||||
|
||||
const params = {
|
||||
inputs,
|
||||
env: {} as Record<string, string>,
|
||||
cwd: process.cwd(),
|
||||
};
|
||||
|
||||
// Run the main function
|
||||
const result = await main(params);
|
||||
|
||||
// Set outputs
|
||||
core.setOutput("status", result.success ? "success" : "failed");
|
||||
core.setOutput("prompt", prompt);
|
||||
core.setOutput("output", result.output || "");
|
||||
// TODO: Set outputs
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Agent execution failed");
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error occurred";
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
||||
core.setFailed(`Action failed: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,7 +1,13 @@
|
||||
import type { MainParams } from "../main";
|
||||
|
||||
const testParams = {
|
||||
prompt: "List all files in the current directory, then create a file called dynamic-test.txt with the content 'This was loaded from a TypeScript file!', then delete it."
|
||||
inputs: {
|
||||
prompt:
|
||||
"List all files in the current directory, then create a file called dynamic-test.txt with the content 'This was loaded from a TypeScript file!', then delete it.",
|
||||
anthropic_api_key: "sk-test-key",
|
||||
},
|
||||
env: {},
|
||||
cwd: process.cwd(),
|
||||
} satisfies MainParams;
|
||||
|
||||
export default testParams;
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
* This exports the main function for programmatic usage
|
||||
*/
|
||||
|
||||
export { main } from "./main";
|
||||
export { ClaudeAgent } from "./agents";
|
||||
export type { Agent, AgentConfig, AgentResult } from "./agents/types";
|
||||
export {
|
||||
type ExecutionInputs,
|
||||
type MainParams,
|
||||
type MainResult,
|
||||
main,
|
||||
} from "./main";
|
||||
|
||||
@@ -1,41 +1,60 @@
|
||||
import * as core from "@actions/core";
|
||||
import { ClaudeAgent } from "./agents";
|
||||
|
||||
export interface MainParams {
|
||||
// Expected environment variables that should be passed as inputs
|
||||
export const EXPECTED_INPUTS: string[] = [
|
||||
"ANTHROPIC_API_KEY",
|
||||
"GITHUB_TOKEN",
|
||||
"GITHUB_INSTALLATION_TOKEN"
|
||||
];
|
||||
|
||||
export interface ExecutionInputs {
|
||||
prompt: string;
|
||||
anthropicApiKey?: string;
|
||||
anthropic_api_key: string;
|
||||
github_token?: string;
|
||||
github_installation_token?: string;
|
||||
}
|
||||
|
||||
export interface MainParams {
|
||||
inputs: ExecutionInputs;
|
||||
env: Record<string, string>;
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
export interface MainResult {
|
||||
success: boolean;
|
||||
output?: string;
|
||||
error?: string;
|
||||
output?: string | undefined;
|
||||
error?: string | undefined;
|
||||
}
|
||||
|
||||
|
||||
export async function main(params: MainParams): Promise<MainResult> {
|
||||
try {
|
||||
// Use provided API key or fall back to environment variable
|
||||
const anthropicApiKey =
|
||||
params.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
|
||||
// Extract inputs from params
|
||||
const { inputs, env, cwd } = params;
|
||||
|
||||
if (!anthropicApiKey) {
|
||||
throw new Error("anthropic_api_key is required");
|
||||
// Set working directory if different from current
|
||||
if (cwd !== process.cwd()) {
|
||||
process.chdir(cwd);
|
||||
}
|
||||
|
||||
// Set environment variables
|
||||
Object.assign(process.env, env);
|
||||
|
||||
core.info(`→ Starting agent run with Claude Code`);
|
||||
|
||||
// Create and install the Claude agent
|
||||
const agent = new ClaudeAgent({ apiKey: anthropicApiKey });
|
||||
const agent = new ClaudeAgent({ apiKey: inputs.anthropic_api_key });
|
||||
await agent.install();
|
||||
|
||||
// Execute the agent with the prompt
|
||||
const result = await agent.execute(params.prompt);
|
||||
const result = await agent.execute(inputs.prompt);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
success: false,
|
||||
error: result.error || "Agent execution failed",
|
||||
output: result.output,
|
||||
output: result.output!,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,8 +63,7 @@ export async function main(params: MainParams): Promise<MainResult> {
|
||||
output: result.output || "",
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error occurred";
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
|
||||
Generated
-1460
File diff suppressed because it is too large
Load Diff
+19
-8
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pullfrog/action",
|
||||
"version": "0.0.6",
|
||||
"version": "0.0.8",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.js",
|
||||
@@ -17,21 +17,22 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "pnpm install && node esbuild.config.js && rm -rf node_modules",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "node esbuild.config.js",
|
||||
"build:npm": "zshy",
|
||||
"build:dev": "node esbuild.config.js",
|
||||
"prepare": "husky",
|
||||
"play": "tsx --env-file=../.env play.ts"
|
||||
"play": "tsx play.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/core": "^1.11.1",
|
||||
"dotenv": "^17.2.2",
|
||||
"execa": "^9.6.0",
|
||||
"table": "^6.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.0",
|
||||
"commander": "^14.0.0",
|
||||
"dotenv": "^17.2.2",
|
||||
"esbuild": "^0.25.9",
|
||||
"husky": "^9.0.0",
|
||||
"typescript": "^5.3.0",
|
||||
@@ -39,16 +40,26 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pullfrog/pullfrog.git"
|
||||
"url": "git+https://github.com/pullfrog/action.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pullfrog/pullfrog/issues"
|
||||
"url": "https://github.com/pullfrog/action/issues"
|
||||
},
|
||||
"homepage": "https://github.com/pullfrog/pullfrog#readme",
|
||||
"homepage": "https://github.com/pullfrog/action#readme",
|
||||
"zshy": {
|
||||
"exports": "./index.ts"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.cts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.cts",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join, resolve, extname } from "node:path";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { dirname, extname, join, resolve } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { Command } from "commander";
|
||||
import { config } from "dotenv";
|
||||
import { main } from "./main";
|
||||
import { runAct } from "./utils/act";
|
||||
import { setupTestRepo } from "./utils/setup";
|
||||
|
||||
// Load environment variables from .env file
|
||||
config();
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
@@ -46,9 +49,7 @@ async function loadPrompt(filePath: string): Promise<string> {
|
||||
const module = await import(fileUrl);
|
||||
|
||||
if (!module.default) {
|
||||
throw new Error(
|
||||
`TypeScript file ${filePath} must have a default export`,
|
||||
);
|
||||
throw new Error(`TypeScript file ${filePath} must have a default export`);
|
||||
}
|
||||
|
||||
// If it's a string, use it directly
|
||||
@@ -66,16 +67,11 @@ async function loadPrompt(filePath: string): Promise<string> {
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Unsupported file type: ${ext}. Supported types: .txt, .json, .ts`,
|
||||
);
|
||||
throw new Error(`Unsupported file type: ${ext}. Supported types: .txt, .json, .ts`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runPlay(
|
||||
filePath: string,
|
||||
options: { act?: boolean },
|
||||
): Promise<void> {
|
||||
async function runPlay(filePath: string, options: { act?: boolean }): Promise<void> {
|
||||
try {
|
||||
// Load the prompt from the specified file
|
||||
const prompt = await loadPrompt(filePath);
|
||||
@@ -85,56 +81,9 @@ async function runPlay(
|
||||
console.log("🐳 Running with Docker/act...");
|
||||
runAct(prompt);
|
||||
} else {
|
||||
// Clone the test repository and run directly
|
||||
// Setup test repository and run directly
|
||||
const tempDir = join(process.cwd(), ".temp");
|
||||
const repoUrl = "git@github.com:pullfrogai/scratch.git";
|
||||
|
||||
// Remove existing temp directory if it exists
|
||||
if (existsSync(tempDir)) {
|
||||
console.log("🗑️ Removing existing .temp directory...");
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// Clone the repository
|
||||
console.log("📦 Cloning pullfrogai/scratch into .temp...");
|
||||
execSync(`git clone ${repoUrl} ${tempDir}`, { stdio: "inherit" });
|
||||
|
||||
// List of environment variables to copy to .temp
|
||||
const envVarsToCopy = [
|
||||
"ANTHROPIC_API_KEY",
|
||||
"GITHUB_TOKEN",
|
||||
// Add more environment variables here as needed
|
||||
];
|
||||
|
||||
// Build .env content from the list
|
||||
const envLines = envVarsToCopy
|
||||
.map((varName) => `${varName}=${process.env[varName] || ""}`)
|
||||
.join("\n");
|
||||
|
||||
const envPath = join(tempDir, ".env");
|
||||
writeFileSync(envPath, envLines + "\n");
|
||||
console.log("📝 Created .env file in .temp directory with:");
|
||||
|
||||
let hasRequiredVars = true;
|
||||
envVarsToCopy.forEach((varName) => {
|
||||
const hasValue = !!process.env[varName];
|
||||
console.log(` - ${varName}: ${hasValue ? "✓" : "✗ (missing)"}`);
|
||||
|
||||
// Check for required variables
|
||||
if (varName === "ANTHROPIC_API_KEY" && !hasValue) {
|
||||
hasRequiredVars = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasRequiredVars) {
|
||||
console.warn("\n⚠️ Warning: ANTHROPIC_API_KEY is not set or empty.");
|
||||
console.warn(
|
||||
" Please ensure you have a valid API key in your .env file.",
|
||||
);
|
||||
console.warn(
|
||||
" Get your API key from: https://console.anthropic.com/api-keys\n",
|
||||
);
|
||||
}
|
||||
setupTestRepo({ tempDir, forceClean: true });
|
||||
|
||||
// Change to the temp directory
|
||||
process.chdir(tempDir);
|
||||
@@ -145,8 +94,35 @@ async function runPlay(
|
||||
console.log(prompt);
|
||||
console.log("─".repeat(50));
|
||||
|
||||
// Run main with the params object
|
||||
const result = await main({ prompt });
|
||||
// Set environment variables from our .env for the action to use
|
||||
const { EXPECTED_INPUTS } = await import("./main");
|
||||
EXPECTED_INPUTS.forEach((inputName) => {
|
||||
const value = process.env[inputName];
|
||||
if (value) {
|
||||
process.env[`INPUT_${inputName.toLowerCase()}`] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Run main with the new params structure
|
||||
const inputs: any = {
|
||||
prompt,
|
||||
anthropic_api_key: process.env.ANTHROPIC_API_KEY || "",
|
||||
};
|
||||
|
||||
// Add optional properties only if they exist
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
inputs.github_token = process.env.GITHUB_TOKEN;
|
||||
}
|
||||
|
||||
if (process.env.GITHUB_INSTALLATION_TOKEN) {
|
||||
inputs.github_installation_token = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
}
|
||||
|
||||
const result = await main({
|
||||
inputs,
|
||||
env: process.env as Record<string, string>,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log("✅ Test completed successfully");
|
||||
@@ -171,15 +147,8 @@ program
|
||||
.name("play")
|
||||
.description("Test the Pullfrog action with various prompts")
|
||||
.version("1.0.0")
|
||||
.argument(
|
||||
"[file]",
|
||||
"Prompt file to use (.txt, .json, or .ts)",
|
||||
"fixtures/play.txt",
|
||||
)
|
||||
.option(
|
||||
"--act",
|
||||
"Use Docker/act to run the action instead of running directly",
|
||||
)
|
||||
.argument("[file]", "Prompt file to use (.txt, .json, or .ts)", "fixtures/basic.txt")
|
||||
.option("--act", "Use Docker/act to run the action instead of running directly")
|
||||
.action(async (file: string, options: { act?: boolean }) => {
|
||||
await runPlay(file, options);
|
||||
});
|
||||
|
||||
Generated
+509
-5
@@ -9,12 +9,24 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@actions/core':
|
||||
specifier: ^1.10.1
|
||||
specifier: ^1.11.1
|
||||
version: 1.11.1
|
||||
dotenv:
|
||||
specifier: ^17.2.2
|
||||
version: 17.2.2
|
||||
execa:
|
||||
specifier: ^9.6.0
|
||||
version: 9.6.0
|
||||
table:
|
||||
specifier: ^6.9.0
|
||||
version: 6.9.0
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^20.10.0
|
||||
version: 20.19.11
|
||||
version: 20.19.13
|
||||
commander:
|
||||
specifier: ^14.0.0
|
||||
version: 14.0.0
|
||||
esbuild:
|
||||
specifier: ^0.25.9
|
||||
version: 0.25.9
|
||||
@@ -24,6 +36,9 @@ importers:
|
||||
typescript:
|
||||
specifier: ^5.3.0
|
||||
version: 5.9.2
|
||||
zshy:
|
||||
specifier: ^0.4.1
|
||||
version: 0.4.1(typescript@5.9.2)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -199,19 +214,258 @@ packages:
|
||||
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@types/node@20.19.11':
|
||||
resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==}
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nodelib/fs.stat@2.0.5':
|
||||
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nodelib/fs.walk@1.2.8':
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@sec-ant/readable-stream@0.4.1':
|
||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||
|
||||
'@sindresorhus/merge-streams@2.3.0':
|
||||
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@sindresorhus/merge-streams@4.0.0':
|
||||
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@types/node@20.19.13':
|
||||
resolution: {integrity: sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==}
|
||||
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
arg@5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
|
||||
astral-regex@2.0.0:
|
||||
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
commander@14.0.0:
|
||||
resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
dotenv@17.2.2:
|
||||
resolution: {integrity: sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
esbuild@0.25.9:
|
||||
resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
execa@9.6.0:
|
||||
resolution: {integrity: sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==}
|
||||
engines: {node: ^18.19.0 || >=20.5.0}
|
||||
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
fast-glob@3.3.3:
|
||||
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fastq@1.19.1:
|
||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||
|
||||
figures@6.1.0:
|
||||
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
fill-range@7.1.1:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
get-stream@9.0.1:
|
||||
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
globby@14.1.0:
|
||||
resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
human-signals@8.0.1:
|
||||
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
||||
husky@9.1.7:
|
||||
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
ignore@7.0.5:
|
||||
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
is-extglob@2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-number@7.0.0:
|
||||
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
is-plain-obj@4.1.0:
|
||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-stream@4.0.1:
|
||||
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-unicode-supported@2.1.0:
|
||||
resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
lodash.truncate@4.4.2:
|
||||
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
micromatch@4.0.8:
|
||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
parse-ms@4.0.0:
|
||||
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
path-key@3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-key@4.0.0:
|
||||
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
path-type@6.0.0:
|
||||
resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
picomatch@2.3.1:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
pretty-ms@9.2.0:
|
||||
resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
require-from-string@2.0.2:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
reusify@1.1.0:
|
||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shebang-regex@3.0.0:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
slash@5.1.0:
|
||||
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
slice-ansi@4.0.0:
|
||||
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-final-newline@4.0.0:
|
||||
resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
table@6.9.0:
|
||||
resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
tunnel@0.0.6:
|
||||
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
||||
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
|
||||
@@ -228,6 +482,25 @@ packages:
|
||||
resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
|
||||
engines: {node: '>=14.0'}
|
||||
|
||||
unicorn-magic@0.3.0:
|
||||
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
yoctocolors@2.1.2:
|
||||
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
zshy@0.4.1:
|
||||
resolution: {integrity: sha512-9BP1xv9BK4xNf8N5K85q+n81uFRT4p92JrT2BShXwgn8iw63QeSbdd7Ytw5RzqFG3AeIGtqpOEJPk4iiM77dsw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: '>5.5.0'
|
||||
|
||||
snapshots:
|
||||
|
||||
'@actions/core@1.11.1':
|
||||
@@ -326,10 +599,67 @@ snapshots:
|
||||
|
||||
'@fastify/busboy@2.1.1': {}
|
||||
|
||||
'@types/node@20.19.11':
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
run-parallel: 1.2.0
|
||||
|
||||
'@nodelib/fs.stat@2.0.5': {}
|
||||
|
||||
'@nodelib/fs.walk@1.2.8':
|
||||
dependencies:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.19.1
|
||||
|
||||
'@sec-ant/readable-stream@0.4.1': {}
|
||||
|
||||
'@sindresorhus/merge-streams@2.3.0': {}
|
||||
|
||||
'@sindresorhus/merge-streams@4.0.0': {}
|
||||
|
||||
'@types/node@20.19.13':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
ajv@8.17.1:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-uri: 3.1.0
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
|
||||
arg@5.0.2: {}
|
||||
|
||||
astral-regex@2.0.0: {}
|
||||
|
||||
braces@3.0.3:
|
||||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
commander@14.0.0: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
dotenv@17.2.2: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
esbuild@0.25.9:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.25.9
|
||||
@@ -359,8 +689,167 @@ snapshots:
|
||||
'@esbuild/win32-ia32': 0.25.9
|
||||
'@esbuild/win32-x64': 0.25.9
|
||||
|
||||
execa@9.6.0:
|
||||
dependencies:
|
||||
'@sindresorhus/merge-streams': 4.0.0
|
||||
cross-spawn: 7.0.6
|
||||
figures: 6.1.0
|
||||
get-stream: 9.0.1
|
||||
human-signals: 8.0.1
|
||||
is-plain-obj: 4.1.0
|
||||
is-stream: 4.0.1
|
||||
npm-run-path: 6.0.0
|
||||
pretty-ms: 9.2.0
|
||||
signal-exit: 4.1.0
|
||||
strip-final-newline: 4.0.0
|
||||
yoctocolors: 2.1.2
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
fast-glob@3.3.3:
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
glob-parent: 5.1.2
|
||||
merge2: 1.4.1
|
||||
micromatch: 4.0.8
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fastq@1.19.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
figures@6.1.0:
|
||||
dependencies:
|
||||
is-unicode-supported: 2.1.0
|
||||
|
||||
fill-range@7.1.1:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
||||
get-stream@9.0.1:
|
||||
dependencies:
|
||||
'@sec-ant/readable-stream': 0.4.1
|
||||
is-stream: 4.0.1
|
||||
|
||||
glob-parent@5.1.2:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
|
||||
globby@14.1.0:
|
||||
dependencies:
|
||||
'@sindresorhus/merge-streams': 2.3.0
|
||||
fast-glob: 3.3.3
|
||||
ignore: 7.0.5
|
||||
path-type: 6.0.0
|
||||
slash: 5.1.0
|
||||
unicorn-magic: 0.3.0
|
||||
|
||||
human-signals@8.0.1: {}
|
||||
|
||||
husky@9.1.7: {}
|
||||
|
||||
ignore@7.0.5: {}
|
||||
|
||||
is-extglob@2.1.1: {}
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
is-number@7.0.0: {}
|
||||
|
||||
is-plain-obj@4.1.0: {}
|
||||
|
||||
is-stream@4.0.1: {}
|
||||
|
||||
is-unicode-supported@2.1.0: {}
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
lodash.truncate@4.4.2: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
micromatch@4.0.8:
|
||||
dependencies:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
unicorn-magic: 0.3.0
|
||||
|
||||
parse-ms@4.0.0: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-key@4.0.0: {}
|
||||
|
||||
path-type@6.0.0: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
pretty-ms@9.2.0:
|
||||
dependencies:
|
||||
parse-ms: 4.0.0
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
reusify@1.1.0: {}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
slash@5.1.0: {}
|
||||
|
||||
slice-ansi@4.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
astral-regex: 2.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
|
||||
strip-final-newline@4.0.0: {}
|
||||
|
||||
table@6.9.0:
|
||||
dependencies:
|
||||
ajv: 8.17.1
|
||||
lodash.truncate: 4.4.2
|
||||
slice-ansi: 4.0.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
|
||||
tunnel@0.0.6: {}
|
||||
|
||||
typescript@5.9.2: {}
|
||||
@@ -370,3 +859,18 @@ snapshots:
|
||||
undici@5.29.0:
|
||||
dependencies:
|
||||
'@fastify/busboy': 2.1.1
|
||||
|
||||
unicorn-magic@0.3.0: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
yoctocolors@2.1.2: {}
|
||||
|
||||
zshy@0.4.1(typescript@5.9.2):
|
||||
dependencies:
|
||||
arg: 5.0.2
|
||||
globby: 14.1.0
|
||||
table: 6.9.0
|
||||
typescript: 5.9.2
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
"compilerOptions": {
|
||||
// File Layout
|
||||
// "rootDir": "./src",
|
||||
// "outDir": "./dist",
|
||||
"outDir": "./dist",
|
||||
|
||||
// Environment Settings
|
||||
// See also https://aka.ms/tsconfig/module
|
||||
@@ -40,6 +40,6 @@
|
||||
"isolatedModules": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"moduleDetection": "force",
|
||||
"skipLibCheck": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
|
||||
+23
-42
@@ -1,59 +1,36 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { existsSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { config, parse } from "dotenv";
|
||||
import { config } from "dotenv";
|
||||
import { buildAction, setupTestRepo } from "./setup";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Environment variables that should be passed as secrets to the workflow
|
||||
const ENV_VARS = ["ANTHROPIC_API_KEY", "GITHUB_INSTALLATION_TOKEN"];
|
||||
|
||||
export function runAct(prompt: string): void {
|
||||
// First, ensure the scratch repo is cloned
|
||||
const tempDir = join(__dirname, "..", ".temp");
|
||||
|
||||
// Check if .temp exists and either reset it or clone it
|
||||
if (existsSync(tempDir)) {
|
||||
console.log("📦 Resetting existing .temp repository...");
|
||||
execSync("git reset --hard HEAD && git clean -fd", {
|
||||
cwd: tempDir,
|
||||
stdio: "inherit",
|
||||
});
|
||||
} else {
|
||||
console.log("📦 Cloning pullfrogai/scratch into .temp...");
|
||||
const repoUrl = "git@github.com:pullfrogai/scratch.git";
|
||||
execSync(`git clone ${repoUrl} ${tempDir}`, { stdio: "inherit" });
|
||||
}
|
||||
|
||||
const workflowPath = join(tempDir, ".github", "workflows", "pullfrog.yml");
|
||||
const actionPath = join(__dirname, "..");
|
||||
const envPath = join(__dirname, "..", "..", ".env");
|
||||
|
||||
// Load environment variables into process
|
||||
// Setup test repository
|
||||
setupTestRepo({ tempDir });
|
||||
|
||||
// Load environment variables
|
||||
config({ path: envPath });
|
||||
|
||||
// Parse environment variables from .env file to get keys
|
||||
let envVars: string[] = [];
|
||||
try {
|
||||
const content = readFileSync(envPath, "utf8");
|
||||
const parsed = parse(content);
|
||||
envVars = Object.keys(parsed);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Warning: Could not read .env file: ${(error as Error).message}`,
|
||||
);
|
||||
}
|
||||
// Build action bundles
|
||||
buildAction(actionPath);
|
||||
|
||||
// Build fresh bundles with esbuild
|
||||
const actionPath = join(__dirname, "..");
|
||||
console.log("🔨 Building fresh bundles with esbuild...");
|
||||
execSync("node esbuild.config.js", {
|
||||
cwd: actionPath,
|
||||
stdio: "inherit",
|
||||
});
|
||||
const workflowPath = join(tempDir, ".github", "workflows", "pullfrog.yml");
|
||||
|
||||
// Create minimal dist for act (avoids pnpm symlink issues)
|
||||
const distPath = join(actionPath, ".act-dist");
|
||||
console.log("📦 Creating minimal distribution for act...");
|
||||
execSync(`rm -rf "${distPath}" && mkdir -p "${distPath}"`, { shell: true });
|
||||
execSync(`rm -rf "${distPath}" && mkdir -p "${distPath}"`, { shell: "/bin/bash" });
|
||||
|
||||
// Copy only necessary files (bundled, no node_modules needed)
|
||||
["action.yml", "entry.cjs", "index.cjs", "package.json"].forEach((file) => {
|
||||
@@ -76,14 +53,18 @@ export function runAct(prompt: string): void {
|
||||
"--input",
|
||||
`prompt='${escapedPrompt}'`,
|
||||
"--local-repository",
|
||||
`pullfrog/pullfrog@v0=${distPath}`, // Use minimal dist without symlinks
|
||||
`pullfrog/action@v0=${distPath}`, // Use minimal dist without symlinks
|
||||
];
|
||||
|
||||
// Add all environment variables as secrets (without values)
|
||||
envVars.forEach((key) => {
|
||||
actCommandParts.push("-s", key);
|
||||
// Add environment variables as secrets that will be available to the workflow
|
||||
ENV_VARS.forEach((key) => {
|
||||
if (process.env[key]) {
|
||||
actCommandParts.push("-s", key);
|
||||
}
|
||||
});
|
||||
|
||||
// We only need the specific ENV_VARS, no need to add other variables
|
||||
|
||||
const actCommand = actCommandParts.join(" ");
|
||||
|
||||
console.log("🚀 Running act with prompt:");
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import * as core from "@actions/core";
|
||||
|
||||
/**
|
||||
* Setup GitHub installation token for the action
|
||||
*/
|
||||
export async function setupGitHubInstallationToken(): Promise<string> {
|
||||
// Check if we have an installation token from inputs or environment
|
||||
const inputToken = core.getInput("github_installation_token");
|
||||
const envToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
|
||||
const existingToken = inputToken || envToken;
|
||||
if (existingToken) {
|
||||
core.info("Using provided GitHub installation token");
|
||||
return existingToken;
|
||||
}
|
||||
|
||||
core.info("No cached installation token found, generating OIDC token...");
|
||||
|
||||
try {
|
||||
// Generate OIDC token for our API
|
||||
const oidcToken = await core.getIDToken("pullfrog-api");
|
||||
core.info("OIDC token generated successfully");
|
||||
|
||||
// Exchange OIDC token for installation token
|
||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||
|
||||
const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${oidcToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
const errorText = await tokenResponse.text();
|
||||
throw new Error(
|
||||
`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorText}`
|
||||
);
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
core.info(
|
||||
`Installation token obtained for ${tokenData.owner}/${tokenData.repository || "all repositories"}`
|
||||
);
|
||||
|
||||
// Set the token as an environment variable for this run
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = tokenData.token;
|
||||
|
||||
return tokenData.token;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to setup GitHub installation token: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from "./files";
|
||||
export * from "./github";
|
||||
export * from "./setup";
|
||||
export * from "./subprocess";
|
||||
export * from "./table";
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync, rmSync } from "node:fs";
|
||||
|
||||
export interface SetupOptions {
|
||||
tempDir: string;
|
||||
repoUrl?: string;
|
||||
forceClean?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the test repository for running actions
|
||||
*/
|
||||
export function setupTestRepo(options: SetupOptions): void {
|
||||
const {
|
||||
tempDir,
|
||||
repoUrl = "git@github.com:pullfrogai/scratch.git",
|
||||
forceClean = false,
|
||||
} = options;
|
||||
|
||||
// Handle existing temp directory
|
||||
if (existsSync(tempDir)) {
|
||||
if (forceClean) {
|
||||
console.log("🗑️ Removing existing .temp directory...");
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
|
||||
// Clone the repository
|
||||
console.log("📦 Cloning pullfrogai/scratch into .temp...");
|
||||
execSync(`git clone ${repoUrl} ${tempDir}`, { stdio: "inherit" });
|
||||
} else {
|
||||
console.log("📦 Resetting existing .temp repository...");
|
||||
execSync("git reset --hard HEAD && git clean -fd", {
|
||||
cwd: tempDir,
|
||||
stdio: "inherit",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log("📦 Cloning pullfrogai/scratch into .temp...");
|
||||
execSync(`git clone ${repoUrl} ${tempDir}`, { stdio: "inherit" });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the action bundles
|
||||
*/
|
||||
export function buildAction(actionPath: string): void {
|
||||
console.log("🔨 Building fresh bundles with esbuild...");
|
||||
execSync("node esbuild.config.js", {
|
||||
cwd: actionPath,
|
||||
stdio: "inherit",
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user