├── data ├── Archive 2022.zip └── Archive 2024.zip ├── .gitignore ├── repo_data ├── Archive 2022.zip └── Archive 2024.zip ├── json_to_repositories.jq ├── tests ├── label_BAR.json ├── label_foo.json ├── label_foo_bar_baz.json └── jq_tests.bats ├── LICENSE ├── json_to_csv.jq ├── README.md ├── hacktoberfest-repositories.sh └── counter-generate-csv.sh /data/Archive 2022.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkins-infra/jenkins-hacktoberfest-stats/main/data/Archive 2022.zip -------------------------------------------------------------------------------- /data/Archive 2024.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkins-infra/jenkins-hacktoberfest-stats/main/data/Archive 2024.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | jenkinsci*.json 2 | jenkins-infra*.json 3 | hacktoberfest-repo*.json 4 | hacktoberfest*.csv 5 | .vsc/ 6 | .idea 7 | -------------------------------------------------------------------------------- /repo_data/Archive 2022.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkins-infra/jenkins-hacktoberfest-stats/main/repo_data/Archive 2022.zip -------------------------------------------------------------------------------- /repo_data/Archive 2024.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkins-infra/jenkins-hacktoberfest-stats/main/repo_data/Archive 2024.zip -------------------------------------------------------------------------------- /json_to_repositories.jq: -------------------------------------------------------------------------------- 1 | map(.items) 2 | | add 3 | | map( 4 | [ 5 | .owner.login, 6 | (.html_url | split("/") | last), 7 | .html_url 8 | ] 9 | )[] 10 | | @csv 11 | -------------------------------------------------------------------------------- /tests/label_BAR.json: -------------------------------------------------------------------------------- 1 | { 2 | "total_count": 1, 3 | "incomplete_results": false, 4 | "items": [ 5 | { 6 | "repository_url": "https://api.github.com/repos/jenkinsci/workflow-api-plugin", 7 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 8 | "title": "Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents", 9 | "user": { 10 | "login": "bats" 11 | }, 12 | "labels": [ 13 | { 14 | "name": "BAR" 15 | }, 16 | { 17 | "name": "other_label" 18 | } 19 | ], 20 | "state": "closed", 21 | "locked": false, 22 | "created_at": "2019-10-04T15:53:45Z", 23 | "updated_at": "2021-11-23T17:51:50Z", 24 | "closed_at": "2019-11-19T20:43:26Z", 25 | "draft": false, 26 | "pull_request": { 27 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 28 | "merged_at": "2019-11-19T20:43:26Z" 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /tests/label_foo.json: -------------------------------------------------------------------------------- 1 | { 2 | "total_count": 1, 3 | "incomplete_results": false, 4 | "items": [ 5 | { 6 | "repository_url": "https://api.github.com/repos/jenkinsci/workflow-api-plugin", 7 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 8 | "title": "Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents", 9 | "user": { 10 | "login": "bats" 11 | }, 12 | "labels": [ 13 | { 14 | "name": "foo" 15 | }, 16 | { 17 | "name": "other_label" 18 | } 19 | ], 20 | "state": "closed", 21 | "locked": false, 22 | "created_at": "2019-10-04T15:53:45Z", 23 | "updated_at": "2021-11-23T17:51:50Z", 24 | "closed_at": "2019-11-19T20:43:26Z", 25 | "draft": false, 26 | "pull_request": { 27 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 28 | "merged_at": "2019-11-19T20:43:26Z" 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /tests/label_foo_bar_baz.json: -------------------------------------------------------------------------------- 1 | { 2 | "total_count": 1, 3 | "incomplete_results": false, 4 | "items": [ 5 | { 6 | "repository_url": "https://api.github.com/repos/jenkinsci/workflow-api-plugin", 7 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 8 | "title": "Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents", 9 | "user": { 10 | "login": "bats" 11 | }, 12 | "labels": [ 13 | { 14 | "name": "foo_bar_baz" 15 | }, 16 | { 17 | "name": "other_label" 18 | } 19 | ], 20 | "state": "closed", 21 | "locked": false, 22 | "created_at": "2019-10-04T15:53:45Z", 23 | "updated_at": "2021-11-23T17:51:50Z", 24 | "closed_at": "2019-11-19T20:43:26Z", 25 | "draft": false, 26 | "pull_request": { 27 | "html_url": "https://github.com/jenkinsci/workflow-api-plugin/pull/107", 28 | "merged_at": "2019-11-19T20:43:26Z" 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jean-Marc MEESSEN 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /json_to_csv.jq: -------------------------------------------------------------------------------- 1 | ($accepted_arg | split(",") | map(ltrimstr(" ") | rtrimstr(" ") | ascii_downcase) ) as $accepted_arr 2 | | map(.items) 3 | | add 4 | | map( 5 | select( 6 | # Spec: - Status is either open or merged 7 | ((.state == "open" or .pull_request.merged_at != null) and (.user.type != "Bot")) 8 | ) 9 | # Spec: Produce a CSV list of PRs with following details: PR URL, PR Title, Repository, Status (Open, Merged), Creation date, Merge date (if applicable), PR Author, Is flag “Hacktoberfest-approved” set? 10 | | [ 11 | $org, 12 | # Hacky, but requires far less API calls 13 | (.repository_url | split("/") | last), 14 | .html_url, 15 | .state, 16 | .created_at, 17 | .pull_request.merged_at, 18 | .user.login, 19 | any(.labels[]; .name | test($hacktoberfest_labeled; "i")), 20 | ([$accepted_arr[] as $accepted | any(.labels[]; .name | ascii_downcase == $accepted)] | any), # Spec: Is flag “Hacktoberfest-approved” set? 21 | any(.labels[]; .name | test($spam; "i")), # Spec: Additional labels should be reported in the result (true/false): spam 22 | any(.labels[]; .name | test($invalid; "i")), # Spec: Additional labels should be reported in the result (true/false): invalid 23 | (.title | split("\n") | first) 24 | 25 | ] 26 | )[] 27 | | @csv -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jenkins-hacktoberfest-stats 2 | 3 | A set of scripts to monitor the Hacktoberfest participation in the Jenkins projects. 4 | 5 | The main script is `counter-generate-csv.sh` (it will automatically call the repository query). 6 | The results are stored in the `data` sub-directory and are time-stamped. 7 | - the list of all PRs created in the `jenkinsci` and `jenkin-infra` orgs is available in `data/hacktoberfest_raw_.csv`. 8 | - the list of potential hacktoberfest PR with their status is available in `data/hacktoberfest_.csv`. The latest version is stored as `data/hacktoberfest_latest.csv`. 9 | - the list of the number of validated PR per contributor is available in `data/hacktoberfest_contributors_.csv`. The latest version is stored as `data/hacktoberfest_contributors_latest.csv` 10 | 11 | The main script relies on the list of repos in both organisations that are welcoming hacktoberfest PRs. This list is computed by the `hacktoberfest_repositories.sh` script. 12 | The results are stored in the `repo_data` sub-directory and are also timestamped. 13 | - the list of participating repositories stored in `repo_data/hacktoberfest_repos_.csv`. The latest version is stored as `repo_data/hacktoberfest_repos_latest.csv`. 14 | - a summary, listing the number of participating repositories per organisation, is available as `repo_data/hacktoberfest_repos_summary_.csv`. The latest verstion is stored as `repo_data/hacktoberfest_repos_summary_latest.csv`. 15 | 16 | The scripts require the following tools to be installed: 17 | 18 | - `gh`: GitHub command line tool 19 | - `jq`: Json query tool 20 | - `datamash`: CSV data manipulation tool 21 | 22 | Special thanks to Jean-Marc Desprez (@jmdesprez)for having provided the original scripts. 23 | 24 | # Results 25 | ## 2024 26 | - Total number of PRs created in jenkinsci and jenkins-infra orgs: `1086` 27 | - Total Hacktoberfest PRs: `231` (by `63` contributors) 28 | - Total validated Hacktoberfest PRs: `209` (by `56` contributors) 29 | -------------------------------------------------------------------------------- /hacktoberfest-repositories.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check whether required tools are available 4 | if ! command -v "gh" >/dev/null 2>&1 5 | then 6 | echo "ERROR: command line 'gh' required but not found. Exiting." 7 | exit 1 8 | fi 9 | 10 | if ! command -v "jq" >/dev/null 2>&1 11 | then 12 | echo "ERROR: command line 'jq' required but not found. Exiting." 13 | exit 1 14 | fi 15 | 16 | if ! command -v "datamash" >/dev/null 2>&1 17 | then 18 | echo "ERROR: command line 'datamash' required but not found. Exiting." 19 | exit 1 20 | fi 21 | 22 | ## Configurations 23 | query='org:jenkins-docs org:jenkinsci org:jenkins-infra topic:hacktoberfest fork:true' 24 | 25 | # CSV files 26 | current_time=$(date "+%Y%m%d-%H%M%S") 27 | data_filename_root="repo_data/hacktoberfest_repos" 28 | filename_latest="${data_filename_root}_latest.csv" 29 | summary_filename_latest="${data_filename_root}_summary_latest.csv" 30 | filename="${data_filename_root}_${current_time}.csv" 31 | summary_filename="${data_filename_root}_summary_$current_time.csv" 32 | 33 | # Create the data directory if it doesn't exist yet 34 | [ -d repo_data ] || mkdir repo_data 35 | [ -d json_data ] || mkdir json_data 36 | ## 37 | 38 | # Function to get repositories based on the query 39 | getRepositories() { 40 | local json_filename="json_data/hacktoberfest-repositories" 41 | 42 | # Remove any existing JSON files 43 | rm -f "$json_filename"*.json 44 | local url_encoded_query 45 | url_encoded_query=$(jq --arg query "$query" --raw-output --null-input '$query|@uri') 46 | local page=1 47 | while true; do 48 | echo "$json_filename get page $page" 49 | gh api -H "Accept: application/vnd.github+json" "/search/repositories?q=$url_encoded_query&sort=updated&order=desc&per_page=100&page=$page" >"$json_filename$page.json" 50 | # Less accurate, can make 1 useless call if the number of issues is a multiple of 100 51 | if test "$(jq --raw-output '.items|length' "$json_filename$page.json")" -ne 100; then 52 | break 53 | fi 54 | ((page++)) 55 | done 56 | 57 | # Combine JSON files into a CSV 58 | jq --raw-output --slurp --from-file json_to_repositories.jq "$json_filename"*.json >>"$filename" 59 | } 60 | 61 | # Initialize the CSV file with headers 62 | echo 'org,name,url' >"$filename" 63 | 64 | # Fetch repositories based on the query 65 | getRepositories 66 | 67 | # Summarize the data and print it 68 | echo "---------------------------------------" 69 | cat $filename | datamash -t, --sort --headers groupby 1 count 1 > "$summary_filename" 70 | cat $summary_filename 71 | echo "---------------------------------------" 72 | nbr_repos=$(wc -l < <(tail -n +2 ${filename})) 73 | echo "Total number of repositories: ${nbr_repos}" 74 | echo "---------------------------------------" 75 | 76 | # Update the latest files 77 | cp $filename $filename_latest 78 | cp $summary_filename $summary_filename_latest 79 | -------------------------------------------------------------------------------- /counter-generate-csv.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ###### 4 | # This script retrieves information from GitHub to track Hacktoberfest participation in the Jenkins project. 5 | # The resulting data is enriched and made available as a CSV. 6 | ###### 7 | 8 | set -e 9 | 10 | # Check whether required tools are available 11 | if ! command -v "gh" >/dev/null 2>&1 12 | then 13 | echo "ERROR: command line 'gh' required but not found. Exiting." 14 | exit 1 15 | fi 16 | 17 | if ! command -v "jq" >/dev/null 2>&1 18 | then 19 | echo "ERROR: command line 'jq' required but not found. Exiting." 20 | exit 1 21 | fi 22 | 23 | if ! command -v "datamash" >/dev/null 2>&1 24 | then 25 | echo "ERROR: command line 'datamash' required but not found. Exiting." 26 | exit 1 27 | fi 28 | 29 | ### Setting up constants 30 | 31 | # We exclude the PRs created by dependabot and renovate and those created outside the period 32 | hacktoberfest_year=$(date "+%Y") 33 | query="is:pr -author:app/dependabot -author:app/renovate" 34 | 35 | # Spec: is "hacktoberfest" flag set? 36 | label_hacktoberfest='\bhacktoberfest\b' 37 | 38 | # Spec: Is flag “Hacktoberfest-approved” set? (case insensitive) 39 | label_accepted='Hacktoberfest-accepted, Hacktoberfest-approved' 40 | # Additional labels should be reported in the result (true/false): spam, invalid 41 | label_spam_regex='\bspam\b' 42 | label_invalid_regex='\binvalid\b' 43 | 44 | # CSV files 45 | current_time=$(date "+%Y%m%d-%H%M%S") 46 | data_filename_root="data/hacktoberfest" 47 | raw_csv_filename="${data_filename_root}_raw_${current_time}.csv" 48 | csv_filename="${data_filename_root}_${current_time}.csv" 49 | csv_filename_latest="${data_filename_root}_latest.csv" 50 | summaryFileContribs="${data_filename_root}_contributors_$current_time.csv" 51 | summaryFileContribs_latest="${data_filename_root}_contributors_latest.csv" 52 | 53 | # CSV file with the hacktoberfest repositories 54 | repos_csv_file="repo_data/hacktoberfest_repos_latest.csv" 55 | 56 | # Create the data directory if it doesn't exist 57 | [ -d data ] || mkdir data 58 | [ -d json_data ] || mkdir json_data 59 | ## 60 | 61 | # Function to facilitate checking whether a PR is complete and acceptable for Hacktoberfest 62 | isAccepted() { 63 | local merge_date="$2" 64 | local hacktoberfest_approved="$1" 65 | 66 | # Is the merge_date empty? 67 | if [ -z "$merge_date" ] 68 | then 69 | # It has not been merged 70 | if test "$hacktoberfest_approved" == "true" 71 | then 72 | echo "1" 73 | else 74 | echo "0" 75 | fi 76 | else 77 | # The PR has been merged 78 | echo "1" 79 | fi 80 | } 81 | 82 | # Loops through the raw CSV to see if the PR is a hacktoberfest candidate 83 | lookupHacktoberfestTopic() { 84 | local raw_csv_file="$1" 85 | local output_csv_file="$2" 86 | 87 | echo "output: ${output_csv_file}" 88 | 89 | ## Create header in output 90 | echo 'org,repository,is_hacktoberfest_repo,url,state,created_at,merged_at,user.login,is_hacktoberfest_labeled,approved,spam,invalid,hacktoberfest_complete,title' >"$output_csv_file" 91 | 92 | while IFS="," read -r org repository url state created_at merged_at user_login is_hacktoberfest_labeled approved spam invalid title 93 | do 94 | trimmed_repository="$(echo "${repository}" | xargs)" 95 | if test "$(grep -c "/${trimmed_repository}\"" "${repos_csv_file}")" -eq 1 96 | then 97 | is_hacktoberfest_repo="true" 98 | hacktoberfest_complete=$(isAccepted $approved $merged_at ) 99 | echo "$org,$repository,$is_hacktoberfest_repo,$url,$state,$created_at,$merged_at,$user_login,$is_hacktoberfest_labeled,$approved,$spam,$invalid,$hacktoberfest_complete,$title" >> "${output_csv_file}" 100 | else 101 | is_hacktoberfest_repo="false" 102 | # It might be a PR tagged "hacktoberfest" or "hacktoberfest-accepted" 103 | if test "$is_hacktoberfest_labeled" == "true" || test "$approved" == "true" 104 | then 105 | hacktoberfest_complete=$(isAccepted $approved $merged_at) 106 | echo "$org,$repository,$is_hacktoberfest_repo,$url,$state,$created_at,$merged_at,$user_login,$is_hacktoberfest_labeled,$approved,$spam,$invalid,$hacktoberfest_complete,$title" >> "${output_csv_file}" 107 | fi 108 | fi 109 | done < <(tail -n +2 ${raw_csv_file}) 110 | } 111 | 112 | # Function that retrieves and processes the GitHub information for a given organization and date range 113 | getOrganizationData() { 114 | local org="$1" 115 | local start_date="$2" 116 | local end_date="$3" 117 | local json_filename="json_data/${org}_${start_date}_to_${end_date}" 118 | 119 | rm -f "$json_filename"*.json 120 | local url_encoded_query 121 | url_encoded_query=$(jq --arg query "org:$org $query created:$start_date..$end_date" --raw-output --null-input '$query|@uri') 122 | local page=1 123 | while true; do 124 | echo "org: $org get page $page for date range $start_date to $end_date" 125 | gh api -H "Accept: application/vnd.github+json Retry-After: 30" "/search/issues?q=$url_encoded_query&sort=updated&order=desc&per_page=100&page=$page" >"$json_filename$page.json" 126 | # Less accurate, can make 1 useless call if the number of issues is a multiple of 100 127 | if test "$(jq --raw-output '.items|length' "$json_filename$page.json")" -ne 100; then 128 | break 129 | fi 130 | ((page++)) 131 | # Dirty trick to avoid hitting secondary rate limit. 132 | sleep 15 133 | done 134 | 135 | jq --arg org "$org" --arg hacktoberfest_labeled "$label_hacktoberfest" --arg accepted_arg "$label_accepted" --arg spam "$label_spam_regex" --arg invalid "$label_invalid_regex" --raw-output --slurp --from-file json_to_csv.jq "$json_filename"*.json >>"$raw_csv_filename" 136 | } 137 | 138 | # Spec: Produce a CSV list of PRs with following details: PR URL, PR Title, Repository, Status (Open, Merged), Creation date, Merge date (if applicable), PR Author, Is flag “Hacktoberfest-approved” set? 139 | echo 'org,repository,url,state,created_at,merged_at,user.login,is_hacktoberfest_labeled,approved,spam,invalid,title' >"$raw_csv_filename" 140 | 141 | # Loop through the weeks in October 142 | for start_date in {01..31..7}; do 143 | end_date=$(date -d "$hacktoberfest_year-10-$start_date +6 days" "+%Y-%m-%d") 144 | getOrganizationData jenkins-docs "$hacktoberfest_year-10-$start_date" "$end_date" 145 | getOrganizationData jenkinsci "$hacktoberfest_year-10-$start_date" "$end_date" 146 | getOrganizationData jenkins-infra "$hacktoberfest_year-10-$start_date" "$end_date" 147 | done 148 | 149 | # Update the list of participating repositories (only if it doesn't exist) 150 | if [ ! -f ${repos_csv_file} ] 151 | then 152 | ./hacktoberfest-repositories.sh 153 | fi 154 | 155 | # Look through the generated file and lookup the repositories that have the hacktoberfest topic 156 | lookupHacktoberfestTopic ${raw_csv_filename} ${csv_filename} 157 | 158 | # https://medium.com/clarityai-engineering/back-to-basics-how-to-analyze-files-with-gnu-commands-fe9f41665eb3 159 | # awk -F'"' -v OFS='"' '{for (i=2; i<=NF; i+=2) {gsub(",", "", $i)}}; $0' hacktoberfest_20220928-162143.csv 160 | awk -F'"' -v OFS='"' '{for (i=2; i<=NF; i+=2) {gsub(",", "", $i)}}; $0' $csv_filename | datamash -t, --sort --headers groupby 8 sum 13 > "$summaryFileContribs" 161 | echo "----------------------------------------" 162 | cat $summaryFileContribs 163 | 164 | # Update the latest 165 | cp ${csv_filename} ${csv_filename_latest} 166 | cp $summaryFileContribs $summaryFileContribs_latest 167 | 168 | echo "----------------------------------------" 169 | echo " SUMMARY" 170 | echo "----------------------------------------" 171 | # Total not automated PRs in Jenkinsci and Jenkin-infra organisation 172 | wrk_raw_pr=$(cat ${raw_csv_filename} | wc -l) 173 | raw_pr=$(echo "${wrk_raw_pr}" | xargs) 174 | echo "Total number of PRs created in jenkins-docs, jenkinsci and jenkins-infra orgs: ${raw_pr}" 175 | set +x 176 | 177 | # Total Hacktoberfest PRs 178 | wrk_tot_pr=$(wc -l < <(tail -n +2 ${csv_filename})) 179 | tot_pr=$(echo "${wrk_tot_pr}" | xargs) 180 | # Total number of Hacktoberfest contributors 181 | wrk_tot_contributors=$(wc -l < <(tail -n +2 ${summaryFileContribs})) 182 | tot_contributors=$(echo "${wrk_tot_contributors}" | xargs) 183 | # Display these results 184 | echo "Total Hacktoberfest PRs: ${tot_pr} (by ${tot_contributors} contributors)" 185 | 186 | # Total number of validated hacktoberfest PRs 187 | wrk_tot_valid_pr=$(cat ${csv_filename}| grep ",1,\"" | wc -l) 188 | tot_valid_pr=$(echo "${wrk_tot_valid_pr}" | xargs) 189 | # Total number of Hacktoberfest contributors with valid PRs 190 | wrk_tot_valid_contributors=$(tail -n +2 $summaryFileContribs | grep -v "\",0" | wc -l) 191 | tot_valid_contributors=$(echo "${wrk_tot_valid_contributors}" | xargs) 192 | # Display these results 193 | echo "Total validated Hacktoberfest PRs: ${tot_valid_pr} (by ${tot_valid_contributors} contributors)" 194 | -------------------------------------------------------------------------------- /tests/jq_tests.bats: -------------------------------------------------------------------------------- 1 | @test "Empty json should produce 0 line" { 2 | run jq --arg org "test_org" --arg accepted_arg "foo" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq <<'JSON' 3 | { "total_count": 0, "incomplete_results": false, "items": [ ] } 4 | JSON 5 | 6 | [ "$status" -eq 0 ] 7 | [ "${lines[0]}" = "" ] 8 | } 9 | 10 | @test "Is approved lowercase" { 11 | run jq --arg org "test_org" --arg accepted_arg "foo" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 12 | [ "$status" -eq 0 ] 13 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",true,false,false' ] 14 | } 15 | 16 | @test "Is approved uppercase" { 17 | run jq --arg org "test_org" --arg accepted_arg "BAR" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_BAR.json" 18 | [ "$status" -eq 0 ] 19 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",true,false,false' ] 20 | } 21 | 22 | @test "Approved label must be exactly the same" { 23 | run jq --arg org "test_org" --arg accepted_arg "foo" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 24 | [ "$status" -eq 0 ] 25 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 26 | 27 | run jq --arg org "test_org" --arg accepted_arg "bar" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 28 | [ "$status" -eq 0 ] 29 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 30 | 31 | run jq --arg org "test_org" --arg accepted_arg "baz" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 32 | [ "$status" -eq 0 ] 33 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 34 | } 35 | 36 | @test "Is not approved" { 37 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 38 | [ "$status" -eq 0 ] 39 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 40 | } 41 | 42 | @test "Is spam lowercase" { 43 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "foo" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 44 | [ "$status" -eq 0 ] 45 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,true,false' ] 46 | } 47 | 48 | @test "Is spam uppercase" { 49 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "BAR" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_BAR.json" 50 | [ "$status" -eq 0 ] 51 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,true,false' ] 52 | } 53 | 54 | @test "Spam label regex is not global" { 55 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "foo" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 56 | [ "$status" -eq 0 ] 57 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,true,false' ] 58 | 59 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "bar" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 60 | [ "$status" -eq 0 ] 61 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,true,false' ] 62 | 63 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "baz" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 64 | [ "$status" -eq 0 ] 65 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,true,false' ] 66 | } 67 | 68 | @test "Is not spam" { 69 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 70 | [ "$status" -eq 0 ] 71 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 72 | } 73 | 74 | @test "Is invalid lowercase" { 75 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "foo" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 76 | [ "$status" -eq 0 ] 77 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,true' ] 78 | } 79 | 80 | @test "Is invalid uppercase" { 81 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "BAR" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_BAR.json" 82 | [ "$status" -eq 0 ] 83 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,true' ] 84 | } 85 | 86 | @test "Invalid label regex is not global" { 87 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "foo" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 88 | [ "$status" -eq 0 ] 89 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,true' ] 90 | 91 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "bar" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 92 | [ "$status" -eq 0 ] 93 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,true' ] 94 | 95 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "baz" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo_bar_baz.json" 96 | [ "$status" -eq 0 ] 97 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,true' ] 98 | } 99 | 100 | @test "Is not invalid" { 101 | run jq --arg org "test_org" --arg accepted_arg "accepted" --arg spam "spam" --arg invalid "invalid" --raw-output --slurp --from-file json_to_csv.jq "$BATS_TEST_DIRNAME/label_foo.json" 102 | [ "$status" -eq 0 ] 103 | [ "${lines[0]}" = '"test_org","https://github.com/jenkinsci/workflow-api-plugin/pull/107","Fix bad assertion in TestVisitor#assertNoIllegalNullsInEvents","workflow-api-plugin","closed","2019-10-04T15:53:45Z",,"bats",false,false,false' ] 104 | } 105 | 106 | @test "Test regex: ^ and $ are boundary" { 107 | run jq --arg regex '\bfoo\b' --null-input '"foo" | test($regex; "i")' 108 | [ "$status" -eq 0 ] 109 | [ "${lines[0]}" = 'true' ] 110 | } 111 | 112 | @test "Test regex: space is boundary" { 113 | run jq --arg regex '\bfoo\b' --null-input '" foo " | test($regex; "i")' 114 | [ "$status" -eq 0 ] 115 | [ "${lines[0]}" = 'true' ] 116 | } 117 | 118 | @test "Test regex: _ is NOT a boundary" { 119 | run jq --arg regex '\bfoo\b' --null-input '"_foo_" | test($regex; "i")' 120 | [ "$status" -eq 0 ] 121 | [ "${lines[0]}" = 'false' ] 122 | } 123 | 124 | @test "Test escape inline regex" { 125 | run jq --null-input '"foo" | test("\\bfoo\\b"; "i")' 126 | [ "$status" -eq 0 ] 127 | [ "${lines[0]}" = 'true' ] 128 | } 129 | --------------------------------------------------------------------------------