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
112 changes: 6 additions & 106 deletions .github/workflows/build-hoppscotch-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ on:
repository:
description: Repository to checkout
required: false
default: "hoppscotch/hoppscotch"
default: "Ford/hoppscotch"
branch:
description: Branch to checkout
required: false
default: "main"
default: "FS-Changes"
tag:
description: Tag to checkout (takes precedence over branch if provided)
required: false
Expand All @@ -33,106 +33,6 @@ env:
DESKTOP_PATH: ${{ github.workspace }}/packages/hoppscotch-desktop
BUNDLER_PATH: ${{ github.workspace }}/packages/hoppscotch-desktop/crates/webapp-bundler
jobs:
build-linux:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v3
with:
repository: ${{ inputs.repository }}
ref: ${{ inputs.tag != '' && inputs.tag || inputs.branch }}
token: ${{ secrets.CHECKOUT_GITHUB_TOKEN }}
- uses: actions/setup-node@v3
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: 10.2.1
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
- name: Install additional tools
run: |
curl -LO "https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.2.0/cargo-tauri-x86_64-unknown-linux-gnu.tgz"
tar -xzf cargo-tauri-x86_64-unknown-linux-gnu.tgz
chmod +x cargo-tauri
sudo mv cargo-tauri /usr/local/bin/tauri
- name: Install system dependencies
run: |
sudo apt update;
sudo apt install -y \
build-essential \
curl \
wget \
file \
libssl-dev \
libgtk-3-dev \
libappindicator3-dev \
librsvg2-dev;

sudo apt install -y \
libwebkit2gtk-4.1-0=2.44.0-2 \
libwebkit2gtk-4.1-dev=2.44.0-2 \
libjavascriptcoregtk-4.1-0=2.44.0-2 \
libjavascriptcoregtk-4.1-dev=2.44.0-2 \
gir1.2-javascriptcoregtk-4.1=2.44.0-2 \
gir1.2-webkit2-4.1=2.44.0-2;
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup environment
run: |
if [ ! -z "${{ secrets.ENV_FILE_CONTENT }}" ]; then
echo "${{ secrets.ENV_FILE_CONTENT }}" > ${{ env.WORKSPACE_PATH }}/.env
echo "Created .env file from repository secret"
elif [ -f "${{ env.WORKSPACE_PATH }}/.env" ]; then
echo "Using existing .env file found in repository"
else
cp ${{ env.WORKSPACE_PATH }}/.env.example ${{ env.WORKSPACE_PATH }}/.env
echo "No .env found, copied from .env.example template"
fi
pnpm install --dir ${{ env.DESKTOP_PATH }}
- name: Build web app
run: |
pnpm install --dir ${{ env.WEB_PATH }}
pnpm --dir ${{ env.WEB_PATH }} generate
- name: Build and run webapp-bundler
run: |
cargo build --release --manifest-path ${{ env.BUNDLER_PATH }}/Cargo.toml
${{ env.BUNDLER_PATH }}/target/release/webapp-bundler \
--input ${{ env.WEB_PATH }}/dist \
--output ${{ env.DESKTOP_PATH }}/bundle.zip \
--manifest ${{ env.DESKTOP_PATH }}/manifest.json
- name: Build AppImage
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
RUST_LOG: debug
run: pnpm --dir ${{ env.DESKTOP_PATH }} tauri build --verbose -b appimage -b updater
- name: Build DEB
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
RUST_LOG: debug
run: pnpm --dir ${{ env.DESKTOP_PATH }} tauri build --verbose -b deb -b updater
- name: Prepare artifacts
run: |
ls -lahR ${{ env.DESKTOP_PATH }}/src-tauri/target/release/bundle/
mkdir -p dist
cp ${{ env.DESKTOP_PATH }}/src-tauri/target/release/bundle/appimage/*.AppImage dist/Hoppscotch_SelfHost_linux_x64.AppImage
cp ${{ env.DESKTOP_PATH }}/src-tauri/target/release/bundle/appimage/*.AppImage.sig dist/Hoppscotch_SelfHost_linux_x64.AppImage.sig
cp ${{ env.DESKTOP_PATH }}/src-tauri/target/release/bundle/deb/*.deb dist/Hoppscotch_SelfHost_linux_x64.deb
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux
path: dist/*
build-windows:
runs-on: windows-latest
steps:
Expand All @@ -151,7 +51,7 @@ jobs:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: 10.2.1
version: 10.15.0
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand Down Expand Up @@ -253,7 +153,7 @@ jobs:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: 10.2.1
version: 10.15.0
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand Down Expand Up @@ -349,7 +249,7 @@ jobs:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: 10.2.1
version: 10.15.0
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand Down Expand Up @@ -433,7 +333,7 @@ jobs:
name: macos-aarch64
path: dist/*
create-update-manifest:
needs: [build-linux, build-windows, build-macos-x64, build-macos-arm64]
needs: [build-windows, build-macos-x64, build-macos-arm64]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ web_modules/
.env
.env.*

# npm configuration files (contains sensitive registry credentials)
.npmrc

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
Expand Down
8 changes: 5 additions & 3 deletions packages/hoppscotch-cli/package.json
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hoppscotch/cli",
"version": "0.24.0",
"name": "@devenap/hoppscotch-cli",
"version": "1.2.5",
"description": "A CLI to run Hoppscotch test scripts in CI environments.",
"homepage": "https://hoppscotch.io",
"type": "module",
Expand Down Expand Up @@ -52,7 +52,9 @@
"qs": "6.14.0",
"verzod": "0.4.0",
"xmlbuilder2": "3.1.1",
"zod": "3.25.32"
"zod": "3.25.32",
"form-data": "4.0.0",
"proxy-agent": "6.4.0"
},
"devDependencies": {
"@hoppscotch/data": "workspace:^",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"params": [],
"headers": [],
"endpoint": "<<url>>",
"testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);}); \n pw.test(\"Receives the www-authenticate header\", ()=> { pw.expect(pw.response.headers['www-authenticate']).toBeType('string');});",
"testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});",
"preRequestScript": "",
"responses": {},
"requestVariables": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
"authActive": true
},
"preRequestScript": "",
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n }); \n\n// Check Content-Type\n pw.test(\"Check Content-Type\", () => {\n let contentType = null;\n for (const header of pw.response.headers) {\n if (header.key.toLowerCase() === 'content-type') {\n contentType = header.value;\n break;\n }\n}\npw.expect(contentType).toBe('application/json');\n });",
"body": {
"contentType": null,
"body": null
},
"requestVariables": []
}
]
}
}
11 changes: 10 additions & 1 deletion packages/hoppscotch-cli/src/utils/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
processRequest,
} from "./request";
import { getTestMetrics } from "./test";
import {ProxyAgent} from "proxy-agent";
import axios from "axios";

const { WARN, FAIL, INFO } = exceptionColors;

Expand Down Expand Up @@ -132,8 +134,15 @@ const processCollection = async (
// Request processing initiated message.
log(WARN(`\nRunning: ${chalk.bold(requestPath)}`));

const agent = new ProxyAgent();
const axiosInstance = axios.create({
httpsAgent : agent,
httpAgent : agent,
proxy: false, // Disable axios's default proxy handling
});

// Processing current request.
const result = await processRequest(processRequestParams)();
const result = await processRequest(processRequestParams,axiosInstance)();

// Updating global & selected envs with new envs from processed-request output.
const { global, selected } = result.envs;
Expand Down
19 changes: 5 additions & 14 deletions packages/hoppscotch-cli/src/utils/mutators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { error } from "../types/errors";
import { FormDataEntry } from "../types/request";
import { isHoppErrnoException } from "./checks";
import { getResourceContents } from "./getters";
import FormData from "form-data";
import fsSync from "fs";

const getValidRequests = (
collections: HoppCollection[],
Expand Down Expand Up @@ -52,20 +54,9 @@ const getValidRequests = (
export const toFormData = (values: FormDataEntry[]) => {
const formData = new FormData();

values.forEach(({ key, value, contentType }) => {
if (contentType) {
formData.append(
key,
new Blob([value], {
type: contentType,
}),
key
);

return;
}

formData.append(key, value);
values.forEach(({ key, value }) => {
const isFilePath = typeof value === "string" && value.startsWith("/");
formData.append(key, isFilePath ? fsSync.createReadStream(value) : value);
});

return formData;
Expand Down
10 changes: 9 additions & 1 deletion packages/hoppscotch-cli/src/utils/pre-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
fetchInitialDigestAuthInfo,
generateDigestAuthHeader,
} from "./auth/digest";
import FormData from "form-data";

import { calculateHawkHeader } from "@hoppscotch/data";

Expand Down Expand Up @@ -388,7 +389,14 @@ export async function getEffectiveRESTRequest(

const effectiveFinalBody = _effectiveFinalBody.right;

if (
if (effectiveFinalBody instanceof FormData) {
effectiveFinalHeaders.push({
active: true,
key: "Content-Type",
value: `multipart/form-data; boundary=${effectiveFinalBody.getBoundary()}`,
description: "",
});
} else if (
request.body.contentType &&
!effectiveFinalHeaders.some(
({ key }) => key.toLowerCase() === "content-type"
Expand Down
57 changes: 43 additions & 14 deletions packages/hoppscotch-cli/src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,38 @@ export const requestRunner =
// NOTE: Temporary parsing check for request endpoint.
requestConfig.url = new URL(requestConfig.url ?? "").toString();

let status: number;
const baseResponse = await axios(requestConfig);
const { config } = baseResponse;
// PR-COMMENT: type error

const end = hrtime(start);
const duration = getDurationInSeconds(end);
const responseTime = duration * 1000; // Convert seconds to milliseconds

// Transform axios headers to required format
const transformedHeaders: { key: string; value: string }[] = [];
if (baseResponse.headers) {
for (const [key, value] of Object.entries(baseResponse.headers)) {
if (value !== undefined) {
transformedHeaders.push({
key,
value: Array.isArray(value) ? value.join(", ") : String(value),
});
}
}
}

const runnerResponse: RequestRunnerResponse = {
...baseResponse,
endpoint: getRequest.endpoint(config.url),
method: getRequest.method(config.method),
body: baseResponse.data,
duration: 0,
duration: responseTime, // Use responseTime (in milliseconds) for duration to match GUI behavior
status: baseResponse.status,
statusText: baseResponse.statusText,
headers: transformedHeaders,
};

const end = hrtime(start);
const duration = getDurationInSeconds(end);
runnerResponse.duration = duration;

return E.right(runnerResponse);
} catch (e) {
let status: number;
const runnerResponse: RequestRunnerResponse = {
endpoint: "",
method: "GET",
Expand All @@ -148,14 +161,30 @@ export const requestRunner =
runnerResponse.body = data;
runnerResponse.statusText = statusText;
runnerResponse.status = status;
runnerResponse.headers = headers;

// Transform axios headers to required format
const transformedHeaders: { key: string; value: string }[] = [];
if (headers) {
for (const [key, value] of Object.entries(headers)) {
if (value !== undefined) {
transformedHeaders.push({
key,
value: Array.isArray(value)
? value.join(", ")
: String(value),
});
}
}
}
runnerResponse.headers = transformedHeaders;
} else if (e.request) {
return E.left(error({ code: "REQUEST_ERROR", data: E.toError(e) }));
}

const end = hrtime(start);
const duration = getDurationInSeconds(end);
runnerResponse.duration = duration;
const responseTime = duration * 1000; // Convert to milliseconds
runnerResponse.duration = responseTime;

return E.right(runnerResponse);
}
Expand Down Expand Up @@ -237,7 +266,7 @@ export const processRequest =
const preRequestRes = await preRequestScriptRunner(
request,
processedEnvs,
legacySandbox,
legacySandbox ?? false,
collectionVariables
)();
if (E.isLeft(preRequestRes)) {
Expand Down Expand Up @@ -289,9 +318,9 @@ export const processRequest =
// Extracting test-script-runner parameters.
const testScriptParams = getTestScriptParams(
_requestRunnerRes,
request,
effectiveRequest,
updatedEnvs,
legacySandbox
legacySandbox ?? false
);

// Executing test-runner.
Expand Down
Loading
Loading