Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d41d409a0e |
@@ -0,0 +1,18 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre-commit-lint:
|
||||
name: pre-commit Linting
|
||||
runs-on: pi
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
- run: pip install pre-commit
|
||||
shell: bash
|
||||
- name: Pre Commit
|
||||
run: SKIP=no-commit-to-branch pre-commit run -a
|
||||
shell: bash
|
||||
@@ -1,55 +0,0 @@
|
||||
name: Recompile dist/ on Renovate PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
paths:
|
||||
- package.json
|
||||
- pnpm-lock.yaml
|
||||
- index.js
|
||||
- monitor.js
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
recompile:
|
||||
runs-on: pi
|
||||
if: |
|
||||
(github.actor == 'renovate[bot]' || contains(github.head_ref, 'renovate/')) &&
|
||||
!contains(github.event.head_commit.message, '[skip compile]')
|
||||
steps:
|
||||
- name: Checkout PR Branch
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: ${{ github.head_ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: pnpm
|
||||
|
||||
- name: Clean Install
|
||||
run: pnpm install --frozen-lockfile --ignore-scripts
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
shell: bash
|
||||
|
||||
- name: Commit dist/
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add dist/
|
||||
if git diff --staged --quiet; then
|
||||
echo "No changes to dist/"
|
||||
else
|
||||
git commit -m "chore: compile action bundle [skip compile]"
|
||||
git push origin HEAD:${{ github.head_ref }}
|
||||
fi
|
||||
shell: bash
|
||||
@@ -2,7 +2,6 @@ name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -11,12 +10,10 @@ jobs:
|
||||
runs-on: pi
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
node-version: '24'
|
||||
- run: npm install
|
||||
shell: bash
|
||||
- run: pnpm test
|
||||
- run: npm test
|
||||
shell: bash
|
||||
|
||||
@@ -21,7 +21,6 @@ repos:
|
||||
hooks:
|
||||
- id: pretty-format-yaml
|
||||
args: [--autofix]
|
||||
exclude: ^pnpm-lock\.yaml$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
@@ -30,11 +29,10 @@ repos:
|
||||
types_or: [css, javascript]
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.38.0
|
||||
rev: 0.37.4
|
||||
hooks:
|
||||
- id: check-renovate
|
||||
- id: check-github-actions
|
||||
exclude: ^action\.yaml$
|
||||
- id: check-github-workflows
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
|
||||
@@ -7,7 +7,6 @@ This repository is maintained by Gemini.
|
||||
* **Test-Driven Development (TDD):** Wherever possible, Test-Driven Development principles should be followed. Write tests before writing the code they are intended to validate.
|
||||
* **Pre-commit Hooks:** Ensure that `pre-commit` hooks are installed and active before making any commits. This can be done by running `pre-commit install` in your local repository.
|
||||
* **Note for Gemini:** Git commits trigger pre-commit hooks, which can take several seconds (or minutes) to complete. Checking the command status for git commit is only appropriate every 120s.
|
||||
* **Package Manager Preferences:** Always use `pnpm` and `pnpx`. Never use `npm` or `npx` under any circumstances. All package management operations, script runs, and tool invocations must use `pnpm` / `pnpx`.
|
||||
|
||||
## Repository Comparison
|
||||
|
||||
@@ -20,7 +19,7 @@ This project uses [Vitest](https://vitest.dev/) for testing. The tests are locat
|
||||
To run the tests locally, use the following command:
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
npm test
|
||||
```
|
||||
|
||||
### Testing Pipeline
|
||||
@@ -30,11 +29,6 @@ The tests are automatically run on every push and workflow dispatch using a Gite
|
||||
The Gitea workflow does the following:
|
||||
|
||||
1. Checks out the code.
|
||||
2. Sets up Node.js and pnpm.
|
||||
3. Installs the dependencies using `pnpm install`.
|
||||
4. Runs the tests using `pnpm test`.
|
||||
|
||||
### Automated Recompilation & Permissions
|
||||
|
||||
* The automated recompilation workflow (`.gitea/workflows/recompile-dist.yaml`) recompiles `dist/index.js` on Renovate PRs and requires `contents: write` permissions to push back to the branch.
|
||||
* Ensure that the Gitea repository workflow settings have write permissions enabled (**Settings** ➔ **Actions** ➔ **General** ➔ **Workflow permissions** ➔ **Read and write permissions**).
|
||||
2. Sets up Node.js.
|
||||
3. Installs the dependencies using `npm install`.
|
||||
4. Runs the tests using `npm test`.
|
||||
|
||||
@@ -84,7 +84,7 @@ This project includes a build step to prepare the action for use.
|
||||
### Why a Build Step?
|
||||
|
||||
We use a build step to compile the JavaScript code and its dependencies into a single, self-contained file (`dist/index.js`). This approach is chosen for the following reasons:
|
||||
1. **Zero-configuration at Runtime:** By bundling everything, the action runner doesn't need to run `pnpm install` or `npm install`, which speeds up the action execution.
|
||||
1. **Zero-configuration at Runtime:** By bundling everything, the action runner doesn't need to run `npm install`, which speeds up the action execution.
|
||||
2. **Reliability:** It guarantees that the exact versions of dependencies tested during development are used in the action, avoiding potential issues with version updates or missing packages.
|
||||
3. **Standard Practice:** This is a recommended practice for JavaScript-based GitHub/Gitea Actions.
|
||||
|
||||
@@ -100,8 +100,8 @@ We chose [`@vercel/ncc`](https://github.com/vercel/ncc) as the compiler because:
|
||||
If you modify `index.js` or change dependencies, you must rebuild the project before committing:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm run build
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
This will update the `dist/index.js` file, which should be committed to the repository.
|
||||
|
||||
+10
-20
@@ -1,4 +1,4 @@
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||
|
||||
// Mock @actions/core for all tests in this file
|
||||
vi.mock("@actions/core", () => ({
|
||||
@@ -24,23 +24,16 @@ vi.mock("../monitor.js", () => ({
|
||||
vi.mock("screeps-api", () => {
|
||||
const mockApi = {
|
||||
auth: vi.fn().mockResolvedValue(),
|
||||
authSignin: vi.fn().mockResolvedValue({ ok: 1, token: "test_token" }),
|
||||
userCodeGet: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ ok: 1, modules: { main: "old_code" } }),
|
||||
userCodeSet: vi.fn().mockResolvedValue({ ok: 1 }),
|
||||
code: {
|
||||
get: vi.fn().mockResolvedValue({ ok: 1, modules: { main: "old_code" } }),
|
||||
set: vi.fn().mockResolvedValue({ ok: 1 }),
|
||||
},
|
||||
};
|
||||
// Use a regular function so it can be called with `new`
|
||||
const MockClient = vi.fn(function () {
|
||||
return mockApi;
|
||||
});
|
||||
return {
|
||||
ScreepsHttpClient: MockClient,
|
||||
ScreepsAPI: MockClient,
|
||||
ScreepsAPI: vi.fn(function () {
|
||||
return mockApi;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -55,7 +48,7 @@ import {
|
||||
applyOnAction,
|
||||
postCode,
|
||||
} from "../index.js";
|
||||
import { ScreepsHttpClient } from "screeps-api";
|
||||
import { ScreepsAPI } from "screeps-api";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
@@ -337,17 +330,14 @@ describe("postCode — monitor wiring", () => {
|
||||
await postCode();
|
||||
|
||||
// Verify rollback was performed
|
||||
const mockApiInstance = new ScreepsHttpClient();
|
||||
const mockApiInstance = new ScreepsAPI();
|
||||
|
||||
// `userCodeSet` should be called twice:
|
||||
// `code.set` should be called twice:
|
||||
// 1st time: uploading the new files
|
||||
// 2nd time: rolling back to oldCode
|
||||
expect(mockApiInstance.userCodeSet).toHaveBeenCalledTimes(2);
|
||||
expect(mockApiInstance.userCodeSet).toHaveBeenNthCalledWith(2, {
|
||||
branch: "default",
|
||||
modules: {
|
||||
main: "old_code",
|
||||
},
|
||||
expect(mockApiInstance.code.set).toHaveBeenCalledTimes(2);
|
||||
expect(mockApiInstance.code.set).toHaveBeenNthCalledWith(2, "default", {
|
||||
main: "old_code",
|
||||
});
|
||||
|
||||
// Verify it called core.setFailed due to traceback
|
||||
|
||||
@@ -382,21 +382,13 @@ function buildMockApi({
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
|
||||
const getTime = vi.fn().mockImplementation(() => {
|
||||
const t = ticks[Math.min(tickIndex, ticks.length - 1)];
|
||||
tickIndex++;
|
||||
return Promise.resolve({ time: t });
|
||||
});
|
||||
|
||||
const api = {
|
||||
opts: { hostname },
|
||||
time: getTime,
|
||||
get gameTime() {
|
||||
return this.time;
|
||||
},
|
||||
set gameTime(fn) {
|
||||
this.time = fn;
|
||||
},
|
||||
time: vi.fn().mockImplementation(() => {
|
||||
const t = ticks[Math.min(tickIndex, ticks.length - 1)];
|
||||
tickIndex++;
|
||||
return Promise.resolve({ time: t });
|
||||
}),
|
||||
socket,
|
||||
// Expose so tests can fire console events
|
||||
_fireConsole: (eventData) => {
|
||||
|
||||
+1
-1
@@ -79,5 +79,5 @@ outputs:
|
||||
saw_warning_log:
|
||||
description: true if console.warn output was detected during monitoring.
|
||||
runs:
|
||||
using: node22
|
||||
using: node20
|
||||
main: dist/index.js
|
||||
|
||||
Vendored
+8
-8
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
import { ScreepsHttpClient } from "screeps-api";
|
||||
import { ScreepsAPI } from "screeps-api";
|
||||
import * as core from "@actions/core";
|
||||
import fs from "fs";
|
||||
import { glob } from "glob";
|
||||
@@ -180,16 +180,12 @@ export async function postCode() {
|
||||
core.error(errorMessage);
|
||||
return;
|
||||
}
|
||||
let api = new ScreepsHttpClient(login_arguments);
|
||||
let api = new ScreepsAPI(login_arguments);
|
||||
|
||||
if (!token) {
|
||||
core.info(`Logging in as user ${username}`);
|
||||
try {
|
||||
if (typeof api.authSignin === "function") {
|
||||
await api.authSignin(username, password);
|
||||
} else {
|
||||
await api.auth(username, password, login_arguments);
|
||||
}
|
||||
await api.auth(username, password, login_arguments);
|
||||
} catch (err) {
|
||||
core.error(`Authentication error: ${err}`);
|
||||
throw err;
|
||||
@@ -209,9 +205,7 @@ export async function postCode() {
|
||||
`Downloading existing code from branch ${branch} for potential rollback...`,
|
||||
);
|
||||
try {
|
||||
const getResponse = await (api.userCodeGet
|
||||
? api.userCodeGet(branch)
|
||||
: api.code.get(branch));
|
||||
const getResponse = await api.code.get(branch);
|
||||
if (getResponse && getResponse.ok && getResponse.modules) {
|
||||
oldCode = getResponse.modules;
|
||||
core.info(
|
||||
@@ -232,9 +226,7 @@ export async function postCode() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await (api.userCodeSet
|
||||
? api.userCodeSet({ branch, modules: files_to_push })
|
||||
: api.code.set(branch, files_to_push));
|
||||
const response = await api.code.set(branch, files_to_push);
|
||||
core.info(JSON.stringify(response, null, 2));
|
||||
core.info(`Code set successfully to ${branch}`);
|
||||
} catch (err) {
|
||||
@@ -287,11 +279,7 @@ export async function postCode() {
|
||||
"Action failed based on monitor configuration. Rolling back to previous code...",
|
||||
);
|
||||
try {
|
||||
if (typeof api.userCodeSet === "function") {
|
||||
await api.userCodeSet({ branch, modules: oldCode });
|
||||
} else {
|
||||
await api.code.set(branch, oldCode);
|
||||
}
|
||||
await api.code.set(branch, oldCode);
|
||||
core.info(
|
||||
`Successfully rolled back to previous code on branch ${branch}.`,
|
||||
);
|
||||
|
||||
+4
-8
@@ -250,7 +250,7 @@ function sleep(ms) {
|
||||
* Calls `onProgress(elapsed, targetTicks)` on every poll so the caller can
|
||||
* log progress at whatever cadence it chooses.
|
||||
*
|
||||
* @param {import('screeps-api').ScreepsHttpClient} api
|
||||
* @param {import('screeps-api').ScreepsAPI} api
|
||||
* @param {number} startTick - Tick number recorded before monitoring started
|
||||
* @param {number} targetTicks - Stop when (currentTick - startTick) >= this
|
||||
* @param {string|undefined} shard - "shard0" for official, undefined for private
|
||||
@@ -270,9 +270,7 @@ export async function pollUntilDone(
|
||||
let elapsed = 0;
|
||||
while (elapsed < targetTicks && !shouldStop()) {
|
||||
await sleep(intervalMs);
|
||||
const { time } = await (typeof api.gameTime === "function"
|
||||
? api.gameTime(shard)
|
||||
: api.time(shard));
|
||||
const { time } = await api.time(shard);
|
||||
elapsed = time - startTick;
|
||||
onProgress(elapsed, targetTicks);
|
||||
}
|
||||
@@ -311,7 +309,7 @@ export async function pollUntilDone(
|
||||
* 6. If logToFile=true: write buffered stdout to a temp file and upload artifact.
|
||||
* 7. Return MonitorResult.
|
||||
*
|
||||
* @param {import('screeps-api').ScreepsHttpClient} api
|
||||
* @param {import('screeps-api').ScreepsAPI} api
|
||||
* @param {MonitorOptions} opts
|
||||
* @returns {Promise<MonitorResult>}
|
||||
*/
|
||||
@@ -339,9 +337,7 @@ export async function monitorConsole(api, opts) {
|
||||
let lastProgressTick = 0;
|
||||
|
||||
// Step 1: record starting tick
|
||||
const { time: startTick } = await (typeof api.gameTime === "function"
|
||||
? api.gameTime(shard)
|
||||
: api.time(shard));
|
||||
const { time: startTick } = await api.time(shard);
|
||||
|
||||
// Step 2: connect socket + subscribe
|
||||
await api.socket.connect();
|
||||
|
||||
Generated
+2326
File diff suppressed because it is too large
Load Diff
+4
-5
@@ -3,7 +3,6 @@
|
||||
"version": "0.2.1",
|
||||
"description": "Deploys screeps code to the official game or a private server.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@11.25.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
@@ -14,11 +13,11 @@
|
||||
"@actions/artifact": "^1.1.2",
|
||||
"@actions/core": "^3.0.0",
|
||||
"glob": "^13.0.0",
|
||||
"screeps-api": "^2.0.0"
|
||||
"screeps-api": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.44.1",
|
||||
"@vitest/coverage-v8": "^4.1.11",
|
||||
"vitest": "^4.1.11"
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"@vitest/coverage-v8": "^4.0.16",
|
||||
"vitest": "^4.0.16"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
-1336
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
allowBuilds:
|
||||
bufferutil: true
|
||||
utf-8-validate: true
|
||||
+15
-6
@@ -5,11 +5,20 @@
|
||||
"config:recommended",
|
||||
":automergeLinters"
|
||||
],
|
||||
"rebaseWhen": "behind-base-branch",
|
||||
"branchConcurrentLimit": 2,
|
||||
"prConcurrentLimit": 2,
|
||||
"gitIgnoredAuthors": [
|
||||
"github-actions[bot]@users.noreply.github.com",
|
||||
"bot@horstenkamp.eu"
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": [
|
||||
"npm"
|
||||
],
|
||||
"postUpgradeTasks": {
|
||||
"commands": [
|
||||
"npm ci",
|
||||
"npm run build"
|
||||
],
|
||||
"fileFilters": [
|
||||
"dist/index.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user