chore: Set aside old content

Signed-off-by: Jeremy Adams <jeremy@dagger.io>
This commit is contained in:
Jeremy Adams 2023-11-13 13:55:25 -08:00
parent 97a086c722
commit 7815dae500
123 changed files with 0 additions and 19430 deletions

View file

@ -1,2 +0,0 @@
/coverage
/node_modules

View file

@ -1,18 +0,0 @@
# This file is for unifying the coding style for different editors and IDEs.
# More information at http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[test/**]
insert_final_newline = false
[*.md]
trim_trailing_whitespace = false

View file

@ -1,23 +0,0 @@
{
"env": {
"node": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"jest",
"prettier"
]
}

2
.gitattributes vendored
View file

@ -1,2 +0,0 @@
/dist/** linguist-generated=true
/lib/** linguist-generated=true

View file

@ -1,32 +0,0 @@
## Contributing
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
to the public under the [project's open source license](LICENSE).
## Submitting a pull request
1. [Fork](https://github.com/dagger/dagger-for-github/fork) and clone the repository
2. Configure and install the dependencies: `yarn install`
3. Create a new branch: `git checkout -b my-branch-name`
4. Make your changes
5. Make sure the tests pass: `docker buildx bake test`
6. Format code and build javascript artifacts: `docker buildx bake pre-checkin`
7. Validate all code has correctly formatted and built: `docker buildx bake validate`
8. Push to your fork and [submit a pull request](https://github.com/dagger/dagger-for-github/compare)
9. Pat your self on the back and wait for your pull request to be reviewed and merged.
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write tests.
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
- [GitHub Help](https://docs.github.com/en)

29
.github/SUPPORT.md vendored
View file

@ -1,29 +0,0 @@
# Support [![](https://isitmaintained.com/badge/resolution/dagger/dagger-for-github.svg)](https://isitmaintained.com/project/dagger/dagger-for-github)
## Reporting an issue
Please do a search in [open issues](https://github.com/dagger/dagger-for-github/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment.
:+1: - upvote
:-1: - downvote
If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.
## Writing good bug reports and feature requests
File a single issue per problem and feature request.
* Do not enumerate multiple bugs or feature requests in the same issue.
* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
You are now ready to [create a new issue](https://github.com/dagger/dagger-for-github/issues/new/choose)!
## Closure policy
* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.
* Issues that go a week without a response from original poster are subject to closure at my discretion.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
.github/dagger.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,18 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- ":game_die: dependencies"
- ":robot: bot"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
allow:
- dependency-type: "production"
labels:
- ":game_die: dependencies"
- ":robot: bot"

View file

@ -1,94 +0,0 @@
name: ci
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *' # everyday at 10am
push:
branches:
- 'main'
- 'releases/v*'
tags:
- 'v*'
pull_request:
jobs:
do:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version:
- latest
- 0.2.232
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Dagger
uses: ./
with:
version: ${{ matrix.version }}
cmds: |
project update
do test
workdir: ./test/ci
args-deprecated:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Dagger
uses: ./
with:
cmds: |
project update
do test
workdir: ./test/ci
install-only:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version:
- 0.2.232
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Dagger
uses: ./
with:
version: ${{ matrix.version }}
install-only: true
-
name: Check
run: |
dagger-cue version
build-ref:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ref:
- refs/heads/cue-sdk
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Dagger
uses: ./
with:
version: https://github.com/dagger/dagger.git#${{ matrix.ref }}
cmds: |
project update
do test
workdir: ./test/ci

View file

@ -1,33 +0,0 @@
name: test
on:
push:
branches:
- 'main'
- 'releases/v*'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
name: Validate
uses: docker/bake-action@v2
with:
targets: validate
-
name: Test
uses: docker/bake-action@v2
with:
targets: test
-
name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage/clover.xml

96
.gitignore vendored
View file

@ -1,96 +0,0 @@
/.dev
node_modules/
lib
# Jetbrains
/.idea
/*.iml
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/

View file

@ -1,11 +0,0 @@
{
"printWidth": 240,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}

View file

@ -1,90 +0,0 @@
import {describe, expect, jest, it} from '@jest/globals';
import * as fs from 'fs';
import * as path from 'path';
import * as context from '../src/context';
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
const tmpDir = path.join('/tmp/.dagger-jest').split(path.sep).join(path.posix.sep);
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
describe('getInputList', () => {
it('handles single line correctly', async () => {
await setInput('foo', 'bar');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar']);
});
it('handles multiple lines correctly', async () => {
setInput('foo', 'bar\nbaz');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz']);
});
it('remove empty lines correctly', async () => {
setInput('foo', 'bar\n\nbaz');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz']);
});
it('handles comma correctly', async () => {
setInput('foo', 'bar,baz');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz']);
});
it('remove empty result correctly', async () => {
setInput('foo', 'bar,baz,');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz']);
});
it('handles different new lines correctly', async () => {
setInput('foo', 'bar\r\nbaz');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz']);
});
it('handles different new lines and comma correctly', async () => {
setInput('foo', 'bar\r\nbaz,bat');
const res = await context.getInputList('foo');
expect(res).toEqual(['bar', 'baz', 'bat']);
});
it('handles multiple lines and ignoring comma correctly', async () => {
setInput('driver-opts', 'foo,bar\nbaz');
const res = await context.getInputList('driver-opts', true);
expect(res).toEqual(['foo,bar', 'baz']);
});
it('handles different new lines and ignoring comma correctly', async () => {
setInput('driver-opts', 'foo,bar\r\nbaz');
const res = await context.getInputList('driver-opts', true);
expect(res).toEqual(['foo,bar', 'baz']);
});
});
describe('asyncForEach', () => {
it('executes async tasks sequentially', async () => {
const testValues = [1, 2, 3, 4, 5];
const results: number[] = [];
await context.asyncForEach(testValues, async value => {
results.push(value);
});
expect(results).toEqual(testValues);
});
});
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
function getInputName(name: string): string {
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
}
function setInput(name: string, value: string): void {
process.env[getInputName(name)] = value;
}

View file

@ -1,22 +0,0 @@
import {describe, expect, it} from '@jest/globals';
import * as fs from 'fs';
import * as dagger from '../src/dagger';
describe('build', () => {
it.skip('valid', async () => {
const daggerBin = await dagger.build('https://github.com/dagger/dagger.git#refs/pull/2161/head');
expect(fs.existsSync(daggerBin)).toBe(true);
}, 100000);
});
describe('install', () => {
it('acquires latest version of dagger-cue', async () => {
const daggerBin = await dagger.install('latest');
expect(fs.existsSync(daggerBin)).toBe(true);
}, 100000);
it('acquires latest 0.2.232 version', async () => {
const daggerBin = await dagger.install('0.2.232');
expect(fs.existsSync(daggerBin)).toBe(true);
}, 100000);
});

View file

@ -1,9 +0,0 @@
import {describe, expect, it} from '@jest/globals';
import * as git from '../src/git';
describe('git', () => {
it('returns git remote ref', async () => {
const ref: string = await git.getRemoteSha('https://github.com/dagger/dagger.git', 'refs/pull/2161/head');
expect(ref).toEqual('aeb8ea3973a7815fff7cbd16f986811baa08ae2f');
});
});

View file

@ -1,12 +0,0 @@
import {describe, expect, test} from '@jest/globals';
import * as util from '../src/util';
describe('isValidUrl', () => {
test.each([
['https://github.com/dagger/dagger.git', true],
['https://github.com/dagger/dagger.git#refs/pull/2161/head', true],
['v0.2.7', false]
])('given %p', async (url, expected) => {
expect(util.isValidUrl(url)).toEqual(expected);
});
});

View file

@ -1,3 +0,0 @@
comment: false
github_checks:
annotations: false

View file

@ -1,81 +0,0 @@
# syntax=docker/dockerfile:1
ARG NODE_VERSION=16
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git
WORKDIR /src
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules <<EOT
yarn install
mkdir /vendor
cp yarn.lock /vendor
EOT
FROM scratch AS vendor-update
COPY --from=deps /vendor /
FROM deps AS vendor-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /vendor/* .
diff=$(git status --porcelain -- yarn.lock)
if [ -n "$diff" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
echo "$diff"
exit 1
fi
EOT
FROM deps AS build
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules <<EOT
yarn run build
mkdir /out
cp -Rf dist /out/
EOT
FROM scratch AS build-update
COPY --from=build /out /
FROM build AS build-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /out/* .
diff=$(git status --porcelain -- dist)
if [ -n "$diff" ]; then
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
echo "$diff"
exit 1
fi
EOT
FROM deps AS format
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules <<EOT
yarn run format
mkdir /out
find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
EOT
FROM scratch AS format-update
COPY --from=format /out /
FROM deps AS lint
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run lint
FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run test --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage /

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

1
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

128
dist/licenses.txt vendored
View file

@ -1,128 +0,0 @@
@actions/core
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/exec
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/http-client
MIT
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/io
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/tool-cache
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
semver
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
tunnel
MIT
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
uuid
MIT
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because one or more lines are too long

View file

@ -1,53 +0,0 @@
group "default" {
targets = ["build"]
}
group "pre-checkin" {
targets = ["vendor-update", "format", "build"]
}
group "validate" {
targets = ["lint", "build-validate", "vendor-validate"]
}
target "build" {
dockerfile = "dev.Dockerfile"
target = "build-update"
output = ["."]
}
target "build-validate" {
dockerfile = "dev.Dockerfile"
target = "build-validate"
output = ["type=cacheonly"]
}
target "format" {
dockerfile = "dev.Dockerfile"
target = "format-update"
output = ["."]
}
target "lint" {
dockerfile = "dev.Dockerfile"
target = "lint"
output = ["type=cacheonly"]
}
target "vendor-update" {
dockerfile = "dev.Dockerfile"
target = "vendor-update"
output = ["."]
}
target "vendor-validate" {
dockerfile = "dev.Dockerfile"
target = "vendor-validate"
output = ["type=cacheonly"]
}
target "test" {
dockerfile = "dev.Dockerfile"
target = "test-coverage"
output = ["./coverage"]
}

View file

@ -1,9 +0,0 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
};

View file

@ -1,49 +0,0 @@
{
"name": "dagger-for-github",
"description": "GitHub Action for Dagger, a programmable deployment system",
"main": "lib/main.js",
"scripts": {
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
"test": "jest --coverage",
"all": "yarn run build && yarn run format && yarn test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/dagger/dagger-for-github.git"
},
"keywords": [
"actions",
"dagger"
],
"author": "Dagger",
"contributors": [
{
"name": "CrazyMax",
"url": "https://crazymax.dev"
}
],
"license": "Apache-2.0",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1",
"@actions/tool-cache": "^2.0.1"
},
"devDependencies": {
"@types/node": "^18.11.0",
"@typescript-eslint/eslint-plugin": "^5.40.0",
"@typescript-eslint/parser": "^5.40.0",
"@vercel/ncc": "^0.34.0",
"eslint": "^8.25.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^27.1.2",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.2.0",
"prettier": "^2.7.1",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
}
}

View file

@ -1,50 +0,0 @@
import fs from 'fs';
import * as os from 'os';
import path from 'path';
import * as core from '@actions/core';
let _tmpDir: string;
export function tmpDir(): string {
if (!_tmpDir) {
_tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dagger-')).split(path.sep).join(path.posix.sep);
}
return _tmpDir;
}
export interface Inputs {
version: string;
workdir: string;
args: string;
installOnly: boolean;
cleanup: boolean;
cmds: string[];
}
export async function getInputs(): Promise<Inputs> {
return {
version: core.getInput('version') || '0.2.232',
workdir: core.getInput('workdir') || '.',
args: core.getInput('args'),
installOnly: core.getBooleanInput('install-only'),
cleanup: core.getBooleanInput('cleanup'),
cmds: await getInputList('cmds')
};
}
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
const items = core.getInput(name);
if (items == '') {
return [];
}
return items
.split(/\r?\n/)
.filter(x => x)
.reduce<string[]>((acc, line) => acc.concat(!ignoreComma ? line.split(',').filter(x => x) : line).map(pat => pat.trim()), []);
}
export const asyncForEach = async (array, callback) => {
for (const index in array) {
await callback(array[index], index, array);
}
};

View file

@ -1,88 +0,0 @@
import * as os from 'os';
import * as path from 'path';
import * as util from 'util';
import * as context from './context';
import * as git from './git';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as http from '@actions/http-client';
import * as tc from '@actions/tool-cache';
const s3URL = 'https://dl.dagger.io/dagger-cue';
const osPlat: string = os.platform();
const osArch: string = os.arch();
export async function build(inputBuildRef: string): Promise<string> {
// eslint-disable-next-line prefer-const
let [repo, ref] = inputBuildRef.split('#');
if (ref.length == 0) {
ref = 'main';
}
const sha = await git.getRemoteSha(repo, ref);
core.debug(`Remote ref ${sha} found`);
let toolPath: string;
toolPath = tc.find('dagger-cue', sha);
if (!toolPath) {
const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep);
toolPath = await exec
.getExecOutput('docker', ['buildx', 'build', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], {
ignoreReturnCode: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
return tc.cacheFile(`${outFolder}/bin/dagger-cue`, osPlat == 'win32' ? 'dagger-cue.exe' : 'dagger-cue', 'dagger-cue', sha);
});
}
return path.join(toolPath, osPlat == 'win32' ? 'dagger-cue.exe' : 'dagger-cue');
}
export async function install(version: string): Promise<string> {
version = await getVersionMapping(version);
version = version.replace(/^v/, '');
const downloadUrl: string = util.format('%s/releases/%s/%s', s3URL, version, getFilename(version));
core.info(`Downloading ${downloadUrl}`);
const downloadPath: string = await tc.downloadTool(downloadUrl);
core.debug(`Downloaded to ${downloadPath}`);
core.info('Extracting Dagger');
let extPath: string;
if (osPlat == 'win32') {
extPath = await tc.extractZip(downloadPath);
} else {
extPath = await tc.extractTar(downloadPath);
}
core.debug(`Extracted to ${extPath}`);
const cachePath: string = await tc.cacheDir(extPath, 'dagger-cue', version);
core.debug(`Cached to ${cachePath}`);
const exePath: string = path.join(cachePath, osPlat == 'win32' ? 'dagger-cue.exe' : 'dagger-cue');
core.debug(`Exe path is ${exePath}`);
return path.join(cachePath, osPlat == 'win32' ? 'dagger-cue.exe' : 'dagger-cue');
}
async function getVersionMapping(version: string): Promise<string> {
const _http = new http.HttpClient('dagger-for-github');
const res = await _http.get(`${s3URL}/versions/${version}`);
if (res.message.statusCode != 200) {
return version;
}
return await res.readBody().then(body => {
return body.trim();
});
}
const getFilename = (version: string): string => {
const platform: string = osPlat == 'win32' ? 'windows' : osPlat;
const arch: string = osArch == 'x64' ? 'amd64' : osArch;
const ext: string = osPlat == 'win32' ? '.zip' : '.tar.gz';
return util.format('dagger-cue_v%s_%s_%s%s', version, platform, arch, ext);
};

View file

@ -1,19 +0,0 @@
import * as exec from '@actions/exec';
export async function getRemoteSha(repo: string, ref: string): Promise<string> {
return await exec
.getExecOutput(`git`, ['ls-remote', repo, ref], {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
const [rsha] = res.stdout.trim().split(/[\s\t]/);
if (rsha.length == 0) {
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
}
return rsha;
});
}

View file

@ -1,77 +0,0 @@
import fs from 'fs';
import path from 'path';
import os from 'os';
import * as context from './context';
import * as dagger from './dagger';
import * as stateHelper from './state-helper';
import * as util from './util';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
async function run(): Promise<void> {
try {
const inputs: context.Inputs = await context.getInputs();
let daggerBin;
if (util.isValidUrl(inputs.version)) {
core.startGroup(`Build and install Dagger`);
daggerBin = await dagger.build(inputs.version);
core.endGroup();
} else {
core.startGroup(`Download and install Dagger`);
daggerBin = await dagger.install(inputs.version);
core.endGroup();
}
if (inputs.installOnly) {
const daggerDir = path.dirname(daggerBin);
core.addPath(daggerDir);
core.debug(`Added ${daggerDir} to PATH`);
return;
} else if (!inputs.args && !inputs.cmds.length) {
throw new Error(`you need to provide either 'args' or 'cmds'`);
}
if (inputs.workdir && inputs.workdir !== '.') {
core.debug(`Using ${inputs.workdir} as working directory`);
process.chdir(inputs.workdir);
}
stateHelper.setCleanup(inputs.cleanup);
if (inputs.args) {
inputs.cmds.unshift(inputs.args);
}
for (const cmd of inputs.cmds) {
await core.group(cmd, async () => {
await exec.exec(`${daggerBin} ${cmd}`, undefined, {
env: Object.assign({}, process.env, {
DAGGER_LOG_FORMAT: 'plain'
}) as {
[key: string]: string;
}
});
});
}
} catch (error) {
core.setFailed(error.message);
}
}
async function cleanup(): Promise<void> {
if (!stateHelper.cleanup) {
return;
}
const daggerHome = path.join(os.homedir(), '.config', 'dagger');
if (fs.existsSync(daggerHome)) {
core.info(`Removing ${daggerHome}`);
fs.rmSync(daggerHome, {recursive: true});
}
}
if (!stateHelper.IsPost) {
run();
} else {
cleanup();
}

View file

@ -1,12 +0,0 @@
import * as core from '@actions/core';
export const IsPost = !!process.env['STATE_isPost'];
export const cleanup = /true/i.test(process.env['STATE_cleanup'] || '');
export function setCleanup(cleanup: boolean) {
core.saveState('cleanup', cleanup);
}
if (!IsPost) {
core.saveState('isPost', 'true');
}

View file

@ -1,8 +0,0 @@
export function isValidUrl(url: string): boolean {
try {
new URL(url);
} catch (e) {
return false;
}
return true;
}

View file

@ -1,8 +0,0 @@
```console
dagger init
cp ~/.config/dagger/keys.txt .
dagger new ci -p ./ci
mkdir -p ./ci
dagger query
dagger up --no-cache --log-format plain
```

View file

@ -1,21 +0,0 @@
package main
import (
"dagger.io/dagger"
"universe.dagger.io/alpine"
"universe.dagger.io/bash"
)
dagger.#Plan & {
actions: test: {
image: alpine.#Build & {
packages: bash: {}
}
bash.#Run & {
input: image.output
script: contents: "echo Hello World!"
}
}
}

View file

@ -1 +0,0 @@
pkg/** linguist-generated=true

View file

@ -1 +0,0 @@
module: ""

View file

@ -1 +0,0 @@
module: "dagger.io"

View file

@ -1,81 +0,0 @@
package dagger
// Execute a command in a container
#Exec: {
$dagger: task: _name: "Exec"
// Container filesystem
input: #FS
// Transient filesystem mounts
// Key is an arbitrary name, for example "app source code"
// Value is mount configuration
mounts: [name=string]: #Mount
// Command to execute
// Example: ["echo", "hello, world!"]
args: [...string]
// Environment variables
env: [key=string]: string | #Secret
// Working directory
workdir: string | *"/"
// User ID or name
user: string | *"root"
// If set, always execute even if the operation could be cached
always: true | *false
// Inject hostname resolution into the container
// key is hostname, value is IP
hosts: [hostname=string]: string
// Modified filesystem
output: #FS
// Command exit code
// Currently this field can only ever be zero.
// If the command fails, DAG execution is immediately terminated.
// FIXME: expand API to allow custom handling of failed commands
exit: int & 0
}
// A transient filesystem mount.
#Mount: {
dest: string
type: string
{
type: "cache"
contents: #CacheDir
} | {
type: "tmp"
contents: #TempDir
} | {
type: "service"
contents: #Service
} | {
type: "fs"
contents: #FS
source?: string
ro?: true | *false
} | {
type: "secret"
contents: #Secret
uid: int | *0
gid: int | *0
mask: int | *0o400
}
}
// A (best effort) persistent cache dir
#CacheDir: {
id: string
concurrency: *"shared" | "private" | "locked"
}
// A temporary directory for command execution
#TempDir: {
size: int64 | *0
}

View file

@ -1,118 +0,0 @@
package dagger
// Access the source directory for the current CUE package
// This may safely be called from any package
#Source: {
$dagger: task: _name: "Source"
// Relative path to source.
path: string
// Optionally exclude certain files
include: [...string]
// Optionally include certain files
exclude: [...string]
output: #FS
}
// Create one or multiple directory in a container
#Mkdir: {
$dagger: task: _name: "Mkdir"
// Container filesystem
input: #FS
// Path of the directory to create
// It can be nested (e.g : "/foo" or "/foo/bar")
path: string
// Permissions of the directory
permissions: *0o755 | int
// If set, it creates parents' directory if they do not exist
parents: *true | false
// Modified filesystem
output: #FS
}
#ReadFile: {
$dagger: task: _name: "ReadFile"
// Filesystem tree holding the file
input: #FS
// Path of the file to read
path: string
// Contents of the file
contents: string
}
// Write a file to a filesystem tree, creating it if needed
#WriteFile: {
$dagger: task: _name: "WriteFile"
// Input filesystem tree
input: #FS
// Path of the file to write
path: string
// Contents to write
contents: string
// Permissions of the file
permissions: *0o600 | int
// Output filesystem tree
output: #FS
}
// Copy files from one FS tree to another
#Copy: {
$dagger: task: _name: "Copy"
// Input of the operation
input: #FS
// Contents to copy
contents: #FS
// Source path (optional)
source: string | *"/"
// Destination path (optional)
dest: string | *"/"
// Output of the operation
output: #FS
}
#CopyInfo: {
source: {
root: #FS
path: string | *"/"
}
dest: string
}
// Merge multiple FS trees into one
#Merge: {
@dagger(notimplemented)
$dagger: task: _name: "Merge"
input: #FS
layers: [...#CopyInfo]
output: #FS
}
// Select a subdirectory from a filesystem tree
#Subdir: {
// Input tree
input: #FS
// Path of the subdirectory
// Example: "/build"
path: string
// Copy action
_copy: #Copy & {
"input": #Scratch
contents: input
source: path
dest: "/"
}
// Subdirectory tree
output: #FS & _copy.output
}

View file

@ -1,30 +0,0 @@
package dagger
// Push a directory to a git remote
#GitPush: {
@dagger(notimplemented)
$dagger: task: _name: "GitPush"
input: #FS
remote: string
ref: string
}
// Pull a directory from a git remote
// Warning: do NOT embed credentials in the remote url as this will expose them in logs.
// By using username and password Dagger will handle this for you in a secure manner.
#GitPull: {
$dagger: task: _name: "GitPull"
remote: string
ref: string
keepGitDir: true | *false
auth?: {
username: string
password: #Secret // can be password or personal access token
} | {
authToken: #Secret
} | {
authHeader: #Secret
}
output: #FS
}

View file

@ -1,47 +0,0 @@
package dagger
// HTTP operations
// Raw buildkit API
//
// package llb // import "github.com/moby/buildkit/client/llb"
//
// func HTTP(url string, opts ...HTTPOption) State
//
// type HTTPOption interface {
// SetHTTPOption(*HTTPInfo)
// }
// func Checksum(dgst digest.Digest) HTTPOption
// func Chmod(perm os.FileMode) HTTPOption
// func Chown(uid, gid int) HTTPOption
// func Filename(name string) HTTPOption
// Fetch a file over HTTP
#HTTPFetch: {
$dagger: task: _name: "HTTPFetch"
// Source url
// Example: https://www.dagger.io/index.html
source: string
// Destination path of the downloaded file
// Example: "/downloads/index.html"
dest: string
// Optionally verify the file checksum
// FIXME: what is the best format to encode checksum?
checksum?: string
// Optionally set file permissions on the downloaded file
// FIXME: find a more developer-friendly way to input file permissions
permissions?: int
// Optionally set UID of the downloaded file
uid?: int
// Optionally set GID of the downloaded file
gid?: int
// New filesystem state containing the downloaded file
output: #FS
}

View file

@ -1,190 +0,0 @@
package dagger
import (
"list"
)
// Upload a container image to a remote repository
#Push: {
$dagger: task: _name: "Push"
// Target repository address
dest: #Ref
// Filesystem contents to push
input: #FS
// Container image config
config: #ImageConfig
// Authentication
auth?: {
username: string
secret: #Secret
}
// Complete ref of the pushed image, including digest
result: #Ref
}
// A ref is an address for a remote container image
//
// Examples:
// - "index.docker.io/dagger"
// - "dagger"
// - "index.docker.io/dagger:latest"
// - "index.docker.io/dagger:latest@sha256:a89cb097693dd354de598d279c304a1c73ee550fbfff6d9ee515568e0c749cfe"
#Ref: string
// Container image config. See [OCI](https://www.opencontainers.org/).
#ImageConfig: {
user?: string
expose?: [string]: {}
env?: [string]: string
entrypoint?: [...string]
cmd?: [...string]
volume?: [string]: {}
workdir?: string
label?: [string]: string
stopsignal?: string
healthcheck?: #HealthCheck
argsescaped?: bool
onbuild?: [...string]
stoptimeout?: int
shell?: [...string]
}
#HealthCheck: {
test?: [...string]
interval?: int
timeout?: int
startperiod?: int
retries?: int
}
// Download a container image from a remote repository
#Pull: {
$dagger: task: _name: "Pull"
// Repository source ref
source: #Ref
// Authentication
auth?: {
username: string
secret: #Secret
}
// Root filesystem of downloaded image
output: #FS
// Image digest
digest: string
// Downloaded container image config
config: #ImageConfig
}
// Build a container image using a Dockerfile
#Dockerfile: {
$dagger: task: _name: "Dockerfile"
// Source directory to build
source: #FS
dockerfile: *{
path: string | *"Dockerfile"
} | {
contents: string
}
// Authentication
auth: [registry=string]: {
username: string
secret: #Secret
}
platforms?: [...string]
target?: string
buildArg?: [string]: string
label?: [string]: string
hosts?: [string]: string
// Root filesystem produced
output: #FS
// Container image config produced
config: #ImageConfig
}
// Change image config
#Set: {
// The source image config
input: #ImageConfig
// The config to merge
config: #ImageConfig
// Resulting config
output: #ImageConfig & {
let structs = ["env", "label", "volume", "expose"]
let lists = ["onbuild"]
// doesn't exist in config, copy away
for field, value in input if config[field] == _|_ {
"\(field)": value
}
// only exists in config, just copy as is
for field, value in config if input[field] == _|_ {
"\(field)": value
}
// these should exist in both places
for field, value in config if input[field] != _|_ {
"\(field)": {
// handle structs that need merging
if list.Contains(structs, field) {
_#mergeStructs & {
#a: input[field]
#b: config[field]
}
}
// handle lists that need concatenation
if list.Contains(lists, field) {
list.Concat([
input[field],
config[field],
])
}
// replace anything else
if !list.Contains(structs+lists, field) {
value
}
}
}
}
}
// Merge two structs by overwriting or adding values
_#mergeStructs: {
// Struct with defaults
#a: [string]: _
// Struct with overrides
#b: [string]: _
{
// FIXME: we need exists() in if because this matches any kind of error (cue-lang/cue#943)
// add anything not in b
for field, value in #a if #b[field] == _|_ {
"\(field)": value
}
// safely add all of b
for field, value in #b {
"\(field)": value
}
}
}

View file

@ -1,132 +0,0 @@
package dagger
// A special kind of program which `dagger` can execute.
#Plan: {
// Access client machine
client: {
// Access client filesystem
// Path may be absolute, or relative to client working directory
filesystem: [path=string]: {
// Read data from that path
read?: _#clientFilesystemRead & {
"path": path
}
// If set, Write to that path
write?: _#clientFilesystemWrite & {
"path": path
// avoid race condition
if read != _|_ {
_after: read
}
}
}
// Access client environment variables
env: [string]: *string | #Secret
// Execute commands in the client
commands: [id=string]: _#clientCommand
// Platform of the client machine
platform: _#clientPlatform
}
// Configure platform execution
platform?: string
// Execute actions in containers
actions: {
...
}
}
_#clientFilesystemRead: {
$dagger: task: _name: "ClientFilesystemRead"
// Path may be absolute, or relative to client working directory
path: string
{
// CUE type defines expected content:
// string: contents of a regular file
// #Secret: secure reference to the file contents
contents: string | #Secret
} | {
// CUE type defines expected content:
// #FS: contents of a directory
contents: #FS
// Filename patterns to include
// Example: ["*.go", "Dockerfile"]
include?: [...string]
// Filename patterns to exclude
// Example: ["node_modules"]
exclude?: [...string]
} | {
// CUE type defines expected content:
// #Service: unix socket or npipe
contents: #Service
// Type of service
type: *"unix" | "npipe"
}
}
_#clientFilesystemWrite: {
$dagger: task: _name: "ClientFilesystemWrite"
// Path may be absolute, or relative to client working directory
path: string
{
// File contents to export (as a string or secret)
contents: string | #Secret
// File permissions (defaults to 0o644)
permissions?: int
} | {
// Filesystem contents to export
// Reference an #FS field produced by an action
contents: #FS
}
}
_#clientCommand: {
$dagger: task: _name: "ClientCommand"
// Name of the command to execute
// Examples: "ls", "/bin/bash"
name: string
// Positional arguments to the command
// Examples: ["/tmp"]
args: [...string]
// Command-line flags represented in a civilized form
// Example: {"-l": true, "-c": "echo hello world"}
flags: [string]: bool | string
// Environment variables
// Example: {"DEBUG": "1"}
env: [string]: string | #Secret
// Capture standard output (as a string or secret)
stdout?: *string | #Secret
// Capture standard error (as a string or secret)
stderr?: *string | #Secret
// Inject standard input (from a string or secret)
stdin?: string | #Secret
}
_#clientPlatform: {
$dagger: task: _name: "ClientPlatform"
// Operating system of the client machine
os: string
// Hardware architecture of the client machine
arch: string
}

View file

@ -1,40 +0,0 @@
package dagger
// Decode the contents of a secrets without leaking it.
// Supported formats: json, yaml
#DecodeSecret: {
$dagger: task: _name: "DecodeSecret"
// A #Secret whose plain text is a JSON or YAML string
input: #Secret
format: "json" | "yaml"
// A new secret or (map of secrets) derived from unmarshaling the input secret's plain text
output: #Secret | {[string]: output}
}
// Create a new a secret from a filesystem tree
#NewSecret: {
$dagger: task: _name: "NewSecret"
// Filesystem tree holding the secret
input: #FS
// Path of the secret to read
path: string
// Whether to trim leading and trailing space characters from secret value
trimSpace: *true | false
// Contents of the secret
output: #Secret
}
// Trim leading and trailing space characters from a secret
#TrimSecret: {
$dagger: task: _name: "TrimSecret"
// Original secret
input: #Secret
// New trimmed secret
output: #Secret
}

View file

@ -1,37 +0,0 @@
package dagger
// A reference to a filesystem tree.
// For example:
// - The root filesystem of a container
// - A source code repository
// - A directory containing binary artifacts
// Rule of thumb: if it fits in a tar archive, it fits in a #FS.
#FS: {
$dagger: fs: _id: string | null
}
// An empty directory
#Scratch: #FS & {
$dagger: fs: _id: null
}
// A reference to an external secret, for example:
// - A password
// - A SSH private key
// - An API token
// Secrets are never merged in the Cue tree. They can only be used
// by a special filesystem mount designed to minimize leak risk.
#Secret: {
$dagger: secret: _id: string
}
// A reference to a network service endpoint, for example:
// - A TCP or UDP port
// - A unix socket
// - An HTTPS endpoint
#Service: {
$dagger: service: _id: string
}
// A network service address
#Address: string & =~"^(tcp://|unix://|udp://).*"

View file

@ -1,76 +0,0 @@
# Europa Universe
## About this directory
`europa-universe/` is a staging area for the upcoming `universe.dagger.io` package namespace,
which will be shipped as part of the [Europa release](https://github.com/dagger/dagger/issues/1088).
## What is Universe?
The Dagger Universe is a catalog of reusable Cue packages, curated by Dagger but possibly authored by third parties. Most packages in Universe contain reusable actions; some may also contain entire configuration templates.
The import domain for Universe will be `universe.dagger.io`. It will deprecate the current domain `alpha.dagger.io`.
## Where is the `dagger` package?
Europa will also introduce a new package for the Dagger Core API: `dagger.io/dagger`.
This is a core package, and is *not* part of Universe (note the import domain).
The development version of the Europa core API can be imported as [alpha.dagger.io/europa/dagger](../stdlib/europa/dagger).
## Where is the `dagger/engine` package?
Europa will also introduce a new package for the Low-Level Dagger Engine API : `dagger.io/dagger/engine`.
This is a core package, and is *not* part of Universe (note the import domain).
The development version of the Europa Low-Level Engine API can be imported as either:
* [alpha.dagger.io/europa/dagger/engine/spec/engine](../stdlib/europa/dagger/engine/spec/engine) for the full spec
* [alpha.dagger.io/dagger/europa/engine](../stdlib/europa/dagger/engine) for the implemented subset of the spec
## Universe vs other packages
This table compares Dagger core packages, Dagger Universe packages, and the overall CUE package ecosystem.
| | *Dagger core* | *Dagger Universe* | *CUE ecosystem* |
|---|----------------|-------------------|-----------------|
| Import path | `dagger.io` | `universe.dagger.io` | Everything else |
| Purpose | Access core Dagger features | Safely reuse code from the Dagger community | Reuse any CUE code from anyone |
| Author | Dagger team | Dagger community, curated by Dagger | Anyone |
| Release cycle | Released with Dagger engine | Released continuously | No release cycle |
| Size | Small | Large | Very large |
| Growth rate | Grows slowly, with engine features | Grows fast, with Dagger community | Grows even faster, with CUE ecosystem |
## Notable packages
### Docker API
*Import path: [`universe.dagger.io/docker`](./universe/docker)*
The `docker` package is a native Cue API for Docker. You can use it to build, run, push and pull Docker containers directly from Cue.
The Dagger container API defines the following types:
* `#Image`: a container image
* `#Run`: run a command in a container
* `#Push`: upload an image to a repository
* `#Pull`: download an image from a repository
* `#Build`: build an image
### Examples
*Import path: [`universe.dagger.io/examples`](./examples)*
This package contains examples of complete Dagger configurations, including the result of following tutorials in the documentations.
For example, [the todoapp example](./examples/todoapp) corresponds to the [Getting Started tutorial](https://docs.dagger.io/1003/get-started/)
## TODO LIST
* Support native language dev in `docker.#Run` with good DX (Python, Go, Typescript etc.)
* Coding style. When to use verbs vs. nouns?
* Easy file injection API (`container.#Image.files` ?)
* Use file injection instead of inline for `#Command.script` (to avoid hitting arg character limits)
* Organize universe packages in sub-categories?

View file

@ -1,42 +0,0 @@
// Base package for Alpine Linux
package alpine
import (
"universe.dagger.io/docker"
)
// Build an Alpine Linux container image
#Build: {
// Alpine version to install.
version: string | *"3.15.0@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300"
// List of packages to install
packages: [pkgName=string]: {
// NOTE(samalba, gh issue #1532):
// it's not recommended to pin the version as it is already pinned by the major Alpine version
// version pinning is for future use (as soon as we support custom repositories like `community`,
// `testing` or `edge`)
version: string | *""
}
docker.#Build & {
steps: [
docker.#Pull & {
source: "index.docker.io/alpine:\(version)"
},
for pkgName, pkg in packages {
docker.#Run & {
command: {
name: "apk"
args: ["add", "\(pkgName)\(pkg.version)"]
flags: {
"-U": true
"--no-cache": true
}
}
}
},
]
}
}

View file

@ -1,8 +0,0 @@
setup() {
load '../../bats_helpers'
common_setup
}
@test "alpine" {
dagger up
}

View file

@ -1,52 +0,0 @@
package alpine
import (
"dagger.io/dagger"
"universe.dagger.io/alpine"
"universe.dagger.io/docker"
)
dagger.#Plan & {
actions: tests: {
// Test: customize alpine version
alpineVersion: {
build: alpine.#Build & {
// install an old version on purpose
version: "3.10.9"
}
verify: dagger.#Readfile & {
input: build.output.rootfs
path: "/etc/alpine-release"
contents: "3.10.9\n"
}
}
// Test: install packages
packageInstall: {
build: alpine.#Build & {
packages: {
jq: {}
curl: {}
}
}
check: docker.#Run & {
input: build.output
command: {
name: "sh"
flags: "-c": """
jq --version > /jq-version.txt
curl --version > /curl-version.txt
"""
}
export: files: {
"/jq-version.txt": contents: =~"^jq"
"/curl-version.txt": contents: =~"^curl"
}
}
}
}
}

View file

@ -1,103 +0,0 @@
// AWS base package
package aws
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
#DefaultLinuxVersion: "amazonlinux:2.0.20220121.0@sha256:f3a37f84f2644095e2c6f6fdf2bf4dbf68d5436c51afcfbfa747a5de391d5d62"
#DefaultCliVersion: "2.4.12"
// Build provides a docker.#Image with the aws cli pre-installed to Amazon Linux 2.
// Can be customized with packages, and can be used with docker.#Run for executing custom scripts.
// Used by default with aws.#Run
#Build: {
docker.#Build & {
steps: [
docker.#Pull & {
source: #DefaultLinuxVersion
},
// cache yum install separately
docker.#Run & {
command: {
name: "yum"
args: ["install", "unzip", "-y"]
}
},
docker.#Run & {
command: {
name: "/scripts/install.sh"
args: [version]
}
mounts: scripts: {
dest: "/scripts"
contents: _scripts.output
}
},
]
}
_scripts: dagger.#Source & {
path: "_scripts"
}
// The version of the AWS CLI to install
version: string | *#DefaultCliVersion
}
// Credentials provides long or short-term credentials.
#Credentials: {
// AWS access key
accessKeyId?: dagger.#Secret
// AWS secret key
secretAccessKey?: dagger.#Secret
// AWS session token (provided with temporary credentials)
sessionToken?: dagger.#Secret
}
// Region provides a schema to validate acceptable region value.
#Region: "us-east-2" | "us-east-1" | "us-west-1" | "us-west-2" | "af-south-1" | "ap-east-1" | "ap-southeast-3" | "ap-south-1" | "ap-northeast-3" | "ap-northeast-2" | "ap-southeast-1" | "ap-southeast-2" | "ap-northeast-1" | "ca-central-1" | "cn-north-1" | "cn-northwest-1" | "eu-central-1" | "eu-west-1" | "eu-west-2" | "eu-south-1" | "eu-west-3" | "eu-north-1" | "me-south-1" | "sa-east-1"
// Container a standalone environment pre-configured with credentials and .aws/config
#Container: {
// _build provides the default image
_build: #Build
// configFile provides access to a config file, typically found in ~/.aws/config
configFile?: dagger.#FS
// credentials provides long or short-term credentials
credentials: #Credentials
docker.#Run & {
input: docker.#Image | *_build.output
env: {
// pass credentials as env vars
if credentials.accessKeyId != _|_ {
AWS_ACCESS_KEY_ID: credentials.accessKeyId
}
if credentials.secretAccessKey != _|_ {
AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey
}
if credentials.sessionToken != _|_ {
AWS_SESSION_TOKEN: credentials.sessionToken
}
}
if configFile != _|_ {
mounts: aws: {
contents: configFile
dest: "/aws"
ro: true
}
env: AWS_CONFIG_FILE: "/aws/config"
}
}
}

View file

@ -1,129 +0,0 @@
package cli
import (
"list"
"strings"
"encoding/json"
"universe.dagger.io/aws"
)
// Command provides a declarative interface to the AWS CLI
#Command: {
// "register" output.txt
export: files: "/output.txt": _
// Global arguments passed to the aws cli.
options: {
// Turn on debug logging.
debug?: bool
// Override command's default URL with the given URL.
"endpoint-url"?: string
// By default, the AWS CLI uses SSL when communicating with AWS services.
// For each SSL connection, the AWS CLI will verify SSL certificates. This
// option overrides the default behavior of verifying SSL certificates.
"no-verify-ssl"?: bool
// Disable automatic pagination.
"no-paginate"?: bool
// The formatting style for command output.
output: *"json" | "text" | "table" | "yaml" | "yaml-stream"
// A JMESPath query to use in filtering the response data.
query?: string
// Use a specific profile from your credential file.
profile?: string
// The region to use. Overrides config/env settings.
region?: string
// Display the version of this tool.
version?: bool
// Turn on/off color output.
color?: "off" | "on" | "auto"
// Do not sign requests. Credentials will not be loaded if this argument
// is provided.
"no-sign-request"?: bool
// The CA certificate bundle to use when verifying SSL certificates. Over-
// rides config/env settings.
"ca-bundle"?: string
// The maximum socket read time in seconds. If the value is set to 0, the
// socket read will be blocking and not timeout. The default value is 60
// seconds.
"cli-read-timeout"?: int
// The maximum socket connect time in seconds. If the value is set to 0,
// the socket connect will be blocking and not timeout. The default value
// is 60 seconds.
"cli-connect-timeout"?: int
// The formatting style to be used for binary blobs. The default format is
// base64. The base64 format expects binary blobs to be provided as a
// base64 encoded string. The raw-in-base64-out format preserves compati-
// bility with AWS CLI V1 behavior and binary values must be passed liter-
// ally. When providing contents from a file that map to a binary blob
// fileb:// will always be treated as binary and use the file contents
// directly regardless of the cli-binary-format setting. When using
// file:// the file contents will need to properly formatted for the con-
// figured cli-binary-format.
"cli-binary-format"?: "base64" | "raw-in-base64-out"
// Disable cli pager for output.
"no-cli-pager": true
// Automatically prompt for CLI input parameters.
"cli-auto-prompt"?: bool
// Disable automatically prompt for CLI input parameters.
"no-cli-auto-prompt"?: bool
}
// Result will contain the cli output. If unmarshal is set to false this will be the raw string as provided by the aws cli command. If unmarshal is set to true this will be a map as returned by json.Unmarshal.
_unmarshalable: string | number | bool | null | [..._unmarshalable] | {[string]: _unmarshalable}
result: _unmarshalable
if unmarshal != false {
options: output: "json"
result: json.Unmarshal(export.files["/output.txt"])
}
if unmarshal == false {
result: export.files["/output.txt"]
}
// The service to run the command against.
service: {
args: [...string]
name: "accessanalyzer" | "account" | "acm" | "acm-pca" | "alexaforbusiness" | "amp" | "amplify" | "amplifybackend" | "amplifyuibuilder" | "apigateway" | "apigatewaymanagementapi" | "apigatewayv2" | "appconfig" | "appconfigdata" | "appflow" | "appintegrations" | "application-autoscaling" | "application-insights" | "applicationcostprofiler" | "appmesh" | "apprunner" | "appstream" | "appsync" | "athena" | "auditmanager" | "autoscaling" | "autoscaling-plans" | "backup" | "backup-gateway" | "batch" | "braket" | "budgets" | "ce" | "chime" | "chime-sdk-identity" | "chime-sdk-meetings" | "chime-sdk-messaging" | "cli-dev" | "cloud9" | "cloudcontrol" | "clouddirectory" | "cloudformation" | "cloudfront" | "cloudhsm" | "cloudtrail" | "cloudwatch" | "codeartifact" | "codebuild" | "codecommit" | "codeguru-reviewer" | "codeguruprofiler" | "codepipeline" | "codestar" | "codestar-connections" | "codestar-notifications" | "cognito-identity" | "cognito-idp" | "cognito-sync" | "comprehend" | "comprehendmedical" | "compute-optimizer" | "configservice" | "configure" | "connect" | "connect-contact-lens" | "connectparticipant" | "cur" | "customer-profiles" | "databrew" | "dataexchange" | "datapipeline" | "datasync" | "dax" | "ddb" | "deploy" | "detective" | "devicefarm" | "devops-guru" | "directconnect" | "discovery" | "dlm" | "dms" | "docdb" | "drs" | "ds" | "dynamodb" | "dynamodbstreams" | "ebs" | "ec2" | "ec2-instance-connect" | "ecr" | "ecr-public" | "ecs" | "efs" | "eks" | "elastic-inference" | "elasticache" | "elasticbeanstalk" | "elastictranscoder" | "elb" | "elbv2" | "emr" | "emr-containers" | "es" | "events" | "evidently" | "finspace" | "finspace-data" | "firehose" | "fis" | "fms" | "forecast" | "forecastquery" | "frauddetector" | "fsx" | "gamelift" | "glacier" | "globalaccelerator" | "glue" | "grafana" | "greengrass" | "greengrassv2" | "groundstation" | "guardduty" | "health" | "healthlake" | "help" | "history" | "honeycode" | "iam" | "identitystore" | "imagebuilder" | "importexport" | "inspector" | "inspector2" | "iot" | "iot-data" | "iot-jobs-data" | "iot1click-devices" | "iot1click-projects" | "iotanalytics" | "iotdeviceadvisor" | "iotevents" | "iotevents-data" | "iotfleethub" | "iotsecuretunneling" | "iotsitewise" | "iotthingsgraph" | "iottwinmaker" | "iotwireless" | "ivs" | "kafka" | "kafkaconnect" | "kendra" | "kinesis" | "kinesis-video-archived-media" | "kinesis-video-media" | "kinesis-video-signaling" | "kinesisanalytics" | "kinesisanalyticsv2" | "kinesisvideo" | "kms" | "lakeformation" | "lambda" | "lex-models" | "lex-runtime" | "lexv2-models" | "lexv2-runtime" | "license-manager" | "lightsail" | "location" | "logs" | "lookoutequipment" | "lookoutmetrics" | "lookoutvision" | "machinelearning" | "macie" | "macie2" | "managedblockchain" | "marketplace-catalog" | "marketplace-entitlement" | "marketplacecommerceanalytics" | "mediaconnect" | "mediaconvert" | "medialive" | "mediapackage" | "mediapackage-vod" | "mediastore" | "mediastore-data" | "mediatailor" | "memorydb" | "meteringmarketplace" | "mgh" | "mgn" | "migration-hub-refactor-spaces" | "migrationhub-config" | "migrationhubstrategy" | "mobile" | "mq" | "mturk" | "mwaa" | "neptune" | "network-firewall" | "networkmanager" | "nimble" | "opensearch" | "opsworks" | "opsworks-cm" | "organizations" | "outposts" | "panorama" | "personalize" | "personalize-events" | "personalize-runtime" | "pi" | "pinpoint" | "pinpoint-email" | "pinpoint-sms-voice" | "polly" | "pricing" | "proton" | "qldb" | "qldb-session" | "quicksight" | "ram" | "rbin" | "rds" | "rds-data" | "redshift" | "redshift-data" | "rekognition" | "resiliencehub" | "resource-groups" | "resourcegroupstaggingapi" | "robomaker" | "route53" | "route53-recovery-cluster" | "route53-recovery-control-config" | "route53-recovery-readiness" | "route53domains" | "route53resolver" | "rum" | "s3" | "s3api" | "s3control" | "s3outposts" | "sagemaker" | "sagemaker-a2i-runtime" | "sagemaker-edge" | "sagemaker-featurestore-runtime" | "sagemaker-runtime" | "savingsplans" | "schemas" | "sdb" | "secretsmanager" | "securityhub" | "serverlessrepo" | "service-quotas" | "servicecatalog" | "servicecatalog-appregistry" | "servicediscovery" | "ses" | "sesv2" | "shield" | "signer" | "sms" | "snow-device-management" | "snowball" | "sns" | "sqs" | "ssm" | "ssm-contacts" | "ssm-incidents" | "sso" | "sso-admin" | "sso-oidc" | "stepfunctions" | "storagegateway" | "sts" | "support" | "swf" | "synthetics" | "textract" | "timestream-query" | "timestream-write" | "transcribe" | "transfer" | "translate" | "voice-id" | "waf" | "waf-regional" | "wafv2" | "wellarchitected" | "wisdom" | "workdocs" | "worklink" | "workmail" | "workmailmessageflow" | "workspaces" | "workspaces-web" | "xray" | ""
command: string
}
// unmarshal determines whether to automatically json.Unmarshal() the command result. If set to true, the output field will be set to "json" and the command output will be Unmarshaled to result:
unmarshal: false | *true
aws.#Container & {
always: true
_optionArgs: list.FlattenN([
for k, v in options {
if (v & bool) != _|_ {
["--\(k)"]
}
if (v & string) != _|_ {
["--\(k)", v]
}
},
], 1)
command: {
name: "/bin/sh"
flags: "-c": strings.Join(["aws"]+_optionArgs+[service.name, service.command]+service.args+[">", "/output.txt"], " ")
}
}
}

View file

@ -1,40 +0,0 @@
package test
import (
"dagger.io/dagger"
"universe.dagger.io/aws"
"universe.dagger.io/aws/cli"
)
dagger.#Plan & {
client: commands: sops: {
name: "sops"
args: ["-d", "--extract", "[\"AWS\"]", "../../../secrets_sops.yaml"]
stdout: dagger.#Secret
}
actions: {
sopsSecrets: dagger.#DecodeSecret & {
format: "yaml"
input: client.commands.sops.stdout
}
getCallerIdentity: cli.#Command & {
credentials: aws.#Credentials & {
accessKeyId: sopsSecrets.output.AWS_ACCESS_KEY_ID.contents
secretAccessKey: sopsSecrets.output.AWS_SECRET_ACCESS_KEY.contents
}
options: region: "us-east-2"
service: {
name: "sts"
command: "get-caller-identity"
}
}
verify: getCallerIdentity.result & {
UserId: !~"^$"
Account: !~"^$"
Arn: !~"^$"
}
}
}

View file

@ -1,9 +0,0 @@
setup() {
load '../../../bats_helpers'
common_setup
}
@test "aws/cli" {
dagger up ./sts_get_caller_identity.cue
}

View file

@ -1,4 +0,0 @@
[profile ci]
credential_source = Environment
region = us-east-2
role_arn = arn:aws:iam::125635003186:role/dagger-ci

View file

@ -1,51 +0,0 @@
package test
import (
"encoding/json"
"dagger.io/dagger"
"universe.dagger.io/aws"
)
dagger.#Plan & {
client: {
filesystem: ".": read: {
contents: dagger.#FS
include: ["config"]
}
commands: sops: {
name: "sops"
args: ["-d", "--extract", "[\"AWS\"]", "../../secrets_sops.yaml"]
stdout: dagger.#Secret
}
}
actions: {
sopsSecrets: dagger.#DecodeSecret & {
format: "yaml"
input: client.commands.sops.stdout
}
getCallerIdentity: aws.#Container & {
always: true
configFile: client.filesystem.".".read.contents
credentials: aws.#Credentials & {
accessKeyId: sopsSecrets.output.AWS_ACCESS_KEY_ID.contents
secretAccessKey: sopsSecrets.output.AWS_SECRET_ACCESS_KEY.contents
}
command: {
name: "sh"
flags: "-c": "aws --profile ci sts get-caller-identity > /output.txt"
}
export: files: "/output.txt": _
}
verify: json.Unmarshal(getCallerIdentity.export.files."/output.txt") & {
UserId: string
Account: =~"^12[0-9]{8}86$"
Arn: =~"^arn:aws:sts::(12[0-9]{8}86):assumed-role/dagger-ci"
}
}
}

View file

@ -1,43 +0,0 @@
package test
import (
"encoding/json"
"dagger.io/dagger"
"universe.dagger.io/aws"
)
dagger.#Plan & {
client: commands: sops: {
name: "sops"
args: ["-d", "--extract", "[\"AWS\"]", "../../secrets_sops.yaml"]
stdout: dagger.#Secret
}
actions: {
sopsSecrets: dagger.#DecodeSecret & {
format: "yaml"
input: client.commands.sops.stdout
}
getCallerIdentity: aws.#Container & {
always: true
credentials: aws.#Credentials & {
accessKeyId: sopsSecrets.output.AWS_ACCESS_KEY_ID.contents
secretAccessKey: sopsSecrets.output.AWS_SECRET_ACCESS_KEY.contents
}
command: {
name: "sh"
flags: "-c": "aws --region us-east-2 sts get-caller-identity > /output.txt"
}
export: files: "/output.txt": _
}
verify: json.Unmarshal(getCallerIdentity.export.files."/output.txt") & {
UserId: string & !~"^$"
Account: =~"^12[0-9]{8}86$"
Arn: =~"(12[0-9]{8}86)"
}
}
}

View file

@ -1,23 +0,0 @@
package test
import (
"dagger.io/dagger"
"universe.dagger.io/aws"
"universe.dagger.io/docker"
)
dagger.#Plan & {
actions: {
build: aws.#Build
getVersion: docker.#Run & {
always: true
input: build.output
command: {
name: "sh"
flags: "-c": "aws --version > /output.txt"
}
export: files: "/output.txt": =~"^aws-cli/\(aws.#DefaultCliVersion)"
}
}
}

View file

@ -1,11 +0,0 @@
setup() {
load '../../bats_helpers'
common_setup
}
@test "aws" {
dagger up ./default_version.cue
dagger up ./credentials.cue
dagger up ./config_file.cue
}

View file

@ -1,59 +0,0 @@
// Helpers to run bash commands in containers
package bash
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
// Run a bash script in a Docker container
// Since this is a thin wrapper over docker.#Run, we embed it.
// Whether to embed or wrap is a case-by-case decision, like in Go.
#Run: {
// The script to execute
script: {
// A directory containing one or more bash scripts
directory: dagger.#FS
// Name of the file to execute
filename: string
_directory: directory
_filename: filename
} | {
// Script contents
contents: string
_filename: "run.sh"
_write: dagger.#WriteFile & {
input: dagger.#Scratch
path: _filename
"contents": contents
}
_directory: _write.output
}
// Arguments to the script
args: [...string]
// Where in the container to mount the scripts directory
_mountpoint: "/bash/scripts"
docker.#Run & {
command: {
name: "bash"
"args": ["\(_mountpoint)/\(script._filename)"] + args
// FIXME: make default flags overrideable
flags: {
"--norc": true
"-e": true
"-o": "pipefail"
}
}
mounts: "Bash scripts": {
contents: script._directory
dest: _mountpoint
}
}
}

View file

@ -1,3 +0,0 @@
#!/bin/sh
echo Hello, world > /out.txt

View file

@ -1,10 +0,0 @@
setup() {
load '../../bats_helpers'
common_setup
}
@test "bash" {
dagger up
}

View file

@ -1,49 +0,0 @@
package bash
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
"universe.dagger.io/bash"
)
dagger.#Plan & {
actions: tests: {
_pull: docker.#Pull & {
source: "index.docker.io/debian"
}
_image: _pull.output
// Run a script from source directory + filename
runFile: {
dir: _load.output
_load: dagger.#Source & {
path: "./data"
include: ["*.sh"]
}
run: bash.#Run & {
input: _image
export: files: "/out.txt": _
script: {
directory: dir
filename: "hello.sh"
}
}
output: run.export.files."/out.txt" & "Hello, world\n"
}
// Run a script from string
runString: {
run: bash.#Run & {
input: _image
export: files: "/output.txt": _
script: contents: "echo 'Hello, inlined world!' > /output.txt"
}
output: run.export.files."/output.txt" & "Hello, inlined world!\n"
}
}
}

View file

@ -1,25 +0,0 @@
common_setup() {
load "$(dirname "${BASH_SOURCE[0]}")/node_modules/bats-support/load.bash"
load "$(dirname "${BASH_SOURCE[0]}")/node_modules/bats-assert/load.bash"
# Dagger Binary
# FIXME: `command -v` must be wrapped in a sub-bash,
# otherwise infinite recursion when DAGGER_BINARY is not set.
export DAGGER="${DAGGER_BINARY:-$(bash -c 'command -v dagger')}"
# Force Europa mode
DAGGER_EUROPA="1"
export DAGGER_EUROPA
# Force plain printing for error reporting
DAGGER_LOG_FORMAT="plain"
export DAGGER_LOG_FORMAT
# cd into the directory containing the bats file
cd "$BATS_TEST_DIRNAME" || exit 1
}
# dagger helper to execute the right binary
dagger() {
"${DAGGER}" "$@"
}

View file

@ -1 +0,0 @@
module: "universe.dagger.io"

View file

@ -1,78 +0,0 @@
package docker
import (
"dagger.io/dagger"
)
// Modular build API for Docker containers
#Build: {
steps: [#Step, ...#Step]
output: #Image
// Generate build DAG from linear steps
_dag: {
for idx, step in steps {
"\(idx)": step & {
// connect input to previous output
if idx > 0 {
// FIXME: the intermediary `output` is needed because of a possible CUE bug.
// `._dag."0".output: 1 errors in empty disjunction::`
// See: https://github.com/cue-lang/cue/issues/1446
// input: _dag["\(idx-1)"].output
_output: _dag["\(idx-1)"].output
input: _output
}
}
}
}
if len(_dag) > 0 {
output: _dag["\(len(_dag)-1)"].output
}
}
// A build step is anything that produces a docker image
#Step: {
input?: #Image
output: #Image
...
}
// Build step that copies files into the container image
#Copy: {
input: #Image
contents: dagger.#FS
source: string | *"/"
dest: string | *"/"
// Execute copy operation
_copy: dagger.#Copy & {
"input": input.rootfs
"contents": contents
"source": source
"dest": dest
}
output: #Image & {
config: input.config
rootfs: _copy.output
}
}
// Build step that executes a Dockerfile
#Dockerfile: {
// Source directory
source: dagger.#FS
// FIXME: not yet implemented
*{
// Look for Dockerfile in source at default path
path: "Dockerfile"
} | {
// Look for Dockerfile in source at a custom path
path: string
} | {
// Custom dockerfile contents
contents: string
}
}

View file

@ -1,23 +0,0 @@
package docker
import (
"dagger.io/dagger"
)
// A container image
#Image: {
// Root filesystem of the image.
rootfs: dagger.#FS
// Image config
config: dagger.#ImageConfig
}
// A ref is an address for a remote container image
// Examples:
// - "index.docker.io/dagger"
// - "dagger"
// - "index.docker.io/dagger:latest"
// - "index.docker.io/dagger:latest@sha256:a89cb097693dd354de598d279c304a1c73ee550fbfff6d9ee515568e0c749cfe"
// FIXME: add formatting constraints
#Ref: dagger.#Ref

View file

@ -1,34 +0,0 @@
// Build, ship and run Docker containers in Dagger
package docker
import (
"dagger.io/dagger"
)
// Download an image from a remote registry
#Pull: {
// Source ref.
source: #Ref
// Registry authentication
auth?: {
username: string
secret: dagger.#Secret
}
_op: dagger.#Pull & {
"source": source
if auth != _|_ {
"auth": auth
}
}
// Downloaded image
image: #Image & {
rootfs: _op.output
config: _op.config
}
// FIXME: compat with Build API
output: image
}

View file

@ -1,32 +0,0 @@
package docker
import (
"dagger.io/dagger"
)
// Upload an image to a remote repository
#Push: {
// Destination ref
dest: #Ref
// Complete ref after pushing (including digest)
result: #Ref & _push.result
// Registry authentication
auth?: {
username: string
secret: dagger.#Secret
}
// Image to push
image: #Image
_push: dagger.#Push & {
"dest": dest
if auth != _|_ {
"auth": auth
}
input: image.rootfs
config: image.config
}
}

View file

@ -1,166 +0,0 @@
package docker
import (
"list"
"dagger.io/dagger"
)
// Run a command in a container
#Run: {
// Docker image to execute
input: #Image
always: bool | *false
// Filesystem mounts
mounts: [name=string]: dagger.#Mount
// Expose network ports
// FIXME: investigate feasibility
ports: [name=string]: {
frontend: dagger.#Service
backend: {
protocol: *"tcp" | "udp"
address: string
}
}
// Command to execute
command?: {
// Name of the command to execute
// Examples: "ls", "/bin/bash"
name: string
// Positional arguments to the command
// Examples: ["/tmp"]
args: [...string]
// Command-line flags represented in a civilized form
// Example: {"-l": true, "-c": "echo hello world"}
flags: [string]: (string | true)
_flatFlags: list.FlattenN([
for k, v in flags {
if (v & bool) != _|_ {
[k]
}
if (v & string) != _|_ {
[k, v]
}
},
], 1)
}
// Environment variables
// Example: {"DEBUG": "1"}
env: [string]: string | dagger.#Secret
// Working directory for the command
// Example: "/src"
workdir: string
// Username or UID to ad
// User identity for this command
// Examples: "root", "0", "1002"
user: string
// Output fields
{
// Has the command completed?
completed: bool & (_exec.exit != _|_)
// Was completion successful?
success: bool & (_exec.exit == 0)
// Details on error, if any
error: {
// Error code
code: _exec.exit
// Error message
message: string | *null
}
export: {
rootfs: dagger.#FS & _exec.output
files: [path=string]: string
_files: {
for path, _ in files {
"\(path)": {
contents: string & _read.contents
_read: dagger.#ReadFile & {
input: _exec.output
"path": path
}
}
}
}
for path, output in _files {
files: "\(path)": output.contents
}
directories: [path=string]: dagger.#FS
_directories: {
for path, _ in directories {
"\(path)": {
contents: dagger.#FS & _subdir.output
_subdir: dagger.#Subdir & {
input: _exec.output
"path": path
}
}
}
}
for path, output in _directories {
directories: "\(path)": output.contents
}
}
}
// For compatibility with #Build
output: #Image & {
rootfs: _exec.output
config: input.config
}
// Actually execute the command
_exec: dagger.#Exec & {
"input": input.rootfs
"always": always
"mounts": mounts
if command != _|_ {
args: [command.name] + command._flatFlags + command.args
}
if command == _|_ {
args: list.Concat([
if input.config.entrypoint != _|_ {
input.config.entrypoint
},
if input.config.cmd != _|_ {
input.config.cmd
},
])
}
"env": env
if input.config.env != _|_ {
for key, val in input.config.env {
if env[key] == _|_ {
env: "\(key)": val
}
}
}
"workdir": workdir
if workdir == _|_ && input.config.workdir != _|_ {
workdir: input.config.workdir
}
"user": user
if user == _|_ && input.config.user != _|_ {
user: input.config.user
}
}
// Command exit code
exit: _exec.exit
}

View file

@ -1,25 +0,0 @@
package docker
import (
"dagger.io/dagger"
)
// Change image config
#Set: {
// The source image
input: #Image
// The image config to change
config: dagger.#ImageConfig
_set: dagger.#Set & {
"input": input.config
"config": config
}
// Resulting image with the config changes
output: #Image & {
rootfs: input.rootfs
config: _set.output
}
}

View file

@ -1,119 +0,0 @@
package docker
import (
"dagger.io/dagger"
"universe.dagger.io/alpine"
"universe.dagger.io/docker"
)
dagger.#Plan & {
actions: tests: build: {
// Test: simple docker.#Build
simple: {
#testValue: "hello world"
image: docker.#Build & {
steps: [
alpine.#Build,
docker.#Run & {
command: {
name: "sh"
flags: "-c": "echo -n $TEST >> /test.txt"
}
env: TEST: #testValue
},
]
}
verify: dagger.#ReadFile & {
input: image.output.rootfs
path: "/test.txt"
}
verify: contents: #testValue
}
// Test: docker.#Build with multiple steps
multiSteps: {
image: docker.#Build & {
steps: [
alpine.#Build,
docker.#Run & {
command: {
name: "sh"
flags: "-c": "echo -n hello > /bar.txt"
}
},
docker.#Run & {
command: {
name: "sh"
flags: "-c": "echo -n $(cat /bar.txt) world > /foo.txt"
}
},
docker.#Run & {
command: {
name: "sh"
flags: "-c": "echo -n $(cat /foo.txt) >> /test.txt"
}
},
]
}
verify: dagger.#ReadFile & {
input: image.output.rootfs
path: "/test.txt"
}
verify: contents: "hello world"
}
// Test: simple nesting of docker.#Build
nested: {
build: docker.#Build & {
steps: [
docker.#Build & {
steps: [
docker.#Pull & {
source: "alpine"
},
docker.#Run & {
command: name: "ls"
},
]
},
docker.#Run & {
command: name: "ls"
},
]
}
}
// Test: nested docker.#Build with 3+ levels of depth
// FIXME: this test currently fails.
nestedDeep: {
// build: docker.#Build & {
// steps: [
// docker.#Build & {
// steps: [
// docker.#Build & {
// steps: [
// docker.#Pull & {
// source: "alpine"
// },
// docker.#Run & {
// command: name: "ls"
// },
// ]
// },
// docker.#Run & {
// command: name: "ls"
// },
// ]
// },
// docker.#Run & {
// command: name: "ls"
// },
// ]
// }
}
}
}

View file

@ -1,120 +0,0 @@
package docker
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
dagger.#Plan & {
actions: tests: image: {
// Test: change image config with docker.#Set
set: {
image: output: docker.#Image & {
rootfs: dagger.#Scratch
config: {
cmd: ["/bin/sh"]
env: PATH: "/sbin:/bin"
onbuild: ["COPY . /app"]
}
}
set: docker.#Set & {
input: image.output
config: {
env: FOO: "bar"
workdir: "/root"
onbuild: ["RUN /app/build.sh"]
}
}
verify: set.output.config & {
env: {
PATH: "/sbin:/bin"
FOO: "bar"
}
cmd: ["/bin/sh"]
workdir: "/root"
onbuild: [
"COPY . /app",
"RUN /app/build.sh",
]
}
}
// Test: image config behavior is correct
config: {
build: dagger.#Dockerfile & {
source: dagger.#Scratch
dockerfile: contents: """
FROM alpine:3.15.0
RUN echo -n 'not hello from dagger' > /dagger.txt
RUN echo '#!/bin/sh' > /bin/dagger
ENV HELLO_FROM=dagger
RUN echo 'echo -n "hello from $HELLO_FROM" > /dagger.txt' >> /bin/dagger
RUN chmod +x /bin/dagger
WORKDIR /bin
CMD /bin/dagger
"""
}
myimage: docker.#Image & {
rootfs: build.output
config: build.config
}
run: docker.#Run & {
input: myimage
command: name: "ls"
export: files: {
"/dagger.txt": _ & {
contents: "not hello from dagger"
}
"/bin/dagger": _ & {
contents: """
#!/bin/sh
echo -n "hello from $HELLO_FROM" > /dagger.txt
"""
}
}
}
verify_cmd_is_run: docker.#Run & {
input: myimage
export: files: "/dagger.txt": _ & {
contents: "hello from dagger"
}
}
verify_env_is_overridden: docker.#Run & {
input: myimage
export: files: "/dagger.txt": _ & {
contents: "hello from europa"
}
env: HELLO_FROM: "europa"
}
verify_working_directory: docker.#Run & {
input: myimage
command: {
name: "sh"
flags: "-c": #"""
pwd > dir.txt
"""#
}
export: files: "/bin/dir.txt": _ & {
contents: "/bin\n"
}
}
verify_working_directory_is_overridden: docker.#Run & {
input: myimage
workdir: "/"
command: {
name: "sh"
flags: "-c": #"""
pwd > dir.txt
"""#
}
export: files: "/dir.txt": _ & {
contents: "/\n"
}
}
}
}
}

View file

@ -1,69 +0,0 @@
package docker
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
"universe.dagger.io/alpine"
)
dagger.#Plan & {
actions: tests: run: {
_build: alpine.#Build
_image: _build.output
// Test: run a simple shell command
simpleShell: {
image: alpine.#Build
run: docker.#Run & {
input: _image
command: {
name: "/bin/sh"
args: ["-c", "echo -n hello world >> /output.txt"]
}
}
verify: dagger.#ReadFile & {
input: run.output.rootfs
path: "/output.txt"
}
verify: contents: "hello world"
}
// Test: export a file
exportFile: {
run: docker.#Run & {
input: _image
command: {
name: "sh"
flags: "-c": #"""
echo -n hello world >> /output.txt
"""#
}
export: files: "/output.txt": string & "hello world"
}
}
// Test: export a directory
exportDirectory: {
run: docker.#Run & {
input: _image
command: {
name: "sh"
flags: "-c": #"""
mkdir -p /test
echo -n hello world >> /test/output.txt
"""#
}
export: directories: "/test": _
}
verify: dagger.#ReadFile & {
input: run.export.directories."/test"
path: "/output.txt"
}
verify: contents: "hello world"
}
}
}

View file

@ -1,9 +0,0 @@
setup() {
load '../../bats_helpers'
common_setup
}
@test "docker" {
dagger up
}

View file

@ -1,3 +0,0 @@
## Dagger examples
A collection of examples to help Dagger developers get started.

View file

@ -1,101 +0,0 @@
package changelog
actions: {
// Reuse in all mix commands
// prod: assets: docker.#Build & {
// steps: [
// // 1. Start from dev assets :)
// dev.assets,
// // 2. Mix magical command
// mix.#Run & {
// script: "mix phx.digest"
// mix: {
// env: "prod"
// app: _appName
// depsCache: "private"
// buildCache: "private"
// }
// workdir: _
// // FIXME: remove copy-pasta
// mounts: nodeModules: {
// contents: dagger.#CacheDir & {
// // FIXME: do we need an ID here?
// id: "\(mix.app)_assets_node_modules"
// // FIXME: does this command need write access to node_modules cache?
// concurrency: "private"
// }
// dest: "\(workdir)/node_modules"
// }
// },
// ]
// }
// dev: {
// compile: mix.#Compile & {
// env: "dev"
// app: "thechangelog"
// base: inputs.params.runtimeImage
// source: inputs.directories.app.contents
// }
// assets: docker.#Build & {
// steps: [
// // 1. Start from dev runtime build
// {
// output: build.output
// },
// // 2. Build web assets
// mix.#Run & {
// mix: {
// env: "dev"
// app: _appName
// depsCache: "private"
// buildCache: "private"
// }
// // FIXME: move this to a reusable def (yarn package? or private?)
// mounts: nodeModules: {
// contents: dagger.#CacheDir & {
// // FIXME: do we need an ID here?
// id: "\(mix.app)_assets_node_modules"
// // FIXME: will there be multiple writers?
// concurrency: "locked"
// }
// dest: "\(workdir)/node_modules"
// }
// // FIXME: run 'yarn install' and 'yarn run compile' separately, with different caching?
// // FIXME: can we reuse universe.dagger.io/yarn ???? 0:-)
// script: "yarn install --frozen-lockfile && yarn run compile"
// workdir: "/app/assets"
// },
// ]
// }
// }
// test: {
// build: mix.#Build & {
// env: "test"
// app: _appName
// base: inputs.params.runtimeImage
// source: inputs.directories.app.contents
// }
// // Run tests
// run: docker.#Run & {
// image: build.output
// script: "mix test"
// }
// db: {
// // Pull test DB image
// pull: docker.#Pull & {
// source: inputs.params.test_db_image
// }
// // Run test DB
// // FIXME: kill once no longer needed (when tests are done running)
// run: docker.#Run & {
// image: pull.output
// }
// }
// }
}

View file

@ -1,87 +0,0 @@
package mix
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
#Get: #Run & {
// Applies to all environments
env: null
cache: {
build: null
deps: "locked"
}
container: command: {
name: "sh"
flags: "-c": "mix do deps.get"
}
}
// Compile Elixir dependencies, including the app
#Compile: #Run & {
cache: {
build: "locked"
deps: "locked"
}
container: command: {
name: "sh"
flags: "-c": "mix do deps.compile, compile"
}
}
// Run mix task with all necessary mounts so compiled artefacts get cached
// FIXME: add default image to hexpm/elixir:1.13.2-erlang-23.3.4.11-debian-bullseye-20210902
#Run: {
app: {
// Application name
name: string
// Application source code
source: dagger.#FS
}
// Mix environment
env: string | null
// Configure mix caching
// FIXME: simpler interface, eg. "ro" | "rw"
cache: {
// Dependencies cache
deps: null | "locked"
// Build cache
build: null | "locked"
}
// Run mix in a docker container
container: docker.#Run & {
if env != null {
"env": MIX_ENV: env
}
workdir: mounts.app.dest
mounts: "app": {
contents: app.source
dest: "/mix/app"
}
if cache.deps != null {
mounts: deps: {
contents: dagger.#CacheDir & {
id: "\(app.name)_deps"
concurrency: cache.deps
}
dest: "\(mounts.app.dest)/deps"
}
}
if cache.build != null {
mounts: buildCache: {
contents: dagger.#CacheDir & {
id: "\(app.name)_build_\(env)"
concurrency: cache.build
}
dest: "\(mounts.app.dest)/_build/\(env)"
}
}
}
}

View file

@ -1,9 +0,0 @@
package changelog
import (
"dagger.io/dagger"
)
dagger.#Plan & {
inputs: directories: app: path: "/Users/gerhard/github.com/thechangelog/changelog.com/"
}

View file

@ -1,83 +0,0 @@
package changelog
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
"universe.dagger.io/git"
"universe.dagger.io/examples/changelog.com/elixir/mix"
)
dagger.#Plan & {
// Receive things from client
inputs: {
directories: {
// App source code
app?: _
}
secrets: {
// Docker ID password
docker: _
}
params: {
app: {
// App name
name: string | *"changelog"
// Address of app base image
image: docker.#Ref | *"thechangelog/runtime:2021-05-29T10.17.12Z"
}
test: {
// Address of test db image
db: image: docker.#Ref | *"circleci/postgres:12.6"
}
}
}
// Do things
actions: {
app: {
name: inputs.params.app.name
// changelog.com source code
source: dagger.#FS
if inputs.directories.app != _|_ {
source: inputs.directories.app.contents
}
if inputs.directories.app == _|_ {
fetch: git.#Pull & {
remote: "https://github.com/thechangelog/changelog.com"
ref: "master"
}
source: fetch.output
}
// Assemble base image
base: docker.#Pull & {
source: inputs.params.app.image
}
image: base.output
// Download Elixir dependencies
deps: mix.#Get & {
app: {
"name": name
"source": source
}
container: "image": image
}
// Compile dev environment
dev: mix.#Compile & {
env: "dev"
app: {
"name": name
"source": source
}
container: "image": image
}
}
}
}

View file

@ -1,3 +0,0 @@
# Todo APP
[Dagger documentation website](https://docs.dagger.io/)

View file

@ -1,94 +0,0 @@
package netlify
import (
"dagger.io/dagger"
"universe.dagger.io/alpine"
"universe.dagger.io/bash"
"universe.dagger.io/docker"
"universe.dagger.io/netlify"
)
dagger.#Plan & {
client: {
filesystem: {
".": read: {
contents: dagger.#FS
exclude: [
"README.md",
"build",
"netlify.cue",
"node_modules",
]
}
build: write: contents: actions.build.contents.output
}
env: {
APP_NAME: string
NETLIFY_TEAM: string
NETLIFY_TOKEN: dagger.#Secret
}
}
actions: {
deps: docker.#Build & {
steps: [
alpine.#Build & {
packages: {
bash: {}
yarn: {}
git: {}
}
},
docker.#Copy & {
contents: client.filesystem.".".read.contents
dest: "/src"
},
// bash.#Run is a superset of docker.#Run
// install yarn dependencies
bash.#Run & {
workdir: "/src"
mounts: "/cache/yarn": dagger.#Mount & {
dest: "/cache/yarn"
type: "cache"
contents: dagger.#CacheDir & {
id: "todoapp-yarn-cache"
}
}
script: contents: #"""
yarn config set cache-folder /cache/yarn
yarn install
"""#
},
]
}
test: bash.#Run & {
input: deps.output
workdir: "/src"
script: contents: #"""
yarn run test
"""#
}
build: {
run: bash.#Run & {
input: test.output
workdir: "/src"
script: contents: #"""
yarn run build
"""#
}
contents: dagger.#Subdir & {
input: run.output.rootfs
path: "/src/build"
}
}
deploy: netlify.#Deploy & {
contents: build.contents.output
site: client.env.APP_NAME
token: client.env.NETLIFY_TOKEN
team: client.env.NETLIFY_TEAM
}
}
}

View file

@ -1,38 +0,0 @@
{
"name": "moz-todo-react",
"version": "0.1.0",
"private": true,
"homepage": "./",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"gh-pages": "^3.2.3",
"nanoid": "^3.1.31",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --watchAll=false --passWithNoTests",
"gh-pages": "gh-pages -d build -u 'github-actions-bot <support+actions@github.com>'",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>My Todo app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View file

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View file

@ -1,120 +0,0 @@
import React, { useState, useRef, useEffect } from "react";
import Form from "./components/Form";
import FilterButton from "./components/FilterButton";
import Todo from "./components/Todo";
import { nanoid } from "nanoid";
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const FILTER_MAP = {
All: () => true,
Active: task => !task.completed,
Completed: task => task.completed
};
const FILTER_NAMES = Object.keys(FILTER_MAP);
function App(props) {
const [tasks, setTasks] = useState(props.tasks);
const [filter, setFilter] = useState('All');
function toggleTaskCompleted(id) {
const updatedTasks = tasks.map(task => {
// if this task has the same ID as the edited task
if (id === task.id) {
// use object spread to make a new obkect
// whose `completed` prop has been inverted
return {...task, completed: !task.completed}
}
return task;
});
setTasks(updatedTasks);
}
function deleteTask(id) {
const remainingTasks = tasks.filter(task => id !== task.id);
setTasks(remainingTasks);
}
function editTask(id, newName) {
const editedTaskList = tasks.map(task => {
// if this task has the same ID as the edited task
if (id === task.id) {
//
return {...task, name: newName}
}
return task;
});
setTasks(editedTaskList);
}
const taskList = tasks
.filter(FILTER_MAP[filter])
.map(task => (
<Todo
id={task.id}
name={task.name}
completed={task.completed}
key={task.id}
toggleTaskCompleted={toggleTaskCompleted}
deleteTask={deleteTask}
editTask={editTask}
/>
));
const filterList = FILTER_NAMES.map(name => (
<FilterButton
key={name}
name={name}
isPressed={name === filter}
setFilter={setFilter}
/>
));
function addTask(name) {
const newTask = { id: "todo-" + nanoid(), name: name, completed: false };
setTasks([...tasks, newTask]);
}
const tasksNoun = taskList.length !== 1 ? 'tasks' : 'task';
const headingText = `${taskList.length} ${tasksNoun} remaining`;
const listHeadingRef = useRef(null);
const prevTaskLength = usePrevious(tasks.length);
useEffect(() => {
if (tasks.length - prevTaskLength === -1) {
listHeadingRef.current.focus();
}
}, [tasks.length, prevTaskLength]);
return (
<div className="todoapp stack-large">
<Form addTask={addTask} />
<div className="filters btn-group stack-exception">
{filterList}
</div>
<h2 id="list-heading" tabIndex="-1" ref={listHeadingRef}>
{headingText}
</h2>
<ul
className="todo-list stack-large stack-exception"
aria-labelledby="list-heading"
>
{taskList}
</ul>
</div>
);
}
export default App;

View file

@ -1,18 +0,0 @@
import React from "react";
function FilterButton(props) {
return (
<button
type="button"
className="btn toggle-btn"
aria-pressed={props.isPressed}
onClick={() => props.setFilter(props.name)}
>
<span className="visually-hidden">Show </span>
<span>{props.name}</span>
<span className="visually-hidden"> tasks</span>
</button>
);
}
export default FilterButton;

View file

@ -1,45 +0,0 @@
import React, { useState } from "react";
function Form(props) {
const [name, setName] = useState('');
function handleSubmit(e) {
e.preventDefault();
if (!name.trim()) {
return;
}
props.addTask(name);
setName("");
}
function handleChange(e) {
setName(e.target.value);
}
return (
<form onSubmit={handleSubmit}>
<h2 className="label-wrapper">
<label htmlFor="new-todo-input" className="label__lg">
What needs to be done?
</label>
</h2>
<input
type="text"
id="new-todo-input"
className="input input__lg"
name="text"
autoComplete="off"
value={name}
onChange={handleChange}
/>
<button type="submit" className="btn btn__primary btn__lg">
Add
</button>
</form>
);
}
export default Form;

View file

@ -1,113 +0,0 @@
import React, { useEffect, useRef, useState } from "react";
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
export default function Todo(props) {
const [isEditing, setEditing] = useState(false);
const [newName, setNewName] = useState('');
const editFieldRef = useRef(null);
const editButtonRef = useRef(null);
const wasEditing = usePrevious(isEditing);
function handleChange(e) {
setNewName(e.target.value);
}
function handleSubmit(e) {
e.preventDefault();
if (!newName.trim()) {
return;
}
props.editTask(props.id, newName);
setNewName("");
setEditing(false);
}
const editingTemplate = (
<form className="stack-small" onSubmit={handleSubmit}>
<div className="form-group">
<label className="todo-label" htmlFor={props.id}>
New name for {props.name}
</label>
<input
id={props.id}
className="todo-text"
type="text"
value={newName || props.name}
onChange={handleChange}
ref={editFieldRef}
/>
</div>
<div className="btn-group">
<button
type="button"
className="btn todo-cancel"
onClick={() => setEditing(false)}
>
Cancel
<span className="visually-hidden">renaming {props.name}</span>
</button>
<button type="submit" className="btn btn__primary todo-edit">
Save
<span className="visually-hidden">new name for {props.name}</span>
</button>
</div>
</form>
);
const viewTemplate = (
<div className="stack-small">
<div className="c-cb">
<input
id={props.id}
type="checkbox"
defaultChecked={props.completed}
onChange={() => props.toggleTaskCompleted(props.id)}
/>
<label className="todo-label" htmlFor={props.id}>
{props.name}
</label>
</div>
<div className="btn-group">
<button
type="button"
className="btn"
onClick={() => setEditing(true)}
ref={editButtonRef}
>
Edit <span className="visually-hidden">{props.name}</span>
</button>
<button
type="button"
className="btn btn__danger"
onClick={() => props.deleteTask(props.id)}
>
Delete <span className="visually-hidden">{props.name}</span>
</button>
</div>
</div>
);
useEffect(() => {
if (!wasEditing && isEditing) {
editFieldRef.current.focus();
}
if (wasEditing && !isEditing) {
editButtonRef.current.focus();
}
}, [wasEditing, isEditing]);
return <li className="todo">{isEditing ? editingTemplate : viewTemplate}</li>;
}

View file

@ -1,293 +0,0 @@
/* RESETS */
*,
*::before,
*::after {
box-sizing: border-box;
}
*:focus {
outline: 3px dashed #228bec;
outline-offset: 0;
}
html {
font: 62.5% / 1.15 sans-serif;
}
h1,
h2 {
margin-bottom: 0;
}
ul {
list-style: none;
padding: 0;
}
button {
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
color: inherit;
font: inherit;
line-height: normal;
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
-webkit-appearance: none;
}
button::-moz-focus-inner {
border: 0;
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
button,
input {
overflow: visible;
}
input[type="text"] {
border-radius: 0;
}
body {
width: 100%;
max-width: 68rem;
margin: 0 auto;
font: 1.6rem/1.25 Arial, sans-serif;
background-color: #f5f5f5;
color: #4d4d4d;
}
@media screen and (min-width: 620px) {
body {
font-size: 1.9rem;
line-height: 1.31579;
}
}
/*END RESETS*/
/* GLOBAL STYLES */
.form-group > input[type="text"] {
display: inline-block;
margin-top: 0.4rem;
}
.btn {
padding: 0.8rem 1rem 0.7rem;
border: 0.2rem solid #4d4d4d;
cursor: pointer;
text-transform: capitalize;
}
.btn.toggle-btn {
border-width: 1px;
border-color: #d3d3d3;
}
.btn.toggle-btn[aria-pressed="true"] {
text-decoration: underline;
border-color: #4d4d4d;
}
.btn__danger {
color: #fff;
background-color: #ca3c3c;
border-color: #bd2130;
}
.btn__filter {
border-color: lightgrey;
}
.btn__primary {
color: #fff;
background-color: #000;
}
.btn-group {
display: flex;
justify-content: space-between;
}
.btn-group > * {
flex: 1 1 49%;
}
.btn-group > * + * {
margin-left: 0.8rem;
}
.label-wrapper {
margin: 0;
flex: 0 0 100%;
text-align: center;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
[class*="stack"] > * {
margin-top: 0;
margin-bottom: 0;
}
.stack-small > * + * {
margin-top: 1.25rem;
}
.stack-large > * + * {
margin-top: 2.5rem;
}
@media screen and (min-width: 550px) {
.stack-small > * + * {
margin-top: 1.4rem;
}
.stack-large > * + * {
margin-top: 2.8rem;
}
}
.stack-exception {
margin-top: 1.2rem;
}
/* END GLOBAL STYLES */
.todoapp {
background: #fff;
margin: 2rem 0 4rem 0;
padding: 1rem;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}
@media screen and (min-width: 550px) {
.todoapp {
padding: 4rem;
}
}
.todoapp > * {
max-width: 50rem;
margin-left: auto;
margin-right: auto;
}
.todoapp > form {
max-width: 100%;
}
.todoapp > h1 {
display: block;
max-width: 100%;
text-align: center;
margin: 0;
margin-bottom: 1rem;
}
.label__lg {
line-height: 1.01567;
font-weight: 300;
padding: 0.8rem;
margin-bottom: 1rem;
text-align: center;
}
.input__lg {
padding: 2rem;
border: 2px solid #000;
}
.input__lg:focus {
border-color: #4d4d4d;
box-shadow: inset 0 0 0 2px;
}
[class*="__lg"] {
display: inline-block;
width: 100%;
font-size: 1.9rem;
}
[class*="__lg"]:not(:last-child) {
margin-bottom: 1rem;
}
@media screen and (min-width: 620px) {
[class*="__lg"] {
font-size: 2.4rem;
}
}
.filters {
width: 100%;
margin: unset auto;
}
/* Todo item styles */
.todo {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.todo > * {
flex: 0 0 100%;
}
.todo-text {
width: 100%;
min-height: 4.4rem;
padding: 0.4rem 0.8rem;
border: 2px solid #565656;
}
.todo-text:focus {
box-shadow: inset 0 0 0 2px;
}
/* CHECKBOX STYLES */
.c-cb {
box-sizing: border-box;
font-family: Arial, sans-serif;
-webkit-font-smoothing: antialiased;
font-weight: 400;
font-size: 1.6rem;
line-height: 1.25;
display: block;
position: relative;
min-height: 44px;
padding-left: 40px;
clear: left;
}
.c-cb > label::before,
.c-cb > input[type="checkbox"] {
box-sizing: border-box;
top: -2px;
left: -2px;
width: 44px;
height: 44px;
}
.c-cb > input[type="checkbox"] {
-webkit-font-smoothing: antialiased;
cursor: pointer;
position: absolute;
z-index: 1;
margin: 0;
opacity: 0;
}
.c-cb > label {
font-size: inherit;
font-family: inherit;
line-height: inherit;
display: inline-block;
margin-bottom: 0;
padding: 8px 15px 5px;
cursor: pointer;
touch-action: manipulation;
}
.c-cb > label::before {
content: "";
position: absolute;
border: 2px solid currentColor;
background: transparent;
}
.c-cb > input[type="checkbox"]:focus + label::before {
border-width: 4px;
outline: 3px dashed #228bec;
}
.c-cb > label::after {
box-sizing: content-box;
content: "";
position: absolute;
top: 11px;
left: 9px;
width: 18px;
height: 7px;
transform: rotate(-45deg);
border: solid;
border-width: 0 0 5px 5px;
border-top-color: transparent;
opacity: 0;
background: transparent;
}
.c-cb > input[type="checkbox"]:checked + label::after {
opacity: 1;
}

View file

@ -1,18 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
const DATA = [
{ id: "todo-0", name: "Eat", completed: true },
{ id: "todo-1", name: "Sleep", completed: false },
{ id: "todo-2", name: "Repeat", completed: false }
];
ReactDOM.render(
<React.StrictMode>
<App tasks={DATA} />
</React.StrictMode>,
document.getElementById('root')
);

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
package git
import (
)
#Pull: dagger.#GitPull
#Push: dagger.#GitPush

View file

@ -1,51 +0,0 @@
package go
import (
"dagger.io/dagger"
)
// Build a go binary
#Build: {
// Source code
source: dagger.#FS
// Target package to build
package: *"." | string
// Target architecture
arch: *"amd64" | string
// Target OS
os: *"linux" | string
// Build tags to use for building
tags: *"" | string
// LDFLAGS to use for linking
ldflags: *"" | string
env: [string]: string
container: #Container & {
"source": source
"env": {
env
GOOS: os
GOARCH: arch
}
command: {
args: [package]
flags: {
build: true
"-v": true
"-tags": tags
"-ldflags": ldflags
"-o": "/output/"
}
}
export: directories: "/output": _
}
// Directory containing the output of the build
output: container.export.directories."/output"
}

View file

@ -1,41 +0,0 @@
// Go operation
package go
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
// A standalone go environment to run go command
#Container: {
// Container app name
name: *"go_builder" | string
// Source code
source: dagger.#FS
// Use go image
_image: #Image
_sourcePath: "/src"
_cachePath: "/root/.cache/gocache"
docker.#Run & {
input: *_image.output | docker.#Image
workdir: "/src"
command: name: "go"
mounts: {
"source": {
dest: _sourcePath
contents: source
}
"go assets cache": {
contents: dagger.#CacheDir & {
id: "\(name)_assets"
}
dest: _cachePath
}
}
env: GOMODCACHE: _cachePath
}
}

View file

@ -1,37 +0,0 @@
package go
import (
"universe.dagger.io/docker"
)
// Go image default version
#DefaultVersion: "1.16"
// Build a go base image
#Image: {
version: *#DefaultVersion | string
packages: [pkgName=string]: version: string | *""
// FIXME Basically a copy of alpine.#Build with a different image
// Should we create a special definition?
docker.#Build & {
steps: [
docker.#Pull & {
source: "index.docker.io/golang:\(version)-alpine"
},
for pkgName, pkg in packages {
docker.#Run & {
command: {
name: "apk"
args: ["add", "\(pkgName)\(pkg.version)"]
flags: {
"-U": true
"--no-cache": true
}
}
}
},
]
}
}

View file

@ -1,17 +0,0 @@
package go
// Test a go package
#Test: {
// Package to test
package: *"." | string
#Container & {
command: {
args: [package]
flags: {
test: true
"-v": true
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more