diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..2d04e26 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,3 @@ +# Add 'code-scanning' label to any changes within 'code-scanning' folder or any subfolders +code-scanning: +- code-scanning/**/* diff --git a/.github/workflows/labeler-triage.yml b/.github/workflows/labeler-triage.yml new file mode 100644 index 0000000..eba05f0 --- /dev/null +++ b/.github/workflows/labeler-triage.yml @@ -0,0 +1,16 @@ +name: "Pull Request Labeler" + +permissions: + contents: read + pull-requests: write + +on: +- pull_request_target + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v3 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 3732a32..8866d17 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,3 @@ -* @actions/actions-experience +* @actions/starter-workflows /code-scanning/ @actions/advanced-security-code-scanning diff --git a/README.md b/README.md index e276691..4b5b9f8 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,9 @@ These are the workflow files for helping people get started with GitHub Actions. -**Directory structure:** -* [ci](ci): solutions for Continuous Integration +### Directory structure + +* [ci](ci): solutions for Continuous Integration and Deployments * [automation](automation): solutions for automating workflows. * [code-scanning](code-scanning): starter workflows for [Code Scanning](https://github.com/features/security) * [icons](icons): svg icons for the relevant template @@ -20,8 +21,28 @@ Each workflow must be written in YAML and have a `.yml` extension. They also nee For example: `ci/django.yml` and `ci/properties/django.properties.json`. -**Valid properties:** -* `name`: the name shown in onboarding +### Valid properties + +* `name`: the name shown in onboarding. This property is unique within the repository. * `description`: the description shown in onboarding -* `iconName`: the icon name in the relevant folder, for example `django` should have an icon `icons/django.svg`. Only SVG is supported at this time -* `categories`: the categories that it will be shown under +* `iconName`: the icon name in the relevant folder, for example, `django` should have an icon `icons/django.svg`. Only SVG is supported at this time. Another option is to use [octicon](https://primer.style/octicons/). The format to use an octicon is `octicon <>`. Example: `octicon person` +* `creator`: creator of the template shown in onboarding. All the workflow templates from an author will have the same `creator` field. +* `categories`: the categories that it will be shown under. Choose at least one category from the list [here](#categories). Further, choose the categories from the list of languages available [here](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml). When a user views the available templates, those templates that match the same language will feature more prominently. + +### Categories +* continuous-integration +* deployment +* testing +* code-quality +* code-review +* dependency-management +* monitoring +* Automation +* utilities + +### Variables +These variables can be placed in the starter workflow and will be substituted as detailed below: + +* `$default-branch`: will substitute the branch from the repository, for example `main` and `master` +* `$protected-branches`: will substitue any protected branches from the repository. +* `$cron-daily`: will substitute a valid but random time within the day diff --git a/ci/android.yml b/ci/android.yml index 4bbc689..3037b9f 100644 --- a/ci/android.yml +++ b/ci/android.yml @@ -18,6 +18,7 @@ jobs: with: java-version: '11' distribution: 'adopt' + cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/ci/deno.yml b/ci/deno.yml index cf91f5e..38f2319 100644 --- a/ci/deno.yml +++ b/ci/deno.yml @@ -3,7 +3,7 @@ # separate terms of service, privacy policy, and support # documentation. -# This workflow will install Deno and run tests across stable and canary builds on Windows, Ubuntu and macOS. +# This workflow will install Deno then run Deno lint and test. # For more information see: https://github.com/denoland/setup-deno name: Deno @@ -16,12 +16,7 @@ on: jobs: test: - runs-on: ${{ matrix.os }} # runs a test on Ubuntu, Windows and macOS - - strategy: - matrix: - deno: ["v1.x", "canary"] - os: [macOS-latest, windows-latest, ubuntu-latest] + runs-on: ubuntu-latest steps: - name: Setup repo @@ -29,9 +24,9 @@ jobs: - name: Setup Deno # uses: denoland/setup-deno@v1 - uses: denoland/setup-deno@4a4e59637fa62bd6c086a216c7e4c5b457ea9e79 + uses: denoland/setup-deno@004814556e37c54a2f6e31384c9e18e9833173669 with: - deno-version: ${{ matrix.deno }} # tests across multiple Deno versions + deno-version: v1.x # Uncomment this step to verify the use of 'deno fmt' on each commit. # - name: Verify formatting @@ -40,8 +35,5 @@ jobs: - name: Run linter run: deno lint - - name: Cache dependencies - run: deno cache deps.ts - - name: Run tests run: deno test -A --unstable diff --git a/ci/go.yml b/ci/go.yml index 22a110a..afff652 100644 --- a/ci/go.yml +++ b/ci/go.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - name: Build run: go build -v ./... diff --git a/ci/gradle.yml b/ci/gradle.yml index 6e7e922..5ecabba 100644 --- a/ci/gradle.yml +++ b/ci/gradle.yml @@ -1,4 +1,4 @@ -# This workflow will build a Java project with Gradle +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle name: Java CI with Gradle @@ -21,6 +21,7 @@ jobs: with: java-version: '11' distribution: 'adopt' + cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle diff --git a/ci/grunt.yml b/ci/grunt.yml new file mode 100644 index 0000000..8c83cb6 --- /dev/null +++ b/ci/grunt.yml @@ -0,0 +1,28 @@ +name: NodeJS with Grunt + +on: + push: + branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x, 14.x, 16.x] + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Build + run: | + npm install + grunt diff --git a/ci/gulp.yml b/ci/gulp.yml new file mode 100644 index 0000000..cc5da13 --- /dev/null +++ b/ci/gulp.yml @@ -0,0 +1,28 @@ +name: NodeJS with Gulp + +on: + push: + branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x, 14.x, 16.x] + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Build + run: | + npm install + gulp diff --git a/ci/ios.yml b/ci/ios.yml index 032b77a..ab92d32 100644 --- a/ci/ios.yml +++ b/ci/ios.yml @@ -26,7 +26,7 @@ jobs: platform: ${{ 'iOS Simulator' }} run: | # xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959) - device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}'`` + device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}'` if [ $scheme = default ]; then scheme=$(cat default); fi if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi file_to_build=`echo $file_to_build | awk '{$1=$1;print}'` diff --git a/ci/maven.yml b/ci/maven.yml index 923425b..ac3b6de 100644 --- a/ci/maven.yml +++ b/ci/maven.yml @@ -1,4 +1,4 @@ -# This workflow will build a Java project with Maven +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven name: Java CI with Maven @@ -21,5 +21,6 @@ jobs: with: java-version: '11' distribution: 'adopt' + cache: maven - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/ci/node.js.yml b/ci/node.js.yml index 2f60984..89b24fe 100644 --- a/ci/node.js.yml +++ b/ci/node.js.yml @@ -1,4 +1,4 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Node.js CI @@ -25,6 +25,7 @@ jobs: uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} + cache: 'npm' - run: npm ci - run: npm run build --if-present - run: npm test diff --git a/ci/npm-publish.yml b/ci/npm-publish.yml index 8462902..025976d 100644 --- a/ci/npm-publish.yml +++ b/ci/npm-publish.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 12 + node-version: 14 - run: npm ci - run: npm test @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 12 + node-version: 14 registry-url: https://registry.npmjs.org/ - run: npm ci - run: npm publish @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 12 + node-version: 14 registry-url: $registry-url(npm) - run: npm ci - run: npm publish diff --git a/ci/properties/blank.properties.json b/ci/properties/blank.properties.json index d244772..610327f 100644 --- a/ci/properties/blank.properties.json +++ b/ci/properties/blank.properties.json @@ -1,6 +1,7 @@ { "name": "Simple workflow", "description": "Start with a file with the minimum necessary structure.", + "creator": "GitHub", "iconName": "blank", "categories": null } diff --git a/ci/properties/gem-push.properties.json b/ci/properties/gem-push.properties.json index af43020..0002ac5 100644 --- a/ci/properties/gem-push.properties.json +++ b/ci/properties/gem-push.properties.json @@ -2,5 +2,5 @@ "name": "Ruby Gem", "description": "Pushes a Ruby Gem to RubyGems and GitHub Package Registry.", "iconName": "ruby-gems", - "categories": ["Continuous integration", "Ruby", "SDLC"] + "categories": ["Continuous integration", "Ruby"] } diff --git a/ci/properties/grunt.properties.json b/ci/properties/grunt.properties.json new file mode 100644 index 0000000..c8a5b9f --- /dev/null +++ b/ci/properties/grunt.properties.json @@ -0,0 +1,6 @@ +{ + "name": "Grunt", + "description": "Build a NodeJS project with npm and grunt.", + "iconName": "grunt", + "categories": ["JavaScript", "TypeScript", "npm", "Grunt"] +} diff --git a/ci/properties/gulp.properties.json b/ci/properties/gulp.properties.json new file mode 100644 index 0000000..658325b --- /dev/null +++ b/ci/properties/gulp.properties.json @@ -0,0 +1,6 @@ +{ + "name": "Gulp", + "description": "Build a NodeJS project with npm and gulp.", + "iconName": "gulp", + "categories": ["JavaScript", "TypeScript", "npm", "Gulp"] +} diff --git a/ci/properties/node.js.properties.json b/ci/properties/node.js.properties.json index 3b0b094..1939bd2 100644 --- a/ci/properties/node.js.properties.json +++ b/ci/properties/node.js.properties.json @@ -2,5 +2,5 @@ "name": "Node.js", "description": "Build and test a Node.js project with npm.", "iconName": "nodejs", - "categories": ["Continuous integration", "JavaScript", "Node", "Npm"] + "categories": ["Continuous integration", "JavaScript", "npm"] } diff --git a/ci/properties/npm-publish.properties.json b/ci/properties/npm-publish.properties.json index a1c3543..9371d7b 100644 --- a/ci/properties/npm-publish.properties.json +++ b/ci/properties/npm-publish.properties.json @@ -2,5 +2,5 @@ "name": "Publish Node.js Package", "description": "Publishes a Node.js package to npm and GitHub Packages.", "iconName": "node-package-transparent", - "categories": ["Continuous integration", "JavaScript", "SDLC"] + "categories": ["Continuous integration", "JavaScript", "npm"] } diff --git a/ci/properties/terraform.properties.json b/ci/properties/terraform.properties.json index bfeabdf..12afabe 100644 --- a/ci/properties/terraform.properties.json +++ b/ci/properties/terraform.properties.json @@ -3,5 +3,5 @@ "description": "Set up Terraform CLI in your GitHub Actions workflow.", "creator": "HashiCorp", "iconName": "terraform", - "categories": null + "categories": ["Deployment"] } diff --git a/ci/properties/webpack.properties.json b/ci/properties/webpack.properties.json new file mode 100644 index 0000000..1e22ccb --- /dev/null +++ b/ci/properties/webpack.properties.json @@ -0,0 +1,6 @@ +{ + "name": "Webpack", + "description": "Build a NodeJS project with npm and webpack.", + "iconName": "webpack", + "categories": ["JavaScript", "TypeScript", "npm", "Webpack"] +} diff --git a/ci/pylint.yml b/ci/pylint.yml index c16ba22..0805af7 100644 --- a/ci/pylint.yml +++ b/ci/pylint.yml @@ -9,10 +9,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v1 + - name: Set up Python 3.9 + uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/ci/r.yml b/ci/r.yml index efc6587..f257fbd 100644 --- a/ci/r.yml +++ b/ci/r.yml @@ -16,7 +16,7 @@ on: jobs: build: - runs-on: macOS-latest + runs-on: macos-latest strategy: matrix: r-version: [3.5, 3.6] diff --git a/ci/tencent.yml b/ci/tencent.yml index 1a059a6..0be339e 100644 --- a/ci/tencent.yml +++ b/ci/tencent.yml @@ -43,7 +43,7 @@ jobs: - name: Login TKE Registry run: | - docker login -u ${{ secrets.TENCENT_CLOUD_ACCOUNT_ID }} -p ${{ secrets.TKE_REGISTRY_PASSWORD }} ${TKE_IMAGE_URL} + docker login -u ${{ secrets.TENCENT_CLOUD_ACCOUNT_ID }} -p '${{ secrets.TKE_REGISTRY_PASSWORD }}' ${TKE_IMAGE_URL} # Push the Docker image to TKE Registry - name: Publish @@ -73,4 +73,4 @@ jobs: ./kustomize edit set image ${TKE_IMAGE_URL}:${GITHUB_SHA} ./kustomize build . | kubectl apply -f - kubectl rollout status deployment/${DEPLOYMENT_NAME} - kubectl get services -o wide \ No newline at end of file + kubectl get services -o wide diff --git a/ci/webpack.yml b/ci/webpack.yml new file mode 100644 index 0000000..8edb34f --- /dev/null +++ b/ci/webpack.yml @@ -0,0 +1,28 @@ +name: NodeJS with Webpack + +on: + push: + branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x, 14.x, 16.x] + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Build + run: | + npm install + npx webpack diff --git a/code-scanning/flawfinder.yml b/code-scanning/flawfinder.yml new file mode 100644 index 0000000..080953e --- /dev/null +++ b/code-scanning/flawfinder.yml @@ -0,0 +1,38 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: flawfinder + +on: + push: + branches: [ $default-branch, $protected-branches ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ $default-branch ] + schedule: + - cron: $cron-weekly + +jobs: + flawfinder: + name: Flawfinder + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: flawfinder_scan + uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c + with: + arguments: '--sarif ./' + output: 'flawfinder_results.sarif' + + - name: Upload analysis results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: ${{github.workspace}}/flawfinder_results.sarif \ No newline at end of file diff --git a/code-scanning/properties/devskim.properties.json b/code-scanning/properties/devskim.properties.json index 0eab5c6..40fd52b 100644 --- a/code-scanning/properties/devskim.properties.json +++ b/code-scanning/properties/devskim.properties.json @@ -1,7 +1,7 @@ { "name": "DevSkim", "creator": "Microsoft CST-E", - "description": "DevSkim is security linter that highlights common security issues in source code.", + "description": "DevSkim is a security linter that highlights common security issues in source code.", "iconName": "cst-logo", "categories": ["Code Scanning", "C", "C#", "C++", "Go", "Java", "JavaScript", "TypeScript", "Python", "Powershell", "Cobol", "Objective C", "PHP", "Ruby", "Rust", "SQL", "Swift", "Visual Basic"] } diff --git a/code-scanning/properties/flawfinder.properties.json b/code-scanning/properties/flawfinder.properties.json new file mode 100644 index 0000000..f784d03 --- /dev/null +++ b/code-scanning/properties/flawfinder.properties.json @@ -0,0 +1,7 @@ +{ + "name": "Flawfinder", + "creator": "David A. Wheeler", + "description": "Flawfinder is a simple program that scans C/C++ source code and reports potential security flaws.", + "iconName": "flawfinder", + "categories": [ "Code Scanning", "C", "C++" ] +} \ No newline at end of file diff --git a/code-scanning/properties/stackhawk.properties.json b/code-scanning/properties/stackhawk.properties.json new file mode 100644 index 0000000..f422535 --- /dev/null +++ b/code-scanning/properties/stackhawk.properties.json @@ -0,0 +1,24 @@ +{ + "name": "StackHawk", + "creator": "StackHawk", + "description": "Integrate dynamic application security testing (DAST) and API security testing into your CI pipeline with StackHawk", + "iconName": "stackhawk", + "categories": [ + "Code Scanning", + "C", + "C#", + "C++", + "Go", + "Java", + "JavaScript", + "Kotlin", + "Objective C", + "PHP", + "Python", + "Ruby", + "Rust", + "Scala", + "Swift", + "TypeScript" + ] +} diff --git a/code-scanning/stackhawk.yml b/code-scanning/stackhawk.yml new file mode 100644 index 0000000..9701b1f --- /dev/null +++ b/code-scanning/stackhawk.yml @@ -0,0 +1,57 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# 🦅 STACKHAWK https://stackhawk.com + +# The StackHawk HawkScan action makes it easy to integrate dynamic application security testing (DAST) into your +# CI pipeline. See the Getting Started guide (https://docs.stackhawk.com/hawkscan/) to get up and running with +# StackHawk quickly. + +# To use this workflow, you must: +# +# 1. Create an API Key and Application: Sign up for a free StackHawk account to obtain an API Key and +# create your first app and configuration file at https://app.stackhawk.com. +# +# 2. Save your API Key as a Secret: Save your API key as a GitHub Secret named HAWK_API_KEY. +# +# 3. Add your Config File: Add your stackhawk.yml configuration file to the base of your repository directory. +# +# 4. Set the Scan Failure Threshold: Add the hawk.failureThreshold configuration option +# (https://docs.stackhawk.com/hawkscan/configuration/#hawk) to your stackhawk.yml configuration file. If your scan +# produces alerts that meet or exceed the hawk.failureThreshold alert level, the scan will return exit code 42 +# and trigger a Code Scanning alert with a link to your scan results. +# +# 5. Update the "Start your service" Step: Update the "Start your service" step in the StackHawk workflow below to +# start your service so that it can be scanned with the "Run HawkScan" step. + + +name: "StackHawk" + +on: + push: + branches: [ $default-branch, $protected-branches ] + pull_request: + branches: [ $default-branch ] + schedule: + - cron: $cron-weekly + +jobs: + stackhawk: + name: StackHawk + runs-on: ubuntu-20.04 + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Start your service + run: ./your-service.sh & # ✏️ Update this to run your own service to be scanned + + - name: Run HawkScan + uses: stackhawk/hawkscan-action@4c3258cd62248dac6d9fe91dd8d45928c697dee0 + continue-on-error: true # ✏️ Set to false to break your build on scan errors + with: + apiKey: ${{ secrets.HAWK_API_KEY }} + codeScanningAlerts: true + githubToken: ${{ github.token }} diff --git a/icons/flawfinder.svg b/icons/flawfinder.svg new file mode 100644 index 0000000..2324dca --- /dev/null +++ b/icons/flawfinder.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/icons/stackhawk.svg b/icons/stackhawk.svg new file mode 100644 index 0000000..6b47520 --- /dev/null +++ b/icons/stackhawk.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/script/sync-ghes/index.ts b/script/sync-ghes/index.ts index 0fa3440..e37eca3 100755 --- a/script/sync-ghes/index.ts +++ b/script/sync-ghes/index.ts @@ -19,6 +19,8 @@ interface WorkflowProperties { iconName?: string; categories: string[] | null; + + creator?: string; } interface WorkflowsCheckResult { @@ -28,12 +30,14 @@ interface WorkflowsCheckResult { async function checkWorkflows( folders: string[], - enabledActions: string[] + enabledActions: string[], + partners: string[] ): Promise { const result: WorkflowsCheckResult = { compatibleWorkflows: [], incompatibleWorkflows: [], }; + const partnersSet = new Set(partners.map((x) => x.toLowerCase())); for (const folder of folders) { const dir = await fs.readdir(folder, { @@ -51,11 +55,10 @@ async function checkWorkflows( )); const iconName: string | undefined = workflowProperties["iconName"]; - const isBlankTemplate = workflowId === "blank"; - const partnerWorkflow = workflowProperties.categories === null; + const isPartnerWorkflow = workflowProperties.creator ? partnersSet.has(workflowProperties.creator.toLowerCase()) : false; const enabled = - (isBlankTemplate || !partnerWorkflow) && + !isPartnerWorkflow && (await checkWorkflow(workflowFilePath, enabledActions)); const workflowDesc: WorkflowDesc = { @@ -90,7 +93,6 @@ async function checkWorkflow( ): Promise { // Create set with lowercase action names for easier, case-insensitive lookup const enabledActionsSet = new Set(enabledActions.map((x) => x.toLowerCase())); - try { const workflowFileContent = await fs.readFile(workflowPath, "utf8"); const workflow = safeLoad(workflowFileContent); @@ -126,7 +128,8 @@ async function checkWorkflow( const result = await checkWorkflows( settings.folders, - settings.enabledActions + settings.enabledActions, + settings.partners ); console.group( diff --git a/script/sync-ghes/settings.json b/script/sync-ghes/settings.json index 050ea0a..60b70ed 100644 --- a/script/sync-ghes/settings.json +++ b/script/sync-ghes/settings.json @@ -16,5 +16,15 @@ "actions/starter-workflows", "actions/upload-artifact", "actions/upload-release-asset" + ], + "partners": [ + "Alibaba Cloud", + "Amazon Web Services", + "Microsoft Azure", + "Google Cloud", + "IBM", + "Red Hat", + "Tencent Cloud", + "HashiCorp" ] } diff --git a/script/validate-data/index.ts b/script/validate-data/index.ts index 81048f8..8413653 100755 --- a/script/validate-data/index.ts +++ b/script/validate-data/index.ts @@ -7,6 +7,7 @@ import { endGroup, error, info, setFailed, startGroup } from '@actions/core'; interface WorkflowWithErrors { id: string; + name: string; errors: string[]; } @@ -20,7 +21,7 @@ interface WorkflowProperties { const propertiesSchema = { type: "object", properties: { - name: { type: "string", required: true }, + name: { type: "string", required: true , "minLength": 1}, description: { type: "string", required: true }, creator: { type: "string", required: false }, iconName: { type: "string", required: true }, @@ -41,7 +42,7 @@ const propertiesSchema = { async function checkWorkflows(folders: string[]): Promise { const result: WorkflowWithErrors[] = [] - + const workflow_template_names = new Set() for (const folder of folders) { const dir = await fs.readdir(folder, { withFileTypes: true, @@ -54,9 +55,12 @@ async function checkWorkflows(folders: string[]): Promise const workflowFilePath = join(folder, e.name); const propertiesFilePath = join(folder, "properties", `${fileType}.properties.json`) - const errors = await checkWorkflow(workflowFilePath, propertiesFilePath); - if (errors.errors.length > 0) { - result.push(errors) + const workflowWithErrors = await checkWorkflow(workflowFilePath, propertiesFilePath); + if(workflowWithErrors.name && workflow_template_names.size == workflow_template_names.add(workflowWithErrors.name).size) { + workflowWithErrors.errors.push(`Workflow template name "${workflowWithErrors.name}" already exists`) + } + if (workflowWithErrors.errors.length > 0) { + result.push(workflowWithErrors) } } } @@ -68,6 +72,7 @@ async function checkWorkflows(folders: string[]): Promise async function checkWorkflow(workflowPath: string, propertiesPath: string): Promise { let workflowErrors: WorkflowWithErrors = { id: workflowPath, + name: null, errors: [] } @@ -77,17 +82,28 @@ async function checkWorkflow(workflowPath: string, propertiesPath: string): Prom const propertiesFileContent = await fs.readFile(propertiesPath, "utf8") const properties: WorkflowProperties = JSON.parse(propertiesFileContent) - + if(properties.name && properties.name.trim().length > 0) { + workflowErrors.name = properties.name + } let v = new validator(); const res = v.validate(properties, propertiesSchema) workflowErrors.errors = res.errors.map(e => e.toString()) - - if (properties.iconName && !properties.iconName.startsWith("octicon")) { - try { - await fs.access(`../../icons/${properties.iconName}.svg`) - } catch (e) { - workflowErrors.errors.push(`No icon named ${properties.iconName} found`) + + if (properties.iconName) { + if(! /^octicon\s+/.test(properties.iconName)) { + try { + await fs.access(`../../icons/${properties.iconName}.svg`) + } catch (e) { + workflowErrors.errors.push(`No icon named ${properties.iconName} found`) + } } + else { + let iconName = properties.iconName.match(/^octicon\s+(.*)/) + if(!iconName || iconName[1].split(".")[0].length <= 0) { + workflowErrors.errors.push(`No icon named ${properties.iconName} found`) + } + } + } } catch (e) { workflowErrors.errors.push(e.toString())