Skip to content

Actions: start accepting a config as input#1991

Merged
dscho merged 9 commits intomainfrom
vars-CONFIG
Mar 4, 2026
Merged

Actions: start accepting a config as input#1991
dscho merged 9 commits intomainfrom
vars-CONFIG

Conversation

@dscho
Copy link
Copy Markdown
Member

@dscho dscho commented Sep 1, 2025

GitGitGadget's GitHub Actions all implicitly use the defaultConfig that hard-codes the configuration of the OG GitGitGadget that supports the Git project (and the Git project only).

However, for a long time there have been feature requests and musings towards using GitGitGadget also for other projects.

GitGitGadget already does have some beginnings of a support for other projects, e.g. the IConfig interface. With these changes, that interface gets extended a little, a validator is added that can verify whether or not an arbitrary object conforms to that interface, and then new inputs are introduced, accepting this (JSON-encoded) configuration as a user-provided string. The idea is that a project-specific fork of https://github.com/gitgitgadget/gitgitgadget-workflows/ contains this configuration in the gitgitgadget-config.json file in a dedicated config branch, from where it is synchronized via a GitHub workflow to the repository variable called CONFIG.

This somewhat non-trivial setup allows the config to be conveniently tracked via Git, updated via Pull Requests, validated via GitHub workflows, and still to be used in a trivial manner in the main workflows via ${{ vars.CONFIG }} (as opposed to having to play games with multi-branch checkouts or curl'ing a file from a different branch).

This PR is step number 2 in that direction. Step number 1 was to register the cygwingitgadget GitHub org for experimenting with GitGitGadget support for a different mailing-list-based project than Git: Cygwin.

That org is where I experimented with this change as well as with all the others leading up to gitgitgadget/gitgitgadget-github-app#7.

This PR is stacked on top of #1993 and #1994

@dscho dscho requested a review from webstech September 1, 2025 16:58
@dscho dscho self-assigned this Sep 1, 2025
export interface IRepoConfig {
name: string; // name of the repo
owner: string; // owner of repo holding the notes (tracking data)
baseOwner: string; // owner of upstream ("base") repo
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webstech since I started referring to the corresponding repository as upstream-repo, what would you think about the idea to rename this from baseOwner to upstreamOwner?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no issue with renaming. My choice in names may not always be as git oriented as they could be.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, I am going forward with this: dscho@2de5309

owner: string; // owner of repo holding the notes (tracking data)
baseOwner: string; // owner of upstream ("base") repo
testOwner?: string; // owner of the test repo (if any)
owners: string[]; // owners of clones being monitored (PR checking)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webstech what do you think about the idea to move this attribute to IAppConfig and to rename it to installedOn? That way, the repo still can have an upstreamOwner on whose repository, however, GitGitGadget is not installed...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used several times in CIHelper so the location could be justified. On the other hand, move it if you like.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the in-development patch to do so: dscho@9c2e794.

@dscho
Copy link
Copy Markdown
Member Author

dscho commented Sep 2, 2025

Note to self: check whether default: ${{ vars.CONFIG }} works, and would avoid the need for the explicit config: ${{ vars.CONFIG }} lines added in gitgitgadget/gitgitgadget-workflows@2952485.

@webstech
Copy link
Copy Markdown
Contributor

webstech commented Sep 4, 2025

An aside while I was looking at this, I noticed CIHelper.parsePRURLInput() could be using getPullRequestKeyFromURL.

dscho added a commit to cygwingitgadget/gitgitgadget-workflows that referenced this pull request Sep 8, 2025
In gitgitgadget/gitgitgadget#1991, I adjusted
and augmented the `IConfig` interface a bit. Concretely, I renamed
`repo.baseOwner` to `repo.upstreamOwner` in 2de5309e (IConfig: rename
the attribute defining the `upstream-repo`'s org, 2025-09-08) and moved
`repo.owners` to `app.installedOn` in 9c2e7944 (IConfig: move
`repo.owners` to a better place, 2025-09-08).

Let's adjust to that new schema.

Note: the `baseOwner` and `owners` attributes are left as-are, for the
transitional period until that PR and its friends are merged.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Sep 9, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Copy Markdown
Member Author

dscho commented Sep 10, 2025

An aside while I was looking at this, I noticed CIHelper.parsePRURLInput() could be using getPullRequestKeyFromURL.

True! I have implemented that (still need to clean up the branch thicket, it needed fixes): dscho@8b3badb

Note to self: check whether default: ${{ vars.CONFIG }} works, and would avoid the need for the explicit config: ${{ vars.CONFIG }} lines added in gitgitgadget/gitgitgadget-workflows@2952485.

Okay, this does not work:

image
as text
Error: /home/runner/work/gitgitgadget/gitgitgadget/./check-run/action.yml (Line: 7, Col: 14): Unrecognized named-value: 'vars'. Located at position 1 within expression: vars.CONFIG
Error: Failed to load /home/runner/work/gitgitgadget/gitgitgadget/./check-run/action.yml

Sadness!

Even more sad is the excuse of a documentation of inputs.<input_id>.default which does not even mention that some contexts can be used, as some smarter people found out. But of course nothing official, because why would anyone want to know what they can use, and what not?</s>

dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 3, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 6, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 6, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 6, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to cygwingitgadget/gitgitgadget-workflows that referenced this pull request Oct 6, 2025
In gitgitgadget/gitgitgadget#1991, I adjusted
and augmented the `IConfig` interface a bit. Concretely, I renamed
`repo.baseOwner` to `repo.upstreamOwner` in c374c542 (IConfig: rename
the attribute defining the `upstream-repo`'s org, 2025-09-08) and moved
`repo.owners` to `app.installedOn` in 907807fb (IConfig: move
`repo.owners` to a better place, 2025-09-08).

Let's adjust to that new schema.

Note: the `baseOwner` and `owners` attributes are left as-are, for the
transitional period until that PR and its friends are merged.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 6, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 7, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho marked this pull request as ready for review October 7, 2025 06:35
@dscho dscho requested a review from mjcheetham October 7, 2025 06:35
@dscho
Copy link
Copy Markdown
Member Author

dscho commented Oct 7, 2025

@webstech would you kindly have a look?

@dscho dscho enabled auto-merge October 7, 2025 06:37
dscho added a commit to dscho/gitgitgadget that referenced this pull request Oct 7, 2025
There was prior art that I should have used, as pointed out in
gitgitgadget#1991 (comment)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@webstech
Copy link
Copy Markdown
Contributor

The commit message npx typia setup is misleading without explaining the change is instead of using it.

Review is done.

dscho added a commit that referenced this pull request Feb 22, 2026
The `todo` branch is completely divergent from Git's `master` branch,
and as such contains different files. Yet it still belongs to the Git
project...

This is needed to fix the `Unrecognized project` error in https://
github.com/git/git/pull/2209

The underlying logic was correct until c72d162 (project-options: handle
shallow worktrees gracefully, 2024-01-01) broke it; This change was
needed to allow migrating from running on a self-hosted Azure Pipelines
runner to running on hosted GitHub Actions runners, but the logic was
incomplete and would no longer reliably detect whether GitGitGadget is
running in a PR that targets the Git project.

Another fix would have been to move forward with the `vars.CONFIG` idea
championed in #1991.
However, my attention was directed away from that effort for a long time
now, and it won't be _so_ easy to push that over the finish line. Let's
unblock the contributor first.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit that referenced this pull request Feb 22, 2026
The `todo` branch is completely divergent from Git's `master` branch,
and as such contains different files. Yet it still belongs to the Git
project...

This is needed to fix the `Unrecognized project` error in https://
github.com/git/git/pull/2209

The underlying logic was correct until c72d162 (project-options: handle
shallow worktrees gracefully, 2024-01-01) broke it; This change was
needed to allow migrating from running on a self-hosted Azure Pipelines
runner to running on hosted GitHub Actions runners, but the logic was
incomplete and would no longer reliably detect whether GitGitGadget is
running in a PR that targets the Git project.

Another fix would have been to move forward with the `vars.CONFIG` idea
championed in #1991.
However, my attention was directed away from that effort for a long time
now, and it won't be _so_ easy to push that over the finish line. Let's
unblock the contributor first.
In my endeavor to support projects other than Git, I am currently
adapting GitGitGadget to allow sending Cygwin PRs to the Cygwin-patches
mailing list.

I identified a couple of gaps in the project configuration when setting
up stuff in https://github.com/cygwingitgadget.

Let's close those gaps.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
We've settled on the nomenclature `upstream-repo` to refer to the
original repository of the project, as opposed to the `pr-repo` which is
a fork that exists exclusively to let GitGitGadget handle PRs in (and to
store its global state in the Git notes). So let's call the owner of the
`upstream-repo` the `upstreamOwner`, not the `baseOwner`.

Besides, with GitHub's naming conventions referring to the branch a PR
targets as the "base", it is a bit confusing to have `baseOwner` to
refer to anything except the owner of the repository in which the PR
lives.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `owners` array refers to a list of orgs/owners where the GitHub App
is installed, i.e. where GitGitGadget can operate.

Therefore, a much better place is `app.installedOn`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The idea is to configure GitGitGadget via a `gitgitgadget-config.json`
file that contains the project-specific instance of the `IConfig`
interface, tracked in the `config` branch of a fork of the
`gitgitgadget-workflows` repository, from where it is automatically
synchronized via a GitHub workflow to the repository variable `CONFIG`,
and then passed to all of GitGitGadget's Actions via:

	```yml
	config: '${{ vars.CONFIG }}'
	```

For now, this input is optional, to ease the transition of GitGitGadget;
Eventually, this config will be required, so that several projects can
be served using identical source code in forks of the
`gitgitgadget-github-app` and `gitgitgadget-workflows` repositories.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the vars-CONFIG branch 2 times, most recently from 4f91d43 to 5b1166f Compare February 28, 2026 16:49
@dscho
Copy link
Copy Markdown
Member Author

dscho commented Feb 28, 2026

Sorry for the delay. I essentially ran into a large problem and then failed to find the time to fix it until yesterday. The result of this investigation can be found here: #2157

Now I finally implemented the promised changes, rebased onto main, and force-pushed.

Range-diff relative to previously-reviewed branch
  • 1: 62fce79 = 1: 78c6c3c Extend the IConfig interface as needed for 3rd-party projects

  • 2: 23c6d23 ! 2: 1bad447 IConfig: rename the attribute defining the upstream-repo's org

    @@ lib/project-config.ts: export async function getExternalConfig(file: string): Pr
     -    if (!newConfig.repo.baseOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) {
     -        throw new Error(`Invalid 'baseOwner' ${newConfig.repo.baseOwner} in ${filePath}`);
     +    if (!newConfig.repo.upstreamOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) {
    -+        throw new Error(`Invalid 'baseOwner' ${newConfig.repo.upstreamOwner} in ${filePath}`);
    ++        throw new Error(`Invalid 'upstreamOwner' ${newConfig.repo.upstreamOwner} in ${filePath}`);
          }
      
          return newConfig;
  • 3: 9890596 = 3: 3e65c68 IConfig: move repo.owners to a better place

  • 4: 211dbb2 = 4: 0971b1a Actions: accept the config input

  • 5: 24a0e2a ! 5: 2f03696 Install typia

    @@ Commit message
         Let's install `typia` to use the `IConfig` interface as a source of
         truth when validating the user input.
     
    +    In a slight variation of what is recommended at https://typia.io/docs/
    +    setup/, I ran:
    +
    +      npm install --save-dev typia
    +      npx typia setup
    +
    +    Then, I undid the damage done to `tsconfig.json` ;-) (`npx typia setup`
    +    edited that file and wanted to add just a plugin, but changed plenty of
    +    white-space, getting utterly confused by the commented-out lines.)
    +
    +    Finally, to fix running the tests via `ts-jest`, I needed to force
    +    it to use `ts-patch`, which unfortunately runs into problems because
    +    of 281204bf (fix: set isolatedModules true for ts-jest, 2025-11-05),
    +    because the `ts-patch` transformation is only triggered with
    +    `isolatedModules: false`:
    +
    +      "compiler": "ts-patch/compiler",
    +      "tsconfig": {
    +        "isolatedModules": false
    +      },
    +
    +    Sadly, this spits out the warning "ts-jest[config] (WARN) message
    +    TS151002: Using hybrid module kind (Node16/18/Next) is only
    +    supported in "isolatedModules: true". Please set "isolatedModules:
    +    true" in your tsconfig.json. To disable this message, you can set
    +    "diagnostics.ignoreCodes" to include 151002 in your ts-jest config.
    +    See more at https://kulshekhar.github.io/ts-jest/docs/getting-started/
    +    options/diagnostics". We abide by that suggestion:
    +
    +      "diagnostics": {
    +        "ignoreCodes": [151002]
    +      },
    +
    +    Assisted-by: Claude Opus 4.6
         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
     
      ## package-lock.json ##
     @@
    +         "ts-jest": "^29.4.6",
              "ts-jest-resolver": "^2.0.1",
              "ts-node": "^10.9.2",
    -         "typescript": "^5.9.3",
    --        "typescript-eslint": "8.46.0"
    -+        "typescript-eslint": "8.46.0",
    -+        "typia": "^9.7.2"
    +-        "typescript": "^5.9.3",
    +-        "typescript-eslint": "8.56.1"
    ++        "ts-patch": "^3.3.0",
    ++        "typescript": "~5.9.3",
    ++        "typescript-eslint": "8.56.1",
    ++        "typia": "^11.0.3"
            },
            "engines": {
              "node": ">= 18.16.1"
    +@@
    +       "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@ampproject/remapping": "^2.2.0",
    +         "@babel/code-frame": "^7.27.1",
     @@
              "url": "https://github.com/sponsors/nzakas"
            }
          },
     +    "node_modules/@inquirer/external-editor": {
    -+      "version": "1.0.1",
    -+      "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz",
    -+      "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==",
    ++      "version": "1.0.3",
    ++      "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
    ++      "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
     +      "dev": true,
     +      "license": "MIT",
     +      "dependencies": {
    -+        "chardet": "^2.1.0",
    -+        "iconv-lite": "^0.6.3"
    ++        "chardet": "^2.1.1",
    ++        "iconv-lite": "^0.7.0"
     +      },
     +      "engines": {
     +        "node": ">=18"
    @@ package-lock.json
     +          "optional": true
     +        }
     +      }
    ++    },
    ++    "node_modules/@inquirer/external-editor/node_modules/iconv-lite": {
    ++      "version": "0.7.2",
    ++      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
    ++      "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
    ++      "dev": true,
    ++      "license": "MIT",
    ++      "dependencies": {
    ++        "safer-buffer": ">= 2.1.2 < 3.0.0"
    ++      },
    ++      "engines": {
    ++        "node": ">=0.10.0"
    ++      },
    ++      "funding": {
    ++        "type": "opencollective",
    ++        "url": "https://opencollective.com/express"
    ++      }
     +    },
          "node_modules/@isaacs/cliui": {
            "version": "8.0.2",
            "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
    +@@
    +       "version": "29.6.3",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@jest/schemas": "^29.6.3",
    +         "@types/istanbul-lib-coverage": "^2.0.0",
    +@@
    +       "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz",
    +       "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==",
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@octokit/auth-token": "^6.0.0",
    +         "@octokit/graphql": "^9.0.3",
     @@
              "url": "https://opencollective.com/pkgr"
            }
          },
     +    "node_modules/@samchon/openapi": {
    -+      "version": "4.7.1",
    -+      "resolved": "https://registry.npmjs.org/@samchon/openapi/-/openapi-4.7.1.tgz",
    -+      "integrity": "sha512-+rkMlSKMt7l3KGWJVWUle1CXEm0vA8FIF2rufHl+T1gN/gGrTEhL1gDK3FHYf8Nl5XReK0r1vL6Q2QTMwQN7xQ==",
    ++      "version": "6.0.1",
    ++      "resolved": "https://registry.npmjs.org/@samchon/openapi/-/openapi-6.0.1.tgz",
    ++      "integrity": "sha512-+nkznmCf/6YavoVkvWg60YoC0UbXY/oK9uMZReyrFcIcXecf+YoWmOLUg+TlgHi+h+6DPgRy6zRkZfiRd3uRnA==",
     +      "dev": true,
     +      "license": "MIT"
     +    },
    @@ package-lock.json
            "version": "0.11.0",
            "license": "MIT",
     @@
    -         "node": ">=18.0.0"
    +         "@sinonjs/commons": "^3.0.1"
            }
          },
     +    "node_modules/@standard-schema/spec": {
    -+      "version": "1.0.0",
    -+      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
    -+      "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
    ++      "version": "1.1.0",
    ++      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
    ++      "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
     +      "dev": true,
     +      "license": "MIT"
     +    },
          "node_modules/@stylistic/eslint-plugin": {
    -       "version": "5.4.0",
    -       "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.4.0.tgz",
    +       "version": "5.9.0",
    +       "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.9.0.tgz",
    +@@
    +       "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "undici-types": "~7.18.0"
    +       }
    +@@
    +       "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@eslint-community/regexpp": "^4.12.2",
    +         "@typescript-eslint/scope-manager": "8.56.1",
    +@@
    +       "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@typescript-eslint/scope-manager": "8.56.1",
    +         "@typescript-eslint/types": "8.56.1",
    +@@
    +       "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "bin": {
    +         "acorn": "bin/acorn"
    +       },
     @@
            "dev": true,
            "license": "Python-2.0"
    @@ package-lock.json
     +      "dev": true,
     +      "license": "MIT"
     +    },
    -     "node_modules/babel-jest": {
    -       "version": "30.2.0",
    -       "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz",
    +     "node_modules/b4a": {
    +       "version": "1.7.3",
    +       "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz",
     @@
    -         "node": ">=0.12.0"
    +         }
            }
          },
     +    "node_modules/base64-js": {
    @@ package-lock.json
     +        "readable-stream": "^3.4.0"
     +      }
     +    },
    -     "node_modules/bowser": {
    -       "version": "2.12.0",
    -       "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.0.tgz",
    +     "node_modules/brace-expansion": {
    +       "version": "1.1.12",
    +       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
    +@@
    +         }
    +       ],
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "caniuse-lite": "^1.0.30001726",
    +         "electron-to-chromium": "^1.5.173",
     @@
              "node-int64": "^0.4.0"
            }
    @@ package-lock.json
     +    },
          "node_modules/buffer-equal-constant-time": {
            "version": "1.0.1",
    -       "license": "BSD-3-Clause"
    +       "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
     @@
              "node": ">=10"
            }
          },
     +    "node_modules/chardet": {
    -+      "version": "2.1.0",
    -+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
    -+      "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==",
    ++      "version": "2.1.1",
    ++      "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
    ++      "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
     +      "dev": true,
     +      "license": "MIT"
     +    },
    -     "node_modules/chownr": {
    -       "version": "2.0.0",
    -       "license": "ISC",
    +     "node_modules/ci-info": {
    +       "version": "3.8.0",
    +       "dev": true,
     @@
            "dev": true,
            "license": "MIT"
    @@ package-lock.json
            }
          },
     +    "node_modules/comment-json": {
    -+      "version": "4.2.5",
    -+      "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz",
    -+      "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==",
    ++      "version": "4.5.1",
    ++      "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.5.1.tgz",
    ++      "integrity": "sha512-taEtr3ozUmOB7it68Jll7s0Pwm+aoiHyXKrEC8SEodL4rNpdfDLqa7PfBlrgFoCNNdR8ImL+muti5IGvktJAAg==",
     +      "dev": true,
     +      "license": "MIT",
     +      "dependencies": {
     +        "array-timsort": "^1.0.3",
     +        "core-util-is": "^1.0.3",
    -+        "esprima": "^4.0.1",
    -+        "has-own-prop": "^2.0.0",
    -+        "repeat-string": "^1.6.1"
    ++        "esprima": "^4.0.1"
     +      },
     +      "engines": {
     +        "node": ">= 6"
     +      }
     +    },
          "node_modules/comment-parser": {
    -       "version": "1.4.1",
    -       "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
    +       "version": "1.4.5",
    +       "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.5.tgz",
     @@
            "dev": true,
            "license": "MIT"
    @@ package-lock.json
     +      }
     +    },
          "node_modules/dugite": {
    -       "version": "2.7.1",
    -       "resolved": "https://registry.npmjs.org/dugite/-/dugite-2.7.1.tgz",
    +       "version": "3.2.0",
    +       "resolved": "https://registry.npmjs.org/dugite/-/dugite-3.2.0.tgz",
    +@@
    +       "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@eslint-community/eslint-utils": "^4.8.0",
    +         "@eslint-community/regexpp": "^4.12.1",
    +@@
    +       "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "bin": {
    +         "eslint-config-prettier": "bin/cli.js"
    +       },
     @@
              "bser": "2.1.1"
            }
    @@ package-lock.json
            "version": "8.0.0",
            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
     @@
    -         "node": ">=8"
    +         "node": ">=16 || 14 >=14.17"
            }
          },
    -+    "node_modules/has-own-prop": {
    -+      "version": "2.0.0",
    -+      "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz",
    -+      "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==",
    ++    "node_modules/global-prefix": {
    ++      "version": "4.0.0",
    ++      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz",
    ++      "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==",
     +      "dev": true,
     +      "license": "MIT",
    ++      "dependencies": {
    ++        "ini": "^4.1.3",
    ++        "kind-of": "^6.0.3",
    ++        "which": "^4.0.0"
    ++      },
     +      "engines": {
    -+        "node": ">=8"
    ++        "node": ">=16"
    ++      }
    ++    },
    ++    "node_modules/global-prefix/node_modules/isexe": {
    ++      "version": "3.1.5",
    ++      "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz",
    ++      "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==",
    ++      "dev": true,
    ++      "license": "BlueOak-1.0.0",
    ++      "engines": {
    ++        "node": ">=18"
    ++      }
    ++    },
    ++    "node_modules/global-prefix/node_modules/which": {
    ++      "version": "4.0.0",
    ++      "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
    ++      "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
    ++      "dev": true,
    ++      "license": "ISC",
    ++      "dependencies": {
    ++        "isexe": "^3.1.1"
    ++      },
    ++      "bin": {
    ++        "node-which": "bin/which.js"
    ++      },
    ++      "engines": {
    ++        "node": "^16.13.0 || >=18.0.0"
     +      }
     +    },
    -     "node_modules/has-property-descriptors": {
    -       "version": "1.0.2",
    -       "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
    +     "node_modules/globals": {
    +       "version": "14.0.0",
    +       "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
     @@
              "node": ">=0.10.0"
            }
    @@ package-lock.json
            "dev": true,
            "license": "ISC"
          },
    ++    "node_modules/ini": {
    ++      "version": "4.1.3",
    ++      "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
    ++      "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
    ++      "dev": true,
    ++      "license": "ISC",
    ++      "engines": {
    ++        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
    ++      }
    ++    },
     +    "node_modules/inquirer": {
     +      "version": "8.2.7",
     +      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz",
    @@ package-lock.json
          "node_modules/isarray": {
            "version": "2.0.5",
            "license": "MIT"
    +@@
    +       "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@jest/core": "30.2.0",
    +         "@jest/types": "30.2.0",
    +@@
    +       "version": "29.7.0",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "chalk": "^4.0.0",
    +         "graceful-fs": "^4.2.9",
    +@@
    +       "version": "29.7.0",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@jest/types": "^29.6.3",
    +         "@types/node": "*",
    +@@
    +         "json-buffer": "3.0.1"
    +       }
    +     },
    ++    "node_modules/kind-of": {
    ++      "version": "6.0.3",
    ++      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
    ++      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
    ++      "dev": true,
    ++      "license": "MIT",
    ++      "engines": {
    ++        "node": ">=0.10.0"
    ++      }
    ++    },
    +     "node_modules/leac": {
    +       "version": "0.6.0",
    +       "license": "MIT",
     @@
              "url": "https://github.com/sponsors/sindresorhus"
            }
          },
     +    "node_modules/lodash": {
    -+      "version": "4.17.21",
    -+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
    -+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
    ++      "version": "4.17.23",
    ++      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
    ++      "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
     +      "dev": true,
     +      "license": "MIT"
     +    },
    @@ package-lock.json
     +      ],
     +      "license": "MIT"
     +    },
    -     "node_modules/queue-microtask": {
    -       "version": "1.2.3",
    -       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
    -@@
    -       ],
    -       "license": "MIT"
    -     },
     +    "node_modules/randexp": {
     +      "version": "0.5.3",
     +      "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz",
    @@ package-lock.json
          "node_modules/regexp-tree": {
            "version": "0.1.27",
            "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
    -@@
    -         "regexp-tree": "bin/regexp-tree"
    -       }
    -     },
    -+    "node_modules/repeat-string": {
    -+      "version": "1.6.1",
    -+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
    -+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
    -+      "dev": true,
    -+      "license": "MIT",
    -+      "engines": {
    -+        "node": ">=0.10"
    -+      }
    -+    },
    -     "node_modules/require-directory": {
    -       "version": "2.1.1",
    -       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
     @@
              "node": ">=10"
            }
    @@ package-lock.json
     +        "node": ">=4"
     +      }
     +    },
    -     "node_modules/reusify": {
    -       "version": "1.1.0",
    -       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
    +     "node_modules/rfc2047": {
    +       "version": "4.0.1",
    +       "license": "BSD-3-Clause",
     @@
              "node": ">=0.8.0"
            }
    @@ package-lock.json
     +        "node": ">=0.12.0"
     +      }
     +    },
    -     "node_modules/run-parallel": {
    -       "version": "1.2.0",
    -       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
    -@@
    -         "queue-microtask": "^1.2.2"
    -       }
    -     },
     +    "node_modules/rxjs": {
     +      "version": "7.8.2",
     +      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
    @@ package-lock.json
            "version": "5.2.1",
            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
     @@
    -         "node": ">=8"
    +         "text-decoder": "^1.1.0"
            }
          },
     +    "node_modules/string_decoder": {
    @@ package-lock.json
            "version": "4.0.2",
            "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
     @@
    -         "node": ">= 18.16.1"
    +         "b4a": "^1.6.4"
            }
          },
     +    "node_modules/through": {
    @@ package-lock.json
     +      "dev": true,
     +      "license": "MIT"
     +    },
    -     "node_modules/tlds": {
    -       "version": "1.259.0",
    -       "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz",
    +     "node_modules/tinyglobby": {
    +       "version": "0.2.15",
    +       "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
    +@@
    +       "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "engines": {
    +         "node": ">=12"
    +       },
    +@@
    +       "version": "10.9.2",
    +       "dev": true,
    +       "license": "MIT",
    ++      "peer": true,
    +       "dependencies": {
    +         "@cspotcode/source-map-support": "^0.8.0",
    +         "@tsconfig/node10": "^1.0.7",
    +@@
    +         }
    +       }
    +     },
    ++    "node_modules/ts-patch": {
    ++      "version": "3.3.0",
    ++      "resolved": "https://registry.npmjs.org/ts-patch/-/ts-patch-3.3.0.tgz",
    ++      "integrity": "sha512-zAOzDnd5qsfEnjd9IGy1IRuvA7ygyyxxdxesbhMdutt8AHFjD8Vw8hU2rMF89HX1BKRWFYqKHrO8Q6lw0NeUZg==",
    ++      "dev": true,
    ++      "license": "MIT",
    ++      "dependencies": {
    ++        "chalk": "^4.1.2",
    ++        "global-prefix": "^4.0.0",
    ++        "minimist": "^1.2.8",
    ++        "resolve": "^1.22.2",
    ++        "semver": "^7.6.3",
    ++        "strip-ansi": "^6.0.1"
    ++      },
    ++      "bin": {
    ++        "ts-patch": "bin/ts-patch.js",
    ++        "tspc": "bin/tspc.js"
    ++      }
    ++    },
    +     "node_modules/tslib": {
    +       "version": "2.8.1",
    +       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
    +       "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
    +       "dev": true,
    +-      "license": "0BSD",
    +-      "optional": true
    ++      "license": "0BSD"
    +     },
    +     "node_modules/tunnel": {
    +       "version": "0.0.6",
    +@@
    +       "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
    +       "dev": true,
    +       "license": "Apache-2.0",
    ++      "peer": true,
    +       "bin": {
    +         "tsc": "bin/tsc",
    +         "tsserver": "bin/tsserver"
     @@
              "typescript": ">=4.8.4 <6.0.0"
            }
          },
     +    "node_modules/typia": {
    -+      "version": "9.7.2",
    -+      "resolved": "https://registry.npmjs.org/typia/-/typia-9.7.2.tgz",
    -+      "integrity": "sha512-eLIKd0KHZtSvbsA+FYwX+Y0ZBt0BwVGz3GgODQX+6GfGL4DOzKW02LEx62oUZg6vCQX1BL5xyiPXAIdW+Hc51g==",
    ++      "version": "11.0.3",
    ++      "resolved": "https://registry.npmjs.org/typia/-/typia-11.0.3.tgz",
    ++      "integrity": "sha512-L7x7WzOCpFyNCauWl6VYJVEG9EHZi5EPNBRzxTO1luaLCd6WEDf+xrJNT+hMZ8U+0X7hCsR1EUpi29LdHhvCvA==",
     +      "dev": true,
     +      "license": "MIT",
     +      "dependencies": {
    -+        "@samchon/openapi": "^4.7.1",
    ++        "@samchon/openapi": "^6.0.0",
     +        "@standard-schema/spec": "^1.0.0",
     +        "commander": "^10.0.0",
     +        "comment-json": "^4.2.3",
    @@ package-lock.json
     
      ## package.json ##
     @@
    +     "test:clean": "jest --clearCache && npm test",
    +     "test:config": "npm run test -- --testRegex=/tests-config/.*\.test\.ts",
    +     "test:watch": "jest --watch --notify --notifyMode=change --coverage",
    +-    "ci": "npm run lint && npm run test -- --ci --reporters=default --reporters=jest-junit"
    ++    "ci": "npm run lint && npm run test -- --ci --reporters=default --reporters=jest-junit",
    ++    "prepare": "ts-patch install"
    +   },
    +   "bugs": {
    +     "url": "https://github.com/gitgitgadget/gitgitgadget/issues"
    +@@
    +       "\.(ts|tsx)$": [
    +         "ts-jest",
    +         {
    ++          "compiler": "ts-patch/compiler",
    ++          "diagnostics": {
    ++            "ignoreCodes": [151002]
    ++          },
    ++          "tsconfig": {
    ++            "isolatedModules": false
    ++          },
    +           "useESM": true
    +         }
    +       ]
    +@@
    +     "ts-jest": "^29.4.6",
          "ts-jest-resolver": "^2.0.1",
          "ts-node": "^10.9.2",
    -     "typescript": "^5.9.3",
    --    "typescript-eslint": "8.46.0"
    -+    "typescript-eslint": "8.46.0",
    -+    "typia": "^9.7.2"
    +-    "typescript": "^5.9.3",
    +-    "typescript-eslint": "8.56.1"
    ++    "ts-patch": "^3.3.0",
    ++    "typescript": "~5.9.3",
    ++    "typescript-eslint": "8.56.1",
    ++    "typia": "^11.0.3"
        },
        "dependencies": {
    -     "@actions/core": "^1.11.1",
    +     "@actions/core": "^3.0.0",
    +
    + ## tsconfig.json ##
    +@@
    +     "types": [ "node" ],                      /* Type declaration files to be included in compilation. */
    +     // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    +     "esModuleInterop": true,                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    +-    "forceConsistentCasingInFileNames": true
    ++    "forceConsistentCasingInFileNames": true,
    +     // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    + 
    +     /* Source Map Options */
    +@@
    +     /* Experimental Options */
    +     // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    +     // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
    ++    "plugins": [
    ++      {
    ++        "transform": "typia/lib/transform"
    ++      }
    ++    ],
    ++    "skipLibCheck": true,
    ++    "strictNullChecks": true
    +   },
    +   "include": [
    +     "lib/**/*.ts",
  • 6: 255ece3 < -: -------- npx typia setup

  • 7: a603513 = 6: 8fc2f19 CIHelper: validate the user-provided config Action input

  • 8: e68da6a ! 7: 5f0808f IConfig: avoid "anonymous types"

    @@ lib/project-config.ts: export type projectInfo = {
     +    mirrorRef?: string;
     +    descriptiveName: string;
     +}
    ++
     +export interface IMailConfig {
     +    author: string;
     +    sender: string;
  • 9: d25eafa ! 8: 8988c67 Include the LintCommit configuration in IConfig

    @@ Commit message
         This way, the maximal number of columns can be configured freely per
         project, via the project-specific config.
     
    +    To reduce friction for on-boarding new projects by not having to look
    +    in multiple locations when creating a config file, the definition of the
    +    `ILintCommitConfig` interface is moved to `project-config.ts`, where all
    +    the other project-specific interfaces live already.
    +
         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
     
      ## lib/ci-helper.ts ##
    @@ lib/ci-helper.ts: export class CIHelper {
      
     
      ## lib/commit-lint.ts ##
    -@@ lib/commit-lint.ts: export interface ILintError {
    +@@
    + import { IPRCommit } from "./github-glue.js";
    ++import { ILintCommitConfig } from "./project-config.js";
    + 
    + export interface ILintError {
    +     checkFailed: boolean; // true if check failed
          message: string;
      }
      
     -export interface ILintOptions {
    -+export interface ILintCommitConfig {
    -     maxColumns?: number | undefined; // max line length
    - }
    - 
    +-    maxColumns?: number | undefined; // max line length
    +-}
    +-
    + /*
    +  * Simple single use class to drive lint tests on commit messages.
    +  */
     @@ lib/commit-lint.ts: export class LintCommit {
          private messages: string[] = [];
          private maxColumns = 76;
    @@ lib/commit-lint.ts: export class LintCommit {
              this.patch = patch;
     
      ## lib/project-config.ts ##
    -@@
    - import * as fs from "fs";
    - import path from "path";
    -+import { ILintCommitConfig } from "./commit-lint.js";
    - 
    - export type projectInfo = {
    -     to: string; // email to send patches to
     @@ lib/project-config.ts: export interface IAppConfig {
    +     altname: string | undefined; // is this even needed?
    + }
    + 
    ++export interface ILintCommitConfig {
    ++    maxColumns?: number | undefined; // max line length
    ++}
    ++
      export interface ILintConfig {
          maxCommitsIgnore?: string[]; // array of pull request urls to skip check
          maxCommits: number; // limit on number of commits in a pull request
    @@ tests/commit-lint.test.ts
     @@
      import { expect, jest, test } from "@jest/globals";
     -import { ILintError, ILintOptions, LintCommit } from "../lib/commit-lint.js";
    -+import { ILintError, ILintCommitConfig, LintCommit } from "../lib/commit-lint.js";
    ++import { ILintError, LintCommit } from "../lib/commit-lint.js";
      import { IPRCommit } from "../lib/github-glue.js";
    ++import { ILintCommitConfig } from "../lib/project-config.js";
      
      jest.setTimeout(180000);
    + 
     @@ tests/commit-lint.test.ts: jest.setTimeout(180000);
       * @param check a function to verify the lint result
       * @param options extra linter options, if any
  • 10: 07b2da3 = 9: 5b1166f /submit: use correct URL in the "Submitted as" message

A lot of churn in package-lock.json, to be sure ☹️ But it's needed by typia and was done automatically.

package.json Outdated
"typescript": "^5.9.3",
"typescript-eslint": "8.56.1"
"ts-patch": "^3.3.0",
"typescript": "~5.9.3",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intend to switch to this more restrictive updating?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, that was Typia's setup... Let me undo it, and hope that it does not break anything in the future (read: that Typia requires tighter coupling to Typescript versions). If it breaks, we will find out soon enough.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest force-push.

dscho added 5 commits March 4, 2026 09:14
GitGitGadget now accepts the project configuration as a `config` Action
input, in the form of a string that contains the JSON-encoded `IConfig`
object. That is a bit fragile, though, as it is all-too-easy to have a
typo in that object.

Let's install `typia` to use the `IConfig` interface as a source of
truth when validating the user input.

In a slight variation of what is recommended at https://typia.io/docs/
setup/, I ran:

  npm install --save-dev typia
  npx typia setup

Then, I undid the damage done to `tsconfig.json` ;-) (`npx typia setup`
edited that file and wanted to add just a plugin, but changed plenty of
white-space, getting utterly confused by the commented-out lines.)

Finally, to fix running the tests via `ts-jest`, I needed to force
it to use `ts-patch`, which unfortunately runs into problems because
of 281204b (fix: set isolatedModules true for ts-jest, 2025-11-05),
because the `ts-patch` transformation is only triggered with
`isolatedModules: false`:

  "compiler": "ts-patch/compiler",
  "tsconfig": {
    "isolatedModules": false
  },

Sadly, this spits out the warning "ts-jest[config] (WARN) message
TS151002: Using hybrid module kind (Node16/18/Next) is only
supported in "isolatedModules: true". Please set "isolatedModules:
true" in your tsconfig.json. To disable this message, you can set
"diagnostics.ignoreCodes" to include 151002 in your ts-jest config.
See more at https://kulshekhar.github.io/ts-jest/docs/getting-started/
options/diagnostics". We abide by that suggestion:

  "diagnostics": {
    "ignoreCodes": [151002]
  },

Note that `npx typia setup` also switched the version coupling from

  "typescript": "^5.9.3"

to

  "typescript": "~5.9.3"

but we do not want that, so I undid that change in `package.json` and
`package-lock.json` manually.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This uses the freshly-installed `typia` module to create a validator for
the `IConfig` interface at compile-time, and uses it to validate
user-provided JSON against that interface.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
For the `typia`-based validator, it is good to label each and every
attribute's type so that the error messages are helpful.

This commit is best viewed with `--ignore-space-change`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This way, the maximal number of columns can be configured freely per
project, via the project-specific config.

To reduce friction for on-boarding new projects by not having to look
in multiple locations when creating a config file, the definition of the
`ILintCommitConfig` interface is moved to `project-config.ts`, where all
the other project-specific interfaces live already.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Currently this URL is constructed from the `host` and the `name`
attributes of the project config setting's `mailrepo` attribute.

However, the `name` is supposed to refer to the mailing list _mirror
repository_, while we are interested in the URL where the web UI of the
public-inbox instance lives. Luckily, we already have that in the
project configuration: It's the `url` attribute.

I noticed the need for this patch in
cygwingitgadget/cygwin#1, where the URL
displayed after submitting v1 pointed to an incorrect location.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Copy Markdown
Member Author

dscho commented Mar 4, 2026

Range-diff
  • 1: 2f03696 ! 1: c160f9a Install typia

    @@ Commit message
             "ignoreCodes": [151002]
           },
     
    +    Note that `npx typia setup` also switched the version coupling from
    +
    +      "typescript": "^5.9.3"
    +
    +    to
    +
    +      "typescript": "~5.9.3"
    +
    +    but we do not want that, so I undid that change in `package.json` and
    +    `package-lock.json` manually.
    +
         Assisted-by: Claude Opus 4.6
         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
     
    @@ package-lock.json
              "ts-jest": "^29.4.6",
              "ts-jest-resolver": "^2.0.1",
              "ts-node": "^10.9.2",
    --        "typescript": "^5.9.3",
    --        "typescript-eslint": "8.56.1"
     +        "ts-patch": "^3.3.0",
    -+        "typescript": "~5.9.3",
    +         "typescript": "^5.9.3",
    +-        "typescript-eslint": "8.56.1"
     +        "typescript-eslint": "8.56.1",
     +        "typia": "^11.0.3"
            },
    @@ package.json
          "ts-jest": "^29.4.6",
          "ts-jest-resolver": "^2.0.1",
          "ts-node": "^10.9.2",
    --    "typescript": "^5.9.3",
    --    "typescript-eslint": "8.56.1"
     +    "ts-patch": "^3.3.0",
    -+    "typescript": "~5.9.3",
    +     "typescript": "^5.9.3",
    +-    "typescript-eslint": "8.56.1"
     +    "typescript-eslint": "8.56.1",
     +    "typia": "^11.0.3"
        },
  • 2: 8fc2f19 = 2: f0bfeab CIHelper: validate the user-provided config Action input

  • 3: 5f0808f = 3: fe54a84 IConfig: avoid "anonymous types"

  • 4: 8988c67 = 4: 8d7955a Include the LintCommit configuration in IConfig

  • 5: 5b1166f = 5: 27ff7c6 /submit: use correct URL in the "Submitted as" message

Copy link
Copy Markdown
Contributor

@webstech webstech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

@dscho dscho merged commit dc2bd7d into main Mar 4, 2026
6 checks passed
@dscho dscho deleted the vars-CONFIG branch March 4, 2026 18:56
github-actions bot pushed a commit that referenced this pull request Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants