Compare commits

...

2 Commits

Author SHA1 Message Date
dependabot[bot]
5a56211d04 chore(deps-dev): bump the npm-development-dependencies group across 1 directory with 2 updates
Some checks are pending
Internal - Main - Continuous Integration / ci (push) Waiting to run
Internal - Main - Continuous Integration / prepare-docs (push) Blocked by required conditions
Internal - Main - Continuous Integration / sync-docs (push) Blocked by required conditions
Need fix to Issue / main (push) Waiting to run
Prepare release / release (push) Waiting to run
Bumps the npm-development-dependencies group with 2 updates in the / directory:
- [@ts-dev-tools/core](https://github.com/escemi-tech/ts-dev-tools)
- [eslint-plugin-jsonc](https://github.com/ota-meshi/eslint-plugin-jsonc)

Updates `@ts-dev-tools/core` from 1.10.0 to 1.11.1
- [Release notes](https://github.com/escemi-tech/ts-dev-tools/releases)

Updates `eslint-plugin-jsonc` from 2.21.1 to 3.1.1
- [Release notes](https://github.com/ota-meshi/eslint-plugin-jsonc/releases)
- [Changelog](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/CHANGELOG.md)

---
updated-dependencies:
- dependency-name: "@ts-dev-tools/core"
  dependency-version: 1.11.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development-dependencies
- dependency-name: eslint-plugin-jsonc
  dependency-version: 3.1.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: npm-development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
2026-03-05 11:20:58 +01:00
dependabot[bot]
65c12c82c2 chore(deps): bump the github-actions-dependencies group across 1 directory with 2 updates
Bumps the github-actions-dependencies group with 2 updates in the / directory:
- [docker/setup-docker-action](https://github.com/docker/setup-docker-action)
- [actions/upload-artifact](https://github.com/actions/upload-artifact)

Updates `docker/setup-docker-action` from 4.7.0 to 5.0.0
- [Release notes](https://github.com/docker/setup-docker-action/releases)

Updates `actions/upload-artifact` from 6.0.0 to 7.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)

---
updated-dependencies:
- dependency-name: docker/setup-docker-action
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions-dependencies
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 10:40:34 +01:00
12 changed files with 2995 additions and 4636 deletions

View File

@ -179,7 +179,7 @@ jobs:
- name: Set up Docker context - name: Set up Docker context
if: ${{ matrix.docker-context }} if: ${{ matrix.docker-context }}
uses: docker/setup-docker-action@e43656e248c0bd0647d3f5c195d116aacf6fcaf4 # v4.7.0 uses: docker/setup-docker-action@1a6edb0ba9ac496f6850236981f15d8f9a82254d # v5.0.0
with: with:
context: ${{ matrix.docker-context }} context: ${{ matrix.docker-context }}

View File

@ -74,7 +74,7 @@ jobs:
[skip ci] [skip ci]
- id: upload-artifact - id: upload-artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: documentation-files-${{ github.run_id }} name: documentation-files-${{ github.run_id }}
path: | path: |

1015
dist/index.js generated vendored

File diff suppressed because it is too large Load Diff

25
dist/licenses.txt generated vendored
View File

@ -512,6 +512,31 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
json-with-bigint
MIT
MIT License
Copyright (c) 2023 Ivan Korolenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
semver semver
ISC ISC
The ISC License The ISC License

26
dist/post.js generated vendored
View File

@ -28436,7 +28436,7 @@ function composeCollection(CN, ctx, token, props, onError) {
let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType); let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
if (!tag) { if (!tag) {
const kt = ctx.schema.knownTags[tagName]; const kt = ctx.schema.knownTags[tagName];
if (kt && kt.collection === expType) { if (kt?.collection === expType) {
ctx.schema.tags.push(Object.assign({}, kt, { default: false })); ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
tag = kt; tag = kt;
} }
@ -29315,7 +29315,7 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError, ta
}); });
if (!props.found) { if (!props.found) {
if (props.anchor || props.tag || value) { if (props.anchor || props.tag || value) {
if (value && value.type === 'block-seq') if (value?.type === 'block-seq')
onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column'); onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column');
else else
onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator'); onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator');
@ -29530,7 +29530,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
} }
} }
else if (value) { else if (value) {
if ('source' in value && value.source && value.source[0] === ':') if ('source' in value && value.source?.[0] === ':')
onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`); onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`);
else else
onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`); onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`);
@ -29574,7 +29574,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
const expectedEnd = isMap ? '}' : ']'; const expectedEnd = isMap ? '}' : ']';
const [ce, ...ee] = fc.end; const [ce, ...ee] = fc.end;
let cePos = offset; let cePos = offset;
if (ce && ce.source === expectedEnd) if (ce?.source === expectedEnd)
cePos = ce.offset + ce.source.length; cePos = ce.offset + ce.source.length;
else { else {
const name = fcName[0].toUpperCase() + fcName.substring(1); const name = fcName[0].toUpperCase() + fcName.substring(1);
@ -30943,7 +30943,7 @@ const prettifyError = (src, lc) => (error) => {
if (/[^ ]/.test(lineStr)) { if (/[^ ]/.test(lineStr)) {
let count = 1; let count = 1;
const end = error.linePos[1]; const end = error.linePos[1];
if (end && end.line === line && end.col > col) { if (end?.line === line && end.col > col) {
count = Math.max(1, Math.min(end.col - col, 80 - ci)); count = Math.max(1, Math.min(end.col - col, 80 - ci));
} }
const pointer = ' '.repeat(ci) + '^'.repeat(count); const pointer = ' '.repeat(ci) + '^'.repeat(count);
@ -31108,7 +31108,7 @@ class Alias extends Node.NodeBase {
data = anchors.get(source); data = anchors.get(source);
} }
/* istanbul ignore if */ /* istanbul ignore if */
if (!data || data.res === undefined) { if (data?.res === undefined) {
const msg = 'This should not happen: Alias anchor was not resolved?'; const msg = 'This should not happen: Alias anchor was not resolved?';
throw new ReferenceError(msg); throw new ReferenceError(msg);
} }
@ -33434,7 +33434,7 @@ class Parser {
} }
*step() { *step() {
const top = this.peek(1); const top = this.peek(1);
if (this.type === 'doc-end' && (!top || top.type !== 'doc-end')) { if (this.type === 'doc-end' && top?.type !== 'doc-end') {
while (this.stack.length > 0) while (this.stack.length > 0)
yield* this.pop(); yield* this.pop();
this.stack.push({ this.stack.push({
@ -33966,7 +33966,7 @@ class Parser {
do { do {
yield* this.pop(); yield* this.pop();
top = this.peek(1); top = this.peek(1);
} while (top && top.type === 'flow-collection'); } while (top?.type === 'flow-collection');
} }
else if (fc.end.length === 0) { else if (fc.end.length === 0) {
switch (this.type) { switch (this.type) {
@ -36124,7 +36124,7 @@ function stringifyNumber({ format, minFractionDigits, tag, value }) {
const num = typeof value === 'number' ? value : Number(value); const num = typeof value === 'number' ? value : Number(value);
if (!isFinite(num)) if (!isFinite(num))
return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf'; return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf';
let n = JSON.stringify(value); let n = Object.is(value, -0) ? '-0' : JSON.stringify(value);
if (!format && if (!format &&
minFractionDigits && minFractionDigits &&
(!tag || tag === 'tag:yaml.org,2002:float') && (!tag || tag === 'tag:yaml.org,2002:float') &&
@ -36254,7 +36254,7 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`; ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`;
} }
if (valueStr === '' && !ctx.inFlow) { if (valueStr === '' && !ctx.inFlow) {
if (ws === '\n') if (ws === '\n' && valueComment)
ws = '\n\n'; ws = '\n\n';
} }
else { else {
@ -37108,7 +37108,7 @@ const external_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.me
var external_http_ = __nccwpck_require__(8611); var external_http_ = __nccwpck_require__(8611);
// EXTERNAL MODULE: external "https" // EXTERNAL MODULE: external "https"
var external_https_ = __nccwpck_require__(5692); var external_https_ = __nccwpck_require__(5692);
;// CONCATENATED MODULE: ./node_modules/@actions/core/node_modules/@actions/http-client/lib/proxy.js ;// CONCATENATED MODULE: ./node_modules/@actions/http-client/lib/proxy.js
function getProxyUrl(reqUrl) { function getProxyUrl(reqUrl) {
const usingSsl = reqUrl.protocol === 'https:'; const usingSsl = reqUrl.protocol === 'https:';
if (checkBypass(reqUrl)) { if (checkBypass(reqUrl)) {
@ -37203,7 +37203,7 @@ class DecodedURL extends URL {
var node_modules_tunnel = __nccwpck_require__(770); var node_modules_tunnel = __nccwpck_require__(770);
// EXTERNAL MODULE: ./node_modules/undici/index.js // EXTERNAL MODULE: ./node_modules/undici/index.js
var undici = __nccwpck_require__(6752); var undici = __nccwpck_require__(6752);
;// CONCATENATED MODULE: ./node_modules/@actions/core/node_modules/@actions/http-client/lib/index.js ;// CONCATENATED MODULE: ./node_modules/@actions/http-client/lib/index.js
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@ -37900,7 +37900,7 @@ class lib_HttpClient {
} }
const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map
;// CONCATENATED MODULE: ./node_modules/@actions/core/node_modules/@actions/http-client/lib/auth.js ;// CONCATENATED MODULE: ./node_modules/@actions/http-client/lib/auth.js
var auth_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { var auth_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) { return new (P || (P = Promise))(function (resolve, reject) {

6456
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -32,10 +32,10 @@
"docker-compose": "^1.3.1" "docker-compose": "^1.3.1"
}, },
"devDependencies": { "devDependencies": {
"@ts-dev-tools/core": "^1.10.0", "@ts-dev-tools/core": "^1.11.1",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.4",
"eslint-plugin-github": "^6.0.0", "eslint-plugin-github": "^6.0.0",
"eslint-plugin-jsonc": "^2.21.1" "eslint-plugin-jsonc": "^3.1.1"
}, },
"scripts": { "scripts": {
"package": "npm run package:index && npm run package:post", "package": "npm run package:index && npm run package:post",

View File

@ -24,18 +24,25 @@ jest.unstable_mockModule("docker-compose", () => ({
})); }));
// Mock node:fs // Mock node:fs
jest.unstable_mockModule("node:fs", () => ({ jest.unstable_mockModule("node:fs", async () => {
existsSync: jest.fn().mockReturnValue(true), const actualFs = await jest.requireActual<typeof import("node:fs")>("node:fs");
default: { existsSync: jest.fn().mockReturnValue(true) },
})); return {
...actualFs,
existsSync: jest.fn().mockReturnValue(true),
default: {
...actualFs,
existsSync: jest.fn().mockReturnValue(true),
},
};
});
// Dynamic imports after mock setup // Dynamic imports after mock setup
const { run } = await import("./index-runner.js"); const { run } = await import("./index-runner.js");
const { InputService } = await import("./services/input.service.js"); const { InputService } = await import("./services/input.service.js");
const { LoggerService, LogLevel } = await import("./services/logger.service.js"); const { LoggerService, LogLevel } = await import("./services/logger.service.js");
const { DockerComposeInstallerService } = await import( const { DockerComposeInstallerService } =
"./services/docker-compose-installer.service.js" await import("./services/docker-compose-installer.service.js");
);
const { DockerComposeService } = await import("./services/docker-compose.service.js"); const { DockerComposeService } = await import("./services/docker-compose.service.js");
describe("run", () => { describe("run", () => {

View File

@ -24,17 +24,24 @@ jest.unstable_mockModule("docker-compose", () => ({
})); }));
// Mock node:fs // Mock node:fs
jest.unstable_mockModule("node:fs", () => ({ jest.unstable_mockModule("node:fs", async () => {
existsSync: jest.fn().mockReturnValue(true), const actualFs = await jest.requireActual<typeof import("node:fs")>("node:fs");
default: { existsSync: jest.fn().mockReturnValue(true) },
})); return {
...actualFs,
existsSync: jest.fn().mockReturnValue(true),
default: {
...actualFs,
existsSync: jest.fn().mockReturnValue(true),
},
};
});
// Dynamic imports after mock setup // Dynamic imports after mock setup
const { InputService } = await import("./services/input.service.js"); const { InputService } = await import("./services/input.service.js");
const { LoggerService, LogLevel } = await import("./services/logger.service.js"); const { LoggerService, LogLevel } = await import("./services/logger.service.js");
const { DockerComposeInstallerService } = await import( const { DockerComposeInstallerService } =
"./services/docker-compose-installer.service.js" await import("./services/docker-compose-installer.service.js");
);
const { DockerComposeService } = await import("./services/docker-compose.service.js"); const { DockerComposeService } = await import("./services/docker-compose.service.js");
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>; let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;

View File

@ -80,6 +80,23 @@ describe("DockerComposeInstallerService", () => {
}); });
describe("install", () => { describe("install", () => {
it("should install latest when compose version is not specified and Compose is missing", async () => {
// Arrange: first call to version() fails (Compose missing)
versionMock.mockRejectedValueOnce(new Error("version not installed"));
const latestVersion = "v2.0.0";
mockLatestRelease(latestVersion);
versionMock.mockResolvedValueOnce(composeVersionResponse(latestVersion));
setPlatform("linux");
// Act
const result = await installCompose(null, "token");
// Assert
expect(result).toBe(latestVersion);
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(latestVersion);
});
it("should return current version when no version is provided", async () => { it("should return current version when no version is provided", async () => {
// Arrange // Arrange
versionMock.mockResolvedValue(composeVersionResponse("2.0.0")); versionMock.mockResolvedValue(composeVersionResponse("2.0.0"));
@ -236,5 +253,20 @@ describe("DockerComposeInstallerService", () => {
); );
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(targetVersion); expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(targetVersion);
}); });
it("should throw with unknown installed version when post-install version check fails", async () => {
// Arrange
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
const targetVersion = "v1.4.0";
versionMock.mockRejectedValueOnce(new Error("version check failed after install"));
setPlatform("linux");
// Act & Assert
await expect(installCompose(targetVersion, "token")).rejects.toThrow(
`Failed to install Docker Compose version "${targetVersion}", installed version is "unknown"`
);
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(targetVersion);
});
}); });
}); });

View File

@ -1,5 +1,9 @@
import { jest, describe, it, expect, beforeEach } from "@jest/globals"; import { jest, describe, it, expect, beforeEach } from "@jest/globals";
import type { IDockerComposeOptions, IDockerComposeResult } from "docker-compose"; import type {
IDockerComposeLogOptions,
IDockerComposeOptions,
IDockerComposeResult,
} from "docker-compose";
// Mock docker-compose before importing the module under test // Mock docker-compose before importing the module under test
const upAllMock = jest.fn<(options: IDockerComposeOptions) => Promise<IDockerComposeResult>>(); const upAllMock = jest.fn<(options: IDockerComposeOptions) => Promise<IDockerComposeResult>>();
@ -7,7 +11,9 @@ const upManyMock =
jest.fn<(services: string[], options: IDockerComposeOptions) => Promise<IDockerComposeResult>>(); jest.fn<(services: string[], options: IDockerComposeOptions) => Promise<IDockerComposeResult>>();
const downMock = jest.fn<(options: IDockerComposeOptions) => Promise<IDockerComposeResult>>(); const downMock = jest.fn<(options: IDockerComposeOptions) => Promise<IDockerComposeResult>>();
const logsMock = const logsMock =
jest.fn<(services: string[], options: IDockerComposeOptions) => Promise<IDockerComposeResult>>(); jest.fn<
(services: string[], options: IDockerComposeLogOptions) => Promise<IDockerComposeResult>
>();
jest.unstable_mockModule("docker-compose", () => ({ jest.unstable_mockModule("docker-compose", () => ({
upAll: upAllMock, upAll: upAllMock,

View File

@ -1,5 +1,6 @@
import { jest, describe, it, expect, beforeEach } from "@jest/globals"; import { jest, describe, it, expect, beforeEach } from "@jest/globals";
import type { ExecOptions } from "@actions/exec"; import type { ExecOptions } from "@actions/exec";
import type { OutgoingHttpHeaders } from "node:http";
// Mock @actions/exec // Mock @actions/exec
const execMock = const execMock =
@ -17,8 +18,20 @@ jest.unstable_mockModule("@actions/io", () => ({
})); }));
// Mock @actions/tool-cache // Mock @actions/tool-cache
const cacheFileMock = jest.fn<() => Promise<string>>(); const cacheFileMock =
const downloadToolMock = jest.fn<() => Promise<string>>(); jest.fn<
(
sourceFile: string,
targetFile: string,
tool: string,
version: string,
arch?: string
) => Promise<string>
>();
const downloadToolMock =
jest.fn<
(url: string, dest?: string, auth?: string, headers?: OutgoingHttpHeaders) => Promise<string>
>();
jest.unstable_mockModule("@actions/tool-cache", () => ({ jest.unstable_mockModule("@actions/tool-cache", () => ({
cacheFile: cacheFileMock, cacheFile: cacheFileMock,