├── .gitignore ├── .fluentci ├── .gitignore ├── .vscode │ └── settings.json ├── mod.ts ├── src │ ├── dagger │ │ ├── runner.ts │ │ ├── index.ts │ │ ├── list_jobs.ts │ │ ├── pipeline.ts │ │ └── jobs.ts │ ├── gitlab │ │ ├── init.ts │ │ ├── config_test.ts │ │ └── config.ts │ └── github │ │ ├── init.ts │ │ ├── config_test.ts │ │ ├── config.ts │ │ └── README.md ├── ci.ts ├── deno.json ├── flake.nix ├── fixtures │ └── workflow.yml ├── LICENSE ├── .devcontainer │ └── devcontainer.json ├── import_map.json ├── flake.lock ├── README.md ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md └── deno.lock ├── .vscode └── settings.json ├── fixtures ├── Code-Quality.gitlab-ci.yml ├── Deploy-ECS.gitlab-ci.yml ├── Clojure.gitlab-ci.yml ├── Elixir.gitlab-ci.yml ├── Go.gitlab-ci.yml ├── Terraform.latest.gitlab-ci.yml ├── Composer.gitlab-ci.yml ├── C++.gitlab-ci.yml ├── Gradle.gitlab-ci.yml ├── Nodejs.gitlab-ci.yml ├── Bash.gitlab-ci.yml ├── Flutter.gitlab-ci.yml ├── Docker.gitlab-ci.yml ├── Scala.gitlab-ci.yml ├── Crystal.gitlab-ci.yml ├── Swift.gitlab-ci.yml ├── Python.gitlab-ci.yml ├── Getting-Started.gitlab-ci.yml ├── Chef.gitlab-ci.yml ├── Rust.gitlab-ci.yml ├── Ruby.gitlab-ci.yml ├── Grails.gitlab-ci.yml ├── Android.latest.gitlab-ci.yml ├── Dart.gitlab-ci.yml ├── Android.gitlab-ci.yml ├── Django.gitlab-ci.yml ├── Kaniko.gitlab-ci.yml ├── 5-Minute-Production-App.gitlab-ci.yml ├── Katalon.gitlab-ci.yml ├── Laravel.gitlab-ci.yml ├── Indeni.Cloudrail.gitlab-ci.yml ├── Julia.gitlab-ci.yml ├── Android-Fastlane.gitlab-ci.yml └── Auto-DevOps.gitlab-ci.yml ├── mod.ts ├── deps.ts ├── src ├── index.ts ├── environment.ts ├── gitlabci.ts ├── job.ts └── gitlabci_spec.ts ├── examples ├── Rust.ts ├── Elixir.ts ├── Nodejs.ts ├── Gradle.ts ├── Go.ts ├── Scala.ts ├── Docker.ts ├── Clojure.ts ├── Ruby.ts ├── demo.ts ├── Python.ts ├── Django.ts ├── C++.ts ├── Swift.ts ├── Flutter.ts ├── Laravel.ts ├── Crystal.ts ├── Getting-Started.ts ├── Chef.ts ├── Android.latest.ts ├── Android.ts ├── Dart.ts ├── 5-Minute-Production-App.ts ├── Android-Fastlane.ts └── Auto-DevOps.ts ├── flake.nix ├── deno.json ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── .devcontainer └── devcontainer.json ├── README.md ├── flake.lock ├── CONTRIBUTING.md ├── deno.lock └── CODE_OF_CONDUCT.md /.gitignore: -------------------------------------------------------------------------------- 1 | .gitlab-ci.yml -------------------------------------------------------------------------------- /.fluentci/.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | coverage.lcov -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true 3 | } -------------------------------------------------------------------------------- /.fluentci/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true 3 | } 4 | -------------------------------------------------------------------------------- /.fluentci/mod.ts: -------------------------------------------------------------------------------- 1 | import * as Dagger from "./src/dagger/index.ts"; 2 | 3 | export { Dagger }; 4 | -------------------------------------------------------------------------------- /fixtures/Code-Quality.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | template: Jobs/Code-Quality.gitlab-ci.yml 3 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/runner.ts: -------------------------------------------------------------------------------- 1 | import pipeline from "./pipeline.ts"; 2 | 3 | pipeline(".", Deno.args); 4 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().write(); 4 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job, Environment } from "./src/index.ts"; 2 | 3 | export { GitlabCI, Job, Environment }; 4 | -------------------------------------------------------------------------------- /.fluentci/src/github/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().save(".github/workflows/ci.yml"); 4 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/index.ts: -------------------------------------------------------------------------------- 1 | import pipeline from "./pipeline.ts"; 2 | import { fmt, lint, test } from "./jobs.ts"; 3 | 4 | export { fmt, lint, pipeline, test }; 5 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export { assertEquals } from "jsr:@std/testing@0.217.0/asserts"; 2 | export { stringify } from "npm:yaml@2.3.1"; 3 | export { z } from "npm:zod@3.22.1"; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import GitlabCI from "./gitlabci.ts"; 2 | import Job from "./job.ts"; 3 | import Environment from "./environment.ts"; 4 | 5 | export { GitlabCI, Job, Environment }; 6 | -------------------------------------------------------------------------------- /.fluentci/ci.ts: -------------------------------------------------------------------------------- 1 | const command = new Deno.Command(Deno.execPath(), { 2 | args: [ 3 | "run", 4 | "-A", 5 | "--import-map=https://deno.land/x/deno_pipeline/import_map.json", 6 | "https://deno.land/x/deno_pipeline/src/dagger/runner.ts", 7 | ], 8 | }); 9 | 10 | const { stdout } = await command.output(); 11 | 12 | console.log(new TextDecoder().decode(stdout)); 13 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateGitlabCITest() { 5 | const gitlabci = generateYaml(); 6 | const actual = gitlabci.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/.gitlab-ci.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/github/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateGithubActionsWorkflowTest() { 5 | const workflow = generateYaml(); 6 | const actual = workflow.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/workflow.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": "import_map.json", 3 | "tasks": { 4 | "esm:add": "deno run -A https://esm.sh/v128 add", 5 | "esm:update": "deno run -A https://esm.sh/v128 update", 6 | "esm:remove": "deno run -A https://esm.sh/v128 remove" 7 | }, 8 | "fmt": { 9 | "exclude": ["example/", ".fluentci/"] 10 | }, 11 | "lint": { 12 | "exclude": ["example/", ".fluentci/"] 13 | }, 14 | "test": { 15 | "exclude": ["example/", ".fluentci/"] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/Rust.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const test = new Job().script(` 4 | rustc --version && cargo --version 5 | cargo test --workspace --verbose 6 | `); 7 | 8 | const deploy = new Job() 9 | .stage("deploy") 10 | .script('echo "Define your deployment script!"') 11 | .environment("production"); 12 | 13 | const gitlabci = new GitlabCI() 14 | .image("rust:latest") 15 | .addJob("test:cargo", test) 16 | .addJob("deploy", deploy); 17 | 18 | console.log(gitlabci.toString()); 19 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/config.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "fluent_gitlab_ci"; 2 | 3 | export function generateYaml(): GitlabCI { 4 | const setupDagger = ` 5 | deno install -A -r https://cli.fluentci.io -n fluentci 6 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 7 | sudo mv bin/dagger /usr/local/bin 8 | dagger version`; 9 | 10 | const tests = new Job() 11 | .beforeScript(setupDagger, { 12 | multiline: true, 13 | }) 14 | .script("dagger run fluentci deno_pipeline fmt lint test"); 15 | 16 | return new GitlabCI().addJob("tests", tests); 17 | } 18 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A Nix-flake-based Deno development environment"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/release-23.05"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = { 10 | self, 11 | nixpkgs, 12 | flake-utils, 13 | }: 14 | flake-utils.lib.eachDefaultSystem 15 | (system: let 16 | pkgs = import nixpkgs { 17 | inherit system; 18 | }; 19 | in { 20 | devShells.default = pkgs.mkShell { 21 | buildInputs = [ 22 | pkgs.deno 23 | ]; 24 | }; 25 | }); 26 | } -------------------------------------------------------------------------------- /examples/Elixir.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const mix = new Job().script("mix test"); 4 | 5 | const deploy = new Job() 6 | .stage("deploy") 7 | .script('echo "Define your deployment script!"') 8 | .environment("production"); 9 | 10 | const gitlabci = new GitlabCI() 11 | .image("elixir:latest") 12 | .services(["redis:latest", "postgres:latest"]) 13 | .beforeScript( 14 | ` 15 | mix local.rebar --force 16 | mix local.hex --force 17 | mix deps.get 18 | ` 19 | ) 20 | .addJob("mix", mix) 21 | .addJob("deploy", deploy); 22 | 23 | console.log(gitlabci.toString()); 24 | -------------------------------------------------------------------------------- /.fluentci/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A Nix-flake-based Deno development environment"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/release-23.05"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = { 10 | self, 11 | nixpkgs, 12 | flake-utils, 13 | }: 14 | flake-utils.lib.eachDefaultSystem 15 | (system: let 16 | pkgs = import nixpkgs { 17 | inherit system; 18 | }; 19 | in { 20 | devShells.default = pkgs.mkShell { 21 | buildInputs = [ 22 | pkgs.deno 23 | ]; 24 | }; 25 | }); 26 | } -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tsirysndr/fluent-gitlab-ci", 3 | "version": "0.5.0", 4 | "exports": "./mod.ts", 5 | "tasks": { 6 | "esm:add": "deno run -A https://esm.sh/v128 add", 7 | "esm:update": "deno run -A https://esm.sh/v128 update", 8 | "esm:remove": "deno run -A https://esm.sh/v128 remove" 9 | }, 10 | "fmt": { 11 | "exclude": [ 12 | "example/", 13 | ".fluentci/" 14 | ] 15 | }, 16 | "lint": { 17 | "exclude": [ 18 | "example/", 19 | ".fluentci/" 20 | ] 21 | }, 22 | "test": { 23 | "exclude": [ 24 | "example/", 25 | ".fluentci/" 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /.fluentci/src/dagger/list_jobs.ts: -------------------------------------------------------------------------------- 1 | import { brightGreen } from "https://deno.land/std@0.191.0/fmt/colors.ts"; 2 | import { runnableJobs, jobDescriptions, Job } from "./jobs.ts"; 3 | import { stringifyTree } from "https://esm.sh/stringify-tree@1.1.1"; 4 | 5 | const tree = { 6 | name: brightGreen("deno_pipeline"), 7 | children: (Object.keys(runnableJobs) as Job[]).map((job) => ({ 8 | name: jobDescriptions[job] 9 | ? `${brightGreen(job)} - ${jobDescriptions[job]}` 10 | : brightGreen(job), 11 | children: [], 12 | })), 13 | }; 14 | 15 | console.log( 16 | stringifyTree( 17 | tree, 18 | (t) => t.name, 19 | (t) => t.children 20 | ) 21 | ); 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by Fluent Github Actions 2 | 3 | name: Tests 4 | on: 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | branches: 10 | - master 11 | jobs: 12 | tests: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup Fluent CI CLI 17 | uses: fluentci-io/setup-fluentci@v4 18 | - name: Run Dagger Pipelines 19 | run: fluentci run deno_pipeline fmt test 20 | - name: Upload to Codecov 21 | run: fluentci run codecov_pipeline 22 | env: 23 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 24 | -------------------------------------------------------------------------------- /examples/Nodejs.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const testAsync = new Job().script(` 4 | npm install 5 | node ./specs/start.js ./specs/async.spec.js 6 | `); 7 | 8 | const testDb = new Job().script(` 9 | npm install 10 | node ./specs/start.js ./specs/db-postgres.spec.js 11 | `); 12 | 13 | const deploy = new Job() 14 | .stage("deploy") 15 | .script('echo "Define your deployment script!"') 16 | .environment("production"); 17 | 18 | const gitlabci = new GitlabCI() 19 | .image("node:latest") 20 | .services(["mysql:latest", "redis:latest", "postgres:latest"]) 21 | .cache(["node_modules/"]) 22 | .addJob("test_async", testAsync) 23 | .addJob("test_db", testDb) 24 | .addJob("deploy", deploy); 25 | 26 | console.log(gitlabci.toString()); 27 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/pipeline.ts: -------------------------------------------------------------------------------- 1 | import Client, { connect } from "@dagger.io/dagger"; 2 | import * as jobs from "./jobs.ts"; 3 | 4 | const { fmt, lint, test, runnableJobs } = jobs; 5 | 6 | export default function pipeline(src = ".", args: string[] = []) { 7 | connect(async (client: Client) => { 8 | if (args.length > 0) { 9 | await runSpecificJobs(client, args as jobs.Job[]); 10 | return; 11 | } 12 | 13 | await fmt(client, src); 14 | await lint(client, src); 15 | await test(client, src); 16 | }); 17 | } 18 | 19 | async function runSpecificJobs(client: Client, args: jobs.Job[]) { 20 | for (const name of args) { 21 | const job = runnableJobs[name]; 22 | if (!job) { 23 | throw new Error(`Job ${name} not found`); 24 | } 25 | await job(client); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.fluentci/fixtures/workflow.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by Fluent Github Actions 2 | 3 | name: Tests 4 | on: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | tests: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: denolib/setup-deno@v2 14 | with: 15 | deno-version: v1.36 16 | - name: Setup Fluent CI CLI 17 | run: deno install -A -r https://cli.fluentci.io -n fluentci 18 | - name: Setup Dagger 19 | run: | 20 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 21 | sudo mv bin/dagger /usr/local/bin 22 | dagger version 23 | - name: Run Dagger Pipelines 24 | run: dagger run fluentci deno_pipeline fmt lint test 25 | -------------------------------------------------------------------------------- /fixtures/Deploy-ECS.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # This template is deprecated. 2 | # 3 | # If you have referenced this template in your CI pipeline, please 4 | # update your CI configuration by replacing the following occurrence(s): 5 | # 6 | # template: Deploy-ECS.gitlab-ci.yml 7 | # 8 | # with 9 | # 10 | # template: AWS/Deploy-ECS.gitlab-ci.yml 11 | # 12 | # -------------------- 13 | # 14 | # Documentation: https://docs.gitlab.com/ee/ci/cloud_deployment/#deploy-your-application-to-ecs 15 | 16 | stages: 17 | - build 18 | - test 19 | - review 20 | - deploy 21 | - production 22 | 23 | "error: Template has moved": 24 | stage: deploy 25 | script: 26 | - echo "Deploy-ECS.gitlab-ci.yml has been moved to AWS/Deploy-ECS.gitlab-ci.yml, see https://docs.gitlab.com/ee/ci/cloud_deployment/#deploy-your-application-to-ecs for more details." 27 | - exit 1 28 | -------------------------------------------------------------------------------- /examples/Gradle.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const build = new Job() 4 | .stage("build") 5 | .script("gradle --build-cache assemble") 6 | .cache(["build", ".gradle"], "$CI_COMMIT_REF_NAME", undefined, "pull"); 7 | 8 | const test = new Job() 9 | .stage("test") 10 | .script("gradle check") 11 | .cache(["build", ".gradle"], "$CI_COMMIT_REF_NAME", undefined, "pull"); 12 | 13 | const deploy = new Job() 14 | .stage("deploy") 15 | .script('echo "Define your deployment script!"') 16 | .environment("production"); 17 | 18 | const gitlabci = new GitlabCI() 19 | .image("gradle:alpine") 20 | .beforeScript( 21 | ` 22 | GRADLE_USER_HOME="$(pwd)/.gradle" 23 | export GRADLE_USER_HOME 24 | ` 25 | ) 26 | .addJob("build", build) 27 | .addJob("test", test) 28 | .addJob("deploy", deploy); 29 | 30 | console.log(gitlabci.toString()); 31 | -------------------------------------------------------------------------------- /fixtures/Clojure.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 4 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 5 | 6 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 7 | # https://docs.gitlab.com/ee/development/cicd/templates.html 8 | # This specific template is located at: 9 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml 10 | 11 | # Based on openjdk:8, already includes lein 12 | image: clojure:lein-2.7.0 13 | 14 | before_script: 15 | - lein deps 16 | 17 | test: 18 | script: 19 | - lein test 20 | 21 | deploy: 22 | stage: deploy 23 | script: echo "Define your deployment script!" 24 | environment: production 25 | -------------------------------------------------------------------------------- /examples/Go.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const format = new Job().stage("test").script(` 4 | go fmt $(go list ./... | grep -v /vendor/) 5 | go vet $(go list ./... | grep -v /vendor/) 6 | go test -race $(go list ./... | grep -v /vendor/) 7 | `); 8 | 9 | const compile = new Job() 10 | .stage("build") 11 | .script( 12 | ` 13 | mkdir -p mybinaries 14 | go build -o mybinaries ./... 15 | ` 16 | ) 17 | .artifacts({ 18 | paths: ["mybinaries"], 19 | }); 20 | 21 | const deploy = new Job() 22 | .stage("deploy") 23 | .script('echo "Define your deployment script!"') 24 | .environment("production"); 25 | 26 | const gitlabci = new GitlabCI() 27 | .image("golang:latest") 28 | .stages(["build", "test", "deploy"]) 29 | .addJob("format", format) 30 | .addJob("compile", compile) 31 | .addJob("deploy", deploy); 32 | 33 | console.log(gitlabci.toString()); 34 | -------------------------------------------------------------------------------- /examples/Scala.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const test = new Job().script("sbt clean test"); 4 | 5 | const deploy = new Job() 6 | .stage("deploy") 7 | .script('echo "Define your deployment script!"') 8 | .environment("production"); 9 | 10 | const gitlabci = new GitlabCI() 11 | .image("openjdk:8") 12 | .beforeScript( 13 | ` 14 | apt-get update -yqq 15 | apt-get install apt-transport-https -yqq 16 | echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list 17 | mkdir -p /root/.gnupg 18 | gpg --recv-keys --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/scalasbt-release.gpg --keyserver hkp://keyserver.ubuntu.com:80 2EE0EA64E40A89B84B2DF73499E82A75642AC823 19 | chmod 644 /etc/apt/trusted.gpg.d/scalasbt-release.gpg 20 | apt-get update -yqq 21 | apt-get install sbt -yqq 22 | sbt sbtVersion 23 | ` 24 | ) 25 | .addJob("test", test) 26 | .addJob("deploy", deploy); 27 | 28 | console.log(gitlabci.toString()); 29 | -------------------------------------------------------------------------------- /examples/Docker.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts "; 2 | 3 | const dockerBuild = new Job() 4 | .image("docker:latest") 5 | .stage("build") 6 | .services(["docker:dind"]) 7 | .beforeScript( 8 | 'docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY' 9 | ) 10 | .script( 11 | ` 12 | if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then 13 | tag="" 14 | echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'" 15 | else 16 | tag=":$CI_COMMIT_REF_SLUG" 17 | echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag" 18 | fi 19 | `, 20 | { multiline: true } 21 | ) 22 | .script( 23 | ` 24 | docker build --pull -t "$CI_REGISTRY_IMAGE\${tag}" . 25 | docker push "$CI_REGISTRY_IMAGE\${tag}" 26 | ` 27 | ) 28 | .rules([ 29 | { 30 | if: "$CI_COMMIT_BRANCH", 31 | exists: ["Dockerfile"], 32 | }, 33 | ]); 34 | 35 | const gitlabci = new GitlabCI().addJob("docker_build", dockerBuild); 36 | 37 | console.log(gitlabci.toString()); 38 | -------------------------------------------------------------------------------- /examples/Clojure.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 5 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 6 | 7 | To contribute improvements to CI/CD templates, please follow the Development guide at: 8 | https://docs.gitlab.com/ee/development/cicd/templates.html 9 | This specific template is located at: 10 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml 11 | `; 12 | 13 | const test = new Job().script("lein test"); 14 | 15 | const deploy = new Job() 16 | .stage("deploy") 17 | .script('echo "Define your deployment script!"') 18 | .environment("production"); 19 | 20 | const gitlabci = new GitlabCI() 21 | .comment(header) 22 | .comment("") 23 | .comment("Based on openjdk:8, already includes lein") 24 | .image("clojure:lein-2.7.0") 25 | .beforeScript("lein deps") 26 | .addJob("test", test) 27 | .addJob("deploy", deploy); 28 | 29 | console.log(gitlabci.toString()); 30 | -------------------------------------------------------------------------------- /fixtures/Elixir.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml 8 | 9 | image: elixir:latest 10 | 11 | # Pick zero or more services to be used on all builds. 12 | # Only needed when using a docker container to run your tests in. 13 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 14 | services: 15 | #- mysql:latest 16 | - redis:latest 17 | - postgres:latest 18 | 19 | before_script: 20 | - mix local.rebar --force 21 | - mix local.hex --force 22 | - mix deps.get 23 | 24 | mix: 25 | script: 26 | - mix test 27 | 28 | deploy: 29 | stage: deploy 30 | script: echo "Define your deployment script!" 31 | environment: production 32 | -------------------------------------------------------------------------------- /fixtures/Go.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml 8 | 9 | image: golang:latest 10 | 11 | stages: 12 | - test 13 | - build 14 | - deploy 15 | 16 | format: 17 | stage: test 18 | script: 19 | - go fmt $(go list ./... | grep -v /vendor/) 20 | - go vet $(go list ./... | grep -v /vendor/) 21 | - go test -race $(go list ./... | grep -v /vendor/) 22 | 23 | compile: 24 | stage: build 25 | script: 26 | - mkdir -p mybinaries 27 | - go build -o mybinaries ./... 28 | artifacts: 29 | paths: 30 | - mybinaries 31 | 32 | deploy: 33 | stage: deploy 34 | script: echo "Define your deployment script!" 35 | environment: production 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tsiry Sandratraina 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /examples/Ruby.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const rubocop = new Job().script("rubocop"); 4 | 5 | const rails = new Job().variables({ 6 | DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB", 7 | }).script(` 8 | rails db:migrate 9 | rails db:seed 10 | rails test 11 | `); 12 | 13 | const rspec = new Job().script("rspec spec"); 14 | 15 | const deploy = new Job().stage("deploy").environment("production").script(` 16 | gem install dpl 17 | dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY 18 | `); 19 | 20 | const gitlabci = new GitlabCI() 21 | .image("ruby:latest") 22 | .services(["mysql:latest", "redis:latest", "postgres:latest"]) 23 | .variables({ 24 | POSTGRES_DB: "database_name", 25 | }) 26 | .cache(["vendor/ruby"]) 27 | .beforeScript( 28 | ` 29 | ruby -v 30 | bundle config set --local deployment true 31 | bundle install -j $(nproc) 32 | ` 33 | ) 34 | .addJob("rubocop", rubocop) 35 | .addJob("rails", rails) 36 | .addJob("rspec", rspec) 37 | .addJob("deploy", deploy); 38 | 39 | console.log(gitlabci.toString()); 40 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Debian", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/base:bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers/features/github-cli:1": {}, 9 | "ghcr.io/devcontainers/features/nix:1": {} 10 | }, 11 | 12 | // Features to add to the dev container. More info: https://containers.dev/features. 13 | // "features": {}, 14 | 15 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 16 | // "forwardPorts": [], 17 | 18 | // Use 'postCreateCommand' to run commands after the container is created. 19 | "postCreateCommand": "nix develop --experimental-features \"nix-command flakes\"" 20 | 21 | // Configure tool-specific properties. 22 | // "customizations": {}, 23 | 24 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 25 | // "remoteUser": "root" 26 | } 27 | -------------------------------------------------------------------------------- /.fluentci/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tsiry Sandratraina 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /.fluentci/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Debian", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/base:bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers/features/github-cli:1": {}, 9 | "ghcr.io/devcontainers/features/nix:1": {} 10 | }, 11 | 12 | // Features to add to the dev container. More info: https://containers.dev/features. 13 | // "features": {}, 14 | 15 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 16 | // "forwardPorts": [], 17 | 18 | // Use 'postCreateCommand' to run commands after the container is created. 19 | "postCreateCommand": "nix develop --experimental-features \"nix-command flakes\"" 20 | // Configure tool-specific properties. 21 | // "customizations": {}, 22 | 23 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 24 | // "remoteUser": "root" 25 | } 26 | -------------------------------------------------------------------------------- /fixtures/Terraform.latest.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 2 | # https://docs.gitlab.com/ee/development/cicd/templates.html 3 | # This specific template is located at: 4 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml 5 | 6 | include: 7 | - template: Terraform/Base.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml 8 | - template: Jobs/SAST-IaC.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/SAST-IaC.latest.gitlab-ci.yml 9 | 10 | stages: 11 | - validate 12 | - test 13 | - build 14 | - deploy 15 | - cleanup 16 | 17 | fmt: 18 | extends: .terraform:fmt 19 | needs: [] 20 | 21 | validate: 22 | extends: .terraform:validate 23 | needs: [] 24 | 25 | build: 26 | extends: .terraform:build 27 | environment: 28 | name: $TF_STATE_NAME 29 | action: prepare 30 | 31 | deploy: 32 | extends: .terraform:deploy 33 | dependencies: 34 | - build 35 | environment: 36 | name: $TF_STATE_NAME 37 | action: start 38 | -------------------------------------------------------------------------------- /.fluentci/import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@dagger.io/dagger": "https://esm.sh/v128/*@dagger.io/dagger@0.6.3", 4 | "fluent_gitlab_ci": "https://deno.land/x/fluent_gitlab_ci@v0.3.2/mod.ts", 5 | "fluent_github_actions": "https://deno.land/x/fluent_github_actions@v0.1.2/mod.ts", 6 | "url": "node:url", 7 | "readline": "node:readline", 8 | "process": "node:process", 9 | "path": "node:path", 10 | "os": "node:os", 11 | "fs": "node:fs", 12 | "crypto": "node:crypto" 13 | }, 14 | "scopes": { 15 | "https://esm.sh/v128/": { 16 | "@lifeomic/axios-fetch": "https://esm.sh/v128/@lifeomic/axios-fetch@3.0.1", 17 | "adm-zip": "https://esm.sh/v128/adm-zip@0.5.10", 18 | "env-paths": "https://esm.sh/v128/env-paths@3.0.0", 19 | "execa": "https://esm.sh/v128/execa@7.1.1", 20 | "graphql-request": "https://esm.sh/v128/graphql-request@6.1.0", 21 | "graphql-tag": "https://esm.sh/v128/graphql-tag@2.12.6", 22 | "graphql": "https://esm.sh/v128/graphql@16.7.1", 23 | "node-color-log": "https://esm.sh/v128/node-color-log@10.0.2", 24 | "node-fetch": "https://esm.sh/v128/node-fetch@3.3.1", 25 | "tar": "https://esm.sh/v128/tar@6.1.15" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /fixtures/Composer.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 2 | # https://docs.gitlab.com/ee/development/cicd/templates.html 3 | # This specific template is located at: 4 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Composer.gitlab-ci.yml 5 | 6 | # Publishes a tag/branch to Composer Packages of the current project 7 | publish: 8 | image: curlimages/curl:latest 9 | stage: build 10 | variables: 11 | URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN" 12 | script: 13 | - version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG") 14 | - insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "") 15 | - response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL) 16 | - code=$(echo "$response" | tail -n 1) 17 | - body=$(echo "$response" | head -n 1) 18 | - | 19 | if [ $code -eq 201 ]; then 20 | echo "Package created - Code $code - $body"; 21 | else 22 | echo "Could not create package - Code $code - $body"; 23 | exit 1; 24 | fi 25 | -------------------------------------------------------------------------------- /src/environment.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Action, 3 | DeploymentTier, 4 | Environment as EnvironmentSpec, 5 | } from "./gitlabci_spec.ts"; 6 | 7 | class Environment { 8 | private environment: EnvironmentSpec; 9 | 10 | into(): EnvironmentSpec { 11 | return this.environment; 12 | } 13 | 14 | constructor(name: string, url?: string) { 15 | this.environment = { 16 | name, 17 | url, 18 | }; 19 | } 20 | 21 | url(url: string): Environment { 22 | this.environment.url = url; 23 | return this; 24 | } 25 | 26 | onStop(value: string): Environment { 27 | this.environment.on_stop = value; 28 | return this; 29 | } 30 | 31 | action(value: Action): Environment { 32 | this.environment.action = value; 33 | return this; 34 | } 35 | 36 | auto_stop_in(value: string): Environment { 37 | this.environment.auto_stop_in = value; 38 | return this; 39 | } 40 | 41 | kubernetes(namespace: string): Environment { 42 | this.environment.kubernetes = { 43 | namespace, 44 | }; 45 | return this; 46 | } 47 | 48 | deployment_tier(value: DeploymentTier): Environment { 49 | this.environment.deployment_tier = value; 50 | return this; 51 | } 52 | } 53 | 54 | export default Environment; 55 | -------------------------------------------------------------------------------- /fixtures/C++.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 4 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 5 | 6 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 7 | # https://docs.gitlab.com/ee/development/cicd/templates.html 8 | # This specific template is located at: 9 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/C++.gitlab-ci.yml 10 | 11 | # use the official gcc image, based on debian 12 | # can use versions as well, like gcc:5.2 13 | # see https://hub.docker.com/_/gcc/ 14 | 15 | image: gcc 16 | 17 | build: 18 | stage: build 19 | before_script: 20 | - apt update && apt -y install make autoconf 21 | script: 22 | - g++ helloworld.cpp -o mybinary 23 | artifacts: 24 | paths: 25 | - mybinary 26 | cache: 27 | paths: 28 | - "*.o" 29 | 30 | # run tests using the binary built before 31 | test: 32 | stage: test 33 | script: 34 | - ./runmytests.sh 35 | 36 | deploy: 37 | stage: deploy 38 | script: echo "Define your deployment script!" 39 | environment: production 40 | -------------------------------------------------------------------------------- /fixtures/Gradle.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml 7 | 8 | # This is the Gradle build system for JVM applications 9 | # https://gradle.org/ 10 | # https://github.com/gradle/gradle 11 | 12 | image: gradle:alpine 13 | 14 | before_script: 15 | - GRADLE_USER_HOME="$(pwd)/.gradle" 16 | - export GRADLE_USER_HOME 17 | 18 | build: 19 | stage: build 20 | script: gradle --build-cache assemble 21 | cache: 22 | key: "$CI_COMMIT_REF_NAME" 23 | policy: push 24 | paths: 25 | - build 26 | - .gradle 27 | 28 | test: 29 | stage: test 30 | script: gradle check 31 | cache: 32 | key: "$CI_COMMIT_REF_NAME" 33 | policy: pull 34 | paths: 35 | - build 36 | - .gradle 37 | 38 | deploy: 39 | stage: deploy 40 | script: echo "Define your deployment script!" 41 | environment: production 42 | -------------------------------------------------------------------------------- /examples/demo.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | import Environment from "../src/environment.ts"; 3 | 4 | const build = new Job() 5 | .stage("build") 6 | .environment( 7 | new Environment("review/$CI_COMMIT_REF_NAME", "$CI_ENVIRONMENT_URL") 8 | ) 9 | .script("echo 'Hello, world!'") 10 | .script( 11 | "echo 'This job is running against branch=$CI_COMMIT_REF_NAME and commit=$CI_COMMIT_SHA'" 12 | ) 13 | .only(["merge_requests"]) 14 | .rules([{ if: "$CI_MERGE_REQUEST_ID" }]) 15 | .when("on_success") 16 | .allowFailure(false) 17 | .except(["master"]) 18 | .artifacts({ paths: ["public"] }) 19 | .services(["postgres:11.7"]) 20 | .parallel(2) 21 | .cache(["node_modules/"], "$CI_COMMIT_REF_SLUG"); 22 | 23 | const test = new Job().stage("test"); 24 | const unitTest = new Job().stage("test"); 25 | const lint = new Job().stage("test"); 26 | const deploy = new Job().stage("deploy"); 27 | 28 | const gitlabci = new GitlabCI() 29 | .stages(["build", "test", "deploy"]) 30 | .comment("This is a comment") 31 | .comment("This is another comment") 32 | .comment("") 33 | .addJob("build-job", build) 34 | .addJob("test-job", test) 35 | .addJob("unit-test-job", unitTest) 36 | .addJob("lint-test-job", lint) 37 | .addJob("deploy-job", deploy); 38 | 39 | console.log(gitlabci.toString()); 40 | 41 | gitlabci.write(); 42 | -------------------------------------------------------------------------------- /examples/Python.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const test = new Job().script(` 4 | pip install ruff tox # you can also use tox 5 | pip install --editable ".[test]" 6 | tox -e py,ruff 7 | `); 8 | 9 | const run = new Job().script("pip install .").artifacts({ 10 | paths: ["build/*"], 11 | }); 12 | 13 | const page = new Job() 14 | .script( 15 | ` 16 | pip install sphinx sphinx-rtd-theme 17 | cd doc 18 | make html 19 | mv build/html/ ../public/ 20 | ` 21 | ) 22 | .artifacts({ 23 | paths: ["public"], 24 | }) 25 | .rules([ 26 | { 27 | if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH", 28 | }, 29 | ]); 30 | 31 | const deploy = new Job() 32 | .stage("deploy") 33 | .script('echo "Define your deployment script!"') 34 | .environment("production"); 35 | 36 | const gitlabci = new GitlabCI() 37 | .image("python:latest") 38 | .variables({ 39 | PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip", 40 | }) 41 | .cache([".cache/pip", "venv/"]) 42 | .beforeScript( 43 | ` 44 | python --version ; pip --version 45 | pip install virtualenv 46 | virtualenv venv 47 | source venv/bin/activate 48 | ` 49 | ) 50 | .addJob("test", test) 51 | .addJob("run", run) 52 | .addJob("page", page) 53 | .addJob("deploy", deploy); 54 | 55 | console.log(gitlabci.toString()); 56 | -------------------------------------------------------------------------------- /examples/Django.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const defaultJob = new Job() 4 | .image("ubuntu:20.04") 5 | .services(["mysql:8.0"]) 6 | .cache(["~/.cache/pip/"]).beforeScript(` 7 | apt -y update 8 | apt -y install apt-utils 9 | apt -y install net-tools python3.8 python3-pip mysql-client libmysqlclient-dev 10 | apt -y upgrade 11 | pip3 install -r requirements.txt 12 | `); 13 | 14 | const migrations = new Job().stage("build").script(` 15 | python3 manage.py makemigrations 16 | python3 manage.py migrate 17 | python3 manage.py check 18 | `); 19 | 20 | const djangoTests = new Job().stage("test").script(` 21 | echo "GRANT ALL on *.* to '\${MYSQL_USER}';"| mysql -u root --password="\${MYSQL_ROOT_PASSWORD}" -h mysql 22 | python3 manage.py test 23 | `); 24 | 25 | const deploy = new Job() 26 | .stage("deploy") 27 | .script('echo "Define your deployment script!"') 28 | .environment("production"); 29 | 30 | const gitlabci = new GitlabCI() 31 | .variables({ 32 | MYSQL_DATABASE: "$MYSQL_DB", 33 | MYSQL_ROOT_PASSWORD: "$MYSQL_PASS", 34 | MYSQL_USER: "$MYSQL_USER", 35 | MYSQL_PASSWORD: "$MYSQL_PASS", 36 | }) 37 | .addJob("default", defaultJob) 38 | .addJob("migrations", migrations) 39 | .addJob("django-tests", djangoTests) 40 | .addJob("deploy", deploy); 41 | 42 | console.log(gitlabci.toString()); 43 | -------------------------------------------------------------------------------- /examples/C++.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 5 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 6 | 7 | To contribute improvements to CI/CD templates, please follow the Development guide at: 8 | https://docs.gitlab.com/ee/development/cicd/templates.html 9 | This specific template is located at: 10 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/C++.gitlab-ci.yml 11 | 12 | use the official gcc image, based on debian 13 | can use versions as well, like gcc:5.2 14 | see https://hub.docker.com/_/gcc/ 15 | `; 16 | 17 | const build = new Job() 18 | .stage("build") 19 | .beforeScript("apt update && apt -y install make autoconf") 20 | .script("g++ helloworld.cpp -o mybinary") 21 | .cache(["*.o"]) 22 | .artifacts({ paths: ["mybinary"] }); 23 | 24 | const test = new Job().stage("test").script("./runmytests.sh"); 25 | 26 | const deploy = new Job() 27 | .stage("deploy") 28 | .script('echo "Define your deployment script!"') 29 | .environment("production"); 30 | 31 | const gitlabci = new GitlabCI() 32 | .comment(header) 33 | .comment("") 34 | .image("gcc") 35 | .addJob("build", build) 36 | .addJob("test", test) 37 | .addJob("deploy", deploy); 38 | 39 | console.log(gitlabci.toString()); 40 | -------------------------------------------------------------------------------- /fixtures/Nodejs.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml 8 | 9 | # Official framework image. Look for the different tagged releases at: 10 | # https://hub.docker.com/r/library/node/tags/ 11 | image: node:latest 12 | 13 | # Pick zero or more services to be used on all builds. 14 | # Only needed when using a docker container to run your tests in. 15 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 16 | services: 17 | - mysql:latest 18 | - redis:latest 19 | - postgres:latest 20 | 21 | # This folder is cached between builds 22 | # https://docs.gitlab.com/ee/ci/yaml/index.html#cache 23 | cache: 24 | paths: 25 | - node_modules/ 26 | 27 | test_async: 28 | script: 29 | - npm install 30 | - node ./specs/start.js ./specs/async.spec.js 31 | 32 | test_db: 33 | script: 34 | - npm install 35 | - node ./specs/start.js ./specs/db-postgres.spec.js 36 | 37 | deploy: 38 | stage: deploy 39 | script: echo "Define your deployment script!" 40 | environment: production 41 | -------------------------------------------------------------------------------- /examples/Swift.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const buildProject = new Job() 4 | .stage("build") 5 | .script( 6 | ` 7 | xcodebuild clean -project ProjectName.xcodeproj -scheme SchemeName | xcpretty 8 | xcodebuild test -project ProjectName.xcodeproj -scheme SchemeName -destination 'platform=iOS Simulator,name=iPhone 8,OS=11.3' | xcpretty -s 9 | ` 10 | ) 11 | .tags(["ios_11-3", "xcode_9-3", "macos_10-13"]); 12 | 13 | const archiveProject = new Job() 14 | .stage("archive") 15 | .script( 16 | ` 17 | xcodebuild clean archive -archivePath build/ProjectName -scheme SchemeName 18 | xcodebuild -exportArchive -exportFormat ipa -archivePath "build/ProjectName.xcarchive" -exportPath "build/ProjectName.ipa" -exportProvisioningProfile "ProvisioningProfileName" 19 | ` 20 | ) 21 | .rules([ 22 | { 23 | if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH", 24 | }, 25 | ]) 26 | .artifacts({ 27 | paths: ["build/ProjectName.ipa"], 28 | }) 29 | .tags(["ios_11-3", "xcode_9-3", "macos_10-13"]); 30 | 31 | const deploy = new Job() 32 | .stage("deploy") 33 | .script('echo "Define your deployment script!"') 34 | .environment("production"); 35 | 36 | const gitlabci = new GitlabCI() 37 | .stages(["build", "test", "archive", "deploy"]) 38 | .addJob("build_project", buildProject) 39 | .addJob("archive_project", archiveProject) 40 | .addJob("deploy", deploy); 41 | 42 | console.log(gitlabci.toString()); 43 | -------------------------------------------------------------------------------- /fixtures/Bash.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Bash.gitlab-ci.yml 8 | 9 | # See https://docs.gitlab.com/ee/ci/yaml/index.html for all available options 10 | 11 | # you can delete this line if you're not using Docker 12 | image: busybox:latest 13 | 14 | before_script: 15 | - echo "Before script section" 16 | - echo "For example you might run an update here or install a build dependency" 17 | - echo "Or perhaps you might print out some debugging details" 18 | 19 | after_script: 20 | - echo "After script section" 21 | - echo "For example you might do some cleanup here" 22 | 23 | build1: 24 | stage: build 25 | script: 26 | - echo "Do your build here" 27 | 28 | test1: 29 | stage: test 30 | script: 31 | - echo "Do a test here" 32 | - echo "For example run a test suite" 33 | 34 | test2: 35 | stage: test 36 | script: 37 | - echo "Do another parallel test here" 38 | - echo "For example run a lint test" 39 | 40 | deploy1: 41 | stage: deploy 42 | script: 43 | - echo "Do your deploy here" 44 | environment: production 45 | -------------------------------------------------------------------------------- /.fluentci/src/github/config.ts: -------------------------------------------------------------------------------- 1 | import { JobSpec, Workflow } from "fluent_github_actions"; 2 | 3 | export function generateYaml(): Workflow { 4 | const workflow = new Workflow("Tests"); 5 | 6 | const push = { 7 | branches: ["master"], 8 | }; 9 | 10 | const pull_request = { 11 | branches: ["master"], 12 | }; 13 | 14 | const setupDagger = `\ 15 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 16 | sudo mv bin/dagger /usr/local/bin 17 | dagger version`; 18 | 19 | const tests: JobSpec = { 20 | "runs-on": "ubuntu-latest", 21 | steps: [ 22 | { 23 | uses: "actions/checkout@v2", 24 | }, 25 | { 26 | uses: "denolib/setup-deno@v2", 27 | with: { 28 | "deno-version": "v1.36", 29 | }, 30 | }, 31 | { 32 | name: "Setup Fluent CI CLI", 33 | run: "deno install -A -r https://cli.fluentci.io -n fluentci", 34 | }, 35 | { 36 | name: "Setup Dagger", 37 | run: setupDagger, 38 | }, 39 | { 40 | name: "Run Dagger Pipelines", 41 | run: "dagger run fluentci deno_pipeline fmt lint test", 42 | }, 43 | { 44 | name: "Upload to Codecov", 45 | run: "dagger run fluentci codecov_pipeline", 46 | env: { 47 | CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}", 48 | }, 49 | }, 50 | ], 51 | }; 52 | 53 | workflow.on({ push, pull_request }).jobs({ tests }); 54 | return workflow; 55 | } 56 | -------------------------------------------------------------------------------- /examples/Flutter.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const codeQuality = new Job() 4 | .stage("test") 5 | .image("ghcr.io/cirruslabs/flutter:3.10.3") 6 | .beforeScript( 7 | ` 8 | flutter pub global activate dart_code_metrics 9 | export PATH="$PATH:$HOME/.pub-cache/bin" 10 | ` 11 | ) 12 | .script("metrics lib -r codeclimate > gl-code-quality-report.json") 13 | .artifacts({ 14 | reports: { 15 | codequality: "gl-code-quality-report.json", 16 | }, 17 | }); 18 | 19 | const test = new Job() 20 | .stage("test") 21 | .image("ghcr.io/cirruslabs/flutter:3.10.3") 22 | .beforeScript( 23 | ` 24 | flutter pub global activate junitreport 25 | export PATH="$PATH:$HOME/.pub-cache/bin" 26 | ` 27 | ) 28 | .script( 29 | ` 30 | flutter test --machine --coverage | tojunit -o report.xml 31 | lcov --summary coverage/lcov.info 32 | genhtml coverage/lcov.info --output=coverage 33 | ` 34 | ) 35 | .coverage(`/lines\.*: \d+\.\d+\%/`) 36 | .artifacts({ 37 | name: "coverage", 38 | paths: ["$CI_PROJECT_DIR/coverage"], 39 | reports: { 40 | junit: "report.xml", 41 | }, 42 | }); 43 | 44 | const deploy = new Job() 45 | .stage("deploy") 46 | .script('echo "Define your deployment script!"') 47 | .environment("production"); 48 | 49 | const gitlabci = new GitlabCI() 50 | .addJob("code_quality", codeQuality) 51 | .addJob("test", test) 52 | .addJob("deploy", deploy); 53 | 54 | console.log(gitlabci.toString()); 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fluent GitLab CI 2 | 3 | [![deno module](https://shield.deno.dev/x/fluent_gitlab_ci)](https://deno.land/x/fluent_gitlab_ci) 4 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 5 | [![](https://img.shields.io/codecov/c/gh/tsirysndr/fluent-gitlab-ci)](https://codecov.io/gh/tsirysndr/fluent-gitlab-ci) 6 | 7 | Fluent GitLab CI is a deno module for generating GitLab CI configuration files easily and fluently. 8 | 9 | ## 🚀 Usage 10 | 11 | ```ts 12 | import { GitlabCI, Job } from "https://deno.land/x/fluent_gitlab_ci/mod.ts"; 13 | 14 | const build = new Job().stage("build").script(` 15 | echo "Compiling the code..." 16 | echo "Compile complete." 17 | `); 18 | 19 | const unitTest = new Job().stage("test").script(` 20 | echo "Running unit tests... This will take about 60 seconds." 21 | sleep 60 22 | echo "Code coverage is 90%" 23 | `); 24 | 25 | const lint = new Job().stage("test").script(` 26 | echo "Linting code... This will take about 10 seconds." 27 | sleep 10 28 | echo "No lint issues found." 29 | `); 30 | 31 | const deploy = new Job().stage("deploy").script(` 32 | echo "Deploying application..." 33 | echo "Application successfully deployed." 34 | `); 35 | 36 | const gitlabci = new GitlabCI() 37 | .stages(["build", "test", "deploy"]) 38 | .addJob("build-job", build) 39 | .addJob("unit-test-job", unitTest) 40 | .addJob("lint-test-job", lint) 41 | .addJob("deploy-job", deploy); 42 | 43 | console.log(gitlabci.toString()); 44 | 45 | gitlabci.write(); 46 | ``` 47 | 48 | See [examples](./examples) for more details. -------------------------------------------------------------------------------- /fixtures/Flutter.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml 8 | 9 | code_quality: 10 | stage: test 11 | image: "ghcr.io/cirruslabs/flutter:3.10.3" 12 | before_script: 13 | - flutter pub global activate dart_code_metrics 14 | - export PATH="$PATH:$HOME/.pub-cache/bin" 15 | script: 16 | - metrics lib -r codeclimate > gl-code-quality-report.json 17 | artifacts: 18 | reports: 19 | codequality: gl-code-quality-report.json 20 | 21 | test: 22 | stage: test 23 | image: "ghcr.io/cirruslabs/flutter:3.10.3" 24 | before_script: 25 | - flutter pub global activate junitreport 26 | - export PATH="$PATH:$HOME/.pub-cache/bin" 27 | script: 28 | - flutter test --machine --coverage | tojunit -o report.xml 29 | - lcov --summary coverage/lcov.info 30 | - genhtml coverage/lcov.info --output=coverage 31 | coverage: '/lines\.*: \d+\.\d+\%/' 32 | artifacts: 33 | name: coverage 34 | paths: 35 | - $CI_PROJECT_DIR/coverage 36 | reports: 37 | junit: report.xml 38 | 39 | deploy: 40 | stage: deploy 41 | script: echo "Define your deployment script!" 42 | environment: production 43 | -------------------------------------------------------------------------------- /.fluentci/src/github/README.md: -------------------------------------------------------------------------------- 1 | # Github Actions 2 | 3 | [![deno module](https://shield.deno.dev/x/deno_pipeline)](https://deno.land/x/deno_pipeline) 4 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 5 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/deno-pipeline)](https://codecov.io/gh/fluent-ci-templates/deno-pipeline) 6 | 7 | The following command will generate a `.github/workflows/ci.yml` file in your project: 8 | 9 | ```bash 10 | fluentci gh init -t deno_pipeline 11 | ``` 12 | 13 | Or, if you already have a `.fluentci` folder (generated from `fluentci init -t deno`) in your project: 14 | 15 | ```bash 16 | fluentci gh init 17 | ``` 18 | 19 | Generated file: 20 | 21 | ```yaml 22 | # Do not edit this file directly. It is generated by Fluent Github Actions 23 | 24 | name: Tests 25 | on: 26 | push: 27 | branches: 28 | - main 29 | jobs: 30 | tests: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v2 34 | - uses: denolib/setup-deno@v2 35 | with: 36 | deno-version: v1.36 37 | - name: Setup Fluent CI CLI 38 | run: deno install -A -r https://cli.fluentci.io -n fluentci 39 | - name: Setup Dagger 40 | run: | 41 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 42 | sudo mv bin/dagger /usr/local/bin 43 | dagger version 44 | - name: Run Dagger Pipelines 45 | run: dagger run fluentci deno_pipeline fmt lint test 46 | ``` 47 | 48 | Feel free to edit the template generator at `.fluentci/src/github/config.ts` to your needs. 49 | -------------------------------------------------------------------------------- /fixtures/Docker.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 2 | # https://docs.gitlab.com/ee/development/cicd/templates.html 3 | # This specific template is located at: 4 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Docker.gitlab-ci.yml 5 | 6 | # Build a Docker image with CI/CD and push to the GitLab registry. 7 | # Docker-in-Docker documentation: https://docs.gitlab.com/ee/ci/docker/using_docker_build.html 8 | # 9 | # This template uses one generic job with conditional builds 10 | # for the default branch and all other (MR) branches. 11 | 12 | docker-build: 13 | # Use the official docker image. 14 | image: docker:latest 15 | stage: build 16 | services: 17 | - docker:dind 18 | before_script: 19 | - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY 20 | # Default branch leaves tag empty (= latest tag) 21 | # All other branches are tagged with the escaped branch name (commit ref slug) 22 | script: 23 | - | 24 | if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then 25 | tag="" 26 | echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'" 27 | else 28 | tag=":$CI_COMMIT_REF_SLUG" 29 | echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag" 30 | fi 31 | - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" . 32 | - docker push "$CI_REGISTRY_IMAGE${tag}" 33 | # Run this job in a branch where a Dockerfile exists 34 | rules: 35 | - if: $CI_COMMIT_BRANCH 36 | exists: 37 | - Dockerfile 38 | -------------------------------------------------------------------------------- /examples/Laravel.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const test = new Job().script(` 4 | php vendor/bin/phpunit --coverage-text --colors=never 5 | npm test 6 | `); 7 | 8 | const deploy = new Job() 9 | .stage("deploy") 10 | .script('echo "Define your deployment script!"') 11 | .environment("production"); 12 | 13 | const gitlabci = new GitlabCI() 14 | .image("php:latest") 15 | .services(["mysql:latest"]) 16 | .variables({ 17 | MYSQL_DATABASE: "project_name", 18 | MYSQL_ROOT_PASSWORD: "secret", 19 | }) 20 | .cache(["vendor/", "node_modules/"]) 21 | .beforeScript( 22 | ` 23 | apt-get update -yqq 24 | apt-get install gnupg -yqq 25 | curl -sL https://deb.nodesource.com/setup_8.x | bash - 26 | apt-get install git nodejs libcurl4-gnutls-dev libicu-dev libmcrypt-dev libvpx-dev libjpeg-dev libpng-dev libxpm-dev zlib1g-dev libfreetype6-dev libxml2-dev libexpat1-dev libbz2-dev libgmp3-dev libldap2-dev unixodbc-dev libpq-dev libsqlite3-dev libaspell-dev libsnmp-dev libpcre3-dev libtidy-dev -yqq 27 | docker-php-ext-install mbstring pdo_mysql curl json intl gd xml zip bz2 opcache 28 | pecl install xdebug 29 | docker-php-ext-enable xdebug 30 | curl -sS https://getcomposer.org/installer | php 31 | php composer.phar install 32 | npm install 33 | cp .env.testing .env 34 | npm run build 35 | npm run dev 36 | php artisan key:generate 37 | php artisan config:cache 38 | php artisan migrate 39 | php artisan db:seed 40 | ` 41 | ) 42 | .addJob("test", test) 43 | .addJob("deploy", deploy); 44 | 45 | console.log(gitlabci.toString()); 46 | -------------------------------------------------------------------------------- /fixtures/Scala.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Scala.gitlab-ci.yml 8 | 9 | # Official OpenJDK Java image. Look for the different tagged releases at 10 | # https://hub.docker.com/_/openjdk/ . A Java image is not required 11 | # but an image with a JVM speeds up the build a bit. 12 | image: openjdk:8 13 | 14 | before_script: 15 | # Enable the usage of sources over https 16 | - apt-get update -yqq 17 | - apt-get install apt-transport-https -yqq 18 | # Add keyserver for SBT 19 | - echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list 20 | - mkdir -p /root/.gnupg 21 | - gpg --recv-keys --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/scalasbt-release.gpg --keyserver hkp://keyserver.ubuntu.com:80 2EE0EA64E40A89B84B2DF73499E82A75642AC823 22 | - chmod 644 /etc/apt/trusted.gpg.d/scalasbt-release.gpg 23 | # Install SBT 24 | - apt-get update -yqq 25 | - apt-get install sbt -yqq 26 | # Log the sbt version 27 | - sbt sbtVersion 28 | 29 | test: 30 | script: 31 | # Execute your project's tests 32 | - sbt clean test 33 | 34 | deploy: 35 | stage: deploy 36 | script: echo "Define your deployment script!" 37 | environment: production 38 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1687709756, 9 | "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1688652023, 24 | "narHash": "sha256-a3mdaPxDTp5L/joHAPfduOC5i5GlpnOcWBBT7Av6nEQ=", 25 | "owner": "nixos", 26 | "repo": "nixpkgs", 27 | "rev": "86f8abf1a7007b1c020c7074bd8da11383e4602a", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nixos", 32 | "ref": "release-23.05", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /.fluentci/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1687709756, 9 | "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1688910226, 24 | "narHash": "sha256-kLTsFu9CAU2Gb288JhIBN/WlX4UUUDz4WiC/U59nvwk=", 25 | "owner": "nixos", 26 | "repo": "nixpkgs", 27 | "rev": "2540432a940aee979be6ccfefba9ea0652c273a0", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nixos", 32 | "ref": "release-23.05", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /fixtures/Crystal.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 4 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 5 | 6 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 7 | # https://docs.gitlab.com/ee/development/cicd/templates.html 8 | # This specific template is located at: 9 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml 10 | 11 | # Official language image. Look for the different tagged releases at: 12 | # https://hub.docker.com/r/crystallang/crystal/ 13 | image: "crystallang/crystal:latest" 14 | 15 | # Pick zero or more services to be used on all builds. 16 | # Only needed when using a docker container to run your tests in. 17 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 18 | services: 19 | - mysql:latest 20 | - redis:latest 21 | - postgres:latest 22 | 23 | variables: 24 | POSTGRES_DB: database_name 25 | 26 | # Cache shards in between builds 27 | cache: 28 | paths: 29 | - lib 30 | 31 | # This is a basic example for a shard or script which doesn't use 32 | # services such as redis or postgres 33 | before_script: 34 | - apt-get update -qq && apt-get install -y -qq libxml2-dev 35 | - crystal -v 36 | - shards 37 | 38 | # If you are using built-in Crystal Spec. 39 | spec: 40 | script: 41 | - crystal spec 42 | 43 | # If you are using minitest.cr 44 | minitest: 45 | script: 46 | - crystal test/spec_test.cr 47 | 48 | deploy: 49 | stage: deploy 50 | script: echo "Define your deployment script!" 51 | environment: production 52 | -------------------------------------------------------------------------------- /fixtures/Swift.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Swift.gitlab-ci.yml 8 | 9 | # Lifted from: https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/ 10 | # This file assumes an own GitLab CI runner, setup on a macOS system. 11 | stages: 12 | - build 13 | - test 14 | - archive 15 | - deploy 16 | 17 | build_project: 18 | stage: build 19 | script: 20 | - xcodebuild clean -project ProjectName.xcodeproj -scheme SchemeName | xcpretty 21 | - xcodebuild test -project ProjectName.xcodeproj -scheme SchemeName -destination 'platform=iOS Simulator,name=iPhone 8,OS=11.3' | xcpretty -s 22 | tags: 23 | - ios_11-3 24 | - xcode_9-3 25 | - macos_10-13 26 | 27 | archive_project: 28 | stage: archive 29 | script: 30 | - xcodebuild clean archive -archivePath build/ProjectName -scheme SchemeName 31 | - xcodebuild -exportArchive -exportFormat ipa -archivePath "build/ProjectName.xcarchive" -exportPath "build/ProjectName.ipa" -exportProvisioningProfile "ProvisioningProfileName" 32 | rules: 33 | - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 34 | artifacts: 35 | paths: 36 | - build/ProjectName.ipa 37 | tags: 38 | - ios_11-3 39 | - xcode_9-3 40 | - macos_10-13 41 | 42 | deploy: 43 | stage: deploy 44 | script: echo "Define your deployment script!" 45 | environment: production 46 | -------------------------------------------------------------------------------- /fixtures/Python.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 2 | # https://docs.gitlab.com/ee/development/cicd/templates.html 3 | # This specific template is located at: 4 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Python.gitlab-ci.yml 5 | 6 | # Official language image. Look for the different tagged releases at: 7 | # https://hub.docker.com/r/library/python/tags/ 8 | image: python:latest 9 | 10 | # Change pip's cache directory to be inside the project directory since we can 11 | # only cache local items. 12 | variables: 13 | PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" 14 | 15 | # Pip's cache doesn't store the python packages 16 | # https://pip.pypa.io/en/stable/topics/caching/ 17 | # 18 | # If you want to also cache the installed packages, you have to install 19 | # them in a virtualenv and cache it as well. 20 | cache: 21 | paths: 22 | - .cache/pip 23 | - venv/ 24 | 25 | before_script: 26 | - python --version ; pip --version # For debugging 27 | - pip install virtualenv 28 | - virtualenv venv 29 | - source venv/bin/activate 30 | 31 | test: 32 | script: 33 | - pip install ruff tox # you can also use tox 34 | - pip install --editable ".[test]" 35 | - tox -e py,ruff 36 | 37 | run: 38 | script: 39 | - pip install . 40 | # run the command here 41 | artifacts: 42 | paths: 43 | - build/* 44 | 45 | pages: 46 | script: 47 | - pip install sphinx sphinx-rtd-theme 48 | - cd doc 49 | - make html 50 | - mv build/html/ ../public/ 51 | artifacts: 52 | paths: 53 | - public 54 | rules: 55 | - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 56 | 57 | deploy: 58 | stage: deploy 59 | script: echo "Define your deployment script!" 60 | environment: production 61 | -------------------------------------------------------------------------------- /examples/Crystal.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 5 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 6 | 7 | To contribute improvements to CI/CD templates, please follow the Development guide at: 8 | https://docs.gitlab.com/ee/development/cicd/templates.html 9 | This specific template is located at: 10 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml 11 | 12 | Official language image. Look for the different tagged releases at: 13 | https://hub.docker.com/r/crystallang/crystal/ 14 | `; 15 | 16 | const spec = new Job().script("crystal spec"); 17 | 18 | const minitest = new Job().script("crystal test/spec_test.cr"); 19 | 20 | const deploy = new Job() 21 | .stage("deploy") 22 | .script('echo "Define your deployment script!"') 23 | .environment("production"); 24 | 25 | const gitlabci = new GitlabCI() 26 | .comment(header) 27 | .image("crystallang/crystal:latest") 28 | .services(["mysql:latest", "redis:latest", "postgres:latest"]) 29 | .variables({ 30 | POSTGRES_DB: "database_name", 31 | }) 32 | .comment("Cache shards in between builds") 33 | .cache(["lib"]) 34 | .comment( 35 | ` 36 | This is a basic example for a shard or script which doesn't use 37 | services such as redis or postgres 38 | ` 39 | ) 40 | .beforeScript( 41 | ` 42 | apt-get update -qq && apt-get install -y -qq libxml2-dev 43 | crystal -v 44 | shards 45 | ` 46 | ) 47 | .comment("If you are using built-in Crystal Spec.") 48 | .addJob("spec", spec) 49 | .comment("If you are using minitest.cr") 50 | .addJob("minitest", minitest) 51 | .addJob("deploy", deploy); 52 | 53 | console.log(gitlabci.toString()); 54 | -------------------------------------------------------------------------------- /fixtures/Getting-Started.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # This is a sample GitLab CI/CD configuration file that should run without any modifications. 4 | # It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts, 5 | # it uses echo commands to simulate the pipeline execution. 6 | 7 | # A pipeline is composed of independent jobs that run scripts, grouped into stages. 8 | # Stages run in sequential order, but jobs within stages run in parallel. 9 | 10 | # For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages 11 | 12 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 13 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 14 | 15 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 16 | # https://docs.gitlab.com/ee/development/cicd/templates.html 17 | # This specific template is located at: 18 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml 19 | 20 | stages: 21 | - build 22 | - test 23 | - deploy 24 | 25 | build-job: 26 | stage: build 27 | script: 28 | - echo "Compiling the code..." 29 | - echo "Compile complete." 30 | 31 | unit-test-job: 32 | stage: test 33 | script: 34 | - echo "Running unit tests... This will take about 60 seconds." 35 | - sleep 60 36 | - echo "Code coverage is 90%" 37 | 38 | lint-test-job: 39 | stage: test 40 | script: 41 | - echo "Linting code... This will take about 10 seconds." 42 | - sleep 10 43 | - echo "No lint issues found." 44 | 45 | deploy-job: 46 | stage: deploy 47 | script: 48 | - echo "Deploying application..." 49 | - echo "Application successfully deployed." 50 | 51 | -------------------------------------------------------------------------------- /fixtures/Chef.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # This template uses Test Kitchen with the kitchen-dokken driver to 4 | # perform functional testing. Doing so requires that your runner be a 5 | # Docker runner configured for privileged mode. Please see 6 | # https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode 7 | # for help configuring your runner properly, or, if you want to switch 8 | # to a different driver, see http://kitchen.ci/docs/drivers 9 | 10 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 11 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 12 | 13 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 14 | # https://docs.gitlab.com/ee/development/cicd/templates.html 15 | # This specific template is located at: 16 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Chef.gitlab-ci.yml 17 | 18 | image: "chef/chefdk" 19 | services: 20 | - docker:dind 21 | 22 | variables: 23 | DOCKER_HOST: "tcp://docker:2375" 24 | KITCHEN_LOCAL_YAML: ".kitchen.dokken.yml" 25 | 26 | stages: 27 | - build 28 | - lint 29 | - test 30 | - functional 31 | - deploy 32 | 33 | cookstyle: 34 | stage: lint 35 | script: 36 | - chef exec cookstyle . 37 | 38 | chefspec: 39 | stage: test 40 | script: 41 | - chef exec rspec spec 42 | 43 | # Set up your test matrix here. Example: 44 | verify-centos-6: 45 | stage: functional 46 | before_script: 47 | - apt-get update 48 | - apt-get -y install rsync 49 | script: 50 | - kitchen verify default-centos-6 --destroy=always 51 | 52 | verify-centos-7: 53 | stage: functional 54 | before_script: 55 | - apt-get update 56 | - apt-get -y install rsync 57 | script: 58 | - kitchen verify default-centos-7 --destroy=always 59 | -------------------------------------------------------------------------------- /fixtures/Rust.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Rust.gitlab-ci.yml 8 | 9 | # Official language image. Look for the different tagged releases at: 10 | # https://hub.docker.com/r/library/rust/tags/ 11 | image: "rust:latest" 12 | 13 | # Optional: Pick zero or more services to be used on all builds. 14 | # Only needed when using a docker container to run your tests in. 15 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 16 | # services: 17 | # - mysql:latest 18 | # - redis:latest 19 | # - postgres:latest 20 | 21 | # Optional: Install a C compiler, cmake and git into the container. 22 | # You will often need this when you (or any of your dependencies) depends on C code. 23 | # before_script: 24 | # - apt-get update -yqq 25 | # - apt-get install -yqq --no-install-recommends build-essential 26 | 27 | # Use cargo to test the project 28 | test:cargo: 29 | script: 30 | - rustc --version && cargo --version # Print version info for debugging 31 | - cargo test --workspace --verbose 32 | 33 | # Optional: Use a third party library to generate gitlab junit reports 34 | # test:junit-report: 35 | # script: 36 | # Should be specified in Cargo.toml 37 | # - cargo install junitify 38 | # - cargo test -- --format=json -Z unstable-options --report-time | junitify --out $CI_PROJECT_DIR/tests/ 39 | # artifacts: 40 | # when: always 41 | # reports: 42 | # junit: $CI_PROJECT_DIR/tests/*.xml 43 | 44 | deploy: 45 | stage: deploy 46 | script: echo "Define your deployment script!" 47 | environment: production 48 | -------------------------------------------------------------------------------- /examples/Getting-Started.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | This is a sample GitLab CI/CD configuration file that should run without any modifications. 5 | It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts, 6 | it uses echo commands to simulate the pipeline execution. 7 | 8 | A pipeline is composed of independent jobs that run scripts, grouped into stages. 9 | Stages run in sequential order, but jobs within stages run in parallel. 10 | 11 | For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages 12 | 13 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 14 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 15 | 16 | To contribute improvements to CI/CD templates, please follow the Development guide at: 17 | https://docs.gitlab.com/ee/development/cicd/templates.html 18 | This specific template is located at: 19 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml 20 | `; 21 | 22 | const build = new Job().stage("build").script(` 23 | echo "Compiling the code..." 24 | echo "Compile complete." 25 | `); 26 | 27 | const unitTest = new Job().stage("test").script(` 28 | echo "Running unit tests... This will take about 60 seconds." 29 | sleep 60 30 | echo "Code coverage is 90%" 31 | `); 32 | 33 | const lint = new Job().stage("test").script(` 34 | echo "Linting code... This will take about 10 seconds." 35 | sleep 10 36 | echo "No lint issues found." 37 | `); 38 | 39 | const deploy = new Job().stage("deploy").script(` 40 | echo "Deploying application..." 41 | echo "Application successfully deployed." 42 | `); 43 | 44 | const gitlabci = new GitlabCI() 45 | .comment(header) 46 | .comment("") 47 | .stages(["build", "test", "deploy"]) 48 | .addJob("build-job", build) 49 | .addJob("unit-test-job", unitTest) 50 | .addJob("lint-test-job", lint) 51 | .addJob("deploy-job", deploy); 52 | 53 | console.log(gitlabci.toString()); 54 | -------------------------------------------------------------------------------- /examples/Chef.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | This template uses Test Kitchen with the kitchen-dokken driver to 5 | perform functional testing. Doing so requires that your runner be a 6 | Docker runner configured for privileged mode. Please see 7 | https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode 8 | for help configuring your runner properly, or, if you want to switch 9 | to a different driver, see http://kitchen.ci/docs/drivers 10 | 11 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 12 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 13 | 14 | To contribute improvements to CI/CD templates, please follow the Development guide at: 15 | https://docs.gitlab.com/ee/development/cicd/templates.html 16 | This specific template is located at: 17 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Chef.gitlab-ci.yml 18 | `; 19 | 20 | const cookstyle = new Job().stage("lint").script("chef exec cookstyle ."); 21 | 22 | const chefspec = new Job().stage("test").script("chef exec rspec spec"); 23 | 24 | const verifyCentos6 = new Job() 25 | .stage("functional") 26 | .beforeScript( 27 | ` 28 | apt-get update 29 | apt-get -y install rsync 30 | ` 31 | ) 32 | .script("kitchen verify default-centos-6 --destroy=always"); 33 | 34 | const verifyCentos7 = new Job() 35 | .stage("functional") 36 | .beforeScript( 37 | ` 38 | apt-get update 39 | apt-get -y install rsync 40 | ` 41 | ) 42 | .script("kitchen verify default-centos-7 --destroy=always"); 43 | 44 | const gitlabci = new GitlabCI() 45 | .comment(header) 46 | .comment("") 47 | .image("chef/chefdk") 48 | .services(["docker:dind"]) 49 | .variables({ 50 | DOCKER_HOST: "tcp://docker:2375", 51 | KITCHEN_LOCAL_YAML: ".kitchen.dokken.yml", 52 | }) 53 | .stages(["build", "lint", "test", "functional", "deploy"]) 54 | .addJob("cookstyle", cookstyle) 55 | .addJob("chefspec", chefspec) 56 | .addJob("verifyCentos6", verifyCentos6) 57 | .addJob("verifyCentos7", verifyCentos7); 58 | 59 | console.log(gitlabci.toString()); 60 | -------------------------------------------------------------------------------- /fixtures/Ruby.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml 8 | 9 | # Official language image. Look for the different tagged releases at: 10 | # https://hub.docker.com/r/library/ruby/tags/ 11 | image: ruby:latest 12 | 13 | # Pick zero or more services to be used on all builds. 14 | # Only needed when using a docker container to run your tests in. 15 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 16 | services: 17 | - mysql:latest 18 | - redis:latest 19 | - postgres:latest 20 | 21 | variables: 22 | POSTGRES_DB: database_name 23 | 24 | # Cache gems in between builds 25 | cache: 26 | paths: 27 | - vendor/ruby 28 | 29 | # This is a basic example for a gem or script which doesn't use 30 | # services such as redis or postgres 31 | before_script: 32 | - ruby -v # Print out ruby version for debugging 33 | # Uncomment next line if your rails app needs a JS runtime: 34 | # - apt-get update -q && apt-get install nodejs -yqq 35 | - bundle config set --local deployment true # Install dependencies into ./vendor/ruby 36 | - bundle install -j $(nproc) 37 | 38 | # Optional - Delete if not using `rubocop` 39 | rubocop: 40 | script: 41 | - rubocop 42 | 43 | rspec: 44 | script: 45 | - rspec spec 46 | 47 | rails: 48 | variables: 49 | DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB" 50 | script: 51 | - rails db:migrate 52 | - rails db:seed 53 | - rails test 54 | 55 | # This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk 56 | # are supported too: https://github.com/travis-ci/dpl 57 | deploy: 58 | stage: deploy 59 | environment: production 60 | script: 61 | - gem install dpl 62 | - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY 63 | -------------------------------------------------------------------------------- /.fluentci/README.md: -------------------------------------------------------------------------------- 1 | # Deno Pipeline 2 | 3 | [![deno module](https://shield.deno.dev/x/deno_pipeline)](https://deno.land/x/deno_pipeline) 4 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 5 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/deno-pipeline)](https://codecov.io/gh/fluent-ci-templates/deno-pipeline) 6 | 7 | A ready-to-use CI/CD Pipeline for your Deno projects. 8 | 9 | ## 🚀 Usage 10 | 11 | Run the following command: 12 | 13 | ```bash 14 | dagger run fluentci deno_pipeline 15 | ``` 16 | 17 | Or, if you want to use it as a template: 18 | 19 | ```bash 20 | fluentci init -t deno 21 | ``` 22 | 23 | This will create a `.fluentci` folder in your project. 24 | 25 | Now you can run the pipeline with: 26 | 27 | ```bash 28 | dagger run fluentci . 29 | ``` 30 | 31 | ## Environment variables (Deno Deploy) 32 | 33 | | Variable | Description | Default | 34 | | ----------------- | ------------------------- | ---------- | 35 | | DENO_PROJECT | Your project name | | 36 | | NO_STATIC | Disable static assets | `false` | 37 | | EXCLUDE | Exclude files from deploy | | 38 | | DENO_DEPLOY_TOKEN | Your Deno Deploy token | | 39 | | DENO_MAIN_SCRIPT | Your main script | `main.tsx` | 40 | 41 | ## Jobs 42 | 43 | | Job | Description | Options | 44 | | ------ | ------------------------------ | ---------------------- | 45 | | fmt | Format your code | | 46 | | lint | Lint your code | | 47 | | test | Run your tests | `{ ignore: string[] }` | 48 | | deploy | Deploy your app to Deno Deploy | | 49 | 50 | ## Programmatic usage 51 | 52 | You can also use this pipeline programmatically: 53 | 54 | ```ts 55 | import { Client, connect } from "https://esm.sh/@dagger.io/dagger@0.8.1"; 56 | import { Dagger } from "https://deno.land/x/deno_pipeline/mod.ts"; 57 | 58 | const { fmt, lint, test } = Dagger; 59 | 60 | function pipeline(src = ".") { 61 | connect(async (client: Client) => { 62 | await fmt(client, src); 63 | await lint(client, src); 64 | await test(client, src); 65 | }); 66 | } 67 | 68 | pipeline(); 69 | ``` 70 | -------------------------------------------------------------------------------- /fixtures/Grails.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # This template uses the java:8 docker image because there isn't any 2 | # official Grails image at this moment 3 | # 4 | # Grails Framework https://grails.org/ is a powerful Groovy-based web application framework for the JVM 5 | # 6 | # This yml works with Grails 3.x only 7 | # Feel free to change GRAILS_VERSION version with your project version (3.0.1, 3.1.1,...) 8 | # Feel free to change GRADLE_VERSION version with your gradle project version (2.13, 2.14,...) 9 | # If you use Angular profile, this yml it's prepared to work with it 10 | # 11 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 12 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 13 | # 14 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 15 | # https://docs.gitlab.com/ee/development/cicd/templates.html 16 | # This specific template is located at: 17 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Grails.gitlab-ci.yml 18 | 19 | image: java:8 20 | 21 | variables: 22 | GRAILS_VERSION: "3.1.9" 23 | GRADLE_VERSION: "2.13" 24 | 25 | # We use SDKMan as tool for managing versions 26 | before_script: 27 | - apt-get update -qq && apt-get install -y -qq unzip 28 | - curl -sSL https://get.sdkman.io | bash 29 | - echo sdkman_auto_answer=true >> ~/.sdkman/etc/config 30 | - source ~/.sdkman/bin/sdkman-init.sh 31 | - sdk install gradle $GRADLE_VERSION < /dev/null 32 | - sdk use gradle $GRADLE_VERSION 33 | # As it's not a good idea to version gradle.properties feel free to add your 34 | # environments variable here 35 | - echo grailsVersion=$GRAILS_VERSION > gradle.properties 36 | - echo gradleWrapperVersion=2.14 >> gradle.properties 37 | # refresh dependencies from your project 38 | - ./gradlew --refresh-dependencies 39 | # Be aware that if you are using Angular profile, 40 | # Bower cannot be run as root if you don't allow it before. 41 | # Feel free to remove next line if you are not using Bower 42 | - echo '{"allow_root":true}' > ~/.bowerrc 43 | 44 | # This build job does the full grails pipeline 45 | # (compile, test, integrationTest, war, assemble). 46 | build: 47 | script: 48 | - ./gradlew build 49 | 50 | deploy: 51 | stage: deploy 52 | script: echo "Define your deployment script!" 53 | environment: production 54 | -------------------------------------------------------------------------------- /fixtures/Android.latest.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml 7 | 8 | # Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny 9 | # If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template. 10 | 11 | image: openjdk:11-jdk 12 | 13 | variables: 14 | ANDROID_COMPILE_SDK: "30" 15 | ANDROID_BUILD_TOOLS: 30.0.3 16 | ANDROID_SDK_TOOLS: "7583922" 17 | 18 | # Packages installation before running script 19 | before_script: 20 | - apt-get --quiet update --yes 21 | - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 22 | - export ANDROID_HOME="${PWD}/android-home" 23 | - install -d $ANDROID_HOME 24 | - wget --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip 25 | - pushd $ANDROID_HOME 26 | - unzip -d cmdline-tools cmdline-tools.zip 27 | - pushd cmdline-tools 28 | - mv cmdline-tools tools || true 29 | - popd 30 | - popd 31 | - export PATH=$PATH:${ANDROID_HOME}/cmdline-tools/tools/bin/ 32 | - sdkmanager --version 33 | - yes | sdkmanager --licenses || true 34 | - sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" 35 | - sdkmanager "platform-tools" 36 | - sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" 37 | - chmod +x ./gradlew 38 | 39 | # Basic android and gradle stuff 40 | # Check linting 41 | lintDebug: 42 | interruptible: true 43 | stage: build 44 | script: 45 | - ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint 46 | 47 | # Make Project 48 | assembleDebug: 49 | interruptible: true 50 | stage: build 51 | script: 52 | - ./gradlew assembleDebug 53 | artifacts: 54 | paths: 55 | - app/build/outputs/ 56 | 57 | # Run all tests, if any fails, interrupt the pipeline(fail it) 58 | debugTests: 59 | interruptible: true 60 | stage: test 61 | script: 62 | - ./gradlew -Pci --console=plain :app:testDebug 63 | 64 | -------------------------------------------------------------------------------- /fixtures/Dart.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 4 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 5 | 6 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 7 | # https://docs.gitlab.com/ee/development/cicd/templates.html 8 | # This specific template is located at: 9 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Dart.gitlab-ci.yml 10 | 11 | # https://hub.docker.com/_/dart 12 | image: dart:2.17 13 | 14 | variables: 15 | PUB_VARS: --platform vm --timeout 30s --concurrency=6 --test-randomize-ordering-seed=random --reporter=expanded 16 | 17 | .use-pub-cache-bin: 18 | before_script: 19 | - export PUB_CACHE=".pub-cache" 20 | - export PATH="$PATH:$HOME/$PUB_CACHE/bin" 21 | 22 | # Cache generated files and plugins between builds. 23 | .upload-cache: 24 | cache: 25 | paths: 26 | - .pub-cache/bin/ 27 | - .pub-cache/global_packages/ 28 | - .pub-cache/hosted/ 29 | - .dart_tool/ 30 | - .packages 31 | when: 'on_success' 32 | 33 | # Cache downloaded dependencies and plugins between builds. 34 | # To keep cache across branches add 'key: "$CI_JOB_NAME"' 35 | .download-cache: 36 | cache: 37 | paths: 38 | - .dart_tool/ 39 | - .packages 40 | policy: pull 41 | 42 | install-dependencies: 43 | stage: .pre 44 | extends: 45 | - .use-pub-cache-bin 46 | - .upload-cache 47 | script: 48 | - dart pub get --no-precompile 49 | 50 | build: 51 | stage: build 52 | needs: 53 | - install-dependencies 54 | extends: 55 | - .use-pub-cache-bin 56 | - .upload-cache 57 | script: 58 | - dart pub get --offline --precompile 59 | 60 | unit-test: 61 | stage: test 62 | needs: 63 | - build 64 | extends: 65 | - .use-pub-cache-bin 66 | - .download-cache 67 | script: 68 | - dart test $PUB_VARS 69 | 70 | lint-test: 71 | stage: test 72 | needs: 73 | - install-dependencies 74 | extends: 75 | - .use-pub-cache-bin 76 | - .download-cache 77 | script: 78 | - dart analyze . 79 | 80 | format-test: 81 | stage: test 82 | needs: 83 | - install-dependencies 84 | extends: 85 | - .use-pub-cache-bin 86 | - .download-cache 87 | script: 88 | - dart format --set-exit-if-changed bin/ lib/ test/ 89 | -------------------------------------------------------------------------------- /fixtures/Android.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml 7 | 8 | # Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny 9 | # If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template. 10 | 11 | image: eclipse-temurin:17-jdk-jammy 12 | 13 | variables: 14 | ANDROID_COMPILE_SDK: "33" 15 | ANDROID_BUILD_TOOLS: 33.0.2 16 | ANDROID_SDK_TOOLS: "9477386" 17 | 18 | # Packages installation before running script 19 | before_script: 20 | - apt-get --quiet update --yes 21 | - apt-get --quiet install --yes wget unzip 22 | - export ANDROID_HOME="${PWD}/android-sdk-root" 23 | - install -d $ANDROID_HOME 24 | - wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip 25 | - unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip" 26 | - mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools" 27 | - export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin 28 | - sdkmanager --version 29 | - yes | sdkmanager --licenses > /dev/null || true 30 | - sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" 31 | - sdkmanager "platform-tools" 32 | - sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" 33 | - chmod +x ./gradlew 34 | 35 | # Basic android and gradle stuff 36 | # Check linting 37 | lintDebug: 38 | interruptible: true 39 | stage: build 40 | script: 41 | - ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint 42 | artifacts: 43 | paths: 44 | - app/lint/reports/lint-results-debug.html 45 | expose_as: lint-report 46 | when: always 47 | 48 | # Make Project 49 | assembleDebug: 50 | interruptible: true 51 | stage: build 52 | script: 53 | - ./gradlew assembleDebug 54 | artifacts: 55 | paths: 56 | - app/build/outputs/ 57 | 58 | # Run all tests, if any fails, interrupt the pipeline(fail it) 59 | debugTests: 60 | needs: 61 | - lintDebug 62 | - assembleDebug 63 | interruptible: true 64 | stage: test 65 | script: 66 | - ./gradlew -Pci --console=plain :app:testDebug 67 | 68 | -------------------------------------------------------------------------------- /fixtures/Django.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # This example is for testing Django with MySQL. 4 | 5 | # The test CI/CD variables MYSQL_DB, MYSQL_USER and MYSQL_PASS can be set in the project settings at: 6 | # Settings --> CI/CD --> Variables 7 | 8 | # The Django settings in settings.py, used in tests, might look similar to: 9 | # 10 | # DATABASES = { 11 | # 'default': { 12 | # 'ENGINE': 'django.db.backends.mysql', 13 | # 'NAME': os.environ.get('MYSQL_DATABASE'), 14 | # 'USER': os.environ.get('MYSQL_USER'), 15 | # 'PASSWORD': os.environ.get('MYSQL_PASSWORD'), 16 | # 'HOST': 'mysql', 17 | # 'PORT': '3306', 18 | # 'CONN_MAX_AGE':60, 19 | # }, 20 | # } 21 | 22 | # It is possible to use '--settings' to specify a custom settings file on the command line below or use an environment 23 | # variable to trigger an include on the bottom of your settings.py: 24 | # if os.environ.get('DJANGO_CONFIG')=='test': 25 | # from .settings_test import * 26 | # 27 | # It is also possible to hardcode the database name and credentials in the settings.py file and in the .gitlab-ci.yml file. 28 | 29 | # The mysql service needs some variables too. See https://hub.docker.com/_/mysql for possible mysql env variables 30 | # Note that when using a service in GitLab CI/CD that needs environment variables to run, only variables defined in 31 | # .gitlab-ci.yml are passed to the service and variables defined in the GitLab UI are not. 32 | # https://gitlab.com/gitlab-org/gitlab/-/issues/30178 33 | 34 | variables: 35 | MYSQL_DATABASE: $MYSQL_DB 36 | MYSQL_ROOT_PASSWORD: $MYSQL_PASS 37 | MYSQL_USER: $MYSQL_USER 38 | MYSQL_PASSWORD: $MYSQL_PASS 39 | 40 | default: 41 | image: ubuntu:20.04 42 | services: 43 | - mysql:8.0 44 | cache: 45 | paths: 46 | - ~/.cache/pip/ 47 | before_script: 48 | - apt -y update 49 | - apt -y install apt-utils 50 | - apt -y install net-tools python3.8 python3-pip mysql-client libmysqlclient-dev 51 | - apt -y upgrade 52 | - pip3 install -r requirements.txt 53 | 54 | migrations: 55 | stage: build 56 | script: 57 | - python3 manage.py makemigrations 58 | - python3 manage.py migrate 59 | - python3 manage.py check 60 | 61 | django-tests: 62 | stage: test 63 | script: 64 | - echo "GRANT ALL on *.* to '${MYSQL_USER}';"| mysql -u root --password="${MYSQL_ROOT_PASSWORD}" -h mysql 65 | - python3 manage.py test 66 | 67 | deploy: 68 | stage: deploy 69 | script: echo "Define your deployment script!" 70 | environment: production 71 | -------------------------------------------------------------------------------- /examples/Android.latest.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | https://docs.gitlab.com/ee/development/cicd/templates.html 6 | This specific template is located at: 7 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml 8 | 9 | Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny 10 | If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template. 11 | `; 12 | 13 | const lintDebug = new Job() 14 | .interruptible(true) 15 | .stage("build") 16 | .script("./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint"); 17 | 18 | const assembleDebug = new Job() 19 | .interruptible(true) 20 | .stage("build") 21 | .script("./gradlew assembleDebug") 22 | .artifacts({ 23 | paths: ["app/build/outputs/"], 24 | }); 25 | 26 | const debugTests = new Job() 27 | .interruptible(true) 28 | .stage("test") 29 | .script("./gradlew -Pci --console=plain :app:testDebug"); 30 | 31 | const gitlabci = new GitlabCI() 32 | .comment(header) 33 | .comment("") 34 | .image("openjdk:11-jdk") 35 | .variables({ 36 | ANDROID_COMPILE_SDK: "30", 37 | ANDROID_BUILD_TOOLS: "30.0.3", 38 | ANDROID_SDK_TOOLS: "7583922", 39 | }) 40 | .comment("Packages installation before running script") 41 | .beforeScript( 42 | ` 43 | apt-get --quiet update --yes 44 | apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 45 | export ANDROID_HOME="\${PWD}/android-home" 46 | install -d $ANDROID_HOME 47 | wget --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-\${ANDROID_SDK_TOOLS}_latest.zip 48 | pushd $ANDROID_HOME 49 | unzip -d cmdline-tools cmdline-tools.zip 50 | pushd cmdline-tools 51 | mv cmdline-tools tools || true 52 | popd 53 | popd 54 | export PATH=$PATH:\${ANDROID_HOME}/cmdline-tools/tools/bin/ 55 | sdkmanager --version 56 | yes | sdkmanager --licenses || true 57 | sdkmanager "platforms;android-\${ANDROID_COMPILE_SDK}" 58 | sdkmanager "platform-tools" 59 | sdkmanager "build-tools;\${ANDROID_BUILD_TOOLS}" 60 | chmod +x ./gradlew 61 | ` 62 | ) 63 | .comment("Basic android and gradle stuff") 64 | .comment("Check linting") 65 | .addJob("lintDebug", lintDebug) 66 | .comment("Make Project") 67 | .addJob("assembleDebug", assembleDebug) 68 | .comment("Run all tests, if any fails, interrupt the pipeline(fail it)") 69 | .addJob("debugTests", debugTests); 70 | 71 | console.log(gitlabci.toString()); 72 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 49 | 50 | 51 | ## Licensing 52 | 53 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. -------------------------------------------------------------------------------- /examples/Android.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | https://docs.gitlab.com/ee/development/cicd/templates.html 6 | This specific template is located at: 7 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml 8 | 9 | Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny 10 | If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template. 11 | `; 12 | 13 | const lintDebug = new Job() 14 | .interruptible(true) 15 | .stage("build") 16 | .script("./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint") 17 | .artifacts({ 18 | paths: ["app/lint/reports/lint-results-debug.html"], 19 | expose_as: "lint-report", 20 | when: "always", 21 | }); 22 | 23 | const assembleDebug = new Job() 24 | .interruptible(true) 25 | .stage("build") 26 | .script("./gradlew assembleDebug") 27 | .artifacts({ 28 | paths: ["app/build/outputs/"], 29 | }); 30 | 31 | const debugTests = new Job() 32 | .needs(["lintDebug", "assembleDebug"]) 33 | .interruptible(true) 34 | .stage("test") 35 | .script("./gradlew -Pci --console=plain :app:testDebug"); 36 | 37 | const gitlabci = new GitlabCI() 38 | .comment(header) 39 | .comment("") 40 | .image("eclipse-temurin:17-jdk-jammy") 41 | .variables({ 42 | ANDROID_COMPILE_SDK: "33", 43 | ANDROID_BUILD_TOOLS: "33.0.2", 44 | ANDROID_SDK_TOOLS: "9477386", 45 | }) 46 | .comment("Packages installation before running script") 47 | .beforeScript( 48 | ` 49 | apt-get --quiet update --yes 50 | apt-get --quiet install --yes wget unzip 51 | export ANDROID_HOME="\${PWD}/android-sdk-root" 52 | install -d $ANDROID_HOME 53 | wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-\${ANDROID_SDK_TOOLS}_latest.zip 54 | unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip" 55 | mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools" 56 | export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin 57 | sdkmanager --version 58 | yes | sdkmanager --licenses > /dev/null || true 59 | sdkmanager "platforms;android-\${ANDROID_COMPILE_SDK}" 60 | sdkmanager "platform-tools" 61 | sdkmanager "build-tools;\${ANDROID_BUILD_TOOLS}" 62 | chmod +x ./gradlew 63 | ` 64 | ) 65 | .comment("Basic android and gradle stuff") 66 | .comment("Check linting") 67 | .addJob("lintDebug", lintDebug) 68 | .comment("Make Project") 69 | .addJob("assembleDebug", assembleDebug) 70 | .comment("Run all tests, if any fails, interrupt the pipeline(fail it)") 71 | .addJob("debugTests", debugTests); 72 | 73 | console.log(gitlabci.toString()); 74 | -------------------------------------------------------------------------------- /examples/Dart.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | You can copy and paste this template into a new \`.gitlab-ci.yml\` file. 5 | You should not add this template to an existing \`.gitlab-ci.yml\` file by using the \`include:\` keyword. 6 | 7 | To contribute improvements to CI/CD templates, please follow the Development guide at: 8 | https://docs.gitlab.com/ee/development/cicd/templates.html 9 | This specific template is located at: 10 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Dart.gitlab-ci.yml 11 | 12 | https://hub.docker.com/_/dart 13 | `; 14 | 15 | const usePubCacheBin = new Job().beforeScript(` 16 | export PUB_CACHE=".pub-cache" 17 | export PATH="$PATH:$HOME/$PUB_CACHE/bin" 18 | `); 19 | 20 | const uploadCache = new Job().cache( 21 | [ 22 | ".pub-cache/bin/", 23 | ".pub-cache/global_packages/", 24 | ".pub-cache/hosted/", 25 | ".dart_tool/", 26 | ".packages", 27 | ], 28 | undefined, 29 | "on_success" 30 | ); 31 | 32 | const downloadCache = new Job().cache( 33 | [".dart_tool/:", ".packages"], 34 | undefined, 35 | undefined, 36 | "pull" 37 | ); 38 | 39 | const installDependencies = new Job() 40 | .stage(".pre") 41 | .extends([".use-pub-cache-bin", ".upload-cache"]) 42 | .script("dart pub get --no-precompile"); 43 | 44 | const build = new Job() 45 | .stage("build") 46 | .needs(["install-dependencies"]) 47 | .extends([".use-pub-cache-bin", ".upload-cache"]) 48 | .script("dart pub get --offline --precompile"); 49 | 50 | const unitTest = new Job() 51 | .stage("test") 52 | .needs(["build"]) 53 | .extends([".use-pub-cache-bin", ".upload-cache"]) 54 | .script("dart test $PUB_VARS"); 55 | 56 | const lintTest = new Job() 57 | .stage("test") 58 | .needs(["install-dependencies"]) 59 | .extends([".use-pub-cache-bin", ".upload-cache"]) 60 | .script("dart analyze ."); 61 | 62 | const formatTest = new Job() 63 | .stage("test") 64 | .needs(["install-dependencies"]) 65 | .extends([".use-pub-cache-bin", ".upload-cache"]) 66 | .script("dart format --set-exit-if-changed bin/ lib/ test/"); 67 | 68 | const gitlabci = new GitlabCI() 69 | .comment(header) 70 | .image("dart:2.17") 71 | .variables({ 72 | PUB_VARS: 73 | "--platform vm --timeout 30s --concurrency=6 --test-randomize-ordering-seed=random --reporter=expanded", 74 | }) 75 | .addJob(".use-pub-cache-bin", usePubCacheBin) 76 | .comment("Cache generated files and plugins between builds.") 77 | .addJob(".upload-cache", uploadCache) 78 | .comment( 79 | ` 80 | Cache downloaded dependencies and plugins between builds. 81 | To keep cache across branches add 'key: "$CI_JOB_NAME"' 82 | ` 83 | ) 84 | .addJob(".download-cache", downloadCache) 85 | .addJob("install-dependencies", installDependencies) 86 | .addJob("bulid", build) 87 | .addJob("unit-test", unitTest) 88 | .addJob("lint-test", lintTest) 89 | .addJob("format-test", formatTest); 90 | 91 | console.log(gitlabci.toString()); 92 | -------------------------------------------------------------------------------- /fixtures/Kaniko.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 2 | # https://docs.gitlab.com/ee/development/cicd/templates.html 3 | # This specific template is located at: 4 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Kaniko.gitlab-ci.yml 5 | 6 | # Build and publish a tag/branch to Gitlab Docker Registry using Kaniko and Gitlab Docker executor. 7 | # Kaniko can build Docker images without using Docker-In-Docker and it's permission 8 | # drawbacks. No additional configuration required. 9 | kaniko-build: 10 | variables: 11 | # Additional options for Kaniko executor. 12 | # For more details see https://github.com/GoogleContainerTools/kaniko/blob/master/README.md#additional-flags 13 | KANIKO_ARGS: "" 14 | KANIKO_BUILD_CONTEXT: $CI_PROJECT_DIR 15 | stage: build 16 | image: 17 | # For latest releases see https://github.com/GoogleContainerTools/kaniko/releases 18 | # Only debug/*-debug versions of the Kaniko image are known to work within Gitlab CI 19 | name: gcr.io/kaniko-project/executor:debug 20 | entrypoint: [""] 21 | script: 22 | # if the user provide IMAGE_TAG then use it, else build the image tag using the default logic. 23 | # Default logic 24 | # Compose docker tag name 25 | # Git Branch/Tag to Docker Image Tag Mapping 26 | # * Default Branch: main -> latest 27 | # * Branch: feature/my-feature -> branch-feature-my-feature 28 | # * Tag: v1.0.0/beta2 -> v1.0.0-beta2 29 | - | 30 | if [ -z ${IMAGE_TAG+x} ]; then 31 | if [ "$CI_COMMIT_REF_NAME" = $CI_DEFAULT_BRANCH ]; then 32 | VERSION="latest" 33 | elif [ -n "$CI_COMMIT_TAG" ];then 34 | NOSLASH=$(echo "$CI_COMMIT_TAG" | tr -s / - ) 35 | SANITIZED="${NOSLASH//[^a-zA-Z0-9.-]/}" 36 | VERSION="$SANITIZED" 37 | else \ 38 | NOSLASH=$(echo "$CI_COMMIT_REF_NAME" | tr -s / - ) 39 | SANITIZED="${NOSLASH//[^a-zA-Z0-9-]/}" 40 | VERSION="branch-$SANITIZED" 41 | fi 42 | export IMAGE_TAG=$CI_REGISTRY_IMAGE:$VERSION 43 | fi 44 | - echo $IMAGE_TAG 45 | - mkdir -p /kaniko/.docker 46 | # Write credentials to access Gitlab Container Registry within the runner/ci 47 | - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json 48 | # Build and push the container. To disable push add --no-push 49 | - DOCKERFILE_PATH=${DOCKERFILE_PATH:-"$KANIKO_BUILD_CONTEXT/Dockerfile"} 50 | - /kaniko/executor --context $KANIKO_BUILD_CONTEXT --dockerfile $DOCKERFILE_PATH --destination $IMAGE_TAG $KANIKO_ARGS 51 | # Run this job in a branch/tag where a Dockerfile exists 52 | rules: 53 | - exists: 54 | - Dockerfile 55 | # custom Dockerfile path 56 | - if: $DOCKERFILE_PATH 57 | # custom build context without an explicit Dockerfile path 58 | - if: $KANIKO_BUILD_CONTEXT != $CI_PROJECT_DIR 59 | -------------------------------------------------------------------------------- /fixtures/5-Minute-Production-App.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/5-Minute-Production-App.gitlab-ci.yml 7 | 8 | # This template is on early stage of development. 9 | # Use it with caution. For usage instruction please read 10 | # https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template/-/blob/v3.0.0/README.md 11 | 12 | include: 13 | - template: Workflows/Branch-Pipelines.gitlab-ci.yml 14 | - template: Jobs/Build.gitlab-ci.yml 15 | 16 | stages: 17 | - build 18 | - test 19 | - provision 20 | - deploy 21 | - destroy 22 | 23 | variables: 24 | TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_COMMIT_REF_SLUG} 25 | TF_VAR_ENVIRONMENT_NAME: ${CI_PROJECT_PATH_SLUG}_${CI_PROJECT_ID}_${CI_COMMIT_REF_SLUG} 26 | TF_VAR_SERVICE_DESK_EMAIL: incoming+${CI_PROJECT_PATH_SLUG}-${CI_PROJECT_ID}-issue-@incoming.gitlab.com 27 | TF_VAR_SHORT_ENVIRONMENT_NAME: ${CI_PROJECT_ID}-${CI_COMMIT_REF_SLUG} 28 | TF_VAR_SMTP_FROM: ${SMTP_FROM} 29 | 30 | cache: 31 | paths: 32 | - .terraform 33 | 34 | .needs_aws_vars: 35 | rules: 36 | - if: $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY && $AWS_DEFAULT_REGION 37 | when: on_success 38 | - when: never 39 | 40 | terraform_apply: 41 | stage: provision 42 | image: $CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable 43 | extends: .needs_aws_vars 44 | resource_group: terraform 45 | before_script: 46 | - cp /*.tf . 47 | - cp /deploy.sh . 48 | script: 49 | - gitlab-terraform init 50 | - gitlab-terraform plan 51 | - gitlab-terraform plan-json 52 | - gitlab-terraform apply 53 | 54 | deploy: 55 | stage: deploy 56 | image: $CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable 57 | extends: .needs_aws_vars 58 | resource_group: deploy 59 | before_script: 60 | - cp /*.tf . 61 | - cp /deploy.sh . 62 | - cp /conf.nginx . 63 | script: 64 | - ./deploy.sh 65 | artifacts: 66 | reports: 67 | dotenv: deploy.env 68 | environment: 69 | name: $CI_COMMIT_REF_SLUG 70 | url: $DYNAMIC_ENVIRONMENT_URL 71 | on_stop: terraform_destroy 72 | 73 | terraform_destroy: 74 | variables: 75 | GIT_STRATEGY: none 76 | stage: destroy 77 | image: $CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable 78 | before_script: 79 | - cp /*.tf . 80 | - cp /deploy.sh . 81 | script: 82 | - gitlab-terraform destroy -auto-approve 83 | environment: 84 | name: $CI_COMMIT_REF_SLUG 85 | action: stop 86 | rules: 87 | - if: $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY && $AWS_DEFAULT_REGION && $CI_COMMIT_REF_PROTECTED == "false" 88 | when: manual 89 | - when: never 90 | 91 | -------------------------------------------------------------------------------- /.fluentci/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug 4 | report, new feature, correction, or additional documentation, we greatly value 5 | feedback and contributions from our community. 6 | 7 | Please read through this document before submitting any issues or pull requests 8 | to ensure we have all the necessary information to effectively respond to your 9 | bug report or contribution. 10 | 11 | ## Reporting Bugs/Feature Requests 12 | 13 | We welcome you to use the GitHub issue tracker to report bugs or suggest 14 | features. 15 | 16 | When filing an issue, please check existing open, or recently closed, issues to 17 | make sure somebody else hasn't already reported the issue. Please try to include 18 | as much information as you can. Details like these are incredibly useful: 19 | 20 | - A reproducible test case or series of steps 21 | - The version of our code being used 22 | - Any modifications you've made relevant to the bug 23 | - Anything unusual about your environment or deployment 24 | 25 | ## Contributing via Pull Requests 26 | 27 | Contributions via pull requests are much appreciated. Before sending us a pull 28 | request, please ensure that: 29 | 30 | 1. You are working against the latest source on the _master_ branch. 31 | 2. You check existing open, and recently merged, pull requests to make sure 32 | someone else hasn't addressed the problem already. 33 | 3. You open an issue to discuss any significant work - we would hate for your 34 | time to be wasted. 35 | 36 | To send us a pull request, please: 37 | 38 | 1. Fork the repository. 39 | 2. Modify the source; please focus on the specific change you are contributing. 40 | If you also reformat all the code, it will be hard for us to focus on your 41 | change. 42 | 3. Ensure local tests pass. 43 | 4. Commit to your fork using clear commit messages. 44 | 5. Send us a pull request, answering any default questions in the pull request 45 | interface. 46 | 6. Pay attention to any automated CI failures reported in the pull request, and 47 | stay involved in the conversation. 48 | 49 | GitHub provides additional document on 50 | [forking a repository](https://help.github.com/articles/fork-a-repo/) and 51 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 52 | 53 | ## Finding contributions to work on 54 | 55 | Looking at the existing issues is a great way to find something to contribute 56 | on. As our projects, by default, use the default GitHub issue labels 57 | (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 58 | 'help wanted' issues is a great place to start. 59 | 60 | ## Code of Conduct 61 | 62 | This project has adopted the 63 | [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, 64 | available at 65 | https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 66 | 67 | ## Licensing 68 | 69 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to 70 | confirm the licensing of your contribution. 71 | -------------------------------------------------------------------------------- /fixtures/Katalon.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # This template is provided and maintained by Katalon, an official Technology Partner with GitLab. 2 | # 3 | # Use this template to run a Katalon Studio test from this repository. 4 | # You can: 5 | # - Copy and paste this template into a new `.gitlab-ci.yml` file. 6 | # - Add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 7 | # 8 | # In either case, you must also select which job you want to run, `.katalon_tests` 9 | # or `.katalon_tests_with_artifacts` (see configuration below), and add that configuration 10 | # to a new job with `extends:`. For example: 11 | # 12 | # Katalon-tests: 13 | # extends: 14 | # - .katalon_tests_with_artifacts 15 | # 16 | # Requirements: 17 | # - A Katalon Studio project with the content saved in the root GitLab repository folder. 18 | # - An active KRE license. 19 | # - A valid Katalon API key. 20 | # 21 | # CI/CD variables, set in the project CI/CD settings: 22 | # - KATALON_TEST_SUITE_PATH: The default path is `Test Suites/`. 23 | # Defines which test suite to run. 24 | # - KATALON_API_KEY: The Katalon API key. 25 | # - KATALON_PROJECT_DIR: Optional. Add if the project is in another location. 26 | # - KATALON_ORG_ID: Optional. Add if you are part of multiple Katalon orgs. 27 | # Set to the Org ID that has KRE licenses assigned. For more info on the Org ID, 28 | # see https://support.katalon.com/hc/en-us/articles/4724459179545-How-to-get-Organization-ID- 29 | 30 | .katalon_tests: 31 | # Use the latest version of the Katalon Runtime Engine. You can also use other versions of the 32 | # Katalon Runtime Engine by specifying another tag, for example `katalonstudio/katalon:8.1.2` 33 | # or `katalonstudio/katalon:8.3.0`. 34 | image: 'katalonstudio/katalon' 35 | services: 36 | - docker:dind 37 | variables: 38 | # Specify the Katalon Studio project directory. By default, it is stored under the root project folder. 39 | KATALON_PROJECT_DIR: $CI_PROJECT_DIR 40 | 41 | # The following bash script has two different versions, one if you set the KATALON_ORG_ID 42 | # CI/CD variable, and the other if you did not set it. If you have more than one org in 43 | # admin.katalon.com you must set the KATALON_ORG_ID variable with an ORG ID or 44 | # the Katalon Test Suite fails to run. 45 | # 46 | # You can update or add additional `katalonc` commands below. To see all of the arguments 47 | # `katalonc` supports, go to https://docs.katalon.com/katalon-studio/docs/console-mode-execution.html 48 | script: 49 | - |- 50 | if [[ $KATALON_ORG_ID == "" ]]; then 51 | katalonc.sh -projectPath=$KATALON_PROJECT_DIR -apiKey=$KATALON_API_KEY -browserType="Chrome" -retry=0 -statusDelay=20 -testSuitePath="$KATALON_TEST_SUITE_PATH" -reportFolder=Reports/ 52 | else 53 | katalonc.sh -projectPath=$KATALON_PROJECT_DIR -apiKey=$KATALON_API_KEY -browserType="Chrome" -retry=0 -statusDelay=20 -orgID=$KATALON_ORG_ID -testSuitePath="$KATALON_TEST_SUITE_PATH" -reportFolder=Reports/ 54 | fi 55 | 56 | # Upload the artifacts and make the junit report accessible under the Pipeline Tests 57 | .katalon_tests_with_artifacts: 58 | extends: .katalon_tests 59 | artifacts: 60 | when: always 61 | paths: 62 | - Reports/ 63 | reports: 64 | junit: 65 | Reports/*/*/*/*.xml 66 | -------------------------------------------------------------------------------- /fixtures/Laravel.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 2 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 3 | # 4 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | # https://docs.gitlab.com/ee/development/cicd/templates.html 6 | # This specific template is located at: 7 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml 8 | 9 | # Official framework image. Look for the different tagged releases at: 10 | # https://hub.docker.com/r/library/php 11 | image: php:latest 12 | 13 | # Pick zero or more services to be used on all builds. 14 | # Only needed when using a docker container to run your tests in. 15 | # Check out: https://docs.gitlab.com/ee/ci/services/index.html 16 | services: 17 | - mysql:latest 18 | 19 | variables: 20 | MYSQL_DATABASE: project_name 21 | MYSQL_ROOT_PASSWORD: secret 22 | 23 | # This folder is cached between builds 24 | # https://docs.gitlab.com/ee/ci/yaml/index.html#cache 25 | cache: 26 | paths: 27 | - vendor/ 28 | - node_modules/ 29 | 30 | # This is a basic example for a gem or script which doesn't use 31 | # services such as redis or postgres 32 | before_script: 33 | # Update packages 34 | - apt-get update -yqq 35 | # Prep for Node 36 | - apt-get install gnupg -yqq 37 | # Upgrade to Node 8 38 | - curl -sL https://deb.nodesource.com/setup_8.x | bash - 39 | # Install dependencies 40 | - apt-get install git nodejs libcurl4-gnutls-dev libicu-dev libmcrypt-dev libvpx-dev libjpeg-dev libpng-dev libxpm-dev zlib1g-dev libfreetype6-dev libxml2-dev libexpat1-dev libbz2-dev libgmp3-dev libldap2-dev unixodbc-dev libpq-dev libsqlite3-dev libaspell-dev libsnmp-dev libpcre3-dev libtidy-dev -yqq 41 | # Install php extensions 42 | - docker-php-ext-install mbstring pdo_mysql curl json intl gd xml zip bz2 opcache 43 | # Install & enable Xdebug for code coverage reports 44 | - pecl install xdebug 45 | - docker-php-ext-enable xdebug 46 | # Install Composer and project dependencies. 47 | - curl -sS https://getcomposer.org/installer | php 48 | - php composer.phar install 49 | # Install Node dependencies. 50 | # comment this out if you don't have a node dependency 51 | - npm install 52 | # Copy over testing configuration. 53 | # Don't forget to set the database config in .env.testing correctly 54 | # DB_HOST=mysql 55 | # DB_DATABASE=project_name 56 | # DB_USERNAME=root 57 | # DB_PASSWORD=secret 58 | - cp .env.testing .env 59 | # Run npm build 60 | # comment this out if you don't have a frontend build 61 | # you can change this to to your frontend building script like 62 | # npm run build 63 | - npm run dev 64 | # Generate an application key. Re-cache. 65 | - php artisan key:generate 66 | - php artisan config:cache 67 | # Run database migrations. 68 | - php artisan migrate 69 | # Run database seed 70 | - php artisan db:seed 71 | 72 | test: 73 | script: 74 | # run laravel tests 75 | - php vendor/bin/phpunit --coverage-text --colors=never 76 | # run frontend tests 77 | # if you have any task for testing frontend 78 | # set it in your package.json script 79 | # comment this out if you don't have a frontend test 80 | - npm test 81 | 82 | deploy: 83 | stage: deploy 84 | script: echo "Define your deployment script!" 85 | environment: production 86 | -------------------------------------------------------------------------------- /examples/5-Minute-Production-App.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job, Environment } from "../mod.ts"; 2 | 3 | const header = ` 4 | To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | https://docs.gitlab.com/ee/development/cicd/templates.html 6 | This specific template is located at: 7 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/5-Minute-Production-App.gitlab-ci.yml 8 | 9 | This template is on early stage of development. 10 | Use it with caution. For usage instruction please read 11 | https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template/-/blob/v3.0.0/README.md 12 | `; 13 | 14 | const env = { 15 | TF_ADDRESS: 16 | "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_COMMIT_REF_SLUG}", 17 | TF_VAR_ENVIRONMENT_NAME: 18 | "${CI_PROJECT_PATH_SLUG}_${CI_PROJECT_ID}_${CI_COMMIT_REF_SLUG}", 19 | TF_VAR_SERVICE_DESK_EMAIL: 20 | "incoming+${CI_PROJECT_PATH_SLUG}-${CI_PROJECT_ID}-issue-@incoming.gitlab.com", 21 | TF_VAR_SHORT_ENVIRONMENT_NAME: "${CI_PROJECT_ID}-${CI_COMMIT_REF_SLUG}", 22 | TF_VAR_SMTP_FROM: "${SMTP_FROM}", 23 | }; 24 | 25 | const awsVarsRules = [ 26 | { 27 | if: "$AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY && $AWS_DEFAULT_REGION", 28 | when: "on_success", 29 | }, 30 | { 31 | when: "never", 32 | }, 33 | ]; 34 | 35 | const terraformApply = new Job() 36 | .stage("provision") 37 | .image( 38 | "$CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable" 39 | ) 40 | .extends(".needs_aws_vars") 41 | .resource_group("terraform").beforeScript(` 42 | cp /*.tf . 43 | cp /deploy.sh . 44 | `).script(` 45 | gitlab-terraform init 46 | gitlab-terraform plan 47 | gitlab-terraform plan-json 48 | gitlab-terraform apply 49 | `); 50 | 51 | const deploy = new Job() 52 | .stage("deploy") 53 | .image( 54 | "$CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable" 55 | ) 56 | .extends(".needs_aws_vars") 57 | .resource_group("deploy") 58 | .beforeScript( 59 | ` 60 | cp /*.tf . 61 | cp /deploy.sh . 62 | cp /conf.nginx . 63 | ` 64 | ) 65 | .script("./deploy.sh") 66 | .artifacts({ 67 | reports: { 68 | dotenv: "deploy.env", 69 | }, 70 | }) 71 | .environment( 72 | new Environment("$CI_COMMIT_REF_SLUG", "$DYNAMIC_ENVIRONMENT_URL").onStop( 73 | "terraform_destroy" 74 | ) 75 | ); 76 | 77 | const terraformDestroy = new Job() 78 | .variables({ 79 | GIT_STRATEGY: "none", 80 | }) 81 | .stage("destroy") 82 | .image( 83 | "$CI_TEMPLATE_REGISTRY_HOST/gitlab-org/5-minute-production-app/deploy-template/stable" 84 | ) 85 | .beforeScript( 86 | ` 87 | cp /*.tf . 88 | cp /deploy.sh .` 89 | ) 90 | .script("gitlab-terraform destroy -auto-approve") 91 | .environment(new Environment("$CI_COMMIT_REF_SLUG").action("stop")) 92 | .rules([ 93 | { 94 | if: '$AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY && $AWS_DEFAULT_REGION && $CI_COMMIT_REF_PROTECTED == "false"', 95 | when: "manual", 96 | }, 97 | { 98 | when: "never", 99 | }, 100 | ]); 101 | const gitlabci = new GitlabCI() 102 | .comment(header) 103 | .comment("") 104 | .include({ 105 | template: "Workflows/Branch-Pipelines.gitlab-ci.yml", 106 | }) 107 | .include({ 108 | template: "Jobs/Build.gitlab-ci.yml", 109 | }) 110 | .stages(["build", "test", "provision", "deploy", "destroy"]) 111 | .variables(env) 112 | .cache([".terraform"]) 113 | .addJob(".needs_aws_vars", new Job().rules(awsVarsRules)) 114 | .addJob("terraform_apply", terraformApply) 115 | .addJob("deploy", deploy) 116 | .addJob("terraform_destroy", terraformDestroy); 117 | 118 | console.log(gitlabci.toString()); 119 | -------------------------------------------------------------------------------- /fixtures/Indeni.Cloudrail.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # This template is provided and maintained by Indeni, an official Technology Partner with GitLab. 2 | # See https://about.gitlab.com/partners/technology-partners/#security for more information. 3 | 4 | # For more information about Indeni Cloudrail: https://indeni.com/cloudrail/ 5 | # 6 | # This file shows an example of using Indeni Cloudrail with GitLab CI/CD. 7 | # It is not designed to be included in an existing CI/CD configuration with the "include:" keyword. 8 | # Documentation about this integration: https://indeni.com/doc-indeni-cloudrail/integrate-with-ci-cd/gitlab-instructions 9 | # 10 | # For an example of this used in a GitLab repository, see: https://gitlab.com/indeni/cloudrail-demo/-/blob/master/.gitlab-ci.yml 11 | 12 | # The sast-report output complies with GitLab's format. This report displays Cloudrail's 13 | # results in the Security tab in the pipeline view, if you have that feature enabled 14 | # (GitLab Ultimate only). Otherwise, Cloudrail generates a JUnit report, which displays 15 | # in the "Test summary" in merge requests. 16 | 17 | # Note that Cloudrail's input is the Terraform plan. That is why we've included in this 18 | # template an example of doing that. You are welcome to replace it with your own way 19 | # of generating a Terraform plan. 20 | 21 | # Before you can use this template, get a Cloudrail API key from the Cloudrail web 22 | # user interface. Save it as a CI/CD variable named CLOUDRAIL_API_KEY in your project 23 | # settings. 24 | 25 | variables: 26 | TEST_ROOT: ${CI_PROJECT_DIR}/my_folder_with_terraform_content 27 | 28 | default: 29 | before_script: 30 | - cd ${CI_PROJECT_DIR}/my_folder_with_terraform_content 31 | 32 | init_and_plan: 33 | stage: build 34 | image: "$CI_TEMPLATE_REGISTRY_HOST/gitlab-org/terraform-images/releases/0.13" 35 | rules: 36 | - if: $SAST_DISABLED 37 | when: never 38 | - if: $CI_COMMIT_BRANCH 39 | exists: 40 | - '**/*.tf' 41 | script: 42 | - terraform init 43 | - terraform plan -out=plan.out 44 | artifacts: 45 | name: "$CI_COMMIT_BRANCH-terraform_plan" 46 | paths: 47 | - ./**/plan.out 48 | - ./**/.terraform 49 | 50 | cloudrail_scan: 51 | stage: test 52 | image: indeni/cloudrail-cli:1.2.44 53 | rules: 54 | - if: $SAST_DISABLED 55 | when: never 56 | - if: $CI_COMMIT_BRANCH 57 | exists: 58 | - '**/*.tf' 59 | script: 60 | - | 61 | if [[ "${GITLAB_FEATURES}" == *"security_dashboard"* ]]; then 62 | echo "You are licensed for GitLab Security Dashboards. Your scan results will display in the Security Dashboard." 63 | cloudrail run --tf-plan plan.out \ 64 | --directory . \ 65 | --api-key ${CLOUDRAIL_API_KEY} \ 66 | --origin ci \ 67 | --build-link "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID" \ 68 | --execution-source-identifier "$CI_COMMIT_BRANCH - $CI_JOB_ID" \ 69 | --output-format json-gitlab-sast \ 70 | --output-file ${CI_PROJECT_DIR}/cloudrail-sast-report.json \ 71 | --auto-approve 72 | else 73 | echo "Your scan results will display in the GitLab Test results visualization panel." 74 | cloudrail run --tf-plan plan.out \ 75 | --directory . \ 76 | --api-key ${CLOUDRAIL_API_KEY} \ 77 | --origin ci \ 78 | --build-link "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID" \ 79 | --execution-source-identifier "$CI_COMMIT_BRANCH - $CI_JOB_ID" \ 80 | --output-format junit \ 81 | --output-file ${CI_PROJECT_DIR}/cloudrail-junit-report.xml \ 82 | --auto-approve 83 | fi 84 | artifacts: 85 | reports: 86 | sast: cloudrail-sast-report.json 87 | junit: cloudrail-junit-report.xml 88 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3", 3 | "packages": { 4 | "specifiers": { 5 | "jsr:@std/assert@^0.217.0": "jsr:@std/assert@0.217.0", 6 | "jsr:@std/fmt@^0.217.0": "jsr:@std/fmt@0.217.0", 7 | "jsr:@std/testing@0.217.0": "jsr:@std/testing@0.217.0", 8 | "npm:@types/node": "npm:@types/node@18.16.19", 9 | "npm:yaml@2.3.1": "npm:yaml@2.3.1", 10 | "npm:zod@3.22.1": "npm:zod@3.22.1" 11 | }, 12 | "jsr": { 13 | "@std/assert@0.217.0": { 14 | "integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642", 15 | "dependencies": [ 16 | "jsr:@std/fmt@^0.217.0" 17 | ] 18 | }, 19 | "@std/fmt@0.217.0": { 20 | "integrity": "cb99f82500b8da20202fedfa8bb94dd0222e81f0494ed9087de20ee3d8a39a8d" 21 | }, 22 | "@std/testing@0.217.0": { 23 | "integrity": "97508b254ca1888d512215288bfb3f192a4e6e84336ba56b189c7862258a058b", 24 | "dependencies": [ 25 | "jsr:@std/assert@^0.217.0" 26 | ] 27 | } 28 | }, 29 | "npm": { 30 | "@types/node@18.16.19": { 31 | "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", 32 | "dependencies": {} 33 | }, 34 | "yaml@2.3.1": { 35 | "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", 36 | "dependencies": {} 37 | }, 38 | "zod@3.22.1": { 39 | "integrity": "sha512-+qUhAMl414+Elh+fRNtpU+byrwjDFOS1N7NioLY+tSlcADTx4TkCUua/hxJvxwDXcV4397/nZ420jy4n4+3WUg==", 40 | "dependencies": {} 41 | } 42 | } 43 | }, 44 | "remote": { 45 | "https://deno.land/std@0.191.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", 46 | "https://deno.land/std@0.191.0/testing/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea", 47 | "https://deno.land/std@0.191.0/testing/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", 48 | "https://deno.land/std@0.191.0/testing/asserts.ts": "e16d98b4d73ffc4ed498d717307a12500ae4f2cbe668f1a215632d19fcffc22f", 49 | "https://deno.land/x/zod@v3.22.1/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea", 50 | "https://deno.land/x/zod@v3.22.1/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", 51 | "https://deno.land/x/zod@v3.22.1/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", 52 | "https://deno.land/x/zod@v3.22.1/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", 53 | "https://deno.land/x/zod@v3.22.1/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", 54 | "https://deno.land/x/zod@v3.22.1/helpers/parseUtil.ts": "f791e6e65a0340d85ad37d26cd7a3ba67126cd9957eac2b7163162155283abb1", 55 | "https://deno.land/x/zod@v3.22.1/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", 56 | "https://deno.land/x/zod@v3.22.1/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", 57 | "https://deno.land/x/zod@v3.22.1/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774", 58 | "https://deno.land/x/zod@v3.22.1/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", 59 | "https://deno.land/x/zod@v3.22.1/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", 60 | "https://deno.land/x/zod@v3.22.1/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", 61 | "https://deno.land/x/zod@v3.22.1/types.ts": "4edc1823385f446532c8c9f676d84550c6dc54b17135e34508576647d9612d0e", 62 | "https://esm.sh/v128/yaml@2.3.1": "8ef3aee065e93b03cebf8fd5a3418bc30131344b7f2b8c8ae27bf9f277416087", 63 | "https://esm.sh/v128/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /fixtures/Julia.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # This is an example .gitlab-ci.yml file to test (and optionally report the coverage 2 | # results of) your [Julia][1] packages. Please refer to the [documentation][2] 3 | # for more information about package development in Julia. 4 | # 5 | # Here, it is assumed that your Julia package is named `MyPackage`. Change it to 6 | # whatever name you have given to your package. 7 | # 8 | # [1]: http://julialang.org/ 9 | # [2]: https://docs.julialang.org/en/v1/manual/documentation/index.html 10 | # 11 | # You can copy and paste this template into a new `.gitlab-ci.yml` file. 12 | # You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. 13 | # 14 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 15 | # https://docs.gitlab.com/ee/development/cicd/templates.html 16 | # This specific template is located at: 17 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Julia.gitlab-ci.yml 18 | 19 | # Below is the template to run your tests in Julia 20 | .test_template: &test_definition 21 | # Uncomment below (and adjust as needed) to run the tests for specific references 22 | # only, such as the default branch, a `development` branch, and so on: 23 | # rules: 24 | # - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 25 | # - if: $CI_COMMIT_BRANCH == "development" 26 | script: 27 | # Let's run the tests. Substitute `coverage = false` below, if you do not 28 | # want coverage results. 29 | - julia -e 'using Pkg; Pkg.clone(pwd()); Pkg.build("MyPackage"); Pkg.test("MyPackage"; coverage = true)' 30 | # Comment out below if you do not want coverage results. 31 | - julia -e 'using Pkg; Pkg.add("Coverage"); 32 | import MyPackage; cd(joinpath(dirname(pathof(MyPackage)), "..")); 33 | using Coverage; cl, tl = get_summary(process_folder()); 34 | println("(", cl/tl*100, "%) covered")' 35 | 36 | # Name a test and select an appropriate image. 37 | # images comes from Docker hub 38 | test:0.7: 39 | image: julia:0.7 40 | <<: *test_definition 41 | 42 | test:1.0: 43 | image: julia:1.0 44 | <<: *test_definition 45 | 46 | # Maybe you would like to test your package against the development branch: 47 | # test:1.1-dev (not sure there is such an image in docker, so not tested yet): 48 | # image: julia:v1.1-dev 49 | # # ... allowing for failures, since we are testing against the development 50 | # # branch: 51 | # allow_failure: true 52 | # <<: *test_definition 53 | 54 | # REMARK: Do not forget to enable the coverage feature for your project, if you 55 | # are using code coverage reporting above. This can be done by 56 | # 57 | # - Navigating to the `CI/CD Pipelines` settings of your project, 58 | # - Copying and pasting the default `Simplecov` regex example provided, i.e., 59 | # `\(\d+.\d+\%\) covered` in the `test coverage parsing` textfield. 60 | 61 | # Example documentation deployment 62 | pages: 63 | image: julia:0.7 64 | stage: deploy 65 | script: 66 | - apt-get update -qq && apt-get install -y git # needed by Documenter 67 | - julia -e 'using Pkg; Pkg.clone(pwd()); Pkg.build("MyPackage");' # rebuild Julia (can be put somewhere else I'm sure 68 | - julia -e 'using Pkg; import MyPackage; Pkg.add("Documenter")' # install Documenter 69 | - julia --color=yes docs/make.jl # make documentation 70 | - mv docs/build public # move to the directory picked up by Gitlab pages 71 | artifacts: 72 | paths: 73 | - public 74 | rules: 75 | - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 76 | 77 | # WARNING: This template is using the `julia` images from [Docker 78 | # Hub][3]. One can use custom Julia images and/or the official ones found 79 | # in the same place. However, care must be taken to correctly locate the binary 80 | # file (`/opt/julia/bin/julia` above), which is usually given on the image's 81 | # description page. 82 | # 83 | # [3]: https://hub.docker.com/_/julia/ 84 | 85 | deploy: 86 | stage: deploy 87 | script: echo "Define your deployment script!" 88 | environment: production 89 | -------------------------------------------------------------------------------- /src/gitlabci.ts: -------------------------------------------------------------------------------- 1 | import { stringify } from "../deps.ts"; 2 | import Job from "./job.ts"; 3 | import { 4 | YamlSpec, 5 | Variable, 6 | Include, 7 | Rule, 8 | VariableSchema, 9 | RuleSchema, 10 | } from "./gitlabci_spec.ts"; 11 | 12 | class GitlabCI { 13 | private yaml: YamlSpec; 14 | 15 | constructor() { 16 | this.yaml = []; 17 | } 18 | 19 | addJob(name: string, job: Job): GitlabCI { 20 | this.yaml.push({ 21 | [name]: job.into(), 22 | }); 23 | return this; 24 | } 25 | 26 | stages(stages: string[]): GitlabCI { 27 | this.yaml.push({ 28 | stages, 29 | }); 30 | return this; 31 | } 32 | 33 | variable(name: string, value: string): GitlabCI { 34 | if (this.yaml.find((item) => (item as { variables: Variable }).variables)) { 35 | ( 36 | this.yaml.filter( 37 | (item) => (item as { variables: Variable }).variables 38 | )[0] as { variables: Variable } 39 | ).variables[name] = value; 40 | return this; 41 | } 42 | this.yaml.push({ 43 | variables: { 44 | [name]: value, 45 | }, 46 | }); 47 | 48 | return this; 49 | } 50 | 51 | variables(variables: Variable): GitlabCI { 52 | VariableSchema.parse(variables); 53 | if (this.yaml.find((item) => (item as { variables: Variable }).variables)) { 54 | const { variables: vars } = this.yaml.filter( 55 | (item) => (item as { variables: Variable }).variables 56 | )[0] as { 57 | variables: Variable; 58 | }; 59 | Object.assign(vars, variables); 60 | return this; 61 | } 62 | this.yaml.push({ 63 | variables, 64 | }); 65 | return this; 66 | } 67 | 68 | cache(paths: string[], key?: string): GitlabCI { 69 | this.yaml.push({ 70 | cache: { 71 | paths, 72 | key, 73 | }, 74 | }); 75 | return this; 76 | } 77 | 78 | comment(text: string): GitlabCI { 79 | text = text.trim(); 80 | text 81 | .split("\n") 82 | .map((line) => line.trim()) 83 | .map((line) => 84 | line.length > 0 ? this.yaml.push(`# ${line}`) : this.yaml.push("") 85 | ); 86 | return this; 87 | } 88 | 89 | beforeScript(script: string): GitlabCI { 90 | script = script.trim(); 91 | 92 | const before_script = script 93 | .split("\n") 94 | .map((line) => line.trim()) 95 | .filter((line) => line.length > 0); 96 | 97 | this.yaml.push({ 98 | before_script, 99 | }); 100 | 101 | return this; 102 | } 103 | 104 | image(image: string): GitlabCI { 105 | this.yaml.push({ 106 | image, 107 | }); 108 | return this; 109 | } 110 | 111 | include(value: { template: string }): GitlabCI { 112 | if (this.yaml.find((item) => (item as { include: Include }).include)) { 113 | const { include } = this.yaml.filter( 114 | (item) => (item as { include: Include }).include 115 | )[0] as { 116 | include: Include; 117 | }; 118 | if (include instanceof Array) { 119 | include.push(value); 120 | } 121 | return this; 122 | } 123 | this.yaml.push({ 124 | include: [value], 125 | }); 126 | return this; 127 | } 128 | 129 | workflow(value: { rules: Rule[] }): GitlabCI { 130 | for (const rule of value.rules) { 131 | RuleSchema.parse(rule); 132 | } 133 | this.yaml.push({ 134 | workflow: value, 135 | }); 136 | return this; 137 | } 138 | 139 | services(services: string[]): GitlabCI { 140 | this.yaml.push({ 141 | services, 142 | }); 143 | return this; 144 | } 145 | 146 | toString() { 147 | let str = `# Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci\n\n`; 148 | 149 | for (const item of this.yaml) { 150 | if (typeof item === "string") { 151 | str += `${item}\n`; 152 | continue; 153 | } 154 | str += `${stringify(item, { lineWidth: 0 })}\n`; 155 | } 156 | 157 | return str.replaceAll(" {}", "").replaceAll("|-", "|"); 158 | } 159 | 160 | newLine(): GitlabCI { 161 | this.yaml.push(""); 162 | return this; 163 | } 164 | 165 | write(path = ".gitlab-ci.yml") { 166 | const config = this.toString(); 167 | Deno.writeTextFileSync(path, config); 168 | } 169 | } 170 | 171 | export default GitlabCI; 172 | -------------------------------------------------------------------------------- /fixtures/Android-Fastlane.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml 7 | 8 | # Read more about how to use this script on this blog post https://about.gitlab.com/2019/01/28/android-publishing-with-gitlab-and-fastlane/ 9 | # If you are looking for a simpler template that does not publish, see the Android template. 10 | # You will also need to configure your build.gradle, Dockerfile, and fastlane configuration to make this work. 11 | 12 | # The following environment variables also need to be defined via the CI/CD settings: 13 | 14 | # - $signing_jks_file_hex: A hex-encoded Java keystore file containing your signing keys. 15 | # To encode this file, use `xxd -p .jks` and save the output as `$signing_jks_file_hex` 16 | # - $google_play_service_account_api_key_json: Your Google Play service account credentials - https://docs.fastlane.tools/getting-started/android/setup/#collect-your-google-credentials 17 | 18 | stages: 19 | - environment 20 | - build 21 | - test 22 | - deploy 23 | - internal 24 | - alpha 25 | - beta 26 | - production 27 | 28 | .updateContainerJob: 29 | image: docker:stable 30 | stage: environment 31 | services: 32 | - docker:dind 33 | script: 34 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 35 | - docker pull --quiet $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true 36 | - docker build --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG . 37 | - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 38 | 39 | updateContainer: 40 | extends: .updateContainerJob 41 | only: 42 | changes: 43 | - Dockerfile 44 | 45 | ensureContainer: 46 | extends: .updateContainerJob 47 | allow_failure: true 48 | before_script: 49 | - "mkdir -p ~/.docker && echo '{\"experimental\": \"enabled\"}' > ~/.docker/config.json" 50 | - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 51 | - | 52 | if docker manifest inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG > /dev/null; then 53 | echo 'Skipping job since there is already an image with this tag' 54 | exit 0 55 | fi 56 | 57 | .build_job: 58 | image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 59 | stage: build 60 | before_script: 61 | - echo "$signing_jks_file_hex" | xxd -r -p - > android-signing-keystore.jks 62 | - export VERSION_CODE="$CI_PIPELINE_IID" && echo "$VERSION_CODE" 63 | - export VERSION_SHA="${CI_COMMIT_SHA:0:8}" && echo "$VERSION_SHA" 64 | after_script: 65 | - rm -f android-signing-keystore.jks || true 66 | artifacts: 67 | paths: 68 | - app/build/outputs 69 | 70 | buildDebug: 71 | extends: .build_job 72 | script: 73 | - bundle exec fastlane buildDebug 74 | 75 | buildRelease: 76 | extends: .build_job 77 | script: 78 | - bundle exec fastlane buildRelease 79 | environment: 80 | name: production 81 | 82 | testDebug: 83 | image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 84 | stage: test 85 | dependencies: 86 | - buildDebug 87 | script: 88 | - bundle exec fastlane test 89 | 90 | publishInternal: 91 | image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 92 | stage: internal 93 | dependencies: 94 | - buildRelease 95 | when: manual 96 | before_script: 97 | - echo $google_play_service_account_api_key_json > ~/google_play_api_key.json 98 | after_script: 99 | - rm ~/google_play_api_key.json 100 | script: 101 | - bundle exec fastlane internal 102 | 103 | .promote_job: 104 | image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 105 | when: manual 106 | dependencies: [] 107 | before_script: 108 | - echo $google_play_service_account_api_key_json > ~/google_play_api_key.json 109 | after_script: 110 | - rm ~/google_play_api_key.json 111 | 112 | promoteAlpha: 113 | extends: .promote_job 114 | stage: alpha 115 | script: 116 | - bundle exec fastlane promote_internal_to_alpha 117 | 118 | promoteBeta: 119 | extends: .promote_job 120 | stage: beta 121 | script: 122 | - bundle exec fastlane promote_alpha_to_beta 123 | 124 | promoteProduction: 125 | extends: .promote_job 126 | stage: production 127 | only: 128 | variables: 129 | - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 130 | script: 131 | - bundle exec fastlane promote_beta_to_production 132 | 133 | -------------------------------------------------------------------------------- /src/job.ts: -------------------------------------------------------------------------------- 1 | import Environment from "./environment.ts"; 2 | import { 3 | Artifacts, 4 | Job as JobSpec, 5 | Only, 6 | Parallel, 7 | Policy, 8 | Rule, 9 | Variable, 10 | When, 11 | } from "./gitlabci_spec.ts"; 12 | 13 | class Job { 14 | private job: JobSpec; 15 | 16 | constructor() { 17 | this.job = {}; 18 | } 19 | 20 | stage(stage: string): Job { 21 | this.job.stage = stage; 22 | return this; 23 | } 24 | 25 | interruptible(value: boolean): Job { 26 | this.job.interruptible = value; 27 | return this; 28 | } 29 | 30 | needs(needs: string[]): Job { 31 | this.job.needs = needs; 32 | return this; 33 | } 34 | 35 | dependencies(dependencies: string[]): Job { 36 | this.job.dependencies = dependencies; 37 | return this; 38 | } 39 | 40 | image(image: string): Job { 41 | this.job.image = image; 42 | return this; 43 | } 44 | 45 | extends(value: string | string[]): Job { 46 | this.job.extends = value; 47 | return this; 48 | } 49 | 50 | resource_group(group: string): Job { 51 | this.job.resource_group = group; 52 | return this; 53 | } 54 | 55 | environment(environment: string | Environment): Job { 56 | if (typeof environment === "string") { 57 | this.job.environment = environment; 58 | return this; 59 | } 60 | this.job.environment = environment.into(); 61 | return this; 62 | } 63 | 64 | script(script: string, options?: { multiline: boolean }): Job { 65 | script = script.trim(); 66 | 67 | if (options?.multiline) { 68 | this.job.script 69 | ? this.job.script.push(script) 70 | : (this.job.script = [script]); 71 | return this; 72 | } 73 | 74 | script 75 | .split("\n") 76 | .map((line) => line.trim()) 77 | .filter((line) => line.length > 0) 78 | .forEach((line) => 79 | this.job.script 80 | ? this.job.script.push(line) 81 | : (this.job.script = [line]) 82 | ); 83 | return this; 84 | } 85 | 86 | beforeScript(script: string, options?: { multiline: boolean }): Job { 87 | script = script.trim(); 88 | 89 | if (options?.multiline) { 90 | this.job.before_script 91 | ? this.job.before_script.push(script) 92 | : (this.job.before_script = [script]); 93 | return this; 94 | } 95 | 96 | script 97 | .split("\n") 98 | .map((line) => line.trim()) 99 | .filter((line) => line.length > 0) 100 | .forEach((line) => 101 | this.job.before_script 102 | ? this.job.before_script.push(line) 103 | : (this.job.before_script = [line]) 104 | ); 105 | return this; 106 | } 107 | 108 | afterScript(script: string, options?: { multiline: boolean }): Job { 109 | script = script.trim(); 110 | 111 | if (options?.multiline) { 112 | this.job.after_script 113 | ? this.job.after_script.push(script) 114 | : (this.job.after_script = [script]); 115 | return this; 116 | } 117 | 118 | script 119 | .split("\n") 120 | .map((line) => line.trim()) 121 | .filter((line) => line.length > 0) 122 | .forEach((line) => 123 | this.job.after_script 124 | ? this.job.after_script.push(line) 125 | : (this.job.after_script = [line]) 126 | ); 127 | return this; 128 | } 129 | 130 | only(only: Only): Job { 131 | this.job.only = only; 132 | return this; 133 | } 134 | 135 | rules(rules: Rule[]): Job { 136 | this.job.rules = rules; 137 | return this; 138 | } 139 | 140 | when(when: When): Job { 141 | this.job.when = when; 142 | return this; 143 | } 144 | 145 | allowFailure(allowFailure: boolean): Job { 146 | this.job.allow_failure = allowFailure; 147 | return this; 148 | } 149 | 150 | except(except: string[]): Job { 151 | this.job.except = except; 152 | return this; 153 | } 154 | 155 | artifacts(values: Artifacts): Job { 156 | this.job.artifacts = values; 157 | return this; 158 | } 159 | 160 | services(services: string[]): Job { 161 | this.job.services = services; 162 | return this; 163 | } 164 | 165 | include(local: string, strategy: string): Job { 166 | this.job.include = this.job.include 167 | ? [ 168 | ...this.job.include, 169 | { 170 | local, 171 | strategy, 172 | }, 173 | ] 174 | : [ 175 | { 176 | local, 177 | strategy, 178 | }, 179 | ]; 180 | return this; 181 | } 182 | 183 | parallel(parallel: Parallel): Job { 184 | this.job.parallel = parallel; 185 | return this; 186 | } 187 | 188 | cache(paths: string[], key?: string, when?: When, policy?: Policy): Job { 189 | this.job.cache = { 190 | key, 191 | paths, 192 | when, 193 | policy, 194 | }; 195 | return this; 196 | } 197 | 198 | variables(values: Variable): Job { 199 | this.job.variables = values; 200 | return this; 201 | } 202 | 203 | coverage(coverage: string): Job { 204 | this.job.coverage = coverage; 205 | return this; 206 | } 207 | 208 | tags(tags: string[]): Job { 209 | this.job.tags = tags; 210 | return this; 211 | } 212 | 213 | into(): JobSpec { 214 | return this.job; 215 | } 216 | } 217 | 218 | export default Job; 219 | -------------------------------------------------------------------------------- /examples/Android-Fastlane.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job, Environment } from "../mod.ts"; 2 | 3 | const header = ` 4 | To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | https://docs.gitlab.com/ee/development/cicd/templates.html 6 | This specific template is located at: 7 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml 8 | 9 | Read more about how to use this script on this blog post https://about.gitlab.com/2019/01/28/android-publishing-with-gitlab-and-fastlane/ 10 | If you are looking for a simpler template that does not publish, see the Android template. 11 | You will also need to configure your build.gradle, Dockerfile, and fastlane configuration to make this work. 12 | 13 | The following environment variables also need to be defined via the CI/CD settings: 14 | 15 | - $signing_jks_file_hex: A hex-encoded Java keystore file containing your signing keys. 16 | To encode this file, use \`xxd -p .jks\` and save the output as \`$signing_jks_file_hex\` 17 | - $google_play_service_account_api_key_json: Your Google Play service account credentials - https://docs.fastlane.tools/getting-started/android/setup/#collect-your-google-credentials 18 | `; 19 | 20 | const updateContainerJob = new Job() 21 | .image("docker:stable") 22 | .stage("environment") 23 | .services(["docker:dind"]).script(` 24 | docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 25 | docker pull --quiet $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true 26 | docker build --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG . 27 | docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 28 | `); 29 | 30 | const updateContainer = new Job() 31 | .extends(".updateContainerJob") 32 | .only({ changes: ["Dockerfile"] }); 33 | 34 | const ensureContainer = new Job() 35 | .extends(".updateContainerJob") 36 | .allowFailure(true) 37 | .beforeScript( 38 | ` 39 | mkdir -p ~/.docker && echo '{"experimental": "enabled"}' > ~/.docker/config.json 40 | docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY 41 | ` 42 | ) 43 | .beforeScript( 44 | ` 45 | if docker manifest inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG > /dev/null; then 46 | echo 'Skipping job since there is already an image with this tag' 47 | exit 0 48 | fi`, 49 | { multiline: true } 50 | ); 51 | 52 | const buildJob = new Job() 53 | .image("$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG") 54 | .stage("build") 55 | .beforeScript( 56 | ` 57 | echo \"$signing_jks_file_hex\" | xxd -r -p - > android-signing-keystore.jks 58 | export VERSION_CODE="$CI_PIPELINE_IID" && echo \"$VERSION_CODE\" 59 | export VERSION_SHA=\"\${CI_COMMIT_SHA:0:8}\" && echo \"$VERSION_SHA\" 60 | ` 61 | ) 62 | .afterScript("rm -f android-signing-keystore.jks || true") 63 | .artifacts({ paths: ["app/build/outputs"] }); 64 | 65 | const buildDebug = new Job() 66 | .extends(".build_job") 67 | .script("bundle exec fastlane buildDebug"); 68 | 69 | const buildRelease = new Job() 70 | .extends(".build_job") 71 | .script("bundle exec fastlane buildRelease") 72 | .environment(new Environment("production")); 73 | 74 | const testDebug = new Job() 75 | .image("$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG") 76 | .stage("test") 77 | .dependencies(["buildDebug"]) 78 | .script("bundle exec fastlane test"); 79 | 80 | const publishInternal = new Job() 81 | .image("$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG") 82 | .stage("internal") 83 | .dependencies(["buildRelease"]) 84 | .when("manual") 85 | .beforeScript( 86 | "echo $google_play_service_account_api_key_json > ~/google_play_api_key.json" 87 | ) 88 | .afterScript("rm ~/google_play_api_key.json") 89 | .script("bundle exec fastlane internal"); 90 | 91 | const promoteJob = new Job() 92 | .image("$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG") 93 | .when("manual") 94 | .dependencies([]) 95 | .beforeScript( 96 | "echo $google_play_service_account_api_key_json > ~/google_play_api_key.json" 97 | ) 98 | .afterScript("rm ~/google_play_api_key.json"); 99 | 100 | const promoteAlpha = new Job() 101 | .extends(".promote_job") 102 | .stage("alpha") 103 | .script("bundle exec fastlane promote_internal_to_alpha"); 104 | 105 | const promoteBeta = new Job() 106 | .extends(".promote_job") 107 | .stage("beta") 108 | .script("bundle exec fastlane promote_alpha_to_beta"); 109 | 110 | const promoteProduction = new Job() 111 | .extends(".promote_job") 112 | .stage("production") 113 | .only({ 114 | variables: ["$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"], 115 | }) 116 | .script("bundle exec fastlane promote_beta_to_production"); 117 | 118 | const gitlabci = new GitlabCI() 119 | .comment(header) 120 | .comment("") 121 | .stages([ 122 | "environment", 123 | "build", 124 | "test", 125 | "deploy", 126 | "internal", 127 | "alpha", 128 | "beta", 129 | "production", 130 | ]) 131 | .addJob(".updateContainerJob", updateContainerJob) 132 | .addJob("updateContainer", updateContainer) 133 | .addJob("ensureContainer", ensureContainer) 134 | .addJob(".build_job", buildJob) 135 | .addJob("buildDebug", buildDebug) 136 | .addJob("buildRelease", buildRelease) 137 | .addJob("testDebug", testDebug) 138 | .addJob("publishInternal", publishInternal) 139 | .addJob(".promote_job", promoteJob) 140 | .addJob("promoteAlpha", promoteAlpha) 141 | .addJob("promoteBeta", promoteBeta) 142 | .addJob("promoteProduction", promoteProduction); 143 | 144 | console.log(gitlabci.toString()); 145 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [GitHub Issues](https://github.com/tsirysndr/fluent-gitlab-ci/issues). 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations -------------------------------------------------------------------------------- /.fluentci/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [GitHub Issues](https://github.com/fluent-ci-templates/deno-pipeline/issues). 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/jobs.ts: -------------------------------------------------------------------------------- 1 | import Client from "@dagger.io/dagger"; 2 | import { upload } from "https://deno.land/x/codecov_pipeline@v0.1.0/src/dagger/jobs.ts"; 3 | import { withDevbox } from "https://deno.land/x/nix_installer_pipeline@v0.3.6/src/dagger/steps.ts"; 4 | import { existsSync } from "fs"; 5 | 6 | export enum Job { 7 | fmt = "fmt", 8 | lint = "lint", 9 | test = "test", 10 | deploy = "deploy", 11 | codecov = "codecov", 12 | } 13 | 14 | const baseCtr = (client: Client, pipeline: string) => { 15 | if (existsSync("devbox.json")) { 16 | return withDevbox( 17 | client 18 | .pipeline(pipeline) 19 | .container() 20 | .from("alpine:latest") 21 | .withExec(["apk", "update"]) 22 | .withExec(["apk", "add", "bash", "curl"]) 23 | .withMountedCache("/nix", client.cacheVolume("nix")) 24 | .withMountedCache("/etc/nix", client.cacheVolume("nix-etc")) 25 | ); 26 | } 27 | return client.pipeline(pipeline).container().from("denoland/deno:alpine"); 28 | }; 29 | 30 | export const lint = async (client: Client, src = ".") => { 31 | const context = client.host().directory(src); 32 | let command = ["deno", "lint"]; 33 | 34 | if (existsSync("devbox.json")) { 35 | command = ["sh", "-c", `devbox run -- ${command.join(" ")}`]; 36 | } 37 | 38 | const ctr = baseCtr(client, Job.lint) 39 | .withDirectory("/app", context, { 40 | exclude: [".git", ".devbox", ".fluentci"], 41 | }) 42 | .withWorkdir("/app") 43 | .withExec(command); 44 | 45 | const result = await ctr.stdout(); 46 | 47 | console.log(result); 48 | }; 49 | 50 | export const fmt = async (client: Client, src = ".") => { 51 | const context = client.host().directory(src); 52 | let command = ["deno", "fmt"]; 53 | 54 | if (existsSync("devbox.json")) { 55 | command = ["sh", "-c", `devbox run -- ${command.join(" ")}`]; 56 | } 57 | 58 | const ctr = baseCtr(client, Job.fmt) 59 | .withDirectory("/app", context, { 60 | exclude: [".git", ".devbox", ".fluentci"], 61 | }) 62 | .withWorkdir("/app") 63 | .withExec(command); 64 | 65 | const result = await ctr.stdout(); 66 | 67 | console.log(result); 68 | }; 69 | 70 | export const test = async ( 71 | client: Client, 72 | src = ".", 73 | options: { ignore: string[] } = { ignore: [] } 74 | ) => { 75 | const context = client.host().directory(src); 76 | let command = ["deno", "test", "-A", "--coverage=coverage", "--lock-write"]; 77 | 78 | if (options.ignore.length > 0) { 79 | command = command.concat([`--ignore=${options.ignore.join(",")}`]); 80 | } 81 | 82 | if (existsSync("devbox.json")) { 83 | command = ["sh", "-c", `devbox run -- ${command.join(" ")}`]; 84 | } 85 | 86 | const ctr = baseCtr(client, Job.test) 87 | .from("denoland/deno:alpine") 88 | .withDirectory("/app", context, { 89 | exclude: [".git", ".devbox", ".fluentci"], 90 | }) 91 | .withWorkdir("/app") 92 | .withMountedCache("/root/.cache/deno", client.cacheVolume("deno-cache")) 93 | .withExec(command) 94 | .withExec(["sh", "-c", "deno coverage ./coverage --lcov > coverage.lcov"]); 95 | 96 | await ctr.file("/app/coverage.lcov").export("./coverage.lcov"); 97 | 98 | const result = await ctr.stdout(); 99 | 100 | console.log(result); 101 | }; 102 | 103 | export const deploy = async (client: Client, src = ".") => { 104 | const context = client.host().directory(src); 105 | let installDeployCtl = [ 106 | "deno", 107 | "install", 108 | "--allow-all", 109 | "--no-check", 110 | "-r", 111 | "-f", 112 | "https://deno.land/x/deploy/deployctl.ts", 113 | ]; 114 | const project = Deno.env.get("DENO_PROJECT"); 115 | const noStatic = Deno.env.get("NO_STATIC"); 116 | const exclude = Deno.env.get("EXCLUDE"); 117 | 118 | let command = ["deployctl", "deploy"]; 119 | 120 | if (noStatic) { 121 | command = command.concat(["--no-static"]); 122 | } 123 | 124 | if (exclude) { 125 | command = command.concat([`--exclude=${exclude}`]); 126 | } 127 | 128 | if (!Deno.env.get("DENO_DEPLOY_TOKEN")) { 129 | throw new Error("DENO_DEPLOY_TOKEN environment variable is not set"); 130 | } 131 | 132 | if (!project) { 133 | throw new Error("DENO_PROJECT environment variable is not set"); 134 | } 135 | 136 | const script = Deno.env.get("DENO_MAIN_SCRIPT") || "main.tsx"; 137 | command = command.concat([`--project=${project}`, script]); 138 | 139 | if (existsSync("devbox.json")) { 140 | command = ["sh", "-c", `devbox run -- ${command.join(" ")}`]; 141 | installDeployCtl = [ 142 | "sh", 143 | "-c", 144 | `devbox run -- ${installDeployCtl.join(" ")}`, 145 | ]; 146 | } 147 | 148 | const ctr = baseCtr(client, Job.deploy) 149 | .from("denoland/deno:alpine") 150 | .withDirectory("/app", context, { 151 | exclude: [".git", ".devbox", ".fluentci"], 152 | }) 153 | .withWorkdir("/app") 154 | .withEnvVariable("PATH", "/root/.deno/bin:$PATH", { expand: true }) 155 | .withEnvVariable("DENO_DEPLOY_TOKEN", Deno.env.get("DENO_DEPLOY_TOKEN")!) 156 | .withEnvVariable( 157 | "DENO_MAIN_SCRIPT", 158 | Deno.env.get("DENO_MAIN_SCRIPT") || "main.tsx" 159 | ) 160 | .withExec(installDeployCtl) 161 | .withExec(command); 162 | 163 | const result = await ctr.stdout(); 164 | 165 | console.log(result); 166 | }; 167 | 168 | export type JobExec = ( 169 | client: Client, 170 | src?: string 171 | ) => 172 | | Promise 173 | | (( 174 | client: Client, 175 | src?: string, 176 | options?: { 177 | ignore: string[]; 178 | } 179 | ) => Promise); 180 | 181 | export const codecov = upload; 182 | 183 | export const runnableJobs: Record = { 184 | [Job.fmt]: fmt, 185 | [Job.lint]: lint, 186 | [Job.test]: test, 187 | [Job.deploy]: deploy, 188 | [Job.codecov]: upload, 189 | }; 190 | 191 | export const jobDescriptions: Record = { 192 | [Job.fmt]: "Format your code", 193 | [Job.lint]: "Lint your code", 194 | [Job.test]: "Run your tests", 195 | [Job.deploy]: "Deploy your code to Deno Deploy", 196 | [Job.codecov]: "Upload your code coverage to Codecov", 197 | }; 198 | -------------------------------------------------------------------------------- /fixtures/Auto-DevOps.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | # To contribute improvements to CI/CD templates, please follow the Development guide at: 4 | # https://docs.gitlab.com/ee/development/cicd/templates.html 5 | # This specific template is located at: 6 | # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml 7 | 8 | # Auto DevOps 9 | 10 | # This CI/CD configuration provides a standard pipeline for 11 | # * building a Docker image (using a buildpack if necessary), 12 | # * storing the image in the container registry, 13 | # * running tests from a buildpack, 14 | # * running code quality analysis, 15 | # * creating a review app for each topic branch, 16 | # * and continuous deployment to production 17 | 18 | # Test jobs may be disabled by setting environment variables: 19 | # * test: TEST_DISABLED 20 | # * code_quality: CODE_QUALITY_DISABLED 21 | # * license_management: LICENSE_MANAGEMENT_DISABLED 22 | # * browser_performance: BROWSER_PERFORMANCE_DISABLED 23 | # * load_performance: LOAD_PERFORMANCE_DISABLED 24 | # * sast: SAST_DISABLED 25 | # * secret_detection: SECRET_DETECTION_DISABLED 26 | # * dependency_scanning: DEPENDENCY_SCANNING_DISABLED 27 | # * container_scanning: CONTAINER_SCANNING_DISABLED 28 | # * dast: DAST_DISABLED 29 | # * review: REVIEW_DISABLED 30 | # * stop_review: REVIEW_DISABLED 31 | # * code_intelligence: CODE_INTELLIGENCE_DISABLED 32 | 33 | # In order to deploy, you must have a Kubernetes cluster configured either 34 | # via a project integration, or via group/project variables. 35 | # KUBE_INGRESS_BASE_DOMAIN must also be set on the cluster settings, 36 | # as a variable at the group or project level, or manually added below. 37 | 38 | # Continuous deployment to production is enabled by default. 39 | # If you want to deploy to staging first, set STAGING_ENABLED environment variable. 40 | # If you want to enable incremental rollout, either manual or time based, 41 | # set INCREMENTAL_ROLLOUT_MODE environment variable to "manual" or "timed". 42 | # If you want to use canary deployments, set CANARY_ENABLED environment variable. 43 | 44 | # If Auto DevOps fails to detect the proper buildpack, or if you want to 45 | # specify a custom buildpack, set a project variable `BUILDPACK_URL` to the 46 | # repository URL of the buildpack. 47 | # e.g. BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v142 48 | # If you need multiple buildpacks, add a file to your project called 49 | # `.buildpacks` that contains the URLs, one on each line, in order. 50 | # Note: Auto CI does not work with multiple buildpacks yet 51 | 52 | image: alpine:latest 53 | 54 | variables: 55 | CS_DEFAULT_BRANCH_IMAGE: $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_COMMIT_SHA 56 | POSTGRES_USER: user 57 | POSTGRES_PASSWORD: testing-password 58 | POSTGRES_DB: $CI_ENVIRONMENT_SLUG 59 | DOCKER_DRIVER: overlay2 60 | ROLLOUT_RESOURCE_TYPE: deployment 61 | DOCKER_TLS_CERTDIR: "" 62 | 63 | stages: 64 | - build 65 | - test 66 | - deploy 67 | - review 68 | - dast 69 | - staging 70 | - canary 71 | - production 72 | - incremental rollout 10% 73 | - incremental rollout 25% 74 | - incremental rollout 50% 75 | - incremental rollout 100% 76 | - performance 77 | - cleanup 78 | 79 | workflow: 80 | rules: 81 | - if: $BUILDPACK_URL || $AUTO_DEVOPS_EXPLICITLY_ENABLED == "1" || $DOCKERFILE_PATH 82 | - exists: 83 | - Dockerfile 84 | - exists: 85 | - project.clj 86 | - exists: 87 | - go.mod 88 | - Gopkg.mod 89 | - Godeps/Godeps.json 90 | - vendor/vendor.json 91 | - glide.yaml 92 | - src/**/*.go 93 | - exists: 94 | - gradlew 95 | - build.gradle 96 | - settings.gradle 97 | - exists: 98 | - pom.xml 99 | - pom.atom 100 | - pom.clj 101 | - pom.groovy 102 | - pom.rb 103 | - pom.scala 104 | - pom.yaml 105 | - pom.yml 106 | - exists: 107 | - .buildpacks 108 | - exists: 109 | - package.json 110 | - exists: 111 | - composer.json 112 | - index.php 113 | - exists: 114 | - "**/conf/application.conf" 115 | - exists: 116 | - requirements.txt 117 | - setup.py 118 | - Pipfile 119 | - exists: 120 | - Gemfile 121 | - exists: 122 | - "*.sbt" 123 | - project/*.scala 124 | - .sbt/*.scala 125 | - project/build.properties 126 | - exists: 127 | - .static 128 | 129 | # NOTE: These links point to the latest templates for development in GitLab canonical project, 130 | # therefore the actual templates that were included for Auto DevOps pipelines 131 | # could be different from the contents in the links. 132 | # To view the actual templates, please replace `master` to the specific GitLab version when 133 | # the Auto DevOps pipeline started running e.g. `v13.0.2-ee`. 134 | include: 135 | - template: Jobs/Build.gitlab-ci.yml 136 | - template: Jobs/Test.gitlab-ci.yml 137 | - template: Jobs/Code-Quality.gitlab-ci.yml 138 | - template: Jobs/Code-Intelligence.gitlab-ci.yml 139 | - template: Jobs/Deploy.gitlab-ci.yml 140 | - template: Jobs/Deploy/ECS.gitlab-ci.yml 141 | - template: Jobs/Deploy/EC2.gitlab-ci.yml 142 | - template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml 143 | - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml 144 | - template: Jobs/Helm-2to3.gitlab-ci.yml 145 | - template: Security/DAST.gitlab-ci.yml 146 | - template: Jobs/Container-Scanning.gitlab-ci.yml 147 | - template: Jobs/Dependency-Scanning.gitlab-ci.yml 148 | - template: Jobs/License-Scanning.gitlab-ci.yml 149 | - template: Jobs/SAST.gitlab-ci.yml 150 | - template: Jobs/Secret-Detection.gitlab-ci.yml 151 | 152 | # The latest build job generates a dotenv report artifact with a CI_APPLICATION_TAG 153 | # that also includes the image digest. This configures Auto Deploy to receive 154 | # this artifact and use the updated CI_APPLICATION_TAG for deployments. 155 | .auto-deploy: 156 | dependencies: 157 | - build 158 | 159 | dast_environment_deploy: 160 | dependencies: 161 | - build 162 | 163 | -------------------------------------------------------------------------------- /examples/Auto-DevOps.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "../mod.ts"; 2 | 3 | const header = ` 4 | To contribute improvements to CI/CD templates, please follow the Development guide at: 5 | https://docs.gitlab.com/ee/development/cicd/templates.html 6 | This specific template is located at: 7 | https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml 8 | 9 | Auto DevOps 10 | 11 | This CI/CD configuration provides a standard pipeline for 12 | * building a Docker image (using a buildpack if necessary), 13 | * storing the image in the container registry, 14 | * running tests from a buildpack, 15 | * running code quality analysis, 16 | * creating a review app for each topic branch, 17 | * and continuous deployment to production 18 | 19 | Test jobs may be disabled by setting environment variables: 20 | * test: TEST_DISABLED 21 | * code_quality: CODE_QUALITY_DISABLED 22 | * license_management: LICENSE_MANAGEMENT_DISABLED 23 | * browser_performance: BROWSER_PERFORMANCE_DISABLED 24 | * load_performance: LOAD_PERFORMANCE_DISABLED 25 | * sast: SAST_DISABLED 26 | * secret_detection: SECRET_DETECTION_DISABLED 27 | * dependency_scanning: DEPENDENCY_SCANNING_DISABLED 28 | * container_scanning: CONTAINER_SCANNING_DISABLED 29 | * dast: DAST_DISABLED 30 | * review: REVIEW_DISABLED 31 | * stop_review: REVIEW_DISABLED 32 | * code_intelligence: CODE_INTELLIGENCE_DISABLED 33 | 34 | In order to deploy, you must have a Kubernetes cluster configured either 35 | via a project integration, or via group/project variables. 36 | KUBE_INGRESS_BASE_DOMAIN must also be set on the cluster settings, 37 | as a variable at the group or project level, or manually added below. 38 | 39 | Continuous deployment to production is enabled by default. 40 | If you want to deploy to staging first, set STAGING_ENABLED environment variable. 41 | If you want to enable incremental rollout, either manual or time based, 42 | set INCREMENTAL_ROLLOUT_MODE environment variable to "manual" or "timed". 43 | If you want to use canary deployments, set CANARY_ENABLED environment variable. 44 | 45 | If Auto DevOps fails to detect the proper buildpack, or if you want to 46 | specify a custom buildpack, set a project variable \`BUILDPACK_URL\` to the 47 | repository URL of the buildpack. 48 | e.g. BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v142 49 | If you need multiple buildpacks, add a file to your project called 50 | \`.buildpacks\` that contains the URLs, one on each line, in order. 51 | Note: Auto CI does not work with multiple buildpacks yet 52 | `; 53 | 54 | const env = { 55 | CS_DEFAULT_BRANCH_IMAGE: 56 | "$CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_COMMIT_SHA", 57 | POSTGRES_USER: "user", 58 | POSTGRES_PASSWORD: "testing-password", 59 | POSTGRES_DB: "$CI_ENVIRONMENT_SLUG", 60 | DOCKER_DRIVER: "overlay2", 61 | ROLLOUT_RESOURCE_TYPE: "deployment", 62 | DOCKER_TLS_CERTDIR: "", 63 | }; 64 | 65 | const stages = [ 66 | "build", 67 | "test", 68 | "deploy", 69 | "review", 70 | "dast", 71 | "staging", 72 | "canary", 73 | "production", 74 | "incremental rollout 10%", 75 | "incremental rollout 25%", 76 | "incremental rollout 50%", 77 | "incremental rollout 100%", 78 | "performance", 79 | "cleanup", 80 | ]; 81 | 82 | const workflow = { 83 | rules: [ 84 | { 85 | if: '$BUILDPACK_URL || $AUTO_DEVOPS_EXPLICITLY_ENABLED == "1" || $DOCKERFILE_PATH', 86 | }, 87 | { 88 | exists: ["Dockerfile"], 89 | }, 90 | { 91 | exists: ["project.clj"], 92 | }, 93 | { 94 | exists: [ 95 | "go.mod", 96 | "Gopkg.mod", 97 | "Godeps/Godeps.json", 98 | "vendor/vendor.json", 99 | "glide.yaml", 100 | "src/**/*.go", 101 | ], 102 | }, 103 | { 104 | exists: ["gradlew", "build.gradle", "settings.gradle"], 105 | }, 106 | { 107 | exists: [ 108 | "pom.xml", 109 | "pom.atom", 110 | "pom.clj", 111 | "pom.groovy", 112 | "pom.rb", 113 | "pom.scala", 114 | "pom.yaml", 115 | "pom.yml", 116 | ], 117 | }, 118 | { 119 | exists: [".buildpacks"], 120 | }, 121 | { 122 | exists: ["package.json"], 123 | }, 124 | { 125 | exists: ["composer.json", "index.php"], 126 | }, 127 | { 128 | exists: ["**/conf/application.conf"], 129 | }, 130 | 131 | { 132 | exists: ["requirements.txt", "setup.py", "Pipfile"], 133 | }, 134 | { 135 | exists: ["Gemfile"], 136 | }, 137 | { 138 | exists: [ 139 | "*.sbt", 140 | "project/*.scala", 141 | ".sbt/*.scala", 142 | "project/build.properties", 143 | ], 144 | }, 145 | { 146 | exists: [".static"], 147 | }, 148 | ], 149 | }; 150 | 151 | const gitlabci = new GitlabCI() 152 | .comment(header) 153 | .comment("") 154 | .image("alpine:latest") 155 | .variables(env) 156 | .stages(stages) 157 | .workflow(workflow) 158 | .comment( 159 | ` 160 | NOTE: These links point to the latest templates for development in GitLab canonical project, 161 | therefore the actual templates that were included for Auto DevOps pipelines 162 | could be different from the contents in the links. 163 | To view the actual templates, please replace \`master\` to the specific GitLab version when 164 | the Auto DevOps pipeline started running e.g. \`v13.0.2-ee\`. 165 | ` 166 | ) 167 | .include({ template: "Jobs/Build.gitlab-ci.yml" }) 168 | .include({ template: "Jobs/Test.gitlab-ci.yml" }) 169 | .include({ template: "Jobs/Code-Quality.gitlab-ci.yml" }) 170 | .include({ template: "Jobs/Code-Intelligence.gitlab-ci.yml" }) 171 | .include({ template: "Jobs/Deploy.gitlab-ci.yml" }) 172 | .include({ template: "Jobs/Deploy/ECS.gitlab-ci.yml" }) 173 | .include({ template: "Jobs/Deploy/EC2.gitlab-ci.yml" }) 174 | .include({ template: "Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml" }) 175 | .include({ template: "Jobs/Browser-Performance-Testing.gitlab-ci.yml" }) 176 | .include({ template: "Jobs/Helm-2to3.gitlab-ci.yml" }) 177 | .include({ template: "Security/DAST.gitlab-ci.yml" }) 178 | .include({ template: "Jobs/Container-Scanning.gitlab-ci.yml" }) 179 | .include({ template: "Jobs/Dependency-Scanning.gitlab-ci.yml" }) 180 | .include({ template: "Jobs/License-Scanning.gitlab-ci.yml" }) 181 | .include({ template: "Jobs/SAST.gitlab-ci.yml" }) 182 | .include({ template: "Jobs/Secret-Detection.gitlab-ci.yml" }) 183 | .comment( 184 | ` 185 | The latest build job generates a dotenv report artifact with a CI_APPLICATION_TAG 186 | that also includes the image digest. This configures Auto Deploy to receive 187 | this artifact and use the updated CI_APPLICATION_TAG for deployments. 188 | ` 189 | ) 190 | .addJob(".auto-deploy", new Job().dependencies(["build"])) 191 | .addJob("dast_environment_deploy", new Job().dependencies(["build"])); 192 | 193 | console.log(gitlabci.toString()); 194 | -------------------------------------------------------------------------------- /src/gitlabci_spec.ts: -------------------------------------------------------------------------------- 1 | import { z } from "../deps.ts"; 2 | 3 | export const WhenSchema = z.enum([ 4 | "on_success", 5 | "on_failure", 6 | "always", 7 | "never", 8 | "manual", 9 | ]); 10 | 11 | export const PolicySchema = z.enum(["pull-push", "pull", "push"]); 12 | 13 | export const CacheSchema = z.object({ 14 | when: WhenSchema.optional(), 15 | key: z.string().optional(), 16 | paths: z.array(z.string()), 17 | policy: PolicySchema.optional(), 18 | }); 19 | 20 | export const RuleSchema = z.object({ 21 | if: z.string().optional(), 22 | when: z.string().optional(), 23 | exists: z.array(z.string()).optional(), 24 | }); 25 | 26 | export const ReportsSchema = z.object({ 27 | junit: z.union([z.string(), z.array(z.string())]).optional(), 28 | browser_performance: z.string().optional(), 29 | coverage_report: z 30 | .object({ 31 | coverage_format: z.string(), 32 | path: z.string(), 33 | }) 34 | .optional(), 35 | codequality: z.union([z.string(), z.array(z.string())]).optional(), 36 | dotenv: z.union([z.string(), z.array(z.string())]).optional(), 37 | lsif: z.union([z.string(), z.array(z.string())]).optional(), 38 | sast: z.union([z.string(), z.array(z.string())]).optional(), 39 | dependency_scanning: z.union([z.string(), z.array(z.string())]).optional(), 40 | container_scanning: z.union([z.string(), z.array(z.string())]).optional(), 41 | dast: z.union([z.string(), z.array(z.string())]).optional(), 42 | license_management: z.union([z.string(), z.array(z.string())]).optional(), 43 | license_scanning: z.union([z.string(), z.array(z.string())]).optional(), 44 | requirements: z.union([z.string(), z.array(z.string())]).optional(), 45 | secret_detection: z.union([z.string(), z.array(z.string())]).optional(), 46 | metrics: z.union([z.string(), z.array(z.string())]).optional(), 47 | terraform: z.union([z.string(), z.array(z.string())]).optional(), 48 | cyclonedx: z.union([z.string(), z.array(z.string())]).optional(), 49 | load_performance: z.union([z.string(), z.array(z.string())]).optional(), 50 | }); 51 | 52 | export const ArtifactsSchema = z.object({ 53 | paths: z.array(z.string()).optional(), 54 | exclude: z.array(z.string()).optional(), 55 | expose_as: z.string().optional(), 56 | name: z.string().optional(), 57 | untracked: z.boolean().optional(), 58 | when: WhenSchema.optional(), 59 | expire_in: z.string().optional(), 60 | reports: ReportsSchema.optional(), 61 | }); 62 | 63 | export const ActionSchema = z.enum([ 64 | "start", 65 | "prepare", 66 | "stop", 67 | "verify", 68 | "access", 69 | ]); 70 | 71 | export const DeploymentTierSchema = z.enum([ 72 | "production", 73 | "staging", 74 | "testing", 75 | "development", 76 | "other", 77 | ]); 78 | 79 | export const EnvironmentSchema = z.object({ 80 | name: z.string(), 81 | url: z.string().optional(), 82 | on_stop: z.string().optional(), 83 | action: ActionSchema.optional(), 84 | auto_stop_in: z.string().optional(), 85 | kubernetes: z 86 | .object({ 87 | namespace: z.string(), 88 | }) 89 | .optional(), 90 | deployment_tier: DeploymentTierSchema.optional(), 91 | }); 92 | 93 | export const VariableSchema = z.record(z.string()); 94 | 95 | export const OnlySchema = z.union([ 96 | z.array(z.string()), 97 | z.object({ 98 | changes: z.array(z.string()).optional(), 99 | variables: z.array(z.string()).optional(), 100 | }), 101 | ]); 102 | 103 | export const Parallel = z.union([ 104 | z.number(), 105 | z.object({ 106 | matrix: z.record(z.any()), 107 | }), 108 | ]); 109 | 110 | export const JobSchema = z.object({ 111 | stage: z.string().optional(), 112 | environment: z.union([EnvironmentSchema, z.string()]).optional(), 113 | image: z.string().optional(), 114 | extends: z.union([z.string(), z.array(z.string())]).optional(), 115 | interruptible: z.boolean().optional(), 116 | needs: z.array(z.string()).optional(), 117 | resource_group: z.string().optional(), 118 | script: z.array(z.string()).optional(), 119 | before_script: z.array(z.string()).optional(), 120 | after_script: z.array(z.string()).optional(), 121 | only: OnlySchema.optional(), 122 | rules: z.array(RuleSchema).optional(), 123 | when: WhenSchema.optional(), 124 | allow_failure: z.boolean().optional(), 125 | except: z.array(z.string()).optional(), 126 | artifacts: ArtifactsSchema.optional(), 127 | services: z.array(z.string()).optional(), 128 | parallel: Parallel.optional(), 129 | include: z 130 | .array( 131 | z.object({ 132 | local: z.string(), 133 | strategy: z.string(), 134 | }) 135 | ) 136 | .optional(), 137 | cache: CacheSchema.optional(), 138 | variables: VariableSchema.optional(), 139 | dependencies: z.array(z.string()).optional(), 140 | coverage: z.string().optional(), 141 | tags: z.array(z.string()).optional(), 142 | }); 143 | 144 | export const IncludeSchema = z.union([ 145 | z.array( 146 | z.object({ 147 | template: z.string(), 148 | }) 149 | ), 150 | z.string(), 151 | ]); 152 | 153 | export const GitlabSpecSchema = z.object({ 154 | image: z 155 | .union([ 156 | z.object({ 157 | name: z.string(), 158 | pull_policy: z.string(), 159 | }), 160 | z.string(), 161 | ]) 162 | .optional(), 163 | services: z.array(z.string()).optional(), 164 | before_script: z.array(z.string()).optional(), 165 | after_script: z.array(z.string()).optional(), 166 | variables: VariableSchema.optional(), 167 | cache: CacheSchema.optional(), 168 | artifacts: ArtifactsSchema.optional(), 169 | hooks: z 170 | .object({ 171 | pre_get_sources_script: z.string(), 172 | }) 173 | .optional(), 174 | interruptible: z.boolean().optional(), 175 | retry: z.any().optional(), 176 | tags: z.any().optional(), 177 | timeout: z.any().optional(), 178 | include: z.array(IncludeSchema).optional(), 179 | pages: z.any().optional(), 180 | workflow: z 181 | .object({ 182 | rules: z.array(RuleSchema), 183 | }) 184 | .optional(), 185 | stages: z.array(z.string()).optional(), 186 | ["string"]: z.union([JobSchema, z.any()]).optional(), 187 | }); 188 | 189 | export type When = z.infer; 190 | 191 | export type Policy = z.infer; 192 | 193 | export type Cache = z.infer; 194 | 195 | export type Rule = z.infer; 196 | 197 | export type Reports = z.infer; 198 | 199 | export type Artifacts = z.infer; 200 | 201 | export type Action = z.infer; 202 | 203 | export type DeploymentTier = z.infer; 204 | 205 | export type Environment = z.infer; 206 | 207 | export type Variable = z.infer; 208 | 209 | export type Only = z.infer; 210 | 211 | export type Parallel = z.infer; 212 | 213 | export type Job = z.infer; 214 | 215 | export type Include = z.infer; 216 | 217 | type GitlabSpec = z.infer; 218 | 219 | export type YamlSpec = ( 220 | | { [key: string]: Job } 221 | | string 222 | | { stages: string[] } 223 | | { variables: Variable } 224 | | { cache: Cache } 225 | | { include: Include } 226 | | { image: string } 227 | | { before_script: string[] } 228 | | { services: string[] } 229 | )[]; 230 | 231 | export default GitlabSpec; 232 | -------------------------------------------------------------------------------- /.fluentci/deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2", 3 | "remote": { 4 | "https://deno.land/std@0.150.0/media_types/_util.ts": "ce9b4fc4ba1c447dafab619055e20fd88236ca6bdd7834a21f98bd193c3fbfa1", 5 | "https://deno.land/std@0.150.0/media_types/mod.ts": "2d4b6f32a087029272dc59e0a55ae3cc4d1b27b794ccf528e94b1925795b3118", 6 | "https://deno.land/std@0.150.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af", 7 | "https://deno.land/std@0.191.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", 8 | "https://deno.land/std@0.191.0/testing/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea", 9 | "https://deno.land/std@0.191.0/testing/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", 10 | "https://deno.land/std@0.191.0/testing/asserts.ts": "e16d98b4d73ffc4ed498d717307a12500ae4f2cbe668f1a215632d19fcffc22f", 11 | "https://deno.land/x/codecov_pipeline@v0.1.0/src/dagger/jobs.ts": "e980479e0bcd759773286145f3345ce7e1662c7d6734bfc4bbf8e6bfc93b974e", 12 | "https://deno.land/x/fluent_github_actions@v0.1.2/mod.ts": "dc62b622791da77bc27f68e33cba618983a0770a9a12dcc9e0f9a61161bb90e5", 13 | "https://deno.land/x/fluent_github_actions@v0.1.2/src/event.ts": "c31430af085682cb4ad522c655a8a0800a3ab8b8aec7c979d60c909051d853b0", 14 | "https://deno.land/x/fluent_github_actions@v0.1.2/src/job_spec.ts": "ee7af83e75285b4776ff4f9e14764187737178b4abc6c277da1c32491c41dfca", 15 | "https://deno.land/x/fluent_github_actions@v0.1.2/src/step_spec.ts": "3207071b5dee8487f36fe4ea1881e8fd3b77c472c965c20a14093a3c919af9af", 16 | "https://deno.land/x/fluent_github_actions@v0.1.2/src/workflow.ts": "488556e230fdeeb3a5b0d0bf548c570606aa356b0a7f667ea1d031d3263eb566", 17 | "https://deno.land/x/fluent_github_actions@v0.1.2/src/workflow_spec.ts": "3ca9e565dc1dedd0531e0b852d50b9a3853a1ad35f2010760e0326590b80fa43", 18 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/mod.ts": "3becefe569f5c9814dffa1b534794a42b948481753a5903fa1b48d5337206ced", 19 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/src/environment.ts": "f12ee4fb50e5100fccec29dc1d35aa430bfe8373e84286a8ab9f7b8e178f14e3", 20 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/src/gitlabci.ts": "85d2335622c2def4a9554a9d8b8de4e62156f5d76d59a553e157bab4e6b6591f", 21 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/src/gitlabci_spec.ts": "b60f40ecf26d243db2391aee70fdf71b133de3faaf789052020f58f98cf1b500", 22 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/src/index.ts": "b5e374a24e3bca1d6fead0861f2c1b1e09e087a17e59297263f681ee71c972fe", 23 | "https://deno.land/x/fluent_gitlab_ci@v0.3.2/src/job.ts": "a1ddf8d37ca33239de9d2c61f98835e585f6671748b37af8d647ebba5e1a9974", 24 | "https://deno.land/x/nix_installer_pipeline@v0.3.6/src/dagger/steps.ts": "a34aea3753c7079de5877f592ce31f30d05d552155729ff3e695d77326405133", 25 | "https://deno.land/x/xhr@0.3.0/mod.ts": "094aacd627fd9635cd942053bf8032b5223b909858fa9dc8ffa583752ff63b20", 26 | "https://esm.sh/stringify-tree@1.1.1": "8d994a105481fa944515323d89bd2596c1de79f3d9bd1386266463934716eca0", 27 | "https://esm.sh/v128/*@dagger.io/dagger@0.6.3": "cb691a77c0cdaee22f2b8393731b5143c83ce22dbbea204cdbfd203768d15b64", 28 | "https://esm.sh/v128/@dagger.io/dagger@0.6.3/X-ZS8q/denonext/dagger.mjs": "fd0901784d75b99615b5409c3654b5c7edfc5ba377c9e1a5a67ffff4f7d3ac32", 29 | "https://esm.sh/v128/adm-zip@0.5.10": "d9c54d6d2dd788462781a57d923295bd79304e6fd74b242fd4b30e35b39c5dcf", 30 | "https://esm.sh/v128/adm-zip@0.5.10/denonext/adm-zip.mjs": "07a9731547905e0ca55ae917e1969d7f6d04fb3773f906ce3306891337eb4849", 31 | "https://esm.sh/v128/chownr@2.0.0/denonext/chownr.mjs": "30b8f17084dfbe475a5052b615f706b06ddd17dca0535103340d485c6b94e952", 32 | "https://esm.sh/v128/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", 33 | "https://esm.sh/v128/cross-spawn@7.0.3/denonext/cross-spawn.mjs": "0569a26e7ad4b3376516cbc9b1942e10961a58030eadcea8c848e6b956eb355c", 34 | "https://esm.sh/v128/data-uri-to-buffer@4.0.1/denonext/data-uri-to-buffer.mjs": "70ef987b1da58391495ecfad9888d996469224faf3cd996d81dc2e059feb9f31", 35 | "https://esm.sh/v128/env-paths@3.0.0": "8400fb23319be9b30d7b40d1c865541c5b3c7726cdf9b74000bc0f1678d52ecf", 36 | "https://esm.sh/v128/env-paths@3.0.0/denonext/env-paths.mjs": "77984a05eb16450087f25060a070ed500ec546719d471143e16d976ca73ca956", 37 | "https://esm.sh/v128/execa@7.1.1": "a40c7030df81ab0847a5d844f4c5c6420af973dff05fef88e53cbb9b8667fdc2", 38 | "https://esm.sh/v128/execa@7.1.1/denonext/execa.mjs": "9d5943544c0df3761b52f2c095f89a03ca6c028d818a8f0475ff883b0408f154", 39 | "https://esm.sh/v128/fetch-blob@3.2.0/denonext/fetch-blob.mjs": "0531568b36c0f6db3e9825fbb2d08dee51100eb675c2bf1d98d6971a92010721", 40 | "https://esm.sh/v128/fetch-blob@3.2.0/denonext/file.js": "fd82828163a4e7bdc15190d8c3dbfd92f93274d05bd7f7f5ab81093e3ad7e9c2", 41 | "https://esm.sh/v128/fetch-blob@3.2.0/denonext/from.js": "7d3258c7960755497f90879806f0b815d5e564c2ac1523238af5cb9552ff5c45", 42 | "https://esm.sh/v128/formdata-polyfill@4.0.10/denonext/esm.min.js": "b6d65a204e81eca699d9eb6f867e9efffa42db39a8f161690915a89e5eb1766f", 43 | "https://esm.sh/v128/fs-minipass@2.1.0/denonext/fs-minipass.mjs": "74b00283d556b281bdfd6a669576d852f2c43702043c411985f8f8188d208c5d", 44 | "https://esm.sh/v128/get-stream@6.0.1/denonext/get-stream.mjs": "a947a16f8cb3052fd654a84f8b36b40ce96b6a5acfb3ad4ab69d814bcf3351fb", 45 | "https://esm.sh/v128/graphql-request@6.1.0": "17f00c323eb825811ce14e2b0e88a0c873acb666c382ac963d1edeb03e01f372", 46 | "https://esm.sh/v128/graphql-request@6.1.0/denonext/graphql-request.mjs": "0b15f49d44489423ae6f06004725b6d050b6359da4969e6569bd6ad45065bd94", 47 | "https://esm.sh/v128/graphql-tag@2.12.6": "5bfa27da9c9918fb52a01b8579891e804e0365d91118df1f2e0957a72dacdc39", 48 | "https://esm.sh/v128/graphql-tag@2.12.6/denonext/graphql-tag.mjs": "331d09949efc4ac60c84a69b52a7da8b333210493900e54953ae4604c9874527", 49 | "https://esm.sh/v128/graphql@16.7.1/denonext/graphql.mjs": "418ad7c07b0f2d687f33b6275d3b5f317f4afbef1f462f318229f458dff45416", 50 | "https://esm.sh/v128/human-signals@4.3.1/denonext/human-signals.mjs": "3889110cedd907804443d018cffe0a1d892d5e7467661376caf967feff55cbe9", 51 | "https://esm.sh/v128/is-stream@3.0.0/denonext/is-stream.mjs": "5c8b65f2fa051c4b18e88bbae11dac8bba9caf57752577d69bcea86d1f05c5b7", 52 | "https://esm.sh/v128/isexe@2.0.0/denonext/isexe.mjs": "3cfefd270d1bfdfb864ee98dbb8f41d150cbf480925158f4a8f0ade8a9e17d6c", 53 | "https://esm.sh/v128/merge-stream@2.0.0/denonext/merge-stream.mjs": "2c2af22401c294158d6bff659d157e3d2c028c218cc1bd2246534a45a4c03c61", 54 | "https://esm.sh/v128/mimic-fn@4.0.0/denonext/mimic-fn.mjs": "10bcf0f2f20cbbba0c289ef7bf4d2422639bbc1c36c247be876afd6fe2d67138", 55 | "https://esm.sh/v128/minipass@3.3.6/denonext/minipass.mjs": "59bbe430514455e78cb30c389b21af66efb2bf010cda071820a17d8c76d0d1cf", 56 | "https://esm.sh/v128/minipass@5.0.0/denonext/minipass.mjs": "de0e049728f8c387b58c86439eb9d69a16b6a88756a6bc694e2fecbd7fd00401", 57 | "https://esm.sh/v128/minizlib@2.1.2/denonext/minizlib.mjs": "0d919b6a0c60d5a31e14d748ff9d62aeae2923b604bcc6a22f90fa4bbd400d68", 58 | "https://esm.sh/v128/mkdirp@1.0.4/denonext/mkdirp.mjs": "ee129b32e55dd8bede6b1bbd1978f7775fa5e2720d5a7ae07bf1e8c99abd77c7", 59 | "https://esm.sh/v128/node-color-log@10.0.2": "05a277987c64153af1252167135076155fdc6b39ca260b2bdc39750da12d2a2d", 60 | "https://esm.sh/v128/node-color-log@10.0.2/denonext/node-color-log.mjs": "2504391bd0ce1dd4c2bf0ed0b839b8a3ad84c028d9dd17cc58dccd2e14dacfde", 61 | "https://esm.sh/v128/node-domexception@1.0.0/denonext/node-domexception.mjs": "bb35ba54c1a2b35870618876c0c96310a28ae58aecff33c8eed58a582e270ff4", 62 | "https://esm.sh/v128/node-fetch@3.3.1": "916dcee177a69fb0e46970c528cb66fcd4973488f861844c0a235bfc645b0506", 63 | "https://esm.sh/v128/node-fetch@3.3.1/denonext/node-fetch.mjs": "dc3a8f1f2fc9eb26d0d33e49f3750acc265d51a1a54bbd670c5d9f640b633a93", 64 | "https://esm.sh/v128/node-fetch@3.3.1/denonext/src/utils/multipart-parser.js": "713b1b8cbafc4bfb7358debeb35d507e0d2328f0a28b8a2a7d79a3e5e4f5e5b8", 65 | "https://esm.sh/v128/npm-run-path@5.1.0/denonext/npm-run-path.mjs": "3540b8c2dd1430f10d580f323f3a51aa30094da27a9220cce03ce69884b163bb", 66 | "https://esm.sh/v128/onetime@6.0.0/denonext/onetime.mjs": "6e362222575d815f37fb813168d7069dd6a0f6bb6f972ed54d1bccb0f9fb3e1b", 67 | "https://esm.sh/v128/original-fs@1.2.0/denonext/original-fs.mjs": "2b1098818e54d2c6748ff5b0dd9ea5f6a61b4b6d0f63fb625f21773d11cfc667", 68 | "https://esm.sh/v128/path-key@3.1.1/denonext/path-key.mjs": "add83c631278b7df9b33ae84e41142db88bb291295bcc27eb4e77a1cbdfa71d0", 69 | "https://esm.sh/v128/path-key@4.0.0/denonext/path-key.mjs": "2c2e3922bd0e6e414fa2752ff800bdc6b9208035ce797fa22e49b859f8259417", 70 | "https://esm.sh/v128/shebang-command@2.0.0/denonext/shebang-command.mjs": "404e0fb09a782ca9495d53c721bb84b673b7b2e1054e021852143a6b91ca0e4f", 71 | "https://esm.sh/v128/shebang-regex@3.0.0/denonext/shebang-regex.mjs": "03983ba59dd2cba9402935e21b46d05f5249364cba9f5757aef23c6c2fea65b9", 72 | "https://esm.sh/v128/signal-exit@3.0.7/denonext/signal-exit.mjs": "2a176e5f9b351fa8057213c627a1503d63bf308b64447ef47f1ca6fbb2a91c81", 73 | "https://esm.sh/v128/strip-final-newline@3.0.0/denonext/strip-final-newline.mjs": "03d9be4e8a249d63cbbddeb2fb675a1bbbcb335283e604d4ce56c88c90e6f102", 74 | "https://esm.sh/v128/tar@6.1.15": "0460339f8aba5f287e8bebe258fe3fe13cb12f85820693f25724f0d98ef1258e", 75 | "https://esm.sh/v128/tar@6.1.15/denonext/tar.mjs": "6194d892de8457b3b1f11d5cbacda1d540b453b45e8cb9f5f610abfb3e490b65", 76 | "https://esm.sh/v128/tslib@2.6.0/denonext/tslib.mjs": "2215292e6fcf28a7a081eee911f127bb3c44cdd61ff0651e3e384d7a49b4e42b", 77 | "https://esm.sh/v128/web-streams-polyfill@3.2.1/denonext/dist/ponyfill.es2018.js": "a2edb52a93494cda06386b3d6a168016b366e78f02c5eff1f94a0240be12ac96", 78 | "https://esm.sh/v128/which@2.0.2/denonext/which.mjs": "86bf76e4937edb7fa3464d7bb9a426ef273684d1cefbec5ba5f1bdcb5cafff91", 79 | "https://esm.sh/v128/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", 80 | "https://esm.sh/v130/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", 81 | "https://esm.sh/v130/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "40a9d40e0282b5432302a3da68b88aa11685bc0b8a0b70246168deed5c5773fe", 82 | "https://esm.sh/v131/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", 83 | "https://esm.sh/yaml@v2.3.1": "1fe2490feb3d9c6d2c71c64dbdbed90acd4164b00628b3c68a311b6731ca38b5" 84 | }, 85 | "npm": { 86 | "specifiers": { 87 | "@types/node": "@types/node@18.16.19" 88 | }, 89 | "packages": { 90 | "@types/node@18.16.19": { 91 | "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", 92 | "dependencies": {} 93 | } 94 | } 95 | } 96 | } 97 | --------------------------------------------------------------------------------