├── db-for-testers
├── .gitignore
├── docker-entrypoint-initdb.d
│ ├── schema.sql
│ └── data.sql
└── README.md
├── .gitignore
├── gradle-application
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ └── main
│ │ └── java
│ │ └── org
│ │ └── example
│ │ ├── dto
│ │ ├── MainResponseDto.java
│ │ └── HealthResponseDto.java
│ │ ├── serlvet
│ │ ├── HealthServlet.java
│ │ └── MainServlet.java
│ │ └── Main.java
├── build.gradle
├── .gitignore
├── README.md
├── gradlew.bat
└── gradlew
├── angular-storybook
├── storybook.png
├── projects
│ └── components
│ │ ├── .storybook
│ │ ├── typings.d.ts
│ │ ├── tsconfig.json
│ │ ├── preview.ts
│ │ └── main.ts
│ │ ├── src
│ │ ├── stories
│ │ │ ├── .eslintrc.json
│ │ │ └── Introduction.mdx
│ │ ├── lib
│ │ │ ├── components.service.ts
│ │ │ ├── counter
│ │ │ │ ├── counter.component.html
│ │ │ │ ├── counter.component.css
│ │ │ │ ├── counter.component.spec.ts
│ │ │ │ ├── counter.component.ts
│ │ │ │ └── counter.component.stories.ts
│ │ │ ├── components.component.ts
│ │ │ ├── components.module.ts
│ │ │ ├── components.service.spec.ts
│ │ │ └── components.component.spec.ts
│ │ └── public-api.ts
│ │ ├── ng-package.json
│ │ ├── package.json
│ │ ├── tsconfig.lib.prod.json
│ │ ├── tsconfig.spec.json
│ │ ├── tsconfig.lib.json
│ │ ├── .eslintrc.json
│ │ ├── README.md
│ │ └── documentation.json
├── .editorconfig
├── .gitignore
├── tsconfig.json
├── .eslintrc.json
├── package.json
├── angular.json
└── README.md
├── graalvm-native-image-static
├── src
│ └── main
│ │ └── java
│ │ └── org
│ │ └── example
│ │ ├── Main.java
│ │ └── server
│ │ └── Server.java
├── .gitignore
├── pom.xml
└── README.md
└── README.md
/db-for-testers/.gitignore:
--------------------------------------------------------------------------------
1 | target/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | NOTES.md
3 | Dockerfile.done
4 | docker-compose.done.yml
5 |
--------------------------------------------------------------------------------
/gradle-application/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'gradle-application'
2 |
3 |
--------------------------------------------------------------------------------
/angular-storybook/storybook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slurmio/devopscases/HEAD/angular-storybook/storybook.png
--------------------------------------------------------------------------------
/angular-storybook/projects/components/.storybook/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | const content: string;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/gradle-application/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slurmio/devopscases/HEAD/gradle-application/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle-application/src/main/java/org/example/dto/MainResponseDto.java:
--------------------------------------------------------------------------------
1 | package org.example.dto;
2 |
3 | import java.util.UUID;
4 |
5 | public record MainResponseDto(UUID uuid) {
6 | }
7 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/stories/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "@typescript-eslint/consistent-type-imports": ["error", { "disallowTypeAnnotations": false }]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/components.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | @Injectable({
4 | providedIn: 'root'
5 | })
6 | export class ComponentsService {
7 | }
8 |
--------------------------------------------------------------------------------
/gradle-application/src/main/java/org/example/dto/HealthResponseDto.java:
--------------------------------------------------------------------------------
1 | package org.example.dto;
2 |
3 | public record HealthResponseDto(Status status) {
4 | public enum Status {
5 | UP, DOWN
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/components",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | }
7 | }
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of components
3 | */
4 |
5 | export * from './lib/components.service';
6 | export * from './lib/components.component';
7 | export * from './lib/components.module';
8 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/stories/Introduction.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/blocks';
2 |
3 |
4 |
5 | # Welcome to Storybook
6 |
7 | Этот Storybook демонстрирует использование нашей библиотеки компонентов
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/counter/counter.component.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/gradle-application/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 24 09:08:01 MSK 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/db-for-testers/docker-entrypoint-initdb.d/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE "users"
2 | (
3 | "id" BIGSERIAL PRIMARY KEY,
4 | "login" TEXT NOT NULL UNIQUE,
5 | "password" TEXT NOT NULL,
6 | "roles" TEXT[] NOT NULL DEFAULT '{USER}',
7 | "created" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
8 | );
--------------------------------------------------------------------------------
/angular-storybook/projects/components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "components",
3 | "version": "0.0.1",
4 | "peerDependencies": {
5 | "@angular/common": "^15.2.0",
6 | "@angular/core": "^15.2.0"
7 | },
8 | "dependencies": {
9 | "tslib": "^2.3.0"
10 | },
11 | "sideEffects": false
12 | }
13 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/components.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'lib-components',
5 | template: `
6 |
7 | components works!
8 |
9 | `,
10 | styles: [
11 | ]
12 | })
13 | export class ComponentsComponent {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.lib.json",
4 | "compilerOptions": {
5 | "declarationMap": false
6 | },
7 | "angularCompilerOptions": {
8 | "compilationMode": "partial"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/angular-storybook/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../../out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "**/*.spec.ts",
12 | "**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.lib.json",
3 | "compilerOptions": {
4 | "types": ["node"],
5 | "allowSyntheticDefaultImports": true,
6 | "resolveJsonModule": true
7 | },
8 | "exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
9 | "include": ["../src/**/*", "./preview.ts"],
10 | "files": ["./typings.d.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../../out-tsc/lib",
6 | "declaration": true,
7 | "declarationMap": true,
8 | "inlineSources": true,
9 | "types": []
10 | },
11 | "exclude": [
12 | "**/*.spec.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/components.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { ComponentsComponent } from './components.component';
3 | import { CounterComponent } from './counter/counter.component';
4 |
5 |
6 |
7 | @NgModule({
8 | declarations: [
9 | ComponentsComponent,
10 | CounterComponent
11 | ],
12 | imports: [
13 | ],
14 | exports: [
15 | ComponentsComponent
16 | ]
17 | })
18 | export class ComponentsModule { }
19 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/components.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { ComponentsService } from './components.service';
4 |
5 | describe('ComponentsService', () => {
6 | let service: ComponentsService;
7 |
8 | beforeEach(() => {
9 | TestBed.configureTestingModule({});
10 | service = TestBed.inject(ComponentsService);
11 | });
12 |
13 | it('should be created', () => {
14 | expect(service).toBeTruthy();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/graalvm-native-image-static/src/main/java/org/example/Main.java:
--------------------------------------------------------------------------------
1 | package org.example;
2 |
3 | import org.example.server.Server;
4 |
5 | import java.io.IOException;
6 | import java.util.Optional;
7 |
8 | public class Main {
9 | public static void main(String[] args) throws IOException {
10 | final Server server = new Server();
11 | final String port = Optional.ofNullable(System.getProperty("port"))
12 | .orElse(System.getenv("PORT"))
13 | ;
14 | server.serve(Integer.parseInt(port));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gradle-application/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | group = 'org.example'
7 | version = '1.0.0'
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | // https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core
15 | implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.15'
16 | // https://mvnrepository.com/artifact/com.google.code.gson/gson
17 | implementation 'com.google.code.gson:gson:2.10.1'
18 | }
19 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/.storybook/preview.ts:
--------------------------------------------------------------------------------
1 | import type { Preview } from "@storybook/angular";
2 | import { setCompodocJson } from "@storybook/addon-docs/angular";
3 | import docJson from "../documentation.json";
4 | setCompodocJson(docJson);
5 |
6 | const preview: Preview = {
7 | parameters: {
8 | actions: { argTypesRegex: "^on[A-Z].*" },
9 | controls: {
10 | matchers: {
11 | color: /(background|color)$/i,
12 | date: /Date$/,
13 | },
14 | },
15 | },
16 | };
17 |
18 | export default preview;
19 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from "@storybook/angular";
2 | const config: StorybookConfig = {
3 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
4 | addons: [
5 | "@storybook/addon-links",
6 | "@storybook/addon-essentials",
7 | "@storybook/addon-interactions",
8 | ],
9 | framework: {
10 | name: "@storybook/angular",
11 | options: {},
12 | },
13 | docs: {
14 | autodocs: "tag",
15 | },
16 | core: {
17 | disableTelemetry: true,
18 | },
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/graalvm-native-image-static/.gitignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | dev-*.yml
3 | HELP.md
4 | target/
5 | !.mvn/wrapper/maven-wrapper.jar
6 | !**/src/main/**/target/
7 | !**/src/test/**/target/
8 |
9 | ### STS ###
10 | .apt_generated
11 | .classpath
12 | .factorypath
13 | .project
14 | .settings
15 | .springBeans
16 | .sts4-cache
17 |
18 | ### IntelliJ IDEA ###
19 | .idea
20 | *.iws
21 | *.iml
22 | *.ipr
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
--------------------------------------------------------------------------------
/db-for-testers/docker-entrypoint-initdb.d/data.sql:
--------------------------------------------------------------------------------
1 | -- just emulate hard work
2 | SELECT clock_timestamp(), pg_sleep(30), clock_timestamp();
3 |
4 | INSERT INTO "users"("login", "password", "roles")
5 | VALUES
6 | ('root', '{argon2}$argon2id$v=19$m=4096,t=3,p=1$VD2gbE9s9SvxSU3QnmeO9w$hosiwDgCWLdyZ6xrysnDg9fDE38frM65jxOj58ZkCXs', '{ROOT}'),
7 | ('admin', '{argon2}$argon2id$v=19$m=4096,t=3,p=1$VD2gbE9s9SvxSU3QnmeO9w$hosiwDgCWLdyZ6xrysnDg9fDE38frM65jxOj58ZkCXs', '{ADMIN}'),
8 | ('user', '{argon2}$argon2id$v=19$m=4096,t=3,p=1$VD2gbE9s9SvxSU3QnmeO9w$hosiwDgCWLdyZ6xrysnDg9fDE38frM65jxOj58ZkCXs', DEFAULT)
9 | RETURNING *
10 | ;
--------------------------------------------------------------------------------
/gradle-application/.gitignore:
--------------------------------------------------------------------------------
1 | /tomcat*
2 | .gradle
3 | build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### IntelliJ IDEA ###
9 | .idea/
10 | *.iws
11 | *.iml
12 | *.ipr
13 | out/
14 | !**/src/main/**/out/
15 | !**/src/test/**/out/
16 |
17 | ### Eclipse ###
18 | .apt_generated
19 | .classpath
20 | .factorypath
21 | .project
22 | .settings
23 | .springBeans
24 | .sts4-cache
25 | bin/
26 | !**/src/main/**/bin/
27 | !**/src/test/**/bin/
28 |
29 | ### NetBeans ###
30 | /nbproject/private/
31 | /nbbuild/
32 | /dist/
33 | /nbdist/
34 | /.nb-gradle/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
39 | ### Mac OS ###
40 | .DS_Store
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/counter/counter.component.css:
--------------------------------------------------------------------------------
1 | .lib-counter {
2 | font-family: Helvetica, Arial, sans-serif;
3 | font-weight: 700;
4 | border-radius: 5px;
5 | cursor: pointer;
6 | display: inline-block;
7 | line-height: 1;
8 | }
9 | .lib-counter--primary {
10 | color: white;
11 | background-color: #8a73fc;
12 | border: 1px solid #8a73fc;
13 | }
14 | .lib-counter--secondary {
15 | color: #172b4d;
16 | background-color: transparent;
17 | border: 1px solid #172b4d;
18 | }
19 | .lib-counter--small {
20 | font-size: 12px;
21 | padding: 10px 16px;
22 | }
23 | .lib-counter--medium {
24 | font-size: 14px;
25 | padding: 11px 20px;
26 | }
27 | .lib-counter--large {
28 | font-size: 16px;
29 | padding: 12px 24px;
30 | }
31 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/counter/counter.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { CounterComponent } from './counter.component';
4 |
5 | describe('CounterComponent', () => {
6 | let component: CounterComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [ CounterComponent ]
12 | })
13 | .compileComponents();
14 |
15 | fixture = TestBed.createComponent(CounterComponent);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | });
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/components.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ComponentsComponent } from './components.component';
4 |
5 | describe('ComponentsComponent', () => {
6 | let component: ComponentsComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [ ComponentsComponent ]
12 | })
13 | .compileComponents();
14 |
15 | fixture = TestBed.createComponent(ComponentsComponent);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | });
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/angular-storybook/.gitignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | # See http://help.github.com/ignore-files/ for more about ignoring files.
4 | storybook-static/
5 |
6 | # Compiled output
7 | /dist
8 | /tmp
9 | /out-tsc
10 | /bazel-out
11 |
12 | # Node
13 | /node_modules
14 | npm-debug.log
15 | yarn-error.log
16 |
17 | # IDEs and editors
18 | .idea/
19 | .project
20 | .classpath
21 | .c9/
22 | *.launch
23 | .settings/
24 | *.sublime-workspace
25 |
26 | # Visual Studio Code
27 | .vscode/*
28 | !.vscode/settings.json
29 | !.vscode/tasks.json
30 | !.vscode/launch.json
31 | !.vscode/extensions.json
32 | .history/*
33 |
34 | # Miscellaneous
35 | /.angular/cache
36 | .sass-cache/
37 | /connect.lock
38 | /coverage
39 | /libpeerconnection.log
40 | testem.log
41 | /typings
42 |
43 | # System files
44 | .DS_Store
45 | Thumbs.db
46 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../.eslintrc.json",
3 | "ignorePatterns": [
4 | "!**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "rules": {
12 | "@angular-eslint/directive-selector": [
13 | "error",
14 | {
15 | "type": "attribute",
16 | "prefix": "lib",
17 | "style": "camelCase"
18 | }
19 | ],
20 | "@angular-eslint/component-selector": [
21 | "error",
22 | {
23 | "type": "element",
24 | "prefix": "lib",
25 | "style": "kebab-case"
26 | }
27 | ]
28 | }
29 | },
30 | {
31 | "files": [
32 | "*.html"
33 | ],
34 | "rules": {}
35 | }
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/gradle-application/src/main/java/org/example/serlvet/HealthServlet.java:
--------------------------------------------------------------------------------
1 | package org.example.serlvet;
2 |
3 | import com.google.gson.Gson;
4 | import jakarta.servlet.http.HttpServlet;
5 | import jakarta.servlet.http.HttpServletRequest;
6 | import jakarta.servlet.http.HttpServletResponse;
7 | import org.example.dto.HealthResponseDto;
8 |
9 | import java.io.IOException;
10 |
11 | public class HealthServlet extends HttpServlet {
12 | private final transient Gson gson;
13 |
14 | public HealthServlet(final Gson gson) {
15 | this.gson = gson;
16 | }
17 |
18 | @Override
19 | protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
20 | final HealthResponseDto dto = new HealthResponseDto(HealthResponseDto.Status.UP);
21 | resp.setHeader("Content-Type", "application/json");
22 | this.gson.toJson(dto, resp.getWriter());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle-application/src/main/java/org/example/serlvet/MainServlet.java:
--------------------------------------------------------------------------------
1 | package org.example.serlvet;
2 |
3 | import com.google.gson.Gson;
4 | import jakarta.servlet.ServletException;
5 | import jakarta.servlet.http.HttpServlet;
6 | import jakarta.servlet.http.HttpServletRequest;
7 | import jakarta.servlet.http.HttpServletResponse;
8 | import org.example.dto.MainResponseDto;
9 |
10 | import java.io.IOException;
11 | import java.time.Instant;
12 | import java.util.UUID;
13 |
14 | public class MainServlet extends HttpServlet {
15 | private final transient Gson gson;
16 |
17 | public MainServlet(final Gson gson) {
18 | this.gson = gson;
19 | }
20 |
21 | @Override
22 | protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
23 | final MainResponseDto dto = new MainResponseDto(UUID.randomUUID());
24 | resp.setHeader("Content-Type", "application/json");
25 | this.gson.toJson(dto, resp.getWriter());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/counter/counter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, EventEmitter, Input, Output } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'lib-counter',
5 | templateUrl: './counter.component.html',
6 | styleUrls: ['./counter.component.css']
7 | })
8 | export class CounterComponent {
9 | @Input() prefix = 'lib-counter';
10 | @Input() primary = true;
11 | @Input() size : 'small' | 'medium' | 'large' = 'medium';
12 | @Input() testid = '';
13 | @Input() type = '';
14 | @Input() disabled = false;
15 | @Input() value = 0;
16 | @Output() increase = new EventEmitter();
17 |
18 | public get classes(): string[] {
19 | return [this.prefix, `${this.prefix}--${this.size}`, `${this.prefix}--${this.primary ? 'primary' : 'secondary'}`];
20 | }
21 |
22 | onClick($event: Event) {
23 | $event.preventDefault();
24 | this.value++;
25 | console.log('click');
26 | this.increase.emit(this.value);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/src/lib/counter/counter.component.stories.ts:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/angular';
2 | import { CounterComponent } from './counter.component';
3 |
4 | const meta: Meta = {
5 | title: 'Example/CounterComponent',
6 | component: CounterComponent,
7 | tags: ['autodocs'],
8 | render: (args: CounterComponent) => ({
9 | props: {
10 | ...args,
11 | },
12 | }),
13 | };
14 |
15 | export default meta;
16 | type Story = StoryObj;
17 |
18 | export const PrimaryCounter: Story = {
19 | args: {
20 | primary: true,
21 | value: 1,
22 | },
23 | };
24 |
25 | export const SecondaryCounter: Story = {
26 | args: {
27 | primary: false,
28 | value: 1,
29 | },
30 | };
31 |
32 | export const LargeCounter: Story = {
33 | args: {
34 | size: 'large',
35 | value: 999,
36 | },
37 | };
38 |
39 | export const SmallCounter: Story = {
40 | args: {
41 | size: 'small',
42 | value: 9,
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevOps Cases от Slurm
2 |
3 | В этом репозитории мы собрали интересные кейсы, с которыми сами регулярно сталкиваемся в работе
4 |
5 | Вы можете использовать эти кейсы для прокачки ваших скиллов по интересным вам направлениям
6 |
7 | Сами кейсы представлены в том виде, в котором они формулируются в реальной жизни, при этом:
8 | 1. Из кейсов убрано всё лишнее (т.е. и код, и сборка сильно упрощены)
9 | 2. Даны для удобства некоторые ссылки и временами даже подсказки
10 |
11 | **Важно**: это не набор задач для пошагового выполнения! Это именно набор кейсов, для разбора которых вам, возможно, придётся:
12 | - дополнительно изучить используемые в проекте технологии и их особенности
13 | - поковыряться в настройках и поэкспериментировать с ними
14 |
15 | ## Сборка контейнеров
16 |
17 | * [BuildKit Parallelization](buildkit-parallelization/)
18 | * [Angular Storybook](angular-storybook/)
19 | * [Gradle Application](gradle-application/)
20 | * [GraalVM Native Image - Static](graalvm-native-image-static/)
21 | * [DB for Testers](db-for-testers/)
22 |
--------------------------------------------------------------------------------
/graalvm-native-image-static/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | native
9 | 1.0.0
10 |
11 |
12 | 17
13 | 17
14 | UTF-8
15 | 1.18.30
16 |
17 |
18 |
19 |
20 | org.projectlombok
21 | lombok
22 | ${lombok.version}
23 | provided
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/README.md:
--------------------------------------------------------------------------------
1 | # Components
2 |
3 | This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.0.
4 |
5 | ## Code scaffolding
6 |
7 | Run `ng generate component component-name --project components` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project components`.
8 | > Note: Don't forget to add `--project components` or else it will be added to the default project in your `angular.json` file.
9 |
10 | ## Build
11 |
12 | Run `ng build components` to build the project. The build artifacts will be stored in the `dist/` directory.
13 |
14 | ## Publishing
15 |
16 | After building your library with `ng build components`, go to the dist folder `cd dist/components` and run `npm publish`.
17 |
18 | ## Running unit tests
19 |
20 | Run `ng test components` to execute the unit tests via [Karma](https://karma-runner.github.io).
21 |
22 | ## Further help
23 |
24 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
25 |
--------------------------------------------------------------------------------
/angular-storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "paths": {
7 | "components": [
8 | "dist/components"
9 | ]
10 | },
11 | "outDir": "./dist/out-tsc",
12 | "forceConsistentCasingInFileNames": true,
13 | "strict": true,
14 | "noImplicitOverride": true,
15 | "noPropertyAccessFromIndexSignature": true,
16 | "noImplicitReturns": true,
17 | "noFallthroughCasesInSwitch": true,
18 | "sourceMap": true,
19 | "declaration": false,
20 | "downlevelIteration": true,
21 | "experimentalDecorators": true,
22 | "moduleResolution": "node",
23 | "importHelpers": true,
24 | "target": "ES2022",
25 | "module": "ES2022",
26 | "useDefineForClassFields": false,
27 | "lib": [
28 | "ES2022",
29 | "dom"
30 | ]
31 | },
32 | "angularCompilerOptions": {
33 | "enableI18nLegacyMessageIdFormat": false,
34 | "strictInjectionParameters": true,
35 | "strictInputAccessModifiers": true,
36 | "strictTemplates": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/angular-storybook/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": [
4 | "projects/**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "extends": [
12 | "eslint:recommended",
13 | "plugin:@typescript-eslint/recommended",
14 | "plugin:@angular-eslint/recommended",
15 | "plugin:@angular-eslint/template/process-inline-templates"
16 | ],
17 | "rules": {
18 | "@angular-eslint/directive-selector": [
19 | "error",
20 | {
21 | "type": "attribute",
22 | "prefix": "lib",
23 | "style": "camelCase"
24 | }
25 | ],
26 | "@angular-eslint/component-selector": [
27 | "error",
28 | {
29 | "type": "element",
30 | "prefix": "lib",
31 | "style": "kebab-case"
32 | }
33 | ]
34 | }
35 | },
36 | {
37 | "files": [
38 | "*.html"
39 | ],
40 | "extends": [
41 | "plugin:@angular-eslint/template/recommended"
42 | ],
43 | "rules": {}
44 | }
45 | ],
46 | "extends": [
47 | "plugin:storybook/recommended"
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/gradle-application/src/main/java/org/example/Main.java:
--------------------------------------------------------------------------------
1 | package org.example;
2 |
3 | import com.google.gson.Gson;
4 | import org.apache.catalina.Context;
5 | import org.apache.catalina.LifecycleException;
6 | import org.apache.catalina.connector.Connector;
7 | import org.apache.catalina.startup.Tomcat;
8 | import org.example.serlvet.HealthServlet;
9 | import org.example.serlvet.MainServlet;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.nio.file.Files;
14 | import java.nio.file.Path;
15 |
16 | public class Main {
17 | public static void main(String[] args) throws IOException, LifecycleException {
18 | final int port = 9999;
19 | final Tomcat tomcat = new Tomcat();
20 | tomcat.setPort(port);
21 |
22 | final Connector connector = new Connector("HTTP/1.1");
23 | connector.setPort(port);
24 | tomcat.setConnector(connector);
25 |
26 |
27 | final Path baseDir = Files.createTempDirectory("tomcat-");
28 | tomcat.setBaseDir(baseDir.toFile().getAbsolutePath());
29 |
30 | final Context ctx = tomcat.addContext("", new File(".").getAbsolutePath());
31 |
32 | final Gson gson = new Gson();
33 | final MainServlet mainServlet = new MainServlet(gson);
34 |
35 | Tomcat.addServlet(ctx, "main", mainServlet);
36 | ctx.addServletMappingDecoded("/*", "main");
37 |
38 | final HealthServlet healthServlet = new HealthServlet(gson);
39 | Tomcat.addServlet(ctx, "health", healthServlet);
40 | ctx.addServletMappingDecoded("/health", "health");
41 |
42 | tomcat.start();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/gradle-application/README.md:
--------------------------------------------------------------------------------
1 | Теги: `Docker` `Java` `Gradle`
2 |
3 | # Gradle Application
4 |
5 | ## Задача
6 |
7 | Разработчики проекта совсем не дружат с Docker, контейнерами и "всей этой вашей новомодной \[подставьте наименование по желанию\]", поэтому нам выпала задача упаковать это всё в образ
8 |
9 | Что имеем: проект на Java 17 с системой сборки Gradle
10 |
11 | Используемый порт: `9999`
12 |
13 | Команда для тестирования:
14 | ```shell
15 | curl -X GET http://localhost:9999
16 | ```
17 |
18 | Ожидаемый ответ:
19 | ```shell
20 | {"uuid": "рандомный UUID"}
21 | ```
22 |
23 | Также есть Healthcheck:
24 | ```shell
25 | curl -X GET http://localhost:9999/health
26 | ```
27 |
28 | Ожидаемый ответ:
29 | ```shell
30 | {"status": "UP"}
31 | ```
32 |
33 | Приоритеты по использованию базового образа:
34 | 1. Scratch
35 | 2. Distroless (не `debug`)
36 | 3. Eclipse Temurin
37 |
38 | Запуск не от `root`'а
39 |
40 |
41 | Спойлеры
42 |
43 | Вполне возможно, что первые два варианта использовать нецелесообразно по техническим соображениям: подготовьте обоснованный ответ на вопрос "почему"
44 |
45 |
46 |
47 | ## Инструкции по сборке проекта
48 |
49 | Есть плагин [`application`](https://docs.gradle.org/current/userguide/application_plugin.html), который умеет собирать дистрибутив проекта
50 |
51 | Делается это с помощью следующей команды:
52 |
53 | ```shell
54 | ./gradlew assemble
55 | ```
56 |
57 | Файл `gradle-application-1.0.0.tar` и будет содержать дистрибутив для развёртывания
58 |
59 | ## Реализация
60 |
61 | В качестве реализации CI/CD пайплайна и Docker Registry можно использовать любые, например (из облачных и бесплатных), [GitHub Actions](https://docs.github.com/en/actions) и [GitHub Packages](https://docs.github.com/packages)
62 |
63 |
--------------------------------------------------------------------------------
/graalvm-native-image-static/src/main/java/org/example/server/Server.java:
--------------------------------------------------------------------------------
1 | package org.example.server;
2 |
3 | import lombok.extern.java.Log;
4 |
5 | import java.io.IOException;
6 | import java.net.DatagramPacket;
7 | import java.net.DatagramSocket;
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.UUID;
10 | import java.util.logging.Level;
11 |
12 | @Log
13 | public class Server {
14 | public void serve(final int port) throws IOException {
15 | try (
16 | final DatagramSocket datagramSocket = new DatagramSocket(port);
17 | ) {
18 | log.log(Level.INFO, "server created, listen on: {0}", port);
19 |
20 | while (true) {
21 | final byte[] buffer = new byte[1024];
22 | final DatagramPacket in = new DatagramPacket(buffer, buffer.length);
23 | datagramSocket.receive(in);
24 | log.log(Level.INFO, "received packet from {0}:{1}", new Object[]{in.getAddress(), in.getPort()});
25 | final String incomingMessage = new String(in.getData(), in.getOffset(), in.getLength(), StandardCharsets.UTF_8).trim();
26 | log.log(Level.FINE, "message: {0}", incomingMessage);
27 |
28 | switch (incomingMessage) {
29 | case "UUID": {
30 | final byte[] replyMessage = String.format("%s%n", UUID.randomUUID()).getBytes(StandardCharsets.UTF_8);
31 | final DatagramPacket out = new DatagramPacket(replyMessage, replyMessage.length, in.getAddress(), in.getPort());
32 | datagramSocket.send(out);
33 | break;
34 | }
35 | default: {
36 | final byte[] replyMessage = String.format("Invalid Command: %s%n", incomingMessage).getBytes(StandardCharsets.UTF_8);
37 | final DatagramPacket out = new DatagramPacket(replyMessage, replyMessage.length, in.getAddress(), in.getPort());
38 | datagramSocket.send(out);
39 | break;
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/db-for-testers/README.md:
--------------------------------------------------------------------------------
1 | Теги: `Docker` `PostgreSQL`
2 |
3 | # DB for Testers
4 |
5 | ## Задача
6 |
7 | Наши тестировщики прониклись идеями контейнеризации и активно начинают использовать Docker в своих тестах (ручных, автоматизированных и т.д.)
8 |
9 | Им очень нравится идея, что они могут просто взять контейнер PostgreSQL, закинуть туда БД и запускать тестируемые приложения с нужными данными
10 |
11 | Но вот проблема, они работают следующим образом:
12 | 1. Поднимают чистый контейнер
13 | 2. Инициализируют его данными (закидывая в `docker-entrypoint-initdb.d` конечно же)
14 | 3. Запускают серию тестов
15 |
16 | После этого им снова нужен чистый контейнер с теми же данными (т.е. приходится повторять шаги 1-2)
17 |
18 | Иногда эти шаги достаточно длительные — см. пример в `docker-entrypoint-initdb.d`
19 |
20 | Поэтому они очень просят сделать им образ уже сразу с инициализированным PostgreSQL, где в базе уже будут готовые данные (мы, конечно, понимаем, что это можно сделать и через `docker commit`, но давайте попробуем обойтись `docker build`, раз уж наш Навыкум про сборку контейнеров)
21 |
22 | Название базы и её владельца (и пароль, конечно же) нужно передавать через аргументы при сборке образа
23 |
24 |
25 | Спойлеры
26 |
27 | Для решения этой задачи настоятельно рекомендуем ознакомиться с docker-library/postgres#496
28 |
29 |
30 | ### Что нужно сделать
31 |
32 | Соберите образ с инициализированной БД, используя данные из `docker-entrypoint-initdb.d` (для этого, конечно же, нужно написать `Dockerfile`)
33 |
34 | За основу возьмите образ 15.4-alpine3.18
35 |
36 | При сборке через аргументы передавайте следующие данные:
37 | 1. Имя БД — `db` (`ARG DBNAME`)
38 | 2. Имя пользователя — `app` (`ARG DBUSER`)
39 | 3. Пароль пользователя — `pass` (`ARG DBPASS`)
40 |
41 | Никаких доп.настроек не нужно
42 |
43 | В собранном образе должен запускаться PostgreSQL на порту 5432 с инициализированной базой
44 |
45 | ## Реализация
46 |
47 | В качестве реализации CI/CD пайплайна и Docker Registry можно использовать любые, например (из облачных и бесплатных), [GitHub Actions](https://docs.github.com/en/actions) и [GitHub Packages](https://docs.github.com/packages)
48 |
--------------------------------------------------------------------------------
/angular-storybook/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "components-storybook",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "watch": "ng build --watch --configuration development",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "storybook": "ng run components:storybook",
12 | "build-storybook": "ng run components:build-storybook"
13 | },
14 | "private": true,
15 | "dependencies": {
16 | "@angular/animations": "^15.2.0",
17 | "@angular/common": "^15.2.0",
18 | "@angular/compiler": "^15.2.0",
19 | "@angular/core": "^15.2.0",
20 | "@angular/forms": "^15.2.0",
21 | "@angular/platform-browser": "^15.2.0",
22 | "@angular/platform-browser-dynamic": "^15.2.0",
23 | "@angular/router": "^15.2.0",
24 | "rxjs": "~7.8.0",
25 | "tslib": "^2.3.0",
26 | "zone.js": "~0.12.0"
27 | },
28 | "devDependencies": {
29 | "@angular-devkit/build-angular": "^15.2.4",
30 | "@angular-eslint/builder": "15.2.1",
31 | "@angular-eslint/eslint-plugin": "15.2.1",
32 | "@angular-eslint/eslint-plugin-template": "15.2.1",
33 | "@angular-eslint/schematics": "15.2.1",
34 | "@angular-eslint/template-parser": "15.2.1",
35 | "@angular/cli": "~15.2.4",
36 | "@angular/compiler-cli": "^15.2.0",
37 | "@compodoc/compodoc": "^1.1.19",
38 | "@storybook/addon-essentials": "^7.0.0-rc.8",
39 | "@storybook/addon-interactions": "^7.0.0-rc.8",
40 | "@storybook/addon-links": "^7.0.0-rc.8",
41 | "@storybook/angular": "^7.0.0-rc.8",
42 | "@storybook/blocks": "^7.0.0-rc.8",
43 | "@storybook/testing-library": "^0.0.14-next.1",
44 | "@types/jasmine": "~4.3.0",
45 | "@typescript-eslint/eslint-plugin": "5.48.2",
46 | "@typescript-eslint/parser": "5.48.2",
47 | "eslint": "^8.33.0",
48 | "eslint-plugin-storybook": "^0.6.11",
49 | "jasmine-core": "~4.5.0",
50 | "karma": "~6.4.0",
51 | "karma-chrome-launcher": "~3.1.0",
52 | "karma-coverage": "~2.2.0",
53 | "karma-jasmine": "~5.1.0",
54 | "karma-jasmine-html-reporter": "~2.0.0",
55 | "ng-packagr": "^15.2.2",
56 | "react": "^18.2.0",
57 | "react-dom": "^18.2.0",
58 | "storybook": "^7.0.0-rc.8",
59 | "typescript": "~4.9.4"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/graalvm-native-image-static/README.md:
--------------------------------------------------------------------------------
1 | Теги: `Docker` `Java` `Maven` `GraalVM` `Native`
2 |
3 | # GraalVM Native Image (Static)
4 |
5 | ## Задача
6 |
7 | Есть проект на чистой Java 17, система сборки — Maven, разработчики хотят попробовать [GraalVM Native Image](https://www.graalvm.org/jdk17/reference-manual/native-image/)
8 |
9 | Для Maven есть [Maven Native Plugin](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html), который и позволит скомпилировать приложение в бинарный исполняемый файл формата ELF
10 |
11 | Разработчики хотят сделать так, чтобы выбор между сборкой "обычного приложения" и Native Image осуществлялся через [профили Maven](https://maven.apache.org/guides/introduction/introduction-to-profiles.html), определяемые в самом проекте
12 |
13 | По умолчанию, активным должен быть профиль, который собирает "обычное приложение" (не Native Image)
14 |
15 | ### Сборка
16 |
17 | Сборка проходит стандартным образом, через `mvn package`, никаких внешних зависимостей у проекта (в виде подключаемых при исполнении библиотек нет)
18 |
19 | ### API
20 |
21 | Сервер запускается на порту, указанном через параметр `port` или переменную окружения `PORT` и реагирует на команду `UUID`, выдавая в ответ случайный [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier)
22 |
23 | Как проверить:
24 | 1. Подключаемся с помощью `nc` (`netcat`) по нужному порту
25 | 2. Вводим `UUID⏎`, (где `⏎` — Enter для отправки данных)
26 | 3. Получаем в ответ: `b022e6b9-957a-4f22-b519-2fb57ca76caf` (пример)
27 |
28 |
29 | Спойлеры: пример вызова nc для тестирования
30 |
31 | ```shell
32 | $ nc -u localhost 9999
33 | UUID
34 | b022e6b9-957a-4f22-b519-2fb57ca76caf
35 | ```
36 |
37 |
38 |
39 | ### Что нужно сделать
40 |
41 | 1. Собрать всё с помощью Maven и Native Image (параллелить ничего не нужно, т.к. в приложении нет авто-тестов, проверок стиля кода и т.д.)
42 | 2. Упаковать всё в [`Scratch`](https://hub.docker.com/_/scratch)
43 | 3. Запускать приложение не от root
44 |
45 | ## Реализация
46 |
47 | В качестве реализации CI/CD пайплайна и Docker Registry можно использовать любые, например (из облачных и бесплатных), [GitHub Actions](https://docs.github.com/en/actions) и [GitHub Packages](https://docs.github.com/packages)
48 |
49 | ## Полезные ссылки
50 |
51 | 1. [GraalVM Native Image](https://www.graalvm.org/jdk17/reference-manual/native-image/)
52 | 2. [Netcat MAN](https://linux.die.net/man/1/nc)
53 |
--------------------------------------------------------------------------------
/angular-storybook/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "components": {
7 | "projectType": "library",
8 | "root": "projects/components",
9 | "sourceRoot": "projects/components/src",
10 | "prefix": "lib",
11 | "architect": {
12 | "build": {
13 | "builder": "@angular-devkit/build-angular:ng-packagr",
14 | "options": {
15 | "project": "projects/components/ng-package.json"
16 | },
17 | "configurations": {
18 | "production": {
19 | "tsConfig": "projects/components/tsconfig.lib.prod.json"
20 | },
21 | "development": {
22 | "tsConfig": "projects/components/tsconfig.lib.json"
23 | }
24 | },
25 | "defaultConfiguration": "production"
26 | },
27 | "test": {
28 | "builder": "@angular-devkit/build-angular:karma",
29 | "options": {
30 | "tsConfig": "projects/components/tsconfig.spec.json",
31 | "polyfills": [
32 | "zone.js",
33 | "zone.js/testing"
34 | ]
35 | }
36 | },
37 | "lint": {
38 | "builder": "@angular-eslint/builder:lint",
39 | "options": {
40 | "lintFilePatterns": [
41 | "projects/components/**/*.ts",
42 | "projects/components/**/*.html"
43 | ]
44 | }
45 | },
46 | "storybook": {
47 | "builder": "@storybook/angular:start-storybook",
48 | "options": {
49 | "configDir": "projects/components/.storybook",
50 | "browserTarget": "components:build",
51 | "compodoc": true,
52 | "compodocArgs": [
53 | "-e",
54 | "json",
55 | "-d",
56 | "projects/components"
57 | ],
58 | "port": 6006
59 | }
60 | },
61 | "build-storybook": {
62 | "builder": "@storybook/angular:build-storybook",
63 | "options": {
64 | "configDir": "projects/components/.storybook",
65 | "browserTarget": "components:build",
66 | "compodoc": true,
67 | "compodocArgs": [
68 | "-e",
69 | "json",
70 | "-d",
71 | "projects/components"
72 | ],
73 | "outputDir": "storybook-static"
74 | }
75 | }
76 | }
77 | }
78 | },
79 | "cli": {
80 | "schematicCollections": [
81 | "@angular-eslint/schematics"
82 | ]
83 | }
84 | }
--------------------------------------------------------------------------------
/gradle-application/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/angular-storybook/README.md:
--------------------------------------------------------------------------------
1 | Теги: `Docker` `JS` `TypeScript` `Angular` `Storybook` `NPM`
2 |
3 | # Angular Storybook
4 |
5 | ## Задача
6 |
7 | Есть проект на Angular (исходники хранятся в этом каталоге), который представляет собой библиотеку компонентов одной из [дизайн-систем](https://tilda.education/courses/web-design/designsystem/)
8 |
9 | Необходимо упаковать витрину-компонентов в Docker-образ, используя в качестве базы конечного образа [Nginx](https://hub.docker.com/_/nginx) версии 1.22 (не alpine и не perl)
10 |
11 | Для промежуточных этапов (сборка, тестирование, линтинг) необходимо использовать [Node 18-buster-slim](https://hub.docker.com/_/node)
12 |
13 | **Важно**: нужно упаковывать не сам проект, а [витрину-компонентов на базе Storybook](https://storybook.js.org)
14 |
15 | ## Формулировка разработчика
16 |
17 | Разработчик сказал следующее* (дословно):
18 | > Мы делаем библиотеку компонентов на Angular, которая должна использоваться всеми проектами внутри компании
19 | >
20 | > Чтобы остальные понимали, как ею пользоваться, мы подготовили [Storybook](https://storybook.js.org)
21 | >
22 | > Теперь нам нужно упаковать всё в Docker так, чтобы при запуске Docker-контейнера люди могли увидеть Storybook
23 | >
24 | > Чтобы запустить Storybook локально, нужно выполнить команду `npm run storybook`, чтобы собрать его: `npm run build-storybook`
25 | >
26 | > Вот так примерно выглядит Storybook:
27 | >
28 | > 
29 | >
30 | > **Важно**:
31 | > 1. У нас есть авто-тесты, с UI они запускаются просто командой `npm test` (`Ctrl + C` для остановки)
32 | > 2. Мы придерживаемся определённого CodeStyle, поэтому проверяем стиль кода через `npm run lint`
33 | >
34 |
35 | *Лирическое отступление*: к сожалению, часто бывает, что разработчики знают, как использовать свои инструменты в режиме разработки, но не знают, как использовать "за пределами разработки", например, как опубликовать тот самый Storybook, поэтому с этим придётся разбираться самостоятельно
36 |
37 | Примечание*: мы обещали, что файлов будет немного (до 10 значащих), поэтому явно указываем, куда смотреть:
38 | 1. [`package.json`](package.json)
39 | 2. [`.gitignore`](.gitignore)
40 |
41 | В других файлах ничего смотреть не нужно, кроме того, не нужно вообще что-то в файлах проекта менять (кроме добавления собственного `Dockerfile` и `.dockerignore`)
42 |
43 | Что нужно сделать:
44 | > 1. Упаковать витрину в Docker-образ
45 | > 2. Выложить всё в виде публичного образа на GHCR* (GitHub Container Registry), чтобы мы могли сами затестить и переиспользовать
46 |
47 | Примечание*: GHCR приведён лишь в качестве примера, вы можете использовать любой реестр на собственное усмотрение
48 |
49 | **Важно**: мы хотим запускать и авто-тесты, и проверку стиля кода
50 |
51 | Чего не нужно делать (дословно):
52 | > Никаких `entrypoint.sh` и других sh-скриптов писать не нужно
53 | >
54 | > Переделывать приложение и конфигурационные файлы вроде `package.json` тоже не нужно, настраивайте запуск всего через:
55 | >
56 | > 1. Установку необходимых переменных окружения
57 | >
58 | > 2. Передачу флагов в соответствующие команды, например, в `npm test`
59 | >
60 |
61 | **Важно**: никакие конфигурации Karma и т.д. создавать не нужно (достаточно установки пары переменных окружения и передачи нескольких параметров)
62 |
63 | ## Реализация
64 |
65 | В качестве реализации CI/CD пайплайна и Docker Registry можно использовать любые, например (из облачных и бесплатных), [GitHub Actions](https://docs.github.com/en/actions) и [GitHub Packages](https://docs.github.com/packages)
66 |
--------------------------------------------------------------------------------
/gradle-application/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/angular-storybook/projects/components/documentation.json:
--------------------------------------------------------------------------------
1 | {
2 | "pipes": [],
3 | "interfaces": [],
4 | "injectables": [
5 | {
6 | "name": "ComponentsService",
7 | "id": "injectable-ComponentsService-1a68e5ab8060ac18996868bd337f39aafb46491a3144134c587d69dfd820cf07ba62295c1f88df06847e3ef997966d1275f1d740fea7c0054af98562a751c5c8",
8 | "file": "projects/components/src/lib/components.service.ts",
9 | "properties": [],
10 | "methods": [],
11 | "deprecated": false,
12 | "deprecationMessage": "",
13 | "description": "",
14 | "rawdescription": "\n",
15 | "sourceCode": "import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ComponentsService {\n}\n",
16 | "type": "injectable"
17 | }
18 | ],
19 | "guards": [],
20 | "interceptors": [],
21 | "classes": [],
22 | "directives": [],
23 | "components": [
24 | {
25 | "name": "ComponentsComponent",
26 | "id": "component-ComponentsComponent-9ab62237a9b0bb4002405ad11127778bede646e1f7acafd99d9501b37bd21cd6b3ef9f89e57bab0c22f531acb1df42d8f2e139a6066634bf5afca0f4c9fe0106",
27 | "file": "projects/components/src/lib/components.component.ts",
28 | "encapsulation": [],
29 | "entryComponents": [],
30 | "inputs": [],
31 | "outputs": [],
32 | "providers": [],
33 | "selector": "lib-components",
34 | "styleUrls": [],
35 | "styles": [],
36 | "template": "\n components works!\n
\n",
37 | "templateUrl": [],
38 | "viewProviders": [],
39 | "inputsClass": [],
40 | "outputsClass": [],
41 | "propertiesClass": [],
42 | "methodsClass": [],
43 | "deprecated": false,
44 | "deprecationMessage": "",
45 | "hostBindings": [],
46 | "hostListeners": [],
47 | "description": "",
48 | "rawdescription": "\n",
49 | "type": "component",
50 | "sourceCode": "import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-components',\n template: `\n \n components works!\n
\n `,\n styles: [\n ]\n})\nexport class ComponentsComponent {\n\n}\n",
51 | "assetsDirs": [],
52 | "styleUrlsData": "",
53 | "stylesData": ""
54 | },
55 | {
56 | "name": "CounterComponent",
57 | "id": "component-CounterComponent-dec7b5f254e9a70b3d288a731a015e80650bffd879b0a1e82602958e0cf740d2879ae92e4b810aa8e3b7927c7146a7f7f768bc6f8fef3630e2f9b766a0945adf",
58 | "file": "projects/components/src/lib/counter/counter.component.ts",
59 | "encapsulation": [],
60 | "entryComponents": [],
61 | "inputs": [],
62 | "outputs": [],
63 | "providers": [],
64 | "selector": "lib-counter",
65 | "styleUrls": [
66 | "./counter.component.css"
67 | ],
68 | "styles": [],
69 | "templateUrl": [
70 | "./counter.component.html"
71 | ],
72 | "viewProviders": [],
73 | "inputsClass": [
74 | {
75 | "name": "disabled",
76 | "defaultValue": "false",
77 | "deprecated": false,
78 | "deprecationMessage": "",
79 | "line": 14,
80 | "type": "boolean",
81 | "decorators": []
82 | },
83 | {
84 | "name": "prefix",
85 | "defaultValue": "'lib-counter'",
86 | "deprecated": false,
87 | "deprecationMessage": "",
88 | "line": 9,
89 | "type": "string",
90 | "decorators": []
91 | },
92 | {
93 | "name": "primary",
94 | "defaultValue": "true",
95 | "deprecated": false,
96 | "deprecationMessage": "",
97 | "line": 10,
98 | "type": "boolean",
99 | "decorators": []
100 | },
101 | {
102 | "name": "size",
103 | "defaultValue": "'medium'",
104 | "deprecated": false,
105 | "deprecationMessage": "",
106 | "line": 11,
107 | "type": "\"small\" | \"medium\" | \"large\"",
108 | "decorators": []
109 | },
110 | {
111 | "name": "testid",
112 | "defaultValue": "''",
113 | "deprecated": false,
114 | "deprecationMessage": "",
115 | "line": 12,
116 | "type": "string",
117 | "decorators": []
118 | },
119 | {
120 | "name": "type",
121 | "defaultValue": "''",
122 | "deprecated": false,
123 | "deprecationMessage": "",
124 | "line": 13,
125 | "type": "string",
126 | "decorators": []
127 | },
128 | {
129 | "name": "value",
130 | "defaultValue": "0",
131 | "deprecated": false,
132 | "deprecationMessage": "",
133 | "line": 15,
134 | "type": "number",
135 | "decorators": []
136 | }
137 | ],
138 | "outputsClass": [
139 | {
140 | "name": "increase",
141 | "defaultValue": "new EventEmitter()",
142 | "deprecated": false,
143 | "deprecationMessage": "",
144 | "line": 16,
145 | "type": "EventEmitter"
146 | }
147 | ],
148 | "propertiesClass": [],
149 | "methodsClass": [
150 | {
151 | "name": "onClick",
152 | "args": [
153 | {
154 | "name": "$event",
155 | "type": "Event",
156 | "deprecated": false,
157 | "deprecationMessage": ""
158 | }
159 | ],
160 | "optional": false,
161 | "returnType": "void",
162 | "typeParameters": [],
163 | "line": 22,
164 | "deprecated": false,
165 | "deprecationMessage": "",
166 | "jsdoctags": [
167 | {
168 | "name": "$event",
169 | "type": "Event",
170 | "deprecated": false,
171 | "deprecationMessage": "",
172 | "tagName": {
173 | "text": "param"
174 | }
175 | }
176 | ]
177 | }
178 | ],
179 | "deprecated": false,
180 | "deprecationMessage": "",
181 | "hostBindings": [],
182 | "hostListeners": [],
183 | "description": "",
184 | "rawdescription": "\n",
185 | "type": "component",
186 | "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\n\n@Component({\n selector: 'lib-counter',\n templateUrl: './counter.component.html',\n styleUrls: ['./counter.component.css']\n})\nexport class CounterComponent {\n @Input() prefix = 'lib-counter';\n @Input() primary = true;\n @Input() size : 'small' | 'medium' | 'large' = 'medium';\n @Input() testid = '';\n @Input() type = '';\n @Input() disabled = false;\n @Input() value = 0;\n @Output() increase = new EventEmitter();\n\n public get classes(): string[] {\n return [this.prefix, `${this.prefix}--${this.size}`, `${this.prefix}--${this.primary ? 'primary' : 'secondary'}`];\n }\n\n onClick($event: Event) {\n $event.preventDefault();\n this.value++;\n console.log('click');\n this.increase.emit(this.value);\n }\n}\n",
187 | "assetsDirs": [],
188 | "styleUrlsData": [
189 | {
190 | "data": ".lib-counter {\n font-family: Helvetica, Arial, sans-serif;\n font-weight: 700;\n border-radius: 5px;\n cursor: pointer;\n display: inline-block;\n line-height: 1;\n}\n.lib-counter--primary {\n color: white;\n background-color: #8a73fc;\n border: 1px solid #8a73fc;\n}\n.lib-counter--secondary {\n color: #172b4d;\n background-color: transparent;\n border: 1px solid #172b4d;\n}\n.lib-counter--small {\n font-size: 12px;\n padding: 10px 16px;\n}\n.lib-counter--medium {\n font-size: 14px;\n padding: 11px 20px;\n}\n.lib-counter--large {\n font-size: 16px;\n padding: 12px 24px;\n}\n",
191 | "styleUrl": "./counter.component.css"
192 | }
193 | ],
194 | "stylesData": "",
195 | "accessors": {
196 | "classes": {
197 | "name": "classes",
198 | "getSignature": {
199 | "name": "classes",
200 | "type": "[]",
201 | "returnType": "string[]",
202 | "line": 18
203 | }
204 | }
205 | },
206 | "templateData": "\n\t\n"
207 | }
208 | ],
209 | "modules": [
210 | {
211 | "name": "ComponentsModule",
212 | "id": "module-ComponentsModule-924be5c2c6949aeeed9a9848432fce6586816afa3ae2cd3df16a25531ff649d8148ee6c33be3454bf97abde0ea1c5a746d39eb875b0e0fdd60687b3e45c430bd",
213 | "description": "",
214 | "deprecationMessage": "",
215 | "deprecated": false,
216 | "file": "projects/components/src/lib/components.module.ts",
217 | "methods": [],
218 | "sourceCode": "import { NgModule } from '@angular/core';\nimport { ComponentsComponent } from './components.component';\nimport { CounterComponent } from './counter/counter.component';\n\n\n\n@NgModule({\n declarations: [\n ComponentsComponent,\n CounterComponent\n ],\n imports: [\n ],\n exports: [\n ComponentsComponent\n ]\n})\nexport class ComponentsModule { }\n",
219 | "children": [
220 | {
221 | "type": "providers",
222 | "elements": []
223 | },
224 | {
225 | "type": "declarations",
226 | "elements": [
227 | {
228 | "name": "ComponentsComponent"
229 | },
230 | {
231 | "name": "CounterComponent"
232 | }
233 | ]
234 | },
235 | {
236 | "type": "imports",
237 | "elements": []
238 | },
239 | {
240 | "type": "exports",
241 | "elements": [
242 | {
243 | "name": "ComponentsComponent"
244 | }
245 | ]
246 | },
247 | {
248 | "type": "bootstrap",
249 | "elements": []
250 | },
251 | {
252 | "type": "classes",
253 | "elements": []
254 | }
255 | ]
256 | }
257 | ],
258 | "miscellaneous": {
259 | "variables": [
260 | {
261 | "name": "LargeCounter",
262 | "ctype": "miscellaneous",
263 | "subtype": "variable",
264 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
265 | "deprecated": false,
266 | "deprecationMessage": "",
267 | "type": "Story",
268 | "defaultValue": "{\n args: {\n size: 'large',\n value: 999,\n },\n}"
269 | },
270 | {
271 | "name": "meta",
272 | "ctype": "miscellaneous",
273 | "subtype": "variable",
274 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
275 | "deprecated": false,
276 | "deprecationMessage": "",
277 | "type": "Meta",
278 | "defaultValue": "{\n title: 'Example/CounterComponent',\n component: CounterComponent,\n tags: ['autodocs'],\n render: (args: CounterComponent) => ({\n props: {\n ...args,\n },\n }),\n}"
279 | },
280 | {
281 | "name": "preview",
282 | "ctype": "miscellaneous",
283 | "subtype": "variable",
284 | "file": "projects/components/.storybook/preview.ts",
285 | "deprecated": false,
286 | "deprecationMessage": "",
287 | "type": "Preview",
288 | "defaultValue": "{\n parameters: {\n actions: { argTypesRegex: \"^on[A-Z].*\" },\n controls: {\n matchers: {\n color: /(background|color)$/i,\n date: /Date$/,\n },\n },\n },\n}"
289 | },
290 | {
291 | "name": "PrimaryCounter",
292 | "ctype": "miscellaneous",
293 | "subtype": "variable",
294 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
295 | "deprecated": false,
296 | "deprecationMessage": "",
297 | "type": "Story",
298 | "defaultValue": "{\n args: {\n primary: true,\n value: 1,\n },\n}"
299 | },
300 | {
301 | "name": "SecondaryCounter",
302 | "ctype": "miscellaneous",
303 | "subtype": "variable",
304 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
305 | "deprecated": false,
306 | "deprecationMessage": "",
307 | "type": "Story",
308 | "defaultValue": "{\n args: {\n primary: false,\n value: 1,\n },\n}"
309 | },
310 | {
311 | "name": "SmallCounter",
312 | "ctype": "miscellaneous",
313 | "subtype": "variable",
314 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
315 | "deprecated": false,
316 | "deprecationMessage": "",
317 | "type": "Story",
318 | "defaultValue": "{\n args: {\n size: 'small',\n value: 9,\n },\n}"
319 | }
320 | ],
321 | "functions": [],
322 | "typealiases": [
323 | {
324 | "name": "Story",
325 | "ctype": "miscellaneous",
326 | "subtype": "typealias",
327 | "rawtype": "StoryObj",
328 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
329 | "deprecated": false,
330 | "deprecationMessage": "",
331 | "description": "",
332 | "kind": 177
333 | }
334 | ],
335 | "enumerations": [],
336 | "groupedVariables": {
337 | "projects/components/src/lib/counter/counter.component.stories.ts": [
338 | {
339 | "name": "LargeCounter",
340 | "ctype": "miscellaneous",
341 | "subtype": "variable",
342 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
343 | "deprecated": false,
344 | "deprecationMessage": "",
345 | "type": "Story",
346 | "defaultValue": "{\n args: {\n size: 'large',\n value: 999,\n },\n}"
347 | },
348 | {
349 | "name": "meta",
350 | "ctype": "miscellaneous",
351 | "subtype": "variable",
352 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
353 | "deprecated": false,
354 | "deprecationMessage": "",
355 | "type": "Meta",
356 | "defaultValue": "{\n title: 'Example/CounterComponent',\n component: CounterComponent,\n tags: ['autodocs'],\n render: (args: CounterComponent) => ({\n props: {\n ...args,\n },\n }),\n}"
357 | },
358 | {
359 | "name": "PrimaryCounter",
360 | "ctype": "miscellaneous",
361 | "subtype": "variable",
362 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
363 | "deprecated": false,
364 | "deprecationMessage": "",
365 | "type": "Story",
366 | "defaultValue": "{\n args: {\n primary: true,\n value: 1,\n },\n}"
367 | },
368 | {
369 | "name": "SecondaryCounter",
370 | "ctype": "miscellaneous",
371 | "subtype": "variable",
372 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
373 | "deprecated": false,
374 | "deprecationMessage": "",
375 | "type": "Story",
376 | "defaultValue": "{\n args: {\n primary: false,\n value: 1,\n },\n}"
377 | },
378 | {
379 | "name": "SmallCounter",
380 | "ctype": "miscellaneous",
381 | "subtype": "variable",
382 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
383 | "deprecated": false,
384 | "deprecationMessage": "",
385 | "type": "Story",
386 | "defaultValue": "{\n args: {\n size: 'small',\n value: 9,\n },\n}"
387 | }
388 | ],
389 | "projects/components/.storybook/preview.ts": [
390 | {
391 | "name": "preview",
392 | "ctype": "miscellaneous",
393 | "subtype": "variable",
394 | "file": "projects/components/.storybook/preview.ts",
395 | "deprecated": false,
396 | "deprecationMessage": "",
397 | "type": "Preview",
398 | "defaultValue": "{\n parameters: {\n actions: { argTypesRegex: \"^on[A-Z].*\" },\n controls: {\n matchers: {\n color: /(background|color)$/i,\n date: /Date$/,\n },\n },\n },\n}"
399 | }
400 | ]
401 | },
402 | "groupedFunctions": {},
403 | "groupedEnumerations": {},
404 | "groupedTypeAliases": {
405 | "projects/components/src/lib/counter/counter.component.stories.ts": [
406 | {
407 | "name": "Story",
408 | "ctype": "miscellaneous",
409 | "subtype": "typealias",
410 | "rawtype": "StoryObj",
411 | "file": "projects/components/src/lib/counter/counter.component.stories.ts",
412 | "deprecated": false,
413 | "deprecationMessage": "",
414 | "description": "",
415 | "kind": 177
416 | }
417 | ]
418 | }
419 | },
420 | "routes": [],
421 | "coverage": {
422 | "count": 0,
423 | "status": "low",
424 | "files": [
425 | {
426 | "filePath": "projects/components/.storybook/preview.ts",
427 | "type": "variable",
428 | "linktype": "miscellaneous",
429 | "linksubtype": "variable",
430 | "name": "preview",
431 | "coveragePercent": 0,
432 | "coverageCount": "0/1",
433 | "status": "low"
434 | },
435 | {
436 | "filePath": "projects/components/src/lib/components.component.ts",
437 | "type": "component",
438 | "linktype": "component",
439 | "name": "ComponentsComponent",
440 | "coveragePercent": 0,
441 | "coverageCount": "0/1",
442 | "status": "low"
443 | },
444 | {
445 | "filePath": "projects/components/src/lib/components.service.ts",
446 | "type": "injectable",
447 | "linktype": "injectable",
448 | "name": "ComponentsService",
449 | "coveragePercent": 0,
450 | "coverageCount": "0/1",
451 | "status": "low"
452 | },
453 | {
454 | "filePath": "projects/components/src/lib/counter/counter.component.stories.ts",
455 | "type": "variable",
456 | "linktype": "miscellaneous",
457 | "linksubtype": "variable",
458 | "name": "LargeCounter",
459 | "coveragePercent": 0,
460 | "coverageCount": "0/1",
461 | "status": "low"
462 | },
463 | {
464 | "filePath": "projects/components/src/lib/counter/counter.component.stories.ts",
465 | "type": "variable",
466 | "linktype": "miscellaneous",
467 | "linksubtype": "variable",
468 | "name": "meta",
469 | "coveragePercent": 0,
470 | "coverageCount": "0/1",
471 | "status": "low"
472 | },
473 | {
474 | "filePath": "projects/components/src/lib/counter/counter.component.stories.ts",
475 | "type": "variable",
476 | "linktype": "miscellaneous",
477 | "linksubtype": "variable",
478 | "name": "PrimaryCounter",
479 | "coveragePercent": 0,
480 | "coverageCount": "0/1",
481 | "status": "low"
482 | },
483 | {
484 | "filePath": "projects/components/src/lib/counter/counter.component.stories.ts",
485 | "type": "variable",
486 | "linktype": "miscellaneous",
487 | "linksubtype": "variable",
488 | "name": "SecondaryCounter",
489 | "coveragePercent": 0,
490 | "coverageCount": "0/1",
491 | "status": "low"
492 | },
493 | {
494 | "filePath": "projects/components/src/lib/counter/counter.component.stories.ts",
495 | "type": "variable",
496 | "linktype": "miscellaneous",
497 | "linksubtype": "variable",
498 | "name": "SmallCounter",
499 | "coveragePercent": 0,
500 | "coverageCount": "0/1",
501 | "status": "low"
502 | },
503 | {
504 | "filePath": "projects/components/src/lib/counter/counter.component.ts",
505 | "type": "component",
506 | "linktype": "component",
507 | "name": "CounterComponent",
508 | "coveragePercent": 0,
509 | "coverageCount": "0/10",
510 | "status": "low"
511 | }
512 | ]
513 | }
514 | }
--------------------------------------------------------------------------------