13 Commits

Author SHA1 Message Date
83d2d712f0 build(deps-dev): bump rollup from 4.18.0 to 4.22.4
Bumps [rollup](https://github.com/rollup/rollup) from 4.18.0 to 4.22.4.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.18.0...v4.22.4)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-24 01:23:54 +00:00
965531f332 build(deps-dev): bump vite from 5.2.12 to 5.4.6 (#131)
* build(deps-dev): bump vite from 5.2.12 to 5.4.6

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.12 to 5.4.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* pnpm i

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cole Helbling <cole.helbling@determinate.systems>
2024-09-19 16:42:07 +00:00
a2bbe0274e Merge pull request #128 from detsys-pr-bot/detsys-ts-update-65dd73c562ac60a068340f8e0c040bdcf2c59afe
Update `detsys-ts`: Merge pull request #63 from DeterminateSystems/retry-streams
2024-09-04 14:14:50 -04:00
802501548e Update detsys-ts for: Merge pull request #63 from DeterminateSystems/retry-streams (65dd73c562ac60a068340f8e0c040bdcf2c59afe) 2024-09-04 18:05:28 +00:00
7d80c329b4 Merge pull request #126 from detsys-pr-bot/detsys-ts-update-817e4d4123b6fb4eae5aa557658f25f8539e7240
Update `detsys-ts`: Merge pull request #62 from DeterminateSystems/dont-pull-microstackshots
2024-08-26 19:46:57 -04:00
7bc6ec59cc Update detsys-ts for: Merge pull request #62 from DeterminateSystems/dont-pull-microstackshots (817e4d4123b6fb4eae5aa557658f25f8539e7240) 2024-08-26 15:26:03 +00:00
4cf6b19203 Merge pull request #125 from detsys-pr-bot/detsys-ts-update-e8f6e8f54d85aa0fd3d0b694dd3279a21497a33b
Update `detsys-ts`: Merge pull request #61 from DeterminateSystems/use-coalesce-for-array
2024-08-26 10:09:12 -04:00
73ba0ca899 Update detsys-ts for: Merge pull request #61 from DeterminateSystems/use-coalesce-for-array (e8f6e8f54d85aa0fd3d0b694dd3279a21497a33b) 2024-08-26 14:05:27 +00:00
24f53daa86 Merge pull request #124 from detsys-pr-bot/detsys-ts-update-cf1897a891edc164a8240f469cd56d14364e6be1
Update `detsys-ts`: Merge pull request #58 from DeterminateSystems/collect-crash-logs
2024-08-26 09:41:53 -04:00
420fb2aaf7 Update detsys-ts for: Merge pull request #58 from DeterminateSystems/collect-crash-logs (cf1897a891edc164a8240f469cd56d14364e6be1) 2024-08-26 13:31:25 +00:00
db4ee38117 Fixup support for Nix 2.23.0 and later 2024-06-28 14:11:30 -07:00
b0723e0fae Add instructions for new fine grained GitHub PAT 2024-06-18 09:23:51 -07:00
af9a980c7d Lock third-party actions
A caller of this action can lock this action to a specific commit. However because the action itself does not lock its dependent actions to a specific commit this opens the end-user up to possible supply-chain attacks if the dependent actions rewrite their tags.

This PR changes all third party actions to be explicitly locked.

Dependabot will still work and update these hashes for you


I also suggest installing https://github.com/ossf/scorecard in this repo. It will report about these kind of issues.

Note that you should in turn have to audit all the third party deps of the actions that your action depends on. In general this is all a bit of a mess and GitHub's security model is very meh

e.g. see https://github.com/ossf/scorecard/issues/2189
2024-06-18 09:17:15 -07:00
11 changed files with 3240 additions and 11420 deletions

View File

@ -138,23 +138,6 @@ jobs:
path-to-flake-dir: 'nix/' # in this example our flake doesn't sit at the root of the repository, it sits under 'nix/flake.nix'
```
You can also run the update operation in multiple directories, provided that each directory is a valid flake:
```yaml
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@vX
with:
flake-dirs: |
flake1
flake2
flake3
```
> **Warning**: If you choose multiple directories, `update-flake-lock` can only update all flake inputs,
> meaning that you can't set the `inputs` parameter. This is due to limitations in input handling in
> GitHub Actions, which only allows for strings, numbers, Booleans, and arrays but not objects, which
> would be the much preferred data type for expressing per-directory inputs.
## Example using a different Git user
If you want to change the author and / or committer of the flake.lock update commit, you can tweak the `git-{author,committer}-{name,email}` options:
@ -202,7 +185,7 @@ git push origin update_flake_lock_action --force
### With a Personal Authentication Token
By providing a Personal Authentication Token, the PR will be submitted in a way that bypasses this limitation (GitHub will essentially think it is the owner of the PAT submitting the PR, and not an Action).
You can create a token by visiting https://github.com/settings/tokens and select at least the `repo` scope. Then, store this token in your repository secrets (i.e. `https://github.com/<USER>/<REPO>/settings/secrets/actions`) as `GH_TOKEN_FOR_UPDATES` and set up your workflow file like the following:
You can create a token by visiting https://github.com/settings/tokens and select at least the `repo` scope. For the new fine-grained tokens, you need to enable read and write access for "Contents" and "Pull Requests" permissions. Then, store this token in your repository secrets (i.e. `https://github.com/<USER>/<REPO>/settings/secrets/actions`) as `GH_TOKEN_FOR_UPDATES` and set up your workflow file like the following:
```yaml
name: update-flake-lock

View File

@ -9,21 +9,10 @@ inputs:
description: "GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)"
required: false
default: ${{ github.token }}
commit-msg-template:
description: |
The commit message template to use. You can use these variables in your template:
* `{{ flake_dot_lock }}` is the path to the `flake.lock` file being updated
* `{{ flake_dot_lock_dir }}` is the `flake.lock` file's directory
If you set both this and `commit-msg`, the `commit-msg` setting is used (it does not support templating).
required: false
default: |
flake.lock: Updated in {{ flake_dot_lock_dir }}
commit-msg:
description: |
The message provided with the commit.
description: "The message provided with the commit"
required: false
default: "flake.lock: Update"
base:
description: "Sets the pull request base branch. Defaults to the branch checked out in the workflow."
required: false
@ -32,32 +21,12 @@ inputs:
required: false
default: "update_flake_lock_action"
path-to-flake-dir:
description: |
The path of the directory containing `flake.nix` file within your repository.
Useful when `flake.nix` cannot reside at the root of your repository.
description: "The path of the directory containing `flake.nix` file within your repository. Useful when `flake.nix` cannot reside at the root of your repository."
required: false
flake-dirs:
description: |
A space-separated list of directories containing `flake.nix` files within your repository.
Useful when you have multiple flakes in your repository.
required: false
default: ""
pr-title:
description: "The title of the PR to be created"
required: false
default: "flake.lock: Update"
pr-body-template:
description: |
The pull request body template to use. You can use these variables in your template:
* `{{ comma_separated_dirs }}` is the flake directories that were updated separated by comma
* `{{ space_separated_dirs }}` is the flake directories that were updated separated by space
* `{{ updated_dirs_list }}` is the flake directories that were updated as a Markdown list
If you set both this and `pr-body`, the `pr-body` setting is used (it does not support templating).
required: false
default: |
Just testing.
pr-body:
description: "The body of the PR to be created"
required: false
@ -146,7 +115,7 @@ runs:
- name: Import bot's GPG key for signing commits
if: ${{ inputs.sign-commits == 'true' }}
id: import-gpg
uses: crazy-max/ghaction-import-gpg@v6
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
with:
gpg_private_key: ${{ inputs.gpg-private-key }}
fingerprint: ${{ inputs.gpg-fingerprint }}
@ -177,7 +146,6 @@ runs:
echo "GIT_COMMITTER_NAME=${{ inputs.git-committer-name }}" >> $GITHUB_ENV
echo "GIT_COMMITTER_EMAIL=<${{ inputs.git-committer-email }}>" >> $GITHUB_ENV
- name: Run update-flake-lock
id: update-flake-lock
shell: bash
run: node "$GITHUB_ACTION_PATH/dist/index.js"
env:
@ -186,7 +154,6 @@ runs:
INPUT_BASE: ${{ inputs.base }}
INPUT_BRANCH: ${{ inputs.branch }}
INPUT_COMMIT-MSG: ${{ inputs.commit-msg }}
INPUT_COMMIT-MSG-TEMPLATE: ${{ inputs.commit-msg-template }}
INPUT_GIT-AUTHOR-EMAIL: ${{ inputs.git-author-email }}
INPUT_GIT-AUTHOR-NAME: ${{ inputs.git-author-name }}
INPUT_GIT-COMMITTER-EMAIL: ${{ inputs.git-committer-email }}
@ -197,10 +164,8 @@ runs:
INPUT_INPUTS: ${{ inputs.inputs }}
INPUT_NIX-OPTIONS: ${{ inputs.nix-options }}
INPUT_PATH-TO-FLAKE-DIR: ${{ inputs.path-to-flake-dir }}
INPUT_FLAKE-DIRS: ${{ inputs.flake-dirs }}
INPUT_PR-ASSIGNEES: ${{ inputs.pr-assignees }}
INPUT_PR-BODY: ${{ inputs.pr-body }}
INPUT_PR-BODY-TEMPLATE: ${{ inputs.pr-body-template }}
INPUT_PR-LABELS: ${{ inputs.pr-labels }}
INPUT_PR-REVIEWERS: ${{ inputs.pr-reviewers }}
INPUT_PR-TITLE: ${{ inputs.pr-title }}
@ -213,7 +178,7 @@ runs:
uses: DamianReeves/write-file-action@v1.3
with:
path: pr_body.template
contents: ${{ steps.update-flake-lock.outputs.pr-body }}
contents: ${{ inputs.pr-body }}
env: {}
- name: Set additional env variables (GIT_COMMIT_MESSAGE)
shell: bash
@ -225,7 +190,7 @@ runs:
echo "$DELIMITER" >> $GITHUB_ENV
echo "GIT_COMMIT_MESSAGE is: ${COMMIT_MESSAGE}"
- name: Interpolate PR Body
uses: pedrolamas/handlebars-action@v2.4.0
uses: pedrolamas/handlebars-action@2995d7eadacbc8f2f6ab8431a01d84a5fa3b8bb4 # v2.4.0
with:
files: "pr_body.template"
output-filename: "pr_body.txt"
@ -242,7 +207,7 @@ runs:
run: rm -f pr_body.txt pr_body.template
- name: Create PR
id: create-pr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
with:
base: ${{ inputs.base }}
branch: ${{ inputs.branch }}

8649
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,6 @@
"lint": "eslint src/**/*.ts --ignore-pattern *.test.ts",
"package": "ncc build",
"test": "vitest --watch false",
"test-dev": "vitest",
"all": "pnpm run format && pnpm run lint && pnpm run build && pnpm run package"
},
"repository": {
@ -29,8 +28,7 @@
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"detsys-ts": "github:DeterminateSystems/detsys-ts",
"handlebars": "^4.7.8"
"detsys-ts": "github:DeterminateSystems/detsys-ts"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",

5589
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,15 @@
import { makeNixCommandArgs } from "./nix.js";
import { renderCommitMessage, renderPullRequestBody } from "./template.js";
import * as actionsCore from "@actions/core";
import * as actionsExec from "@actions/exec";
import { DetSysAction, inputs } from "detsys-ts";
import * as fs from "fs";
const DEFAULT_FLAKE_DIR = ".";
const PR_BODY_OUTPUT_KEY = "pr-body";
const EVENT_EXECUTION_FAILURE = "execution_failure";
class UpdateFlakeLockAction extends DetSysAction {
private commitMessage: string;
private commitMessageTemplate: string;
private prBody: string;
private prBodyTemplate: string;
private nixOptions: string[];
private flakeInputs: string[];
private pathToFlakeDir: string | null;
private flakeDirsInput: string[] | null;
private flakeDirs: string[];
constructor() {
super({
@ -30,55 +19,19 @@ class UpdateFlakeLockAction extends DetSysAction {
});
this.commitMessage = inputs.getString("commit-msg");
this.commitMessageTemplate = inputs.getString("commit-msg-template");
this.prBody = inputs.getString("pr-body");
this.prBodyTemplate = inputs.getString("pr-body-template");
this.flakeInputs = inputs.getArrayOfStrings("inputs", "space");
this.nixOptions = inputs.getArrayOfStrings("nix-options", "space");
this.pathToFlakeDir = inputs.getStringOrNull("path-to-flake-dir");
this.flakeDirsInput = inputs.getArrayOfStringsOrNull("flake-dirs", "space");
this.validateInputs();
if (this.flakeDirsInput !== null && this.flakeDirsInput.length > 0) {
this.flakeDirs = this.flakeDirsInput;
} else {
this.flakeDirs = [this.pathToFlakeDir ?? DEFAULT_FLAKE_DIR];
}
}
async main(): Promise<void> {
for (const directory of this.flakeDirs) {
await this.updateFlakeInDirectory(directory);
}
const prBody =
this.prBody !== ""
? this.prBody
: renderPullRequestBody(this.prBodyTemplate, this.flakeDirs);
actionsCore.setOutput(PR_BODY_OUTPUT_KEY, prBody);
await this.update();
}
// No post phase
async post(): Promise<void> {}
private async updateFlakeInDirectory(flakeDir: string): Promise<void> {
this.ensureDirectoryExists(flakeDir);
this.ensureDirectoryIsFlake(flakeDir);
actionsCore.debug(`Running flake lock update in directory \`${flakeDir}\``);
const flakeDotLock = `${flakeDir}/flake.lock`;
const commitMessage =
this.commitMessage !== ""
? this.commitMessage
: renderCommitMessage(
this.commitMessageTemplate,
flakeDir,
flakeDotLock,
);
async update(): Promise<void> {
// Nix command of this form:
// nix ${maybe nix options} flake ${"update" or "lock"} ${maybe --update-input flags} --commit-lock-file --commit-lockfile-summary ${commit message}
// Example commands:
@ -87,12 +40,11 @@ class UpdateFlakeLockAction extends DetSysAction {
const nixCommandArgs: string[] = makeNixCommandArgs(
this.nixOptions,
this.flakeInputs,
commitMessage,
this.commitMessage,
);
actionsCore.debug(
JSON.stringify({
directory: flakeDir,
options: this.nixOptions,
inputs: this.flakeInputs,
message: this.commitMessage,
@ -101,7 +53,7 @@ class UpdateFlakeLockAction extends DetSysAction {
);
const execOptions: actionsExec.ExecOptions = {
cwd: flakeDir,
cwd: this.pathToFlakeDir !== null ? this.pathToFlakeDir : undefined,
};
const exitCode = await actionsExec.exec("nix", nixCommandArgs, execOptions);
@ -110,69 +62,9 @@ class UpdateFlakeLockAction extends DetSysAction {
this.recordEvent(EVENT_EXECUTION_FAILURE, {
exitCode,
});
actionsCore.setFailed(
`non-zero exit code of ${exitCode} detected while updating directory \`${flakeDir}\``,
);
actionsCore.setFailed(`non-zero exit code of ${exitCode} detected`);
} else {
actionsCore.info(
`flake.lock file in \`${flakeDir}\` was successfully updated`,
);
}
}
private validateInputs(): void {
// Ensure that either `path-to-flake-dir` or `flake-dirs` is set to a meaningful value but not both
if (
this.flakeDirsInput !== null &&
this.flakeDirsInput.length > 0 &&
this.pathToFlakeDir !== null &&
this.pathToFlakeDir !== ""
) {
throw new Error(
"Both `path-to-flake-dir` and `flake-dirs` are set, whereas only one can be",
);
}
// Ensure that `flake-dirs` isn't an empty array if set
if (this.flakeDirsInput !== null && this.flakeDirsInput.length === 0) {
throw new Error(
"The `flake-dirs` input is set to an empty array; it must contain at least one directory",
);
}
// Ensure that both `flake-dirs` and `inputs` aren't set at the same time
if (
this.flakeDirsInput !== null &&
this.flakeDirsInput.length > 0 &&
this.flakeInputs.length > 0
) {
throw new Error(
`You've set both \`flake-dirs\` and \`inputs\` but you can only set one`,
);
}
}
private ensureDirectoryExists(flakeDir: string): void {
actionsCore.debug(`Checking that flake directory \`${flakeDir}\` exists`);
// Ensure the directory exists
fs.access(flakeDir, fs.constants.F_OK, (err) => {
if (err !== null) {
throw new Error(`Directory \`${flakeDir}\` doesn't exist`);
} else {
actionsCore.debug(`Flake directory \`${flakeDir}\` exists`);
}
});
}
private ensureDirectoryIsFlake(flakeDir: string): void {
const flakeDotNix = `${flakeDir}/flake.nix`;
if (!fs.existsSync(flakeDotNix)) {
throw new Error(
`Directory \`${flakeDir}\` is not a valid flake as it doesn't contain a \`flake.nix\``,
);
} else {
actionsCore.debug(`Directory \`${flakeDir}\` is a valid flake`);
actionsCore.info(`flake.lock file was successfully updated`);
}
}
}

View File

@ -1,16 +1,16 @@
import { makeNixCommandArgs } from "./nix.js";
import { expect, test } from "vitest";
test("Nix command arguments", () => {
type TestCase = {
type TestCase = {
inputs: {
nixOptions: string[];
flakeInputs: string[];
commitMessage: string;
};
expected: string[];
};
};
test("Nix command arguments", () => {
const testCases: TestCase[] = [
{
inputs: {
@ -24,7 +24,8 @@ test("Nix command arguments", () => {
"flake",
"update",
"--commit-lock-file",
"--commit-lockfile-summary",
"--option",
"commit-lockfile-summary",
"just testing",
],
},
@ -42,7 +43,8 @@ test("Nix command arguments", () => {
"--update-input",
"rust-overlay",
"--commit-lock-file",
"--commit-lockfile-summary",
"--option",
"commit-lockfile-summary",
"just testing",
],
},
@ -57,7 +59,8 @@ test("Nix command arguments", () => {
"flake",
"update",
"--commit-lock-file",
"--commit-lockfile-summary",
"--option",
"commit-lockfile-summary",
"just testing",
],
},

View File

@ -9,10 +9,23 @@ export function makeNixCommandArgs(
input,
]);
// NOTE(cole-h): In Nix versions 2.23.0 and later, `commit-lockfile-summary` became an alias to
// the setting `commit-lock-file-summary` (https://github.com/NixOS/nix/pull/10691), and Nix does
// not treat aliases the same as their "real" setting by requiring setting aliases to be
// configured via `--option <alias name> <option value>`
// (https://github.com/NixOS/nix/issues/10989).
// So, we go the long way so that we can support versions both before and after Nix 2.23.0.
const lockfileSummaryFlags = [
"--option",
"commit-lockfile-summary",
commitMessage,
];
const updateLockMechanism = flakeInputFlags.length === 0 ? "update" : "lock";
return nixOptions
.concat(["flake", updateLockMechanism])
.concat(flakeInputFlags)
.concat(["--commit-lock-file", "--commit-lockfile-summary", commitMessage]);
.concat(["--commit-lock-file"])
.concat(lockfileSummaryFlags);
}

View File

@ -1,75 +0,0 @@
import { renderCommitMessage, renderPullRequestBody } from "./template.js";
import { template } from "handlebars";
import { Test, describe, expect, test } from "vitest";
describe("templating", () => {
test("commit message", () => {
type TestCase = {
template: string;
flakeDotLockDir: string;
flakeDotLock: string;
expected: string;
};
const testCases: TestCase[] = [
{
template: "Updating flake.lock in dir {{ flake_dot_lock_dir }}",
flakeDotLockDir: ".",
flakeDotLock: "./flake.lock",
expected: "Updating flake.lock in dir .",
},
{
template:
"Here I go doing some updating of my pristine flake.lock at {{ flake_dot_lock }}",
flakeDotLockDir: "subflake",
flakeDotLock: "subflake/flake.lock",
expected:
"Here I go doing some updating of my pristine flake.lock at subflake/flake.lock",
},
{
template: "This variable doesn't exist: {{ foo }}",
flakeDotLockDir: ".",
flakeDotLock: "./flake.lock",
expected: "This variable doesn't exist: ",
},
];
testCases.forEach(
({ template, flakeDotLockDir, flakeDotLock, expected }) => {
expect(
renderCommitMessage(template, flakeDotLockDir, flakeDotLock),
).toEqual(expected);
},
);
});
test("pull request body", () => {
type TestCase = {
template: string;
dirs: string[];
expected: string;
};
const testCases: TestCase[] = [
{
template: "Updated inputs: {{ comma_separated_dirs }}",
dirs: ["."],
expected: "Updated inputs: .",
},
{
template: "Updated inputs: {{ space_separated_dirs }}",
dirs: ["subflake", "subflake2"],
expected: "Updated inputs: subflake subflake2",
},
{
template: "Updated inputs:\n{{ updated_dirs_list }}",
dirs: ["flake1", "flake2"],
expected: `Updated inputs:\n* flake1\n* flake2`,
},
];
testCases.forEach(({ template, dirs, expected }) => {
expect(renderPullRequestBody(template, dirs)).toEqual(expected);
});
});
});

View File

@ -1,39 +0,0 @@
import Handlebars from "handlebars";
export function renderPullRequestBody(
template: string,
dirs: string[],
): string {
const commaSeparated = dirs.join(", ");
const spaceSeparated = dirs.join(" ");
const dirsList = dirs.map((d: string) => `* ${d}`).join("\n");
const tpl = Handlebars.compile(template);
return tpl({
// eslint-disable-next-line camelcase
comma_separated_dirs: commaSeparated,
// eslint-disable-next-line camelcase
space_separated_dirs: spaceSeparated,
// eslint-disable-next-line camelcase
updated_dirs_list: dirsList,
});
}
export function renderCommitMessage(
template: string,
flakeDotLockDir: string,
flakeDotLock: string,
): string {
return render(template, {
// eslint-disable-next-line camelcase
flake_dot_lock_dir: flakeDotLockDir,
// eslint-disable-next-line camelcase
flake_dot_lock: flakeDotLock,
});
}
function render(template: string, inputs: Record<string, string>): string {
const tpl = Handlebars.compile(template);
return tpl(inputs);
}