@xpertss/projen-types 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.jsii +1083 -92
  2. package/API.md +7459 -4313
  3. package/README.md +103 -1
  4. package/lib/actions/action-build-workflow.d.ts +17 -0
  5. package/lib/actions/action-build-workflow.js +52 -0
  6. package/lib/actions/action-dogfood-workflow.d.ts +47 -0
  7. package/lib/actions/action-dogfood-workflow.js +84 -0
  8. package/lib/actions/action-sonar-workflow.d.ts +25 -0
  9. package/lib/actions/action-sonar-workflow.js +64 -0
  10. package/lib/actions/github-action-project.d.ts +60 -0
  11. package/lib/actions/github-action-project.js +155 -0
  12. package/lib/cdk/app-runtime-scaffold.js +1 -1
  13. package/lib/cdk/cdk-app-project.js +2 -4
  14. package/lib/cdk/cdk-infra-project.js +1 -1
  15. package/lib/cdk/cdk-typescript-base.js +16 -3
  16. package/lib/cdk/components/ecr-ecs-constructs.js +1 -1
  17. package/lib/cdk/components/edge-networking-constructs.js +1 -1
  18. package/lib/cdk/database-component.js +1 -1
  19. package/lib/cdk/options.d.ts +0 -2
  20. package/lib/cdk/options.js +1 -1
  21. package/lib/common/actions-allowlist-guard.d.ts +37 -0
  22. package/lib/common/actions-allowlist-guard.js +70 -0
  23. package/lib/common/internal-actions.d.ts +10 -0
  24. package/lib/common/internal-actions.js +33 -0
  25. package/lib/common/manual-deploy-workflow.d.ts +0 -2
  26. package/lib/common/manual-deploy-workflow.js +1 -12
  27. package/lib/common/projen-drift-check-workflow.d.ts +36 -0
  28. package/lib/common/projen-drift-check-workflow.js +73 -0
  29. package/lib/common/upgrade-workflow.js +6 -2
  30. package/lib/common/workflow-change-notice-workflow.d.ts +33 -0
  31. package/lib/common/workflow-change-notice-workflow.js +58 -0
  32. package/lib/index.d.ts +8 -0
  33. package/lib/index.js +9 -1
  34. package/lib/java/components/cdk-deploy-hook.js +1 -1
  35. package/lib/java/components/code-index-workflow.js +1 -1
  36. package/lib/java/components/docker-publish.js +1 -1
  37. package/lib/java/components/flyway-migration.js +1 -1
  38. package/lib/java/components/github-packages-publish.js +1 -1
  39. package/lib/java/components/maven-central-publish.js +1 -1
  40. package/lib/java/java-app-project.js +1 -1
  41. package/lib/java/java-library-project.js +1 -1
  42. package/lib/java/java-maven-base.js +13 -4
  43. package/lib/java/java-service-project.js +1 -1
  44. package/package.json +1 -1
  45. package/release-publishing.md +125 -0
  46. package/lib/common/drift-check.d.ts +0 -8
  47. package/lib/common/drift-check.js +0 -18
  48. package/spec/npm-publishing-setup.md +0 -150
  49. package/spec/projen-cdk-spec.md +0 -80
  50. package/spec/projen-java-spec.md +0 -96
package/README.md CHANGED
@@ -13,6 +13,7 @@ Instead of hand-maintaining `pom.xml`, `cdk.json`, and GitHub workflows, you dec
13
13
  | `JavaLibraryProject` | Reusable Java library | Maven Central | `build`, `upgrade` (nightly), `publish-maven-central`, `codeindex` |
14
14
  | `JavaServiceProject` | Spring Boot service | Docker Hub | `build`, `upgrade` (nightly), `publish-docker`, `deploy-cdk` |
15
15
  | `JavaAppProject` | GUI/TUI/CLI Java application | GitHub Packages | `build`, `upgrade` (nightly), `publish-ghpackages` |
16
+ | `GitHubActionProject` | Reusable GitHub Action or Workflow | GitHub Releases | `build`, `test-dogfood`, `sonar`, `release` |
16
17
 
17
18
  Two foundation classes are also exported for advanced use: `CdkTypescriptProject` (shared CDK + TypeScript base for the CDK types) and `JavaMavenProject` (shared Maven base for the Java types).
18
19
 
@@ -176,6 +177,72 @@ project.synth();
176
177
 
177
178
  You get everything from `JavaMavenProject`, plus `.github/workflows/publish-ghpackages.yml` - manual dispatch running `mvn -B deploy -DaltDeploymentRepository=github::<registry>`, authenticated with `GITHUB_TOKEN`. `ghPackagesRegistry` defaults to `https://maven.pkg.github.com/<repo>` derived from the repository URL.
178
179
 
180
+ ### GitHubActionProject
181
+
182
+ A reusable GitHub Action or Workflow. This example scaffolds an action that stages a folder and, only if it changed, commits and pushes it.
183
+
184
+ ```typescript
185
+ // .projenrc.ts
186
+ import { GitHubActionProject } from '@xpertss/projen-types';
187
+
188
+ const project = new GitHubActionProject({
189
+ name: 'auto-commit',
190
+ description: 'Stage a folder and, only if it changed, commit and push it',
191
+ sonarHostUrl: 'https://sonar.xpertss.org', // required, no default - your self-hosted SonarQube
192
+ dogfood: {
193
+ // Two scenario steps: the "changed" path and the "no-op" path are both
194
+ // load-bearing behavior for this action (a double-commit or a
195
+ // push-when-empty bug is the failure mode a hand-rolled inline-shell
196
+ // alternative is most likely to introduce).
197
+ scenario: [
198
+ {
199
+ name: 'Changed path',
200
+ fixtureSteps: [
201
+ 'echo "$(date -u +%Y%m%dT%H%M%SZ)" >> test/fixtures/dogfood-state.txt',
202
+ ],
203
+ inputs: {
204
+ commit_message: 'test: dogfood',
205
+ branches: 'test/dogfood',
206
+ },
207
+ assertions: [
208
+ // step id defaults to a slug of `name` - here "changed-path-0"
209
+ '[ "${{ steps.changed-path-0.outputs.committed }}" = "true" ]',
210
+ ],
211
+ },
212
+ {
213
+ // No fixture change this time - nothing new to commit.
214
+ name: 'No-op path',
215
+ id: 'no-op-check', // pin an explicit id instead of relying on the default slug
216
+ inputs: {
217
+ commit_message: 'test: dogfood',
218
+ branches: 'test/dogfood',
219
+ },
220
+ assertions: [
221
+ '[ "${{ steps.no-op-check.outputs.committed }}" = "false" ]',
222
+ ],
223
+ },
224
+ ],
225
+ cleanup: [
226
+ 'git push origin --delete test/dogfood || true',
227
+ ],
228
+ },
229
+ });
230
+
231
+ project.synth();
232
+ ```
233
+
234
+ You get:
235
+
236
+ - `action.yml` and `auto-commit.sh` are hand-written - this type only lints their content via `build.yml`'s shellcheck/yamllint/actionlint checks.
237
+ - `.github/workflows/build.yml` - lint gate: `apt`-installed shellcheck/yamllint plus a pinned, SHA-256-verified `actionlint` release binary. Gates `main` alongside `sonar.yml`.
238
+ - `.github/workflows/test-dogfood.yml` - runs the `dogfood.scenario` steps above against this repo's own `action.yml` (via `uses: .`), then the shared `cleanup`, on `workflow_dispatch`, every `pull_request`, and nightly.
239
+ - `.github/workflows/sonar.yml` - self-hosted SonarQube via the Scanner CLI, scanning `action.yml`/`.github/workflows/**`/`**/*.sh` explicitly.
240
+ - `.github/workflows/release.yml` - `feat:`/`fix:` commits on `main` bump the version, tag `vX.Y.Z`, and create a GitHub Release.
241
+ - `.github/workflows/projen-drift-check.yml`, `workflow-change-notice.yml`, `actions-allowlist-guard.yml` - drift detection, a change notice, and an action allow-list guard, always included.
242
+ - `package.json` (**private**, version source only), `tsconfig.json`, `.yamllint`, `LICENSE` (MIT by default), and a `README.md` template - all regenerated by `npx projen`.
243
+
244
+ Needs the same two secrets as everything else in this package: `PROJEN_GITHUB_TOKEN` (used for automated PR comments) and `SONAR_TOKEN` (the Sonar scan). Onboarding a brand-new action repo from scratch: `npm init -y && npm install -D projen constructs @xpertss/projen-types`, write the `.projenrc.ts` above, `npx projen && npm install`, then hand-write `action.yml`/`auto-commit.sh`/`test/fixtures/`.
245
+
179
246
  ## Common options
180
247
 
181
248
  CDK project types (`CdkInfraProjectOptions` / `CdkAppProjectOptions`):
@@ -216,12 +283,44 @@ interface EnvironmentOptions {
216
283
 
217
284
  Plain strings (`'dev'`) are shorthand for `{ name: 'dev' }`.
218
285
 
286
+ `GitHubActionProjectOptions`:
287
+
288
+ | Option | Default | Description |
289
+ | --- | --- | --- |
290
+ | `name` | - (required) | Project name |
291
+ | `description` | - | One-line description; used in the default README template and recorded in the private `package.json` |
292
+ | `sonarHostUrl` | - (required) | URL of your self-hosted SonarQube instance; must be reachable from github.com-hosted runners |
293
+ | `sonarTokenSecret` | `SONAR_TOKEN` | GitHub secret holding the Sonar token |
294
+ | `sonarPullRequestGate` | `true` | Whether `sonar.yml` also runs on `pull_request` as a pass/fail gate |
295
+ | `dogfood` | - (required) | `ActionDogfoodOptions` - the scenario that exercises the action end-to-end via `uses: .` |
296
+ | `license` | `MIT` | SPDX identifier for the generated `LICENSE` |
297
+ | `gheTokenSecret` | `PROJEN_GITHUB_TOKEN` | GitHub secret holding projen's PAT |
298
+
299
+ `ActionDogfoodOptions`/`ActionDogfoodStep` - the dogfood scenario (`test-dogfood.yml`):
300
+
301
+ ```typescript
302
+ interface ActionDogfoodOptions {
303
+ readonly scenario: ActionDogfoodStep[]; // one or more, run in order - required
304
+ readonly cleanup: string[]; // shared, run once at the end with `if: always()` - required
305
+ }
306
+
307
+ interface ActionDogfoodStep {
308
+ readonly name: string; // labels this step-group's generated workflow steps
309
+ readonly id?: string; // step id for the `uses: .` call; default: a slug of `name`
310
+ readonly fixtureSteps?: string[]; // shell, before the invocation (default: none)
311
+ readonly inputs?: Record<string, string>; // `with:` for this invocation (default: none)
312
+ readonly assertions: string[]; // shell, after the invocation - required, job fails unless all exit 0
313
+ }
314
+ ```
315
+
316
+ Most actions need exactly one `scenario` step. Actions with a re-run/no-op/idempotency behavior to verify (e.g. `auto-commit`'s no-op-on-no-change path, `create-pull-request`'s reuse-the-PR path) declare two - the second typically omits `fixtureSteps` so its invocation sees no new state, and its assertion checks the opposite outcome of the first. Reference an invocation's own outputs from a later assertion via `${{ steps.<id>.outputs.<name> }}`, using either the default slug or an explicit `id`.
317
+
219
318
  ## Required GitHub secrets
220
319
 
221
320
  | Secret | Used by | Notes |
222
321
  | --- | --- | --- |
223
322
  | `PROJEN_GITHUB_TOKEN` | all types | PAT for projen's self-mutation/automation; override via `gheTokenSecret` |
224
- | `SONAR_TOKEN` | Java types with `sonarProjectKey` | SonarQube scan step in `build.yml` |
323
+ | `SONAR_TOKEN` | Java types with `sonarProjectKey`; `GitHubActionProject` | SonarQube scan step in `build.yml` / `sonar.yml`; override via `sonarTokenSecret` on `GitHubActionProject` |
225
324
  | `DOCKER_USERNAME` / `DOCKER_PASSWORD` | `JavaServiceProject` | Docker image push |
226
325
  | `MAVEN_GPG_PRIVATE_KEY`, `MAVEN_GPG_PASSPHRASE`, `MAVEN_CENTRAL_USERNAME`, `MAVEN_CENTRAL_PASSWORD` | `JavaLibraryProject` without `mavenCentralOidc` | Not needed with OIDC trusted publishing |
227
326
  | (your Slack webhook secret) | CDK types with `slackWebhookSecret` | Deploy notifications |
@@ -242,6 +341,9 @@ The project types are composed from smaller components you can also attach to yo
242
341
  | `FlywayMigration` | `JavaProject` | Flyway plugin/dependency + migrations directory |
243
342
  | `CdkDeployHook` | `JavaProject` | Manual-dispatch workflow that triggers `deploy.yml` in a companion CDK repo |
244
343
  | `CodeIndexWorkflow` | `JavaProject` | Code index generation on push to `main` |
344
+ | `ActionBuildWorkflow` | `GitHubProject` | The `lint` task (shellcheck/yamllint/pinned actionlint) + `build.yml` |
345
+ | `ActionDogfoodWorkflow` | `GitHubProject` | `test-dogfood.yml` from an `ActionDogfoodOptions` scenario |
346
+ | `ActionSonarWorkflow` | `GitHubProject` | `sonar.yml` (self-hosted SonarQube via the Scanner CLI) |
245
347
 
246
348
  Example - adding a Docker publish to a plain projen `JavaProject`:
247
349
 
@@ -0,0 +1,17 @@
1
+ import { Component, Task, github } from 'projen';
2
+ /**
3
+ * The AD-001 Layer-1 lint gate for a composite-action repo: shellcheck,
4
+ * yamllint, and a pinned `actionlint` release binary (verified by SHA-256,
5
+ * never a marketplace action - org policy). Creates a dedicated `lint` task
6
+ * (named to avoid colliding with projen's own reserved `build` task, which
7
+ * spawns the unrelated default/pre-compile/compile/post-compile/test/package
8
+ * chain - including `default`, i.e. re-running `.projenrc.ts`, which is not
9
+ * what this gate is for) and wraps it in a `TaskWorkflow` (`build.yml`)
10
+ * triggered on push-to-`main` and `pull_request`. The same task is reused by
11
+ * the release build job, so the lint commands exist in exactly one place.
12
+ */
13
+ export declare class ActionBuildWorkflow extends Component {
14
+ readonly task: Task;
15
+ readonly workflow: github.TaskWorkflow;
16
+ constructor(scope: github.GitHubProject);
17
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ActionBuildWorkflow = void 0;
4
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
5
+ const projen_1 = require("projen");
6
+ // Pinned release + verified SHA-256 (linux_amd64) - upgrade is a reviewed
7
+ // diff of this constant, never a floating version (AD-001).
8
+ const ACTIONLINT_VERSION = '1.7.12';
9
+ const ACTIONLINT_SHA256 = '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8';
10
+ /**
11
+ * The AD-001 Layer-1 lint gate for a composite-action repo: shellcheck,
12
+ * yamllint, and a pinned `actionlint` release binary (verified by SHA-256,
13
+ * never a marketplace action - org policy). Creates a dedicated `lint` task
14
+ * (named to avoid colliding with projen's own reserved `build` task, which
15
+ * spawns the unrelated default/pre-compile/compile/post-compile/test/package
16
+ * chain - including `default`, i.e. re-running `.projenrc.ts`, which is not
17
+ * what this gate is for) and wraps it in a `TaskWorkflow` (`build.yml`)
18
+ * triggered on push-to-`main` and `pull_request`. The same task is reused by
19
+ * the release build job, so the lint commands exist in exactly one place.
20
+ */
21
+ class ActionBuildWorkflow extends projen_1.Component {
22
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@xpertss/projen-types.ActionBuildWorkflow", version: "0.0.2" };
23
+ task;
24
+ workflow;
25
+ constructor(scope) {
26
+ super(scope, 'ActionBuildWorkflow');
27
+ const gh = scope.github;
28
+ if (!gh) {
29
+ throw new Error('ActionBuildWorkflow requires GitHub integration to be enabled');
30
+ }
31
+ this.task = scope.addTask('lint', {
32
+ description: 'Lint the action (shellcheck, yamllint, actionlint)',
33
+ });
34
+ this.task.exec('sudo apt-get update -y && sudo apt-get install -y shellcheck yamllint');
35
+ this.task.exec(`curl -fsSL -o /tmp/actionlint.tar.gz "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"`);
36
+ this.task.exec(`echo "${ACTIONLINT_SHA256} /tmp/actionlint.tar.gz" | sha256sum -c -`);
37
+ this.task.exec('tar -xzf /tmp/actionlint.tar.gz -C /tmp actionlint');
38
+ this.task.exec('find . -path ./node_modules -prune -o -name "*.sh" -print0 | xargs -0 -r shellcheck');
39
+ this.task.exec('yamllint -c .yamllint action.yml .github/workflows/*.yml');
40
+ this.task.exec('/tmp/actionlint action.yml .github/workflows/*.yml');
41
+ this.workflow = new projen_1.github.TaskWorkflow(gh, {
42
+ name: 'build',
43
+ jobId: 'build',
44
+ task: this.task,
45
+ triggers: { push: { branches: ['main'] }, pullRequest: {} },
46
+ permissions: { contents: projen_1.github.workflows.JobPermission.READ },
47
+ preBuildSteps: [{ name: 'Install dependencies', run: 'npm ci' }],
48
+ });
49
+ }
50
+ }
51
+ exports.ActionBuildWorkflow = ActionBuildWorkflow;
52
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWJ1aWxkLXdvcmtmbG93LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FjdGlvbnMvYWN0aW9uLWJ1aWxkLXdvcmtmbG93LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxtQ0FBaUQ7QUFFakQsMEVBQTBFO0FBQzFFLDREQUE0RDtBQUM1RCxNQUFNLGtCQUFrQixHQUFHLFFBQVEsQ0FBQztBQUNwQyxNQUFNLGlCQUFpQixHQUNyQixrRUFBa0UsQ0FBQztBQUVyRTs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBYSxtQkFBb0IsU0FBUSxrQkFBUzs7SUFDaEMsSUFBSSxDQUFPO0lBQ1gsUUFBUSxDQUFzQjtJQUU5QyxZQUFZLEtBQTJCO1FBQ3JDLEtBQUssQ0FBQyxLQUFLLEVBQUUscUJBQXFCLENBQUMsQ0FBQztRQUVwQyxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNSLE1BQU0sSUFBSSxLQUFLLENBQ2IsK0RBQStELENBQ2hFLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtZQUNoQyxXQUFXLEVBQUUsb0RBQW9EO1NBQ2xFLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUNaLHVFQUF1RSxDQUN4RSxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQ1osZ0dBQWdHLGtCQUFrQixlQUFlLGtCQUFrQixzQkFBc0IsQ0FDMUssQ0FBQztRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUNaLFNBQVMsaUJBQWlCLDRDQUE0QyxDQUN2RSxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0RBQW9ELENBQUMsQ0FBQztRQUNyRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FDWixxRkFBcUYsQ0FDdEYsQ0FBQztRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLDBEQUEwRCxDQUFDLENBQUM7UUFDM0UsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0RBQW9ELENBQUMsQ0FBQztRQUVyRSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksZUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFLEVBQUU7WUFDMUMsSUFBSSxFQUFFLE9BQU87WUFDYixLQUFLLEVBQUUsT0FBTztZQUNkLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtZQUNmLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsV0FBVyxFQUFFLEVBQUUsRUFBRTtZQUMzRCxXQUFXLEVBQUUsRUFBRSxRQUFRLEVBQUUsZUFBTSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFO1lBQzlELGFBQWEsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQztTQUNqRSxDQUFDLENBQUM7SUFDTCxDQUFDOztBQXpDSCxrREEwQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIFRhc2ssIGdpdGh1YiB9IGZyb20gJ3Byb2plbic7XG5cbi8vIFBpbm5lZCByZWxlYXNlICsgdmVyaWZpZWQgU0hBLTI1NiAobGludXhfYW1kNjQpIC0gdXBncmFkZSBpcyBhIHJldmlld2VkXG4vLyBkaWZmIG9mIHRoaXMgY29uc3RhbnQsIG5ldmVyIGEgZmxvYXRpbmcgdmVyc2lvbiAoQUQtMDAxKS5cbmNvbnN0IEFDVElPTkxJTlRfVkVSU0lPTiA9ICcxLjcuMTInO1xuY29uc3QgQUNUSU9OTElOVF9TSEEyNTYgPVxuICAnOGFjYThkYjk2ZjFiOTQ3NzBmMWIwZDcyYjZkZGRjYjFlYmI4MTIzY2IzNzEyNTMwYjA4Y2MzODdiMzQ5YTNkOCc7XG5cbi8qKlxuICogVGhlIEFELTAwMSBMYXllci0xIGxpbnQgZ2F0ZSBmb3IgYSBjb21wb3NpdGUtYWN0aW9uIHJlcG86IHNoZWxsY2hlY2ssXG4gKiB5YW1sbGludCwgYW5kIGEgcGlubmVkIGBhY3Rpb25saW50YCByZWxlYXNlIGJpbmFyeSAodmVyaWZpZWQgYnkgU0hBLTI1NixcbiAqIG5ldmVyIGEgbWFya2V0cGxhY2UgYWN0aW9uIC0gb3JnIHBvbGljeSkuIENyZWF0ZXMgYSBkZWRpY2F0ZWQgYGxpbnRgIHRhc2tcbiAqIChuYW1lZCB0byBhdm9pZCBjb2xsaWRpbmcgd2l0aCBwcm9qZW4ncyBvd24gcmVzZXJ2ZWQgYGJ1aWxkYCB0YXNrLCB3aGljaFxuICogc3Bhd25zIHRoZSB1bnJlbGF0ZWQgZGVmYXVsdC9wcmUtY29tcGlsZS9jb21waWxlL3Bvc3QtY29tcGlsZS90ZXN0L3BhY2thZ2VcbiAqIGNoYWluIC0gaW5jbHVkaW5nIGBkZWZhdWx0YCwgaS5lLiByZS1ydW5uaW5nIGAucHJvamVucmMudHNgLCB3aGljaCBpcyBub3RcbiAqIHdoYXQgdGhpcyBnYXRlIGlzIGZvcikgYW5kIHdyYXBzIGl0IGluIGEgYFRhc2tXb3JrZmxvd2AgKGBidWlsZC55bWxgKVxuICogdHJpZ2dlcmVkIG9uIHB1c2gtdG8tYG1haW5gIGFuZCBgcHVsbF9yZXF1ZXN0YC4gVGhlIHNhbWUgdGFzayBpcyByZXVzZWQgYnlcbiAqIHRoZSByZWxlYXNlIGJ1aWxkIGpvYiwgc28gdGhlIGxpbnQgY29tbWFuZHMgZXhpc3QgaW4gZXhhY3RseSBvbmUgcGxhY2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBBY3Rpb25CdWlsZFdvcmtmbG93IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgcHVibGljIHJlYWRvbmx5IHRhc2s6IFRhc2s7XG4gIHB1YmxpYyByZWFkb25seSB3b3JrZmxvdzogZ2l0aHViLlRhc2tXb3JrZmxvdztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogZ2l0aHViLkdpdEh1YlByb2plY3QpIHtcbiAgICBzdXBlcihzY29wZSwgJ0FjdGlvbkJ1aWxkV29ya2Zsb3cnKTtcblxuICAgIGNvbnN0IGdoID0gc2NvcGUuZ2l0aHViO1xuICAgIGlmICghZ2gpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0FjdGlvbkJ1aWxkV29ya2Zsb3cgcmVxdWlyZXMgR2l0SHViIGludGVncmF0aW9uIHRvIGJlIGVuYWJsZWQnLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLnRhc2sgPSBzY29wZS5hZGRUYXNrKCdsaW50Jywge1xuICAgICAgZGVzY3JpcHRpb246ICdMaW50IHRoZSBhY3Rpb24gKHNoZWxsY2hlY2ssIHlhbWxsaW50LCBhY3Rpb25saW50KScsXG4gICAgfSk7XG4gICAgdGhpcy50YXNrLmV4ZWMoXG4gICAgICAnc3VkbyBhcHQtZ2V0IHVwZGF0ZSAteSAmJiBzdWRvIGFwdC1nZXQgaW5zdGFsbCAteSBzaGVsbGNoZWNrIHlhbWxsaW50JyxcbiAgICApO1xuICAgIHRoaXMudGFzay5leGVjKFxuICAgICAgYGN1cmwgLWZzU0wgLW8gL3RtcC9hY3Rpb25saW50LnRhci5neiBcImh0dHBzOi8vZ2l0aHViLmNvbS9yaHlzZC9hY3Rpb25saW50L3JlbGVhc2VzL2Rvd25sb2FkL3Yke0FDVElPTkxJTlRfVkVSU0lPTn0vYWN0aW9ubGludF8ke0FDVElPTkxJTlRfVkVSU0lPTn1fbGludXhfYW1kNjQudGFyLmd6XCJgLFxuICAgICk7XG4gICAgdGhpcy50YXNrLmV4ZWMoXG4gICAgICBgZWNobyBcIiR7QUNUSU9OTElOVF9TSEEyNTZ9ICAvdG1wL2FjdGlvbmxpbnQudGFyLmd6XCIgfCBzaGEyNTZzdW0gLWMgLWAsXG4gICAgKTtcbiAgICB0aGlzLnRhc2suZXhlYygndGFyIC14emYgL3RtcC9hY3Rpb25saW50LnRhci5neiAtQyAvdG1wIGFjdGlvbmxpbnQnKTtcbiAgICB0aGlzLnRhc2suZXhlYyhcbiAgICAgICdmaW5kIC4gLXBhdGggLi9ub2RlX21vZHVsZXMgLXBydW5lIC1vIC1uYW1lIFwiKi5zaFwiIC1wcmludDAgfCB4YXJncyAtMCAtciBzaGVsbGNoZWNrJyxcbiAgICApO1xuICAgIHRoaXMudGFzay5leGVjKCd5YW1sbGludCAtYyAueWFtbGxpbnQgYWN0aW9uLnltbCAuZ2l0aHViL3dvcmtmbG93cy8qLnltbCcpO1xuICAgIHRoaXMudGFzay5leGVjKCcvdG1wL2FjdGlvbmxpbnQgYWN0aW9uLnltbCAuZ2l0aHViL3dvcmtmbG93cy8qLnltbCcpO1xuXG4gICAgdGhpcy53b3JrZmxvdyA9IG5ldyBnaXRodWIuVGFza1dvcmtmbG93KGdoLCB7XG4gICAgICBuYW1lOiAnYnVpbGQnLFxuICAgICAgam9iSWQ6ICdidWlsZCcsXG4gICAgICB0YXNrOiB0aGlzLnRhc2ssXG4gICAgICB0cmlnZ2VyczogeyBwdXNoOiB7IGJyYW5jaGVzOiBbJ21haW4nXSB9LCBwdWxsUmVxdWVzdDoge30gfSxcbiAgICAgIHBlcm1pc3Npb25zOiB7IGNvbnRlbnRzOiBnaXRodWIud29ya2Zsb3dzLkpvYlBlcm1pc3Npb24uUkVBRCB9LFxuICAgICAgcHJlQnVpbGRTdGVwczogW3sgbmFtZTogJ0luc3RhbGwgZGVwZW5kZW5jaWVzJywgcnVuOiAnbnBtIGNpJyB9XSxcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,47 @@
1
+ import { Component, github } from 'projen';
2
+ /**
3
+ * One invocation of the action within the dogfood scenario: optional fixture
4
+ * setup, the `uses: .` call with this step's inputs, then this step's
5
+ * assertions. Most actions need exactly one; actions with a re-run/no-op
6
+ * behavior to verify (e.g. F006's reuse-the-PR path, F007's no-op-commit
7
+ * path) declare two.
8
+ */
9
+ export interface ActionDogfoodStep {
10
+ /** Label used to name this step-group's generated workflow steps. */
11
+ readonly name: string;
12
+ /**
13
+ * Step id for the `uses: .` invocation, so a later assertion can
14
+ * reference this step's outputs via `${{ steps.<id>.outputs.<name> }}`.
15
+ * @default - a slug derived from `name`, disambiguated by position
16
+ */
17
+ readonly id?: string;
18
+ /**
19
+ * Shell steps executed before this invocation, to produce or alter
20
+ * fixture state.
21
+ * @default []
22
+ */
23
+ readonly fixtureSteps?: string[];
24
+ /**
25
+ * `with:` inputs for this invocation's local `uses: .` call.
26
+ * @default {}
27
+ */
28
+ readonly inputs?: Record<string, string>;
29
+ /** Shell assertions after this invocation - the job fails unless every one exits 0. */
30
+ readonly assertions: string[];
31
+ }
32
+ export interface ActionDogfoodOptions {
33
+ /** One or more scenario steps, run in order, in the dogfood job. */
34
+ readonly scenario: ActionDogfoodStep[];
35
+ /** Shell cleanup, run once at the end with `if: always()`, so repeated runs start clean. */
36
+ readonly cleanup: string[];
37
+ }
38
+ /**
39
+ * Per AD-001's dogfood test: the composite action is run **against this
40
+ * repo**, end-to-end, via a local `uses: .` reference - no external harness.
41
+ * Builds `test-dogfood.yml` from an ordered `scenario` of invocation steps
42
+ * (see `ActionDogfoodStep`) followed by a shared cleanup step.
43
+ */
44
+ export declare class ActionDogfoodWorkflow extends Component {
45
+ readonly workflow: github.GithubWorkflow;
46
+ constructor(scope: github.GitHubProject, options: ActionDogfoodOptions);
47
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ActionDogfoodWorkflow = void 0;
4
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
5
+ const projen_1 = require("projen");
6
+ // Nightly environment-regression canary (AD-001/F006): re-runs the same
7
+ // scenario against settled `main` in today's runner image, independent of
8
+ // the pull_request gate. Quiet UTC hour; a component constant, not a
9
+ // project option - upgrading it is a reviewed diff.
10
+ const NIGHTLY_DOGFOOD_SCHEDULE = '17 3 * * *';
11
+ // Lowercase, non-alphanumerics collapsed to a single `-`, trimmed - then
12
+ // disambiguated by position so two steps sharing a name (or an unnamed
13
+ // slug, e.g. punctuation-only) never collide.
14
+ function slug(name, index) {
15
+ const base = name
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, '-')
18
+ .replace(/^-+|-+$/g, '');
19
+ return `${base || 'step'}-${index}`;
20
+ }
21
+ /**
22
+ * Per AD-001's dogfood test: the composite action is run **against this
23
+ * repo**, end-to-end, via a local `uses: .` reference - no external harness.
24
+ * Builds `test-dogfood.yml` from an ordered `scenario` of invocation steps
25
+ * (see `ActionDogfoodStep`) followed by a shared cleanup step.
26
+ */
27
+ class ActionDogfoodWorkflow extends projen_1.Component {
28
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@xpertss/projen-types.ActionDogfoodWorkflow", version: "0.0.2" };
29
+ workflow;
30
+ constructor(scope, options) {
31
+ super(scope, 'ActionDogfoodWorkflow');
32
+ if (!options.scenario || options.scenario.length === 0) {
33
+ throw new Error('ActionDogfoodWorkflow requires at least one dogfood.scenario step');
34
+ }
35
+ if (!options.cleanup || options.cleanup.length === 0) {
36
+ throw new Error('ActionDogfoodWorkflow requires dogfood.cleanup');
37
+ }
38
+ const gh = scope.github;
39
+ if (!gh) {
40
+ throw new Error('ActionDogfoodWorkflow requires GitHub integration to be enabled');
41
+ }
42
+ const steps = [projen_1.github.WorkflowSteps.checkout()];
43
+ options.scenario.forEach((step, index) => {
44
+ if (step.fixtureSteps && step.fixtureSteps.length > 0) {
45
+ steps.push({
46
+ name: `${step.name}: fixture`,
47
+ run: step.fixtureSteps.join('\n'),
48
+ });
49
+ }
50
+ const hasInputs = step.inputs && Object.keys(step.inputs).length > 0;
51
+ steps.push({
52
+ id: step.id ?? slug(step.name, index),
53
+ name: `${step.name}: run the action`,
54
+ uses: '.',
55
+ ...(hasInputs ? { with: step.inputs } : {}),
56
+ });
57
+ steps.push({
58
+ name: `${step.name}: assert`,
59
+ run: step.assertions.join('\n'),
60
+ });
61
+ });
62
+ steps.push({
63
+ name: 'Cleanup',
64
+ if: 'always()',
65
+ run: options.cleanup.join('\n'),
66
+ });
67
+ this.workflow = new projen_1.github.GithubWorkflow(gh, 'test-dogfood');
68
+ this.workflow.on({
69
+ workflowDispatch: {},
70
+ pullRequest: { branches: ['main'] },
71
+ schedule: [{ cron: NIGHTLY_DOGFOOD_SCHEDULE }],
72
+ });
73
+ this.workflow.addJob('dogfood', {
74
+ runsOn: ['ubuntu-latest'],
75
+ permissions: {
76
+ contents: projen_1.github.workflows.JobPermission.WRITE,
77
+ pullRequests: projen_1.github.workflows.JobPermission.WRITE,
78
+ },
79
+ steps,
80
+ });
81
+ }
82
+ }
83
+ exports.ActionDogfoodWorkflow = ActionDogfoodWorkflow;
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWRvZ2Zvb2Qtd29ya2Zsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWN0aW9ucy9hY3Rpb24tZG9nZm9vZC13b3JrZmxvdy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsbUNBQTJDO0FBRTNDLHdFQUF3RTtBQUN4RSwwRUFBMEU7QUFDMUUscUVBQXFFO0FBQ3JFLG9EQUFvRDtBQUNwRCxNQUFNLHdCQUF3QixHQUFHLFlBQVksQ0FBQztBQXFDOUMseUVBQXlFO0FBQ3pFLHVFQUF1RTtBQUN2RSw4Q0FBOEM7QUFDOUMsU0FBUyxJQUFJLENBQUMsSUFBWSxFQUFFLEtBQWE7SUFDdkMsTUFBTSxJQUFJLEdBQUcsSUFBSTtTQUNkLFdBQVcsRUFBRTtTQUNiLE9BQU8sQ0FBQyxhQUFhLEVBQUUsR0FBRyxDQUFDO1NBQzNCLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDM0IsT0FBTyxHQUFHLElBQUksSUFBSSxNQUFNLElBQUksS0FBSyxFQUFFLENBQUM7QUFDdEMsQ0FBQztBQVVEOzs7OztHQUtHO0FBQ0gsTUFBYSxxQkFBc0IsU0FBUSxrQkFBUzs7SUFDbEMsUUFBUSxDQUF3QjtJQUVoRCxZQUFZLEtBQTJCLEVBQUUsT0FBNkI7UUFDcEUsS0FBSyxDQUFDLEtBQUssRUFBRSx1QkFBdUIsQ0FBQyxDQUFDO1FBRXRDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQ2IsbUVBQW1FLENBQ3BFLENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFFRCxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNSLE1BQU0sSUFBSSxLQUFLLENBQ2IsaUVBQWlFLENBQ2xFLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxLQUFLLEdBQStCLENBQUMsZUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBRTVFLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3ZDLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdEQsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDVCxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsSUFBSSxXQUFXO29CQUM3QixHQUFHLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2lCQUNsQyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ3JFLEtBQUssQ0FBQyxJQUFJLENBQUM7Z0JBQ1QsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDO2dCQUNyQyxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsSUFBSSxrQkFBa0I7Z0JBQ3BDLElBQUksRUFBRSxHQUFHO2dCQUNULEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2FBQzVDLENBQUMsQ0FBQztZQUVILEtBQUssQ0FBQyxJQUFJLENBQUM7Z0JBQ1QsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLElBQUksVUFBVTtnQkFDNUIsR0FBRyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQzthQUNoQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDVCxJQUFJLEVBQUUsU0FBUztZQUNmLEVBQUUsRUFBRSxVQUFVO1lBQ2QsR0FBRyxFQUFFLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztTQUNoQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksZUFBTSxDQUFDLGNBQWMsQ0FBQyxFQUFFLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDOUQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDZixnQkFBZ0IsRUFBRSxFQUFFO1lBQ3BCLFdBQVcsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ25DLFFBQVEsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLHdCQUF3QixFQUFFLENBQUM7U0FDL0MsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1lBQzlCLE1BQU0sRUFBRSxDQUFDLGVBQWUsQ0FBQztZQUN6QixXQUFXLEVBQUU7Z0JBQ1gsUUFBUSxFQUFFLGVBQU0sQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEtBQUs7Z0JBQzlDLFlBQVksRUFBRSxlQUFNLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxLQUFLO2FBQ25EO1lBQ0QsS0FBSztTQUNOLENBQUMsQ0FBQztJQUNMLENBQUM7O0FBbEVILHNEQW1FQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgZ2l0aHViIH0gZnJvbSAncHJvamVuJztcblxuLy8gTmlnaHRseSBlbnZpcm9ubWVudC1yZWdyZXNzaW9uIGNhbmFyeSAoQUQtMDAxL0YwMDYpOiByZS1ydW5zIHRoZSBzYW1lXG4vLyBzY2VuYXJpbyBhZ2FpbnN0IHNldHRsZWQgYG1haW5gIGluIHRvZGF5J3MgcnVubmVyIGltYWdlLCBpbmRlcGVuZGVudCBvZlxuLy8gdGhlIHB1bGxfcmVxdWVzdCBnYXRlLiBRdWlldCBVVEMgaG91cjsgYSBjb21wb25lbnQgY29uc3RhbnQsIG5vdCBhXG4vLyBwcm9qZWN0IG9wdGlvbiAtIHVwZ3JhZGluZyBpdCBpcyBhIHJldmlld2VkIGRpZmYuXG5jb25zdCBOSUdIVExZX0RPR0ZPT0RfU0NIRURVTEUgPSAnMTcgMyAqICogKic7XG5cbi8qKlxuICogT25lIGludm9jYXRpb24gb2YgdGhlIGFjdGlvbiB3aXRoaW4gdGhlIGRvZ2Zvb2Qgc2NlbmFyaW86IG9wdGlvbmFsIGZpeHR1cmVcbiAqIHNldHVwLCB0aGUgYHVzZXM6IC5gIGNhbGwgd2l0aCB0aGlzIHN0ZXAncyBpbnB1dHMsIHRoZW4gdGhpcyBzdGVwJ3NcbiAqIGFzc2VydGlvbnMuIE1vc3QgYWN0aW9ucyBuZWVkIGV4YWN0bHkgb25lOyBhY3Rpb25zIHdpdGggYSByZS1ydW4vbm8tb3BcbiAqIGJlaGF2aW9yIHRvIHZlcmlmeSAoZS5nLiBGMDA2J3MgcmV1c2UtdGhlLVBSIHBhdGgsIEYwMDcncyBuby1vcC1jb21taXRcbiAqIHBhdGgpIGRlY2xhcmUgdHdvLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFjdGlvbkRvZ2Zvb2RTdGVwIHtcbiAgLyoqIExhYmVsIHVzZWQgdG8gbmFtZSB0aGlzIHN0ZXAtZ3JvdXAncyBnZW5lcmF0ZWQgd29ya2Zsb3cgc3RlcHMuICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogU3RlcCBpZCBmb3IgdGhlIGB1c2VzOiAuYCBpbnZvY2F0aW9uLCBzbyBhIGxhdGVyIGFzc2VydGlvbiBjYW5cbiAgICogcmVmZXJlbmNlIHRoaXMgc3RlcCdzIG91dHB1dHMgdmlhIGAke3sgc3RlcHMuPGlkPi5vdXRwdXRzLjxuYW1lPiB9fWAuXG4gICAqIEBkZWZhdWx0IC0gYSBzbHVnIGRlcml2ZWQgZnJvbSBgbmFtZWAsIGRpc2FtYmlndWF0ZWQgYnkgcG9zaXRpb25cbiAgICovXG4gIHJlYWRvbmx5IGlkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTaGVsbCBzdGVwcyBleGVjdXRlZCBiZWZvcmUgdGhpcyBpbnZvY2F0aW9uLCB0byBwcm9kdWNlIG9yIGFsdGVyXG4gICAqIGZpeHR1cmUgc3RhdGUuXG4gICAqIEBkZWZhdWx0IFtdXG4gICAqL1xuICByZWFkb25seSBmaXh0dXJlU3RlcHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogYHdpdGg6YCBpbnB1dHMgZm9yIHRoaXMgaW52b2NhdGlvbidzIGxvY2FsIGB1c2VzOiAuYCBjYWxsLlxuICAgKiBAZGVmYXVsdCB7fVxuICAgKi9cbiAgcmVhZG9ubHkgaW5wdXRzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcblxuICAvKiogU2hlbGwgYXNzZXJ0aW9ucyBhZnRlciB0aGlzIGludm9jYXRpb24gLSB0aGUgam9iIGZhaWxzIHVubGVzcyBldmVyeSBvbmUgZXhpdHMgMC4gKi9cbiAgcmVhZG9ubHkgYXNzZXJ0aW9uczogc3RyaW5nW107XG59XG5cbi8vIExvd2VyY2FzZSwgbm9uLWFscGhhbnVtZXJpY3MgY29sbGFwc2VkIHRvIGEgc2luZ2xlIGAtYCwgdHJpbW1lZCAtIHRoZW5cbi8vIGRpc2FtYmlndWF0ZWQgYnkgcG9zaXRpb24gc28gdHdvIHN0ZXBzIHNoYXJpbmcgYSBuYW1lIChvciBhbiB1bm5hbWVkXG4vLyBzbHVnLCBlLmcuIHB1bmN0dWF0aW9uLW9ubHkpIG5ldmVyIGNvbGxpZGUuXG5mdW5jdGlvbiBzbHVnKG5hbWU6IHN0cmluZywgaW5kZXg6IG51bWJlcik6IHN0cmluZyB7XG4gIGNvbnN0IGJhc2UgPSBuYW1lXG4gICAgLnRvTG93ZXJDYXNlKClcbiAgICAucmVwbGFjZSgvW15hLXowLTldKy9nLCAnLScpXG4gICAgLnJlcGxhY2UoL14tK3wtKyQvZywgJycpO1xuICByZXR1cm4gYCR7YmFzZSB8fCAnc3RlcCd9LSR7aW5kZXh9YDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpb25Eb2dmb29kT3B0aW9ucyB7XG4gIC8qKiBPbmUgb3IgbW9yZSBzY2VuYXJpbyBzdGVwcywgcnVuIGluIG9yZGVyLCBpbiB0aGUgZG9nZm9vZCBqb2IuICovXG4gIHJlYWRvbmx5IHNjZW5hcmlvOiBBY3Rpb25Eb2dmb29kU3RlcFtdO1xuXG4gIC8qKiBTaGVsbCBjbGVhbnVwLCBydW4gb25jZSBhdCB0aGUgZW5kIHdpdGggYGlmOiBhbHdheXMoKWAsIHNvIHJlcGVhdGVkIHJ1bnMgc3RhcnQgY2xlYW4uICovXG4gIHJlYWRvbmx5IGNsZWFudXA6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFBlciBBRC0wMDEncyBkb2dmb29kIHRlc3Q6IHRoZSBjb21wb3NpdGUgYWN0aW9uIGlzIHJ1biAqKmFnYWluc3QgdGhpc1xuICogcmVwbyoqLCBlbmQtdG8tZW5kLCB2aWEgYSBsb2NhbCBgdXNlczogLmAgcmVmZXJlbmNlIC0gbm8gZXh0ZXJuYWwgaGFybmVzcy5cbiAqIEJ1aWxkcyBgdGVzdC1kb2dmb29kLnltbGAgZnJvbSBhbiBvcmRlcmVkIGBzY2VuYXJpb2Agb2YgaW52b2NhdGlvbiBzdGVwc1xuICogKHNlZSBgQWN0aW9uRG9nZm9vZFN0ZXBgKSBmb2xsb3dlZCBieSBhIHNoYXJlZCBjbGVhbnVwIHN0ZXAuXG4gKi9cbmV4cG9ydCBjbGFzcyBBY3Rpb25Eb2dmb29kV29ya2Zsb3cgZXh0ZW5kcyBDb21wb25lbnQge1xuICBwdWJsaWMgcmVhZG9ubHkgd29ya2Zsb3c6IGdpdGh1Yi5HaXRodWJXb3JrZmxvdztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogZ2l0aHViLkdpdEh1YlByb2plY3QsIG9wdGlvbnM6IEFjdGlvbkRvZ2Zvb2RPcHRpb25zKSB7XG4gICAgc3VwZXIoc2NvcGUsICdBY3Rpb25Eb2dmb29kV29ya2Zsb3cnKTtcblxuICAgIGlmICghb3B0aW9ucy5zY2VuYXJpbyB8fCBvcHRpb25zLnNjZW5hcmlvLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnQWN0aW9uRG9nZm9vZFdvcmtmbG93IHJlcXVpcmVzIGF0IGxlYXN0IG9uZSBkb2dmb29kLnNjZW5hcmlvIHN0ZXAnLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zLmNsZWFudXAgfHwgb3B0aW9ucy5jbGVhbnVwLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY3Rpb25Eb2dmb29kV29ya2Zsb3cgcmVxdWlyZXMgZG9nZm9vZC5jbGVhbnVwJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZ2ggPSBzY29wZS5naXRodWI7XG4gICAgaWYgKCFnaCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnQWN0aW9uRG9nZm9vZFdvcmtmbG93IHJlcXVpcmVzIEdpdEh1YiBpbnRlZ3JhdGlvbiB0byBiZSBlbmFibGVkJyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RlcHM6IGdpdGh1Yi53b3JrZmxvd3MuSm9iU3RlcFtdID0gW2dpdGh1Yi5Xb3JrZmxvd1N0ZXBzLmNoZWNrb3V0KCldO1xuXG4gICAgb3B0aW9ucy5zY2VuYXJpby5mb3JFYWNoKChzdGVwLCBpbmRleCkgPT4ge1xuICAgICAgaWYgKHN0ZXAuZml4dHVyZVN0ZXBzICYmIHN0ZXAuZml4dHVyZVN0ZXBzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc3RlcHMucHVzaCh7XG4gICAgICAgICAgbmFtZTogYCR7c3RlcC5uYW1lfTogZml4dHVyZWAsXG4gICAgICAgICAgcnVuOiBzdGVwLmZpeHR1cmVTdGVwcy5qb2luKCdcXG4nKSxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhhc0lucHV0cyA9IHN0ZXAuaW5wdXRzICYmIE9iamVjdC5rZXlzKHN0ZXAuaW5wdXRzKS5sZW5ndGggPiAwO1xuICAgICAgc3RlcHMucHVzaCh7XG4gICAgICAgIGlkOiBzdGVwLmlkID8/IHNsdWcoc3RlcC5uYW1lLCBpbmRleCksXG4gICAgICAgIG5hbWU6IGAke3N0ZXAubmFtZX06IHJ1biB0aGUgYWN0aW9uYCxcbiAgICAgICAgdXNlczogJy4nLFxuICAgICAgICAuLi4oaGFzSW5wdXRzID8geyB3aXRoOiBzdGVwLmlucHV0cyB9IDoge30pLFxuICAgICAgfSk7XG5cbiAgICAgIHN0ZXBzLnB1c2goe1xuICAgICAgICBuYW1lOiBgJHtzdGVwLm5hbWV9OiBhc3NlcnRgLFxuICAgICAgICBydW46IHN0ZXAuYXNzZXJ0aW9ucy5qb2luKCdcXG4nKSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgc3RlcHMucHVzaCh7XG4gICAgICBuYW1lOiAnQ2xlYW51cCcsXG4gICAgICBpZjogJ2Fsd2F5cygpJyxcbiAgICAgIHJ1bjogb3B0aW9ucy5jbGVhbnVwLmpvaW4oJ1xcbicpLFxuICAgIH0pO1xuXG4gICAgdGhpcy53b3JrZmxvdyA9IG5ldyBnaXRodWIuR2l0aHViV29ya2Zsb3coZ2gsICd0ZXN0LWRvZ2Zvb2QnKTtcbiAgICB0aGlzLndvcmtmbG93Lm9uKHtcbiAgICAgIHdvcmtmbG93RGlzcGF0Y2g6IHt9LFxuICAgICAgcHVsbFJlcXVlc3Q6IHsgYnJhbmNoZXM6IFsnbWFpbiddIH0sXG4gICAgICBzY2hlZHVsZTogW3sgY3JvbjogTklHSFRMWV9ET0dGT09EX1NDSEVEVUxFIH1dLFxuICAgIH0pO1xuICAgIHRoaXMud29ya2Zsb3cuYWRkSm9iKCdkb2dmb29kJywge1xuICAgICAgcnVuc09uOiBbJ3VidW50dS1sYXRlc3QnXSxcbiAgICAgIHBlcm1pc3Npb25zOiB7XG4gICAgICAgIGNvbnRlbnRzOiBnaXRodWIud29ya2Zsb3dzLkpvYlBlcm1pc3Npb24uV1JJVEUsXG4gICAgICAgIHB1bGxSZXF1ZXN0czogZ2l0aHViLndvcmtmbG93cy5Kb2JQZXJtaXNzaW9uLldSSVRFLFxuICAgICAgfSxcbiAgICAgIHN0ZXBzLFxuICAgIH0pO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,25 @@
1
+ import { Component, github } from 'projen';
2
+ export interface ActionSonarWorkflowOptions {
3
+ /**
4
+ * URL of the org's self-hosted SonarQube instance. Required, no default -
5
+ * a guessed server is worse than a loud failure.
6
+ */
7
+ readonly sonarHostUrl: string;
8
+ /** @default "SONAR_TOKEN" */
9
+ readonly sonarTokenSecret?: string;
10
+ /**
11
+ * Whether `sonar.yml` also runs on `pull_request` as a pass/fail gate.
12
+ * @default true
13
+ */
14
+ readonly sonarPullRequestGate?: boolean;
15
+ }
16
+ /**
17
+ * AD-001 Layer 2: self-hosted SonarQube Community Edition via the Scanner
18
+ * CLI only (never `SonarSource/sonarqube-scan-action` - third-party, and it
19
+ * carried a security advisory). `sonar.inclusions` is set explicitly since
20
+ * default inclusions may skip `action.yml` outside `.github/`.
21
+ */
22
+ export declare class ActionSonarWorkflow extends Component {
23
+ readonly workflow: github.GithubWorkflow;
24
+ constructor(scope: github.GitHubProject, options: ActionSonarWorkflowOptions);
25
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ActionSonarWorkflow = void 0;
4
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
5
+ const projen_1 = require("projen");
6
+ // Pinned release + verified SHA-256 (linux-x64) - upgrade is a reviewed diff
7
+ // of this constant, never a floating version (AD-001).
8
+ const SONAR_SCANNER_VERSION = '8.1.0.6389';
9
+ const SONAR_SCANNER_SHA256 = 'bb8f709f9cb73352f8d1260a3b3c506c0f41146754bc630762c126d795499d0b';
10
+ /**
11
+ * AD-001 Layer 2: self-hosted SonarQube Community Edition via the Scanner
12
+ * CLI only (never `SonarSource/sonarqube-scan-action` - third-party, and it
13
+ * carried a security advisory). `sonar.inclusions` is set explicitly since
14
+ * default inclusions may skip `action.yml` outside `.github/`.
15
+ */
16
+ class ActionSonarWorkflow extends projen_1.Component {
17
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@xpertss/projen-types.ActionSonarWorkflow", version: "0.0.2" };
18
+ workflow;
19
+ constructor(scope, options) {
20
+ super(scope, 'ActionSonarWorkflow');
21
+ if (!options.sonarHostUrl) {
22
+ throw new Error('ActionSonarWorkflow requires sonarHostUrl');
23
+ }
24
+ const gh = scope.github;
25
+ if (!gh) {
26
+ throw new Error('ActionSonarWorkflow requires GitHub integration to be enabled');
27
+ }
28
+ const sonarTokenSecret = options.sonarTokenSecret ?? 'SONAR_TOKEN';
29
+ const pullRequestGate = options.sonarPullRequestGate ?? true;
30
+ this.workflow = new projen_1.github.GithubWorkflow(gh, 'sonar');
31
+ this.workflow.on({
32
+ push: { branches: ['main'] },
33
+ ...(pullRequestGate ? { pullRequest: {} } : {}),
34
+ });
35
+ this.workflow.addJob('sonar', {
36
+ runsOn: ['ubuntu-latest'],
37
+ permissions: { contents: projen_1.github.workflows.JobPermission.READ },
38
+ env: { SONAR_TOKEN: `\${{ secrets.${sonarTokenSecret} }}` },
39
+ steps: [
40
+ projen_1.github.WorkflowSteps.checkout(),
41
+ {
42
+ name: 'Install sonar-scanner',
43
+ run: `set -euo pipefail
44
+ curl -fsSL -o /tmp/sonar-scanner.zip "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux-x64.zip"
45
+ echo "${SONAR_SCANNER_SHA256} /tmp/sonar-scanner.zip" | sha256sum -c -
46
+ unzip -q /tmp/sonar-scanner.zip -d /tmp
47
+ echo "/tmp/sonar-scanner-${SONAR_SCANNER_VERSION}-linux-x64/bin" >> "$GITHUB_PATH"
48
+ `,
49
+ },
50
+ {
51
+ name: 'Scan',
52
+ run: `sonar-scanner \\
53
+ -Dsonar.host.url=${options.sonarHostUrl} \\
54
+ -Dsonar.projectKey=${scope.name} \\
55
+ -Dsonar.projectVersion="$(git describe --tags --always)" \\
56
+ -Dsonar.inclusions=.github/workflows/**,action.yml,**/*.sh \\
57
+ -Dsonar.qualitygate.wait=true`,
58
+ },
59
+ ],
60
+ });
61
+ }
62
+ }
63
+ exports.ActionSonarWorkflow = ActionSonarWorkflow;
64
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXNvbmFyLXdvcmtmbG93LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FjdGlvbnMvYWN0aW9uLXNvbmFyLXdvcmtmbG93LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxtQ0FBMkM7QUFFM0MsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxNQUFNLHFCQUFxQixHQUFHLFlBQVksQ0FBQztBQUMzQyxNQUFNLG9CQUFvQixHQUN4QixrRUFBa0UsQ0FBQztBQW1CckU7Ozs7O0dBS0c7QUFDSCxNQUFhLG1CQUFvQixTQUFRLGtCQUFTOztJQUNoQyxRQUFRLENBQXdCO0lBRWhELFlBQ0UsS0FBMkIsRUFDM0IsT0FBbUM7UUFFbkMsS0FBSyxDQUFDLEtBQUssRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO1FBRXBDLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFFRCxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNSLE1BQU0sSUFBSSxLQUFLLENBQ2IsK0RBQStELENBQ2hFLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLElBQUksYUFBYSxDQUFDO1FBQ25FLE1BQU0sZUFBZSxHQUFHLE9BQU8sQ0FBQyxvQkFBb0IsSUFBSSxJQUFJLENBQUM7UUFFN0QsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLGVBQU0sQ0FBQyxjQUFjLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZELElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2YsSUFBSSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDNUIsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztTQUNoRCxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7WUFDNUIsTUFBTSxFQUFFLENBQUMsZUFBZSxDQUFDO1lBQ3pCLFdBQVcsRUFBRSxFQUFFLFFBQVEsRUFBRSxlQUFNLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUU7WUFDOUQsR0FBRyxFQUFFLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixnQkFBZ0IsS0FBSyxFQUFFO1lBQzNELEtBQUssRUFBRTtnQkFDTCxlQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRTtnQkFDL0I7b0JBQ0UsSUFBSSxFQUFFLHVCQUF1QjtvQkFDN0IsR0FBRyxFQUFFOzBIQUMyRyxxQkFBcUI7UUFDdkksb0JBQW9COzsyQkFFRCxxQkFBcUI7Q0FDL0M7aUJBQ1E7Z0JBQ0Q7b0JBQ0UsSUFBSSxFQUFFLE1BQU07b0JBQ1osR0FBRyxFQUFFO3FCQUNNLE9BQU8sQ0FBQyxZQUFZO3VCQUNsQixLQUFLLENBQUMsSUFBSTs7O2dDQUdEO2lCQUN2QjthQUNGO1NBQ0YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUF0REgsa0RBdURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBnaXRodWIgfSBmcm9tICdwcm9qZW4nO1xuXG4vLyBQaW5uZWQgcmVsZWFzZSArIHZlcmlmaWVkIFNIQS0yNTYgKGxpbnV4LXg2NCkgLSB1cGdyYWRlIGlzIGEgcmV2aWV3ZWQgZGlmZlxuLy8gb2YgdGhpcyBjb25zdGFudCwgbmV2ZXIgYSBmbG9hdGluZyB2ZXJzaW9uIChBRC0wMDEpLlxuY29uc3QgU09OQVJfU0NBTk5FUl9WRVJTSU9OID0gJzguMS4wLjYzODknO1xuY29uc3QgU09OQVJfU0NBTk5FUl9TSEEyNTYgPVxuICAnYmI4ZjcwOWY5Y2I3MzM1MmY4ZDEyNjBhM2IzYzUwNmMwZjQxMTQ2NzU0YmM2MzA3NjJjMTI2ZDc5NTQ5OWQwYic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQWN0aW9uU29uYXJXb3JrZmxvd09wdGlvbnMge1xuICAvKipcbiAgICogVVJMIG9mIHRoZSBvcmcncyBzZWxmLWhvc3RlZCBTb25hclF1YmUgaW5zdGFuY2UuIFJlcXVpcmVkLCBubyBkZWZhdWx0IC1cbiAgICogYSBndWVzc2VkIHNlcnZlciBpcyB3b3JzZSB0aGFuIGEgbG91ZCBmYWlsdXJlLlxuICAgKi9cbiAgcmVhZG9ubHkgc29uYXJIb3N0VXJsOiBzdHJpbmc7XG5cbiAgLyoqIEBkZWZhdWx0IFwiU09OQVJfVE9LRU5cIiAqL1xuICByZWFkb25seSBzb25hclRva2VuU2VjcmV0Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIGBzb25hci55bWxgIGFsc28gcnVucyBvbiBgcHVsbF9yZXF1ZXN0YCBhcyBhIHBhc3MvZmFpbCBnYXRlLlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBzb25hclB1bGxSZXF1ZXN0R2F0ZT86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQUQtMDAxIExheWVyIDI6IHNlbGYtaG9zdGVkIFNvbmFyUXViZSBDb21tdW5pdHkgRWRpdGlvbiB2aWEgdGhlIFNjYW5uZXJcbiAqIENMSSBvbmx5IChuZXZlciBgU29uYXJTb3VyY2Uvc29uYXJxdWJlLXNjYW4tYWN0aW9uYCAtIHRoaXJkLXBhcnR5LCBhbmQgaXRcbiAqIGNhcnJpZWQgYSBzZWN1cml0eSBhZHZpc29yeSkuIGBzb25hci5pbmNsdXNpb25zYCBpcyBzZXQgZXhwbGljaXRseSBzaW5jZVxuICogZGVmYXVsdCBpbmNsdXNpb25zIG1heSBza2lwIGBhY3Rpb24ueW1sYCBvdXRzaWRlIGAuZ2l0aHViL2AuXG4gKi9cbmV4cG9ydCBjbGFzcyBBY3Rpb25Tb25hcldvcmtmbG93IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgcHVibGljIHJlYWRvbmx5IHdvcmtmbG93OiBnaXRodWIuR2l0aHViV29ya2Zsb3c7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IGdpdGh1Yi5HaXRIdWJQcm9qZWN0LFxuICAgIG9wdGlvbnM6IEFjdGlvblNvbmFyV29ya2Zsb3dPcHRpb25zLFxuICApIHtcbiAgICBzdXBlcihzY29wZSwgJ0FjdGlvblNvbmFyV29ya2Zsb3cnKTtcblxuICAgIGlmICghb3B0aW9ucy5zb25hckhvc3RVcmwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQWN0aW9uU29uYXJXb3JrZmxvdyByZXF1aXJlcyBzb25hckhvc3RVcmwnKTtcbiAgICB9XG5cbiAgICBjb25zdCBnaCA9IHNjb3BlLmdpdGh1YjtcbiAgICBpZiAoIWdoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdBY3Rpb25Tb25hcldvcmtmbG93IHJlcXVpcmVzIEdpdEh1YiBpbnRlZ3JhdGlvbiB0byBiZSBlbmFibGVkJyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgc29uYXJUb2tlblNlY3JldCA9IG9wdGlvbnMuc29uYXJUb2tlblNlY3JldCA/PyAnU09OQVJfVE9LRU4nO1xuICAgIGNvbnN0IHB1bGxSZXF1ZXN0R2F0ZSA9IG9wdGlvbnMuc29uYXJQdWxsUmVxdWVzdEdhdGUgPz8gdHJ1ZTtcblxuICAgIHRoaXMud29ya2Zsb3cgPSBuZXcgZ2l0aHViLkdpdGh1YldvcmtmbG93KGdoLCAnc29uYXInKTtcbiAgICB0aGlzLndvcmtmbG93Lm9uKHtcbiAgICAgIHB1c2g6IHsgYnJhbmNoZXM6IFsnbWFpbiddIH0sXG4gICAgICAuLi4ocHVsbFJlcXVlc3RHYXRlID8geyBwdWxsUmVxdWVzdDoge30gfSA6IHt9KSxcbiAgICB9KTtcbiAgICB0aGlzLndvcmtmbG93LmFkZEpvYignc29uYXInLCB7XG4gICAgICBydW5zT246IFsndWJ1bnR1LWxhdGVzdCddLFxuICAgICAgcGVybWlzc2lvbnM6IHsgY29udGVudHM6IGdpdGh1Yi53b3JrZmxvd3MuSm9iUGVybWlzc2lvbi5SRUFEIH0sXG4gICAgICBlbnY6IHsgU09OQVJfVE9LRU46IGBcXCR7eyBzZWNyZXRzLiR7c29uYXJUb2tlblNlY3JldH0gfX1gIH0sXG4gICAgICBzdGVwczogW1xuICAgICAgICBnaXRodWIuV29ya2Zsb3dTdGVwcy5jaGVja291dCgpLFxuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ0luc3RhbGwgc29uYXItc2Nhbm5lcicsXG4gICAgICAgICAgcnVuOiBgc2V0IC1ldW8gcGlwZWZhaWxcbmN1cmwgLWZzU0wgLW8gL3RtcC9zb25hci1zY2FubmVyLnppcCBcImh0dHBzOi8vYmluYXJpZXMuc29uYXJzb3VyY2UuY29tL0Rpc3RyaWJ1dGlvbi9zb25hci1zY2FubmVyLWNsaS9zb25hci1zY2FubmVyLWNsaS0ke1NPTkFSX1NDQU5ORVJfVkVSU0lPTn0tbGludXgteDY0LnppcFwiXG5lY2hvIFwiJHtTT05BUl9TQ0FOTkVSX1NIQTI1Nn0gIC90bXAvc29uYXItc2Nhbm5lci56aXBcIiB8IHNoYTI1NnN1bSAtYyAtXG51bnppcCAtcSAvdG1wL3NvbmFyLXNjYW5uZXIuemlwIC1kIC90bXBcbmVjaG8gXCIvdG1wL3NvbmFyLXNjYW5uZXItJHtTT05BUl9TQ0FOTkVSX1ZFUlNJT059LWxpbnV4LXg2NC9iaW5cIiA+PiBcIiRHSVRIVUJfUEFUSFwiXG5gLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ1NjYW4nLFxuICAgICAgICAgIHJ1bjogYHNvbmFyLXNjYW5uZXIgXFxcXFxuICAtRHNvbmFyLmhvc3QudXJsPSR7b3B0aW9ucy5zb25hckhvc3RVcmx9IFxcXFxcbiAgLURzb25hci5wcm9qZWN0S2V5PSR7c2NvcGUubmFtZX0gXFxcXFxuICAtRHNvbmFyLnByb2plY3RWZXJzaW9uPVwiJChnaXQgZGVzY3JpYmUgLS10YWdzIC0tYWx3YXlzKVwiIFxcXFxcbiAgLURzb25hci5pbmNsdXNpb25zPS5naXRodWIvd29ya2Zsb3dzLyoqLGFjdGlvbi55bWwsKiovKi5zaCBcXFxcXG4gIC1Ec29uYXIucXVhbGl0eWdhdGUud2FpdD10cnVlYCxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,60 @@
1
+ import { github, release } from 'projen';
2
+ import { ActionBuildWorkflow } from './action-build-workflow';
3
+ import { ActionDogfoodOptions, ActionDogfoodWorkflow } from './action-dogfood-workflow';
4
+ import { ActionSonarWorkflow } from './action-sonar-workflow';
5
+ export interface GitHubActionProjectOptions extends github.GitHubProjectOptions {
6
+ /**
7
+ * One-line description of the action. Used in the default README
8
+ * template and recorded in the private `package.json`.
9
+ */
10
+ readonly description?: string;
11
+ /**
12
+ * Name of the GitHub Actions secret holding the PAT used for
13
+ * projen-automation PR comments (F003/F009) and, when the action has a
14
+ * `token` input, the dogfood's invocation of it.
15
+ * @default "PROJEN_GITHUB_TOKEN"
16
+ */
17
+ readonly gheTokenSecret?: string;
18
+ /**
19
+ * URL of the org's self-hosted SonarQube instance. MUST be reachable from
20
+ * github.com-hosted (public) runners (AD-001). Required, no default: a
21
+ * guessed server is worse than a loud failure.
22
+ */
23
+ readonly sonarHostUrl: string;
24
+ /** @default "SONAR_TOKEN" */
25
+ readonly sonarTokenSecret?: string;
26
+ /**
27
+ * Whether `sonar.yml` also runs on `pull_request` as a pass/fail gate.
28
+ * @default true
29
+ */
30
+ readonly sonarPullRequestGate?: boolean;
31
+ /**
32
+ * The dogfood scenario (AD-001). What fixture state, what to assert, and
33
+ * how to clean up are specified by the action's own F### spec - the
34
+ * highest-risk behavior of that action. Required: a default no-op
35
+ * dogfood would silently hollow out a load-bearing AD-001 workflow.
36
+ */
37
+ readonly dogfood: ActionDogfoodOptions;
38
+ /**
39
+ * SPDX identifier for the generated `LICENSE`.
40
+ * @default "MIT"
41
+ */
42
+ readonly license?: string;
43
+ }
44
+ /**
45
+ * Scaffolds the repo lifecycle (AD-001) around a hand-committed, composite
46
+ * (shell) GitHub Action: the `build`/`test-dogfood`/`sonar`/`release`
47
+ * workflows, versioning and release discipline, the F003 verify components,
48
+ * the F009 allowlist guard, and repo boilerplate (`tsconfig.json` for
49
+ * `.projenrc.ts`, a private version-source `package.json`, `.yamllint`,
50
+ * `LICENSE`, and a `README.md` template). The action's own content
51
+ * (`action.yml`, its shell scripts, `test/` fixtures) is authored by hand
52
+ * per the action's own F### spec - this type only lints it.
53
+ */
54
+ export declare class GitHubActionProject extends github.GitHubProject {
55
+ readonly buildWorkflow: ActionBuildWorkflow;
56
+ readonly dogfoodWorkflow: ActionDogfoodWorkflow;
57
+ readonly sonarWorkflow: ActionSonarWorkflow;
58
+ readonly release: release.Release;
59
+ constructor(options: GitHubActionProjectOptions);
60
+ }