diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..b536bb0d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +__tests__ +.github +.gitlab-ci-local diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bed6057..ad06439d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: # rebuild any PRs and main branch changes - master - 'releases/*' +env: + IMAGE_NAME: wrapper-validation + jobs: build: # make sure build/ci work properly runs-on: ubuntu-latest @@ -22,3 +25,49 @@ jobs: with: # to allow the invalid wrapper jar present in test data allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + + push: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + + steps: + - uses: actions/checkout@v2 + + - name: Build image + run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" + + - name: Setting up GitLab CI + run: | + npm install -g gitlab-ci-local + mkdir -p .gitlab-ci-local + echo "global:" > .gitlab-ci-local/variables.yml + echo " IMAGE_NAME: $IMAGE_NAME" >> .gitlab-ci-local/variables.yml + + - name: Testing GitLab CI + run: | + cat .gitlab-ci-local/variables.yml + gitlab-ci-local --home ./ --file __tests__/.gitlab-ci.yml + + - name: Log in to registry + # This is where you will update the PAT to GITHUB_TOKEN + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + if: github.event_name != 'pull_request' + - name: Push image + run: | + IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME + + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + # Strip git ref prefix from version + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + # Strip "v" prefix from tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + # Use Docker `latest` tag convention + [ "$VERSION" == "master" ] && VERSION=latest + echo IMAGE_ID=$IMAGE_ID + echo VERSION=$VERSION + docker tag $IMAGE_NAME $IMAGE_ID:$VERSION + docker push $IMAGE_ID:$VERSION + if: github.event_name != 'pull_request' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..152f1add --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM node:12-slim + +WORKDIR /app + +COPY . . + +RUN npm install && npm run-script build && npm install -g + +ENTRYPOINT [ "wrapper-validation" ] diff --git a/README.md b/README.md index 1e7cfe5a..93300f62 100644 --- a/README.md +++ b/README.md @@ -104,3 +104,11 @@ Regardless of what you find, we still kindly request that you reach out to us an To learn more about verifying the Gradle Wrapper JAR locally, see our [guide on the topic](https://docs.gradle.org/current/userguide/gradle_wrapper.html#wrapper_checksum_verification). + + +## Usage in GitLab CI + +```yaml +include: + - remote: https://raw.githubusercontent.com/gradle/wrapper-validation-action/master/WrapperValidation.gitlab-ci.yml +``` \ No newline at end of file diff --git a/WrapperValidation.gitlab-ci.yml b/WrapperValidation.gitlab-ci.yml new file mode 100644 index 00000000..5db9bc3d --- /dev/null +++ b/WrapperValidation.gitlab-ci.yml @@ -0,0 +1,7 @@ +validate-wrapper: + stage: .pre + image: + name: ghcr.io/aepfli/wrapper-validation:latest + entrypoint: [""] + script: + - wrapper-validation diff --git a/__tests__/.gitlab-ci.yml b/__tests__/.gitlab-ci.yml new file mode 100644 index 00000000..515b5d64 --- /dev/null +++ b/__tests__/.gitlab-ci.yml @@ -0,0 +1,51 @@ + + +include: + - local: WrapperValidation.gitlab-ci.yml + +.false-test: + script: + - wrapper-validation && false || true + +job: + stage: .pre + script: + - echo "IMAGE $IMAGE_NAME" + +validate-wrapper: + image: + name: $IMAGE_NAME + entrypoint: [""] + stage: test + before_script: + - cd __tests__/data/valid + +validate-wrapper-numbers: + extends: + - validate-wrapper + variables: + MIN_WRAPPER_COUNT: 1 + +.validate-wrapper-invalid: + extends: + - validate-wrapper + before_script: + - cd __tests__/data/invalid + +validate-wrapper-invalid-with-checksum: + extends: + - .validate-wrapper-invalid + variables: + ALLOW_CHECKSUMS: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + +validate-wrapper-invalid-failing: + extends: + - .validate-wrapper-invalid + - .false-test + +validate-wrapper-invalid-numbers-exceeded: + extends: + - .validate-wrapper-invalid + - .false-test + variables: + MIN_WRAPPER_COUNT: 3 diff --git a/package-lock.json b/package-lock.json index 896aedcb..53c95640 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1731,6 +1731,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/js-yaml": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.3.tgz", + "integrity": "sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg==", + "dev": true + }, "@types/json-schema": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", @@ -1738,9 +1744,9 @@ "dev": true }, "@types/node": { - "version": "12.20.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.16.tgz", - "integrity": "sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==", + "version": "12.20.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.33.tgz", + "integrity": "sha512-5XmYX2GECSa+CxMYaFsr2mrql71Q4EvHjKS+ox/SiwSdaASMoBIWE6UmZqFO+VX1jIcsYLStI4FFoB6V7FeIYw==", "dev": true }, "@types/prettier": { @@ -2507,6 +2513,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz", + "integrity": "sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", diff --git a/package.json b/package.json index 299e6073..419f151c 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "private": true, "description": "Gradle Wrapper Validation Action", "main": "lib/main.js", + "bin": { + "wrapper-validation": "lib/main.js" + }, "scripts": { "build": "tsc", "format": "prettier --write **/*.ts", @@ -26,22 +29,24 @@ "license": "MIT", "dependencies": { "@actions/core": "1.4.0", + "commander": "^8.2.0", "typed-rest-client": "1.8.4", "unhomoglyph": "1.0.6" }, "devDependencies": { - "@types/node": "12.20.16", + "@types/js-yaml": "^4.0.3", + "@types/node": "^12.20.33", "@typescript-eslint/parser": "4.28.4", "@vercel/ncc": "0.29.0", "eslint": "7.31.0", "eslint-plugin-github": "4.1.5", "eslint-plugin-jest": "24.4.0", + "glob-parent": ">=5.1.2", "jest": "27.0.6", - "js-yaml": "4.1.0", + "js-yaml": "^4.1.0", "nock": "13.1.1", "prettier": "2.3.2", "ts-jest": "27.0.4", - "typescript": "4.0.8", - "glob-parent": ">=5.1.2" + "typescript": "4.0.8" } } diff --git a/src/main.ts b/src/main.ts old mode 100644 new mode 100755 index bb1cd20a..491dfc92 --- a/src/main.ts +++ b/src/main.ts @@ -1,25 +1,74 @@ -import * as path from 'path' -import * as core from '@actions/core' +#!/usr/bin/env node -import * as validate from './validate' +import { resolve, dirname } from 'path' +import { promises as fs } from 'fs' +import { setFailed, getInput, info } from '@actions/core' + +import { findInvalidWrapperJars } from './validate' +import { Command, Option } from 'commander' +import jsyaml from 'js-yaml' + +interface Action { + name: string; + description: string; + author: string; + inputs: Map; +} + +interface Input { + description: string; + required?: boolean; + default?: string; +} export async function run(): Promise { try { - const result = await validate.findInvalidWrapperJars( - path.resolve('.'), - +core.getInput('min-wrapper-count'), - core.getInput('allow-snapshots') === 'true', - core.getInput('allow-checksums').split(',') + let minWrapperCount: number + let allowSnapshots: string + let allowChecksums: string + + if (process.env.GITHUB_ACTION) { + minWrapperCount = +getInput('min-wrapper-count') + allowSnapshots = getInput('allow-snapshots') + allowChecksums = getInput('allow-checksums') + + } else { + const program = new Command() + const actionYaml = jsyaml.load(await fs.readFile(dirname(require.main?.filename ??'') + '/../action.yml', 'utf8')) as Action + + program + .description(actionYaml.description) + + Object.entries(actionYaml.inputs).forEach(([key, value]) => { + program.addOption( + new Option(`--${key} `, value.description) + .default(value.default) + .env(key.toLocaleUpperCase().replace(/-/g, '_'))) + }) + + program.parse(process.argv) + const options = program.opts() + minWrapperCount = +options.minWrapperCount + allowSnapshots = options.allowSnapshots + allowChecksums = options.allowChecksums + } + + const result = await findInvalidWrapperJars( + resolve('.'), + minWrapperCount, + allowSnapshots === 'true', + allowChecksums.split(',') ) if (result.isValid()) { - core.info(result.toDisplayString()) + info(result.toDisplayString()) } else { - core.setFailed( + setFailed( `Gradle Wrapper Validation Failed!\n See https://github.com/gradle/wrapper-validation-action#reporting-failures\n${result.toDisplayString()}` ) } } catch (error) { - core.setFailed(error.message) + if (error instanceof Error) + setFailed(error.message) } }