Compare commits

...

27 Commits
v0.1.0 ... main

Author SHA1 Message Date
22c2bb1406 Make build 2024-06-16 21:26:31 -06:00
8e8ff90bd6 Use full path when accessing attic 2024-06-16 20:52:16 -06:00
Paul Zinselmeyer
5619ef4781
feat: skip installation of attic when installed (#21) 2024-05-25 08:29:36 +00:00
dependabot[bot]
37f74ba5fa
chore(deps): bump pnpm/action-setup from 2 to 3 (#19)
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 2 to 3.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v2...v3)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 03:37:47 -04:00
dependabot[bot]
6cfb1137df
chore(deps): bump DeterminateSystems/nix-installer-action from 7 to 9 (#15)
Bumps [DeterminateSystems/nix-installer-action](https://github.com/determinatesystems/nix-installer-action) from 7 to 9.
- [Release notes](https://github.com/determinatesystems/nix-installer-action/releases)
- [Commits](https://github.com/determinatesystems/nix-installer-action/compare/v7...v9)

---
updated-dependencies:
- dependency-name: DeterminateSystems/nix-installer-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 03:37:03 -04:00
Ryan
f75ac4b827
fix: support nix >= 2.19 (#18)
* fix: TypeError when pushing

* fix: compatibility with Nix 2.18
2024-01-07 22:00:22 +00:00
seth
6689ac7697
push: don't report failure on error (#16) 2023-12-14 11:12:23 +00:00
dependabot[bot]
4698511c85
chore(deps): bump DeterminateSystems/nix-installer-action from 5 to 7 (#13)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 14:21:59 +00:00
seth
7f0e30fedd
chore: misc cleanups for flake and ci (#12) 2023-11-08 14:21:46 +00:00
Ryan Cao
40fa276ac0
chore: use Node v20 for nvm/fnm 2023-10-25 23:20:59 +08:00
dependabot[bot]
fae7bd1d97
chore(deps): bump actions/setup-node from 3 to 4 (#11)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-24 03:41:22 +00:00
dependabot[bot]
aa6bedf232
chore(deps): bump DeterminateSystems/nix-installer-action from 4 to 5 (#9) 2023-10-10 07:19:24 +08:00
Ryan Cao
6870271f1d
feat!: node18 2023-09-15 15:37:51 +08:00
Ryan Cao
ce977ffab4
fix: various fixes 2023-09-15 00:12:36 +08:00
Daniel Kempkens
8c01d0bda1
feat: automatically configure Nix to use cache (#8) 2023-09-14 16:09:33 +00:00
dependabot[bot]
88dbb4b600
chore(deps): bump actions/checkout from 3 to 4 (#6)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-10 04:24:06 +00:00
dependabot[bot]
fd02e7c96c
chore(deps): bump cachix/install-nix-action from 22 to 23 (#7) 2023-09-05 11:04:12 +08:00
gallexme
56ba67dfc0
fix: save store paths to file (#5)
closes #4
2023-08-06 02:32:52 +00:00
Ryan Cao
e78c87fc0e
fix: split up added paths to avoid argument limit 2023-08-04 20:40:01 +08:00
Ryan Cao
7af24dd783
chore: update flake lock 2023-07-21 21:42:33 +08:00
Ryan Cao
3c5e4de9b2
docs: improve README 2023-07-21 16:11:50 +08:00
Ryan Cao
a2f0acb9d4
chore: add dependabot 2023-07-21 16:07:27 +08:00
seth
ec939ca6ac
chore: don't use channels for testing (#3) 2023-07-21 03:38:26 +00:00
Ryan Cao
3b6f7992de
ci: manually add nixpkgs 2023-07-20 17:50:37 +08:00
Ryan Cao
2533b28a8f
add README 2023-07-20 09:09:48 +08:00
Ryan Cao
00f4a8b31e
improve action.yml 2023-07-20 09:08:36 +08:00
Ryan Cao
ce803b732a
fix: use node import behavior 2023-07-19 12:24:57 +08:00
17 changed files with 179 additions and 110 deletions

7
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -4,20 +4,21 @@ on:
release: release:
types: [published, edited] types: [published, edited]
permissions:
contents: write
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v4
with: with:
ref: ${{ github.event.release.tag_name }} ref: ${{ github.event.release.tag_name }}
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
cache-dependency-path: pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml

View File

@ -16,10 +16,10 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
cache-dependency-path: pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
@ -28,7 +28,7 @@ jobs:
run: pnpm install && pnpm build run: pnpm install && pnpm build
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v22 uses: DeterminateSystems/nix-installer-action@v9
- name: Setup Attic Cache - name: Setup Attic Cache
uses: ./ uses: ./
@ -38,4 +38,4 @@ jobs:
token: ${{ secrets.ATTIC_TOKEN }} token: ${{ secrets.ATTIC_TOKEN }}
- name: Build Nix Package - name: Build Nix Package
run: nix build -f test.nix run: nix-build test.nix

View File

@ -1 +1 @@
16 20

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# attic-action
Cache Nix derivations with [Attic](https://github.com/zhaofengli/attic).
## Usage
Configure your attic instance with an endpoint, a cache, and a token that can read from and write to the cache. Then, add this step to a workflow job after Nix is installed:
```yaml
- name: Setup Attic cache
uses: ryanccn/attic-action@v0
with:
endpoint: ${{ secrets.ATTIC_ENDPOINT }}
cache: ${{ secrets.ATTIC_CACHE }}
token: ${{ secrets.ATTIC_TOKEN }}
```
## Inputs
### `endpoint`
The Attic endpoint. This is the URL without the cache name.
### `cache`
The name of the Attic cache.
### `token`
The authorization token to provide to Attic (**optional**).
### `skip-push`
Disable pushing new derivations to the cache automatically at the end of the job (**default is false**).
This requires you to invoke `attic push <cache>` with the paths you want to push to the cache manually.
## Outputs
None
## License
MIT

View File

@ -1,22 +1,29 @@
name: "attic" name: "attic-action"
author: "Ryan Cao"
description: "Cache Nix derivations with attic" description: "Cache Nix derivations with attic"
branding:
icon: "layers"
color: "blue"
inputs: inputs:
endpoint: endpoint:
description: "attic endpoint" description: "Attic endpoint"
required: true required: true
cache: cache:
description: "attic cache" description: "Attic cache name"
required: true required: true
skip-push: skip-push:
description: "set to true to disable pushing to the cache" description: "Disable pushing to the cache automatically"
required: false required: false
token: token:
description: "attic token" description: "Attic authorization token"
required: false
skip-use:
description: "Set to true to skip using attic cache as a substituter"
required: false required: false
runs: runs:
using: "node16" using: "node20"
main: "dist/index.js" main: "dist/index.js"
post: "dist/index.js" post: "dist/index.js"
post-if: "success()"

8
dist/index.js vendored Normal file

File diff suppressed because one or more lines are too long

6
flake.lock generated
View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1689534811, "lastModified": 1689850295,
"narHash": "sha256-jnSUdzD/414d94plCyNlvTJJtiTogTep6t7ZgIKIHiE=", "narHash": "sha256-fUYf6WdQlhd2H+3aR8jST5dhFH1d0eE22aes8fNIfyk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "6cee3b5893090b0f5f0a06b4cf42ca4e60e5d222", "rev": "5df4d78d54f7a34e9ea1f84a22b4fd9baebc68d0",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -1,36 +1,30 @@
{ {
description = ""; description = "Github Action for caching Nix derivations with attic";
inputs = { inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable"; nixpkgs.url = "nixpkgs/nixos-unstable";
}; };
outputs = outputs = {nixpkgs, ...}: let
{ nixpkgs systems = [
, ... "x86_64-linux"
}: "aarch64-linux"
let "x86_64-darwin"
mkSystems = sys: builtins.map (arch: "${arch}-${sys}") [ "x86_64" "aarch64" ]; "aarch64-darwin"
systems = ];
mkSystems "linux"
++ mkSystems "darwin";
forAllSystems = nixpkgs.lib.genAttrs systems; forAllSystems = fn: nixpkgs.lib.genAttrs systems (system: fn nixpkgs.legacyPackages.${system});
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); in {
devShells = forAllSystems (pkgs: {
forEachSystem = fn:
forAllSystems (s: fn nixpkgsFor.${s});
in
{
devShells = forEachSystem (pkgs: {
default = pkgs.mkShell { default = pkgs.mkShell {
packages = with pkgs; [ packages = with pkgs; [
actionlint actionlint
nodePackages.pnpm nodejs_20
(nodePackages_latest.pnpm.override {nodejs = nodejs_20;})
]; ];
}; };
}); });
formatter = forEachSystem (p: p.nixpkgs-fmt); formatter = forAllSystems (p: p.alejandra);
}; };
} }

View File

@ -6,13 +6,12 @@
"build": "esbuild src/index.ts --outdir=dist --platform=node --format=cjs --bundle --minify-whitespace --minify-syntax", "build": "esbuild src/index.ts --outdir=dist --platform=node --format=cjs --bundle --minify-whitespace --minify-syntax",
"format": "prettier --write ." "format": "prettier --write ."
}, },
"keywords": [],
"author": "Ryan Cao <hello@ryanccn.dev>", "author": "Ryan Cao <hello@ryanccn.dev>",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"ofetch": "^1.1.1" "just-split": "^3.2.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^16.18.38", "@types/node": "^16.18.38",
@ -20,5 +19,5 @@
"prettier": "3.0.0", "prettier": "3.0.0",
"typescript": "^5.1.6" "typescript": "^5.1.6"
}, },
"packageManager": "pnpm@8.6.9" "packageManager": "pnpm@8.7.5"
} }

26
pnpm-lock.yaml generated
View File

@ -11,9 +11,9 @@ dependencies:
'@actions/exec': '@actions/exec':
specifier: ^1.1.1 specifier: ^1.1.1
version: 1.1.1 version: 1.1.1
ofetch: just-split:
specifier: ^1.1.1 specifier: ^3.2.0
version: 1.1.1 version: 3.2.0
devDependencies: devDependencies:
'@types/node': '@types/node':
@ -256,10 +256,6 @@ packages:
resolution: {integrity: sha512-6sfo1qTulpVbkxECP+AVrHV9OoJqhzCsfTNp5NIG+enM4HyM3HvZCO798WShIXBN0+QtDIcutJCjsVYnQP5rIQ==} resolution: {integrity: sha512-6sfo1qTulpVbkxECP+AVrHV9OoJqhzCsfTNp5NIG+enM4HyM3HvZCO798WShIXBN0+QtDIcutJCjsVYnQP5rIQ==}
dev: true dev: true
/destr@2.0.0:
resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==}
dev: false
/esbuild@0.18.14: /esbuild@0.18.14:
resolution: {integrity: sha512-uNPj5oHPYmj+ZhSQeYQVFZ+hAlJZbAGOmmILWIqrGvPVlNLbyOvU5Bu6Woi8G8nskcx0vwY0iFoMPrzT86Ko+w==} resolution: {integrity: sha512-uNPj5oHPYmj+ZhSQeYQVFZ+hAlJZbAGOmmILWIqrGvPVlNLbyOvU5Bu6Woi8G8nskcx0vwY0iFoMPrzT86Ko+w==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -290,16 +286,8 @@ packages:
'@esbuild/win32-x64': 0.18.14 '@esbuild/win32-x64': 0.18.14
dev: true dev: true
/node-fetch-native@1.2.0: /just-split@3.2.0:
resolution: {integrity: sha512-5IAMBTl9p6PaAjYCnMv5FmqIF6GcZnawAVnzaCG0rX2aYZJ4CxEkZNtVPuTRug7fL7wyM5BQYTlAzcyMPi6oTQ==} resolution: {integrity: sha512-hh57dN5koTBkmg3T6gBFISVVaW5bgZ6Ct1W5KODD5M7hQJKqGzTKkfMwOil8MBxyztLQEjh/v6UGXE8cP5tnqQ==}
dev: false
/ofetch@1.1.1:
resolution: {integrity: sha512-SSMoktrp9SNLi20BWfB/BnnKcL0RDigXThD/mZBeQxkIRv1xrd9183MtLdsqRYLYSqW0eTr5t8w8MqjNhvoOQQ==}
dependencies:
destr: 2.0.0
node-fetch-native: 1.2.0
ufo: 1.1.2
dev: false dev: false
/prettier@3.0.0: /prettier@3.0.0:
@ -319,10 +307,6 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/ufo@1.1.2:
resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}
dev: false
/uuid@8.3.2: /uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true hasBin: true

View File

@ -1,12 +1,16 @@
import { install } from "./stages/install"; import { install, isInstalled } from "./stages/install";
import { configure } from "./stages/configure"; import { configure } from "./stages/configure";
import { push } from "./stages/push.ts"; import { push } from "./stages/push";
import { getState, saveState } from "@actions/core"; import { getState, saveState, info } from "@actions/core";
const isPost = !!getState("isPost"); const isPost = !!getState("isPost");
const main = async () => { const main = async () => {
if (await isInstalled()) {
info("Skipping attic installation because it is already installed");
} else {
await install(); await install();
}
await configure(); await configure();
}; };

View File

@ -1,6 +1,6 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import { exec } from "@actions/exec"; import { exec } from "@actions/exec";
import { getStorePaths } from "../utils"; import { saveStorePaths } from "../utils";
export const configure = async () => { export const configure = async () => {
core.startGroup("Configure attic"); core.startGroup("Configure attic");
@ -9,13 +9,20 @@ export const configure = async () => {
const endpoint = core.getInput("endpoint"); const endpoint = core.getInput("endpoint");
const cache = core.getInput("cache"); const cache = core.getInput("cache");
const token = core.getInput("token"); const token = core.getInput("token");
const skipUse = core.getInput("skip-use");
core.info("Logging in to attic cache"); core.info("Logging in to attic cache");
await exec("attic", ["login", "--set-default", cache, endpoint, token]); await exec("/run/current-system/sw/bin/attic", ["login", "--set-default", cache, endpoint, token]);
if (skipUse === "true") {
core.info("Not adding attic cache to substituters as skip-use is set to true");
} else {
core.info("Adding attic cache to substituters");
await exec("/run/current-system/sw/bin/attic", ["use", cache]);
}
core.info("Collecting store paths before build"); core.info("Collecting store paths before build");
const paths = await getStorePaths(); await saveStorePaths();
core.saveState("initial-paths", JSON.stringify(paths));
} catch (e) { } catch (e) {
core.setFailed(`Action failed with error: ${e}`); core.setFailed(`Action failed with error: ${e}`);
} }

View File

@ -1,6 +1,5 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import { exec } from "@actions/exec"; import { exec } from "@actions/exec";
import { fetch } from "ofetch";
import { writeFile } from "node:fs/promises"; import { writeFile } from "node:fs/promises";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
@ -34,3 +33,8 @@ export const install = async () => {
core.endGroup(); core.endGroup();
}; };
export const isInstalled = async () => {
let return_code = await exec("/run/current-system/sw/bin/attic", ["-V"]);
return return_code === 0;
};

View File

@ -1,19 +1,24 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import { exec } from "@actions/exec"; import { exec } from "@actions/exec";
import { getStorePaths } from "../utils";
import splitArray from "just-split";
import { saveStorePaths, getStorePaths } from "../utils";
export const push = async () => { export const push = async () => {
core.startGroup("Push to Attic"); core.startGroup("Push to Attic");
try { try {
const skipPush = core.getInput("skip-push"); const skipPush = core.getInput("skip-push");
if (skipPush === "true") { if (skipPush === "true") {
core.info("Pushing to cache is disabled by skip-push"); core.info("Pushing to cache is disabled by skip-push");
} else { } else {
const cache = core.getInput("cache"); const cache = core.getInput("cache");
core.info("Pushing to cache"); core.info("Pushing to cache");
const oldPaths = JSON.parse(core.getState("initial-paths")) as string[];
const oldPaths = await getStorePaths();
await saveStorePaths();
const newPaths = await getStorePaths(); const newPaths = await getStorePaths();
const addedPaths = newPaths const addedPaths = newPaths
.filter((p) => !oldPaths.includes(p)) .filter((p) => !oldPaths.includes(p))
@ -21,10 +26,14 @@ export const push = async () => {
(p) => !p.endsWith(".drv") && !p.endsWith(".drv.chroot") && !p.endsWith(".check") && !p.endsWith(".lock"), (p) => !p.endsWith(".drv") && !p.endsWith(".drv.chroot") && !p.endsWith(".check") && !p.endsWith(".lock"),
); );
await exec("attic", ["push", cache, ...addedPaths]); const splitAddedPaths = splitArray(addedPaths, 25);
for (const addedPaths of splitAddedPaths) {
await exec("/run/current-system/sw/bin/attic", ["push", cache, ...addedPaths]);
}
} }
} catch (e) { } catch (e) {
core.setFailed(`Action failed with error: ${e}`); core.warning(`Action encountered error: ${e}`);
core.info("Not considering errors during push a failure.");
} }
core.endGroup(); core.endGroup();

View File

@ -1,23 +1,17 @@
import { exec } from "@actions/exec"; import { exec } from "@actions/exec";
import { Writable } from "node:stream";
class StringStream extends Writable { import { readFile } from "node:fs/promises";
chunks: Buffer[] = [];
_write(chunk: WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>, _enc: unknown, next: () => unknown) { export const saveStorePaths = async () => {
this.chunks.push(Buffer.from(chunk)); await exec("sh", ["-c", "nix path-info --all --json > /tmp/store-paths"]);
next(); };
} export const getStorePaths = async () => {
const rawStorePaths = JSON.parse(await readFile("/tmp/store-paths", "utf8")) as { path: string }[];
string() {
return Buffer.concat(this.chunks).toString("utf-8"); // compatibility with Nix 2.18
} if (Array.isArray(rawStorePaths)) {
} return rawStorePaths.map((path) => path.path);
};
export const getStorePaths = async () => {
const outStream = new StringStream(); return Object.keys(rawStorePaths);
await exec("nix", ["path-info", "--all"], { outStream });
const paths = outStream.string().split("\n").filter(Boolean);
return paths;
}; };

View File

@ -1,7 +1,14 @@
let let
pkgs = import <nixpkgs> { }; lock = builtins.fromJSON (builtins.readFile ./flake.lock);
time = with builtins; toString currentTime; pkgs = import (
fetchTarball {
url =
lock.nodes.nixpkgs.locked.url
or "https://github.com/NixOS/nixpkgs/archive/${lock.nodes.nixpkgs.locked.rev}.tar.gz";
sha256 = lock.nodes.nixpkgs.locked.narHash;
}
) {};
in in
pkgs.runCommand "${time}-test" { } '' pkgs.runCommand "non-reproducible-test" {} ''
echo "${time}" > $out echo ${toString builtins.currentTime} > $out
'' ''