diff --git a/.github/codeowners b/.github/codeowners new file mode 100644 index 0000000..5f9c14d --- /dev/null +++ b/.github/codeowners @@ -0,0 +1,7 @@ +# Matched against repo root (asterisk) +* @mishraomp @paulushcgcj @DerekRoberts + +# Matched against directories +# /.github/workflows/ @mishraomp @paulushcgcj @DerekRoberts + +# See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners diff --git a/.github/workflows/pr-open.yml b/.github/workflows/pr-open.yml new file mode 100644 index 0000000..85abd1c --- /dev/null +++ b/.github/workflows/pr-open.yml @@ -0,0 +1,23 @@ +name: PR + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + needs: [build] + permissions: + packages: write + name: Retag + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - id: vars + uses: ./ + + - name: Echo PR number + run: echo "PR: ${{ steps.vars.outputs.pr }}" diff --git a/.gitignore b/.gitignore index c6bba59..6704566 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* -.pnpm-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -42,8 +41,8 @@ build/Release node_modules/ jspm_packages/ -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ +# TypeScript v1 declaration files +typings/ # TypeScript cache *.tsbuildinfo @@ -54,9 +53,6 @@ web_modules/ # Optional eslint cache .eslintcache -# Optional stylelint cache -.stylelintcache - # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ @@ -72,20 +68,15 @@ web_modules/ # Yarn Integrity file .yarn-integrity -# dotenv environment variable files +# dotenv environment variables file .env -.env.development.local -.env.test.local -.env.production.local -.env.local +.env.test # parcel-bundler cache (https://parceljs.org/) .cache -.parcel-cache # Next.js build output .next -out # Nuxt.js build / generate output .nuxt @@ -93,20 +84,13 @@ dist # Gatsby files .cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js +# Comment in the public line in if your project uses Gatsby and *not* Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - # Serverless directories .serverless/ @@ -118,13 +102,3 @@ dist # TernJS port file .tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* diff --git a/README.md b/README.md deleted file mode 100644 index e99f9ee..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# action-get-pr -Get PR number for merge and queue events diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..caed3a5 --- /dev/null +++ b/action.yml @@ -0,0 +1,161 @@ +name: Conditional Container Builder with Fallback +description: Build if trigger conditions are met, else use fallback image +branding: + icon: package + color: blue + +inputs: + ### Required + # Nothing! + + ### Typical / recommended + # Nothing! + + ### Usually a bad idea / not recommended + token: + description: Specify token (GH or PAT), instead of inheriting one from the calling workflow + default: ${{ github.token }} + +outputs: + pr: + description: 'Associated pull request number' + value: ${{ steps.vars.outputs.pr }} + +runs: + using: composite + steps: + # Process variables and inputs + - uses: actions/checkout@v4 + - id: vars + shell: bash + run: | + # Inputs and variables + + # Use package folder as build_context unless an override has been provided + if [ -z ${{ inputs.build_context }} ]; then + BUILD_CONTEXT=${{ inputs.package }} + else + BUILD_CONTEXT=${{ inputs.build_context }} + fi + echo "build_context=${BUILD_CONTEXT}" >> $GITHUB_OUTPUT + + # Use BUILD_CONTEXT/Dockerfile as build_file unless an override has been provided + if [ -z ${{ inputs.build_file }} ]; then + BUILD_FILE=${BUILD_CONTEXT}/Dockerfile + else + BUILD_FILE=${{ inputs.build_file }} + fi + echo "build_file=${BUILD_FILE}" >> $GITHUB_OUTPUT + + # Bug - Docker build hates images with capital letters + TAGS=$( echo "ghcr.io/${{ github.repository }}/${{ inputs.package }}:${{ inputs.tag }}" | tr '[:upper:]' '[:lower:]' ) + echo "tags=${TAGS//[$'\r\n ']}" >> $GITHUB_OUTPUT + + # Check if a build is required (steps.build.outputs.triggered=true|false) + - name: Check for builds + shell: bash + id: build + run: | + # Check for builds + + # Build if an override repository was provided + if [ "${{ inputs.repository }}" != "${{ github.repository }}" ]; then + echo "Build triggered on override repository" + echo "triggered=true" >> $GITHUB_OUTPUT + exit 0 + fi + + # Build if no tag_fallback or no triggers + if [ -z "${{ inputs.tag_fallback }}" ]||[ -z "${{ inputs.triggers }}" ]; then + echo "Build triggered with possible reasons:" + echo " a) tag_fallback provided" + echo " b) triggers not provided" + echo "triggered=true" >> $GITHUB_OUTPUT + exit 0 + fi + + # Build if tag_fallback is no good (requires a valid container) + FALLBACK=ghcr.io/${{ inputs.repository }}/${{ inputs.package }}:${{ inputs.tag_fallback }} + if [ "$(docker buildx imagetools inspect ${FALLBACK} || true | grep -qi '^Name:')" = "" ]; then + # Output triggered=true for next steps + echo "Build triggered. Fallback tag (tag_fallback) not usable." + echo "Manifest checked for: ghcr.io/${FALLBACK}" + echo "triggered=true" >> $GITHUB_OUTPUT + exit 0 + fi + + # Build if changed files (git diff) match triggers + TRIGGERS=${{ inputs.triggers }} + git fetch origin ${{ inputs.diff_branch }} + while read -r check; do + for t in "${TRIGGERS[@]}"; do + if [[ "${check}" =~ "${t}" ]]; then + # Output triggered=true for next steps + echo "Build triggered based on git diff" + echo -e "${t}\n --> ${check}" + echo "triggered=true" >> $GITHUB_OUTPUT + exit 0 + fi + done + done < <(git diff origin/${{ inputs.diff_branch }} --name-only) + + # If at this point, no build is required + echo "Container build not required" + echo "triggered=false" >> $GITHUB_OUTPUT + + # If a build is not required, reuse a previous image + - name: Recycle/retag Previous Images + uses: shrink/actions-docker-registry-tag@v3 + if: steps.build.outputs.triggered != 'true' + with: + registry: ghcr.io + repository: ${{ inputs.repository }}/${{ inputs.package }} + target: ${{ inputs.tag_fallback }} + tags: ${{ inputs.tag }} + + # If a build is required, then login, build and push! + - name: Set up Docker Buildx + if: steps.build.outputs.triggered == 'true' + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + if: steps.build.outputs.triggered == 'true' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ inputs.token }} + + - name: Build and push ${{ inputs.package }} Docker image + if: steps.build.outputs.triggered == 'true' + uses: docker/build-push-action@v5 + with: + context: ${{ steps.vars.outputs.build_context }} + file: ${{ steps.vars.outputs.build_file }} + push: true + tags: ${{ steps.vars.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: ${{ inputs.build_args }} + + # Cleanup if inputs.keep_versions provided + - name: GHCR Cleanup + if: ${{ inputs.keep_versions }} + uses: actions/delete-package-versions@v4 + with: + package-name: "${{ github.event.repository.name }}/${{ inputs.package }}" + package-type: "container" + min-versions-to-keep: ${{ inputs.keep_versions }} + ignore-versions: "${{ inputs.keep_regex }}" + + # Action repo needs to be present for cleanup/tests + - name: Checkout local repo to make sure action.yml is present + if: ${{ github.repository }} != ${{ inputs.repository }} + uses: actions/checkout@v4 + + - name: Return digest of the built image + id: get_digest + shell: bash + run: | + DIGEST=$(docker manifest inspect ${{ steps.vars.outputs.tags }} | jq '.manifests[0].digest') + echo "digest=${DIGEST}" >> $GITHUB_OUTPUT diff --git a/LICENSE b/license similarity index 100% rename from LICENSE rename to license diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..87d587b --- /dev/null +++ b/readme.md @@ -0,0 +1,42 @@ + +[![Issues](https://img.shields.io/github/issues/bcgov-nr/action-get-pr)](/../../issues) +[![Pull Requests](https://img.shields.io/github/issues-pr/bcgov-nr/action-get-pr)](/../../pulls) +[![MIT License](https://img.shields.io/github/license/bcgov-nr/action-get-pr.svg)](/LICENSE) +[![Lifecycle](https://img.shields.io/badge/Lifecycle-Experimental-339999)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md) + +# Get PR Number - Merges and Queues + +PR numbers are easy to come by in PRs, but passing those same numbers to merge queues and PR-backed merges can get tricky. This action makes that convenient in the following cases: +* PR merge queues +* Merged PR workflows +* PRs themselves (just for consistency) + +# Usage + +The build will return a PR number as output. + +```yaml +- id: vars + uses: bcgov-nr/action-get-pr@vX.Y.Z + +- name: Echo PR number + run: echo "PR: ${{ steps.vars.outputs.pr }}" +``` + +# Private Repositories + +Private repositories may need to provide a GitHub token. + +```yaml +- id: vars + uses: bcgov-nr/action-get-pr@vX.Y.Z + with: + token: ${{ secrets.GITHUB_TOKEN }} + +- name: Echo PR number + run: echo "PR: ${{ steps.vars.outputs.pr }}" +``` + + diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..fbf7e58 --- /dev/null +++ b/renovate.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "Presets from https://github.com/bcgov/nr-renovate", + "extends": [ + "github>bcgov/renovate-config" + ] +}